Imported Upstream version 0.0.1 84/145884/1 upstream upstream/0.0.1
authorchanywa <cbible.kim@samsung.com>
Thu, 24 Aug 2017 06:34:50 +0000 (15:34 +0900)
committerchanywa <cbible.kim@samsung.com>
Thu, 24 Aug 2017 06:42:40 +0000 (15:42 +0900)
Change-Id: I04965f3704f681495719ba73aab64daa1e7aaa99
Signed-off-by: chanywa <cbible.kim@samsung.com>
776 files changed:
.clang-format [new file with mode: 0644]
.gitignore [new file with mode: 0644]
.gitmodules [new file with mode: 0644]
.travis.yml [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
CONTRIBUTING.md [new file with mode: 0644]
ISSUE_TEMPLATE.md [new file with mode: 0644]
LICENSE [new file with mode: 0644]
Makefile [new file with mode: 0644]
README.md [new file with mode: 0644]
bench/CMakeLists.txt [new file with mode: 0644]
bench/src/builders.cpp [new file with mode: 0644]
bench/src/tileLoading.cpp [new file with mode: 0644]
circle.yml [new file with mode: 0644]
core/CMakeLists.txt [new file with mode: 0644]
core/deps/CMakeLists.txt [new file with mode: 0644]
core/deps/double-conversion/CMakeLists.txt [new file with mode: 0644]
core/deps/double-conversion/include/double-conversion.h [new file with mode: 0644]
core/deps/double-conversion/src/bignum-dtoa.cc [new file with mode: 0644]
core/deps/double-conversion/src/bignum-dtoa.h [new file with mode: 0644]
core/deps/double-conversion/src/bignum.cc [new file with mode: 0644]
core/deps/double-conversion/src/bignum.h [new file with mode: 0644]
core/deps/double-conversion/src/cached-powers.cc [new file with mode: 0644]
core/deps/double-conversion/src/cached-powers.h [new file with mode: 0644]
core/deps/double-conversion/src/diy-fp.cc [new file with mode: 0644]
core/deps/double-conversion/src/diy-fp.h [new file with mode: 0644]
core/deps/double-conversion/src/double-conversion.cc [new file with mode: 0644]
core/deps/double-conversion/src/fast-dtoa.cc [new file with mode: 0644]
core/deps/double-conversion/src/fast-dtoa.h [new file with mode: 0644]
core/deps/double-conversion/src/fixed-dtoa.cc [new file with mode: 0644]
core/deps/double-conversion/src/fixed-dtoa.h [new file with mode: 0644]
core/deps/double-conversion/src/ieee.h [new file with mode: 0644]
core/deps/double-conversion/src/strtod.cc [new file with mode: 0644]
core/deps/double-conversion/src/strtod.h [new file with mode: 0644]
core/deps/double-conversion/src/utils.h [new file with mode: 0644]
core/deps/glm/copying.txt [new file with mode: 0755]
core/deps/glm/glm/CMakeLists.txt [new file with mode: 0755]
core/deps/glm/glm/common.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_features.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_fixes.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_noise.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_swizzle.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_swizzle_func.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/_vectorize.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/dummy.cpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_common.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_common.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_common_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_exponential.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_exponential.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_exponential_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_geometric.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_geometric.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_geometric_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_integer.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_integer.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_integer_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_matrix.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_matrix.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_matrix_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_packing.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_packing.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_packing_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_trigonometric.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_trigonometric.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_trigonometric_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_vector_relational.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/func_vector_relational.inl [new file with mode: 0755]
core/deps/glm/glm/detail/func_vector_relational_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/glm.cpp [new file with mode: 0755]
core/deps/glm/glm/detail/precision.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/setup.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_float.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_gentype.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_gentype.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_half.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_half.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_int.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x2.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x2.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x3.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x3.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x4.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat2x4.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x2.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x2.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x3.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x3.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x4.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat3x4.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x2.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x2.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x3.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x3.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x4.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x4.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_mat4x4_simd.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec1.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec1.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec2.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec2.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec3.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec3.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec4.hpp [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec4.inl [new file with mode: 0755]
core/deps/glm/glm/detail/type_vec4_simd.inl [new file with mode: 0755]
core/deps/glm/glm/exponential.hpp [new file with mode: 0755]
core/deps/glm/glm/ext.hpp [new file with mode: 0755]
core/deps/glm/glm/fwd.hpp [new file with mode: 0755]
core/deps/glm/glm/geometric.hpp [new file with mode: 0755]
core/deps/glm/glm/glm.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/bitfield.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/bitfield.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/color_encoding.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/color_space.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/color_space.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/constants.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/constants.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/epsilon.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/epsilon.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/functions.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/functions.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/integer.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/integer.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_access.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_access.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_integer.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_inverse.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_inverse.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_transform.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/matrix_transform.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/noise.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/noise.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/packing.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/packing.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/quaternion.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/quaternion.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/quaternion_simd.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/random.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/random.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/reciprocal.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/reciprocal.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/round.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/round.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/type_aligned.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/type_precision.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/type_precision.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/type_ptr.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/type_ptr.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/ulp.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/ulp.inl [new file with mode: 0755]
core/deps/glm/glm/gtc/vec1.hpp [new file with mode: 0755]
core/deps/glm/glm/gtc/vec1.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/associated_min_max.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/associated_min_max.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/bit.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/bit.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/closest_point.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/closest_point.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/color_space.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/color_space.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/color_space_YCoCg.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/color_space_YCoCg.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/common.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/common.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/compatibility.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/compatibility.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/component_wise.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/component_wise.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/dual_quaternion.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/dual_quaternion.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/euler_angles.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/euler_angles.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/extend.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/extend.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/extended_min_max.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/extended_min_max.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_exponential.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_exponential.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_square_root.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_square_root.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_trigonometry.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/fast_trigonometry.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/float_notmalize.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/gradient_paint.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/gradient_paint.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/handed_coordinate_space.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/handed_coordinate_space.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/hash.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/hash.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/integer.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/integer.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/intersect.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/intersect.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/io.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/io.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/log_base.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/log_base.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_cross_product.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_cross_product.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_decompose.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_decompose.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_interpolation.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_interpolation.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_major_storage.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_major_storage.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_operation.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_operation.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_query.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_query.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_transform_2d.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/matrix_transform_2d.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/mixed_product.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/mixed_product.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/norm.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/norm.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/normal.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/normal.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/normalize_dot.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/normalize_dot.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/number_precision.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/number_precision.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/optimum_pow.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/optimum_pow.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/orthonormalize.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/orthonormalize.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/perpendicular.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/perpendicular.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/polar_coordinates.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/polar_coordinates.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/projection.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/projection.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/quaternion.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/quaternion.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/range.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/raw_data.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/raw_data.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/rotate_normalized_axis.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/rotate_normalized_axis.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/rotate_vector.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/rotate_vector.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/scalar_multiplication.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/scalar_relational.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/scalar_relational.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_mat4.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_mat4.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_quat.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_quat.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_vec4.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/simd_vec4.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/spline.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/spline.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/std_based_type.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/std_based_type.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/string_cast.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/string_cast.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/transform.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/transform.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/transform2.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/transform2.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/type_aligned.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/type_aligned.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/type_trait.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/type_trait.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/vector_angle.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/vector_angle.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/vector_query.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/vector_query.inl [new file with mode: 0755]
core/deps/glm/glm/gtx/wrap.hpp [new file with mode: 0755]
core/deps/glm/glm/gtx/wrap.inl [new file with mode: 0755]
core/deps/glm/glm/integer.hpp [new file with mode: 0755]
core/deps/glm/glm/mat2x2.hpp [new file with mode: 0755]
core/deps/glm/glm/mat2x3.hpp [new file with mode: 0755]
core/deps/glm/glm/mat2x4.hpp [new file with mode: 0755]
core/deps/glm/glm/mat3x2.hpp [new file with mode: 0755]
core/deps/glm/glm/mat3x3.hpp [new file with mode: 0755]
core/deps/glm/glm/mat3x4.hpp [new file with mode: 0755]
core/deps/glm/glm/mat4x2.hpp [new file with mode: 0755]
core/deps/glm/glm/mat4x3.hpp [new file with mode: 0755]
core/deps/glm/glm/mat4x4.hpp [new file with mode: 0755]
core/deps/glm/glm/matrix.hpp [new file with mode: 0755]
core/deps/glm/glm/packing.hpp [new file with mode: 0755]
core/deps/glm/glm/simd/common.h [new file with mode: 0755]
core/deps/glm/glm/simd/exponential.h [new file with mode: 0755]
core/deps/glm/glm/simd/geometric.h [new file with mode: 0755]
core/deps/glm/glm/simd/integer.h [new file with mode: 0755]
core/deps/glm/glm/simd/matrix.h [new file with mode: 0755]
core/deps/glm/glm/simd/packing.h [new file with mode: 0755]
core/deps/glm/glm/simd/platform.h [new file with mode: 0755]
core/deps/glm/glm/simd/trigonometric.h [new file with mode: 0755]
core/deps/glm/glm/simd/vector_relational.h [new file with mode: 0755]
core/deps/glm/glm/trigonometric.hpp [new file with mode: 0755]
core/deps/glm/glm/vec2.hpp [new file with mode: 0755]
core/deps/glm/glm/vec3.hpp [new file with mode: 0755]
core/deps/glm/glm/vec4.hpp [new file with mode: 0755]
core/deps/glm/glm/vector_relational.hpp [new file with mode: 0755]
core/deps/glm/readme.md [new file with mode: 0755]
core/deps/hash-library/README.md [new file with mode: 0644]
core/deps/hash-library/md5.cpp [new file with mode: 0644]
core/deps/hash-library/md5.h [new file with mode: 0644]
core/deps/mapbox/geojsonvt_custom_tags.hpp [new file with mode: 0644]
core/deps/mapbox/variant.hpp [new file with mode: 0644]
core/deps/miniz/miniz.c [new file with mode: 0644]
core/deps/miniz/miniz.h [new file with mode: 0644]
core/deps/pbf/pbf.hpp [new file with mode: 0644]
core/deps/rapidjson/allocators.h [new file with mode: 0644]
core/deps/rapidjson/document.h [new file with mode: 0644]
core/deps/rapidjson/encodedstream.h [new file with mode: 0644]
core/deps/rapidjson/encodings.h [new file with mode: 0644]
core/deps/rapidjson/error/en.h [new file with mode: 0644]
core/deps/rapidjson/error/error.h [new file with mode: 0644]
core/deps/rapidjson/filereadstream.h [new file with mode: 0644]
core/deps/rapidjson/filestream.h [new file with mode: 0644]
core/deps/rapidjson/filewritestream.h [new file with mode: 0644]
core/deps/rapidjson/fwd.h [new file with mode: 0644]
core/deps/rapidjson/internal/biginteger.h [new file with mode: 0644]
core/deps/rapidjson/internal/diyfp.h [new file with mode: 0644]
core/deps/rapidjson/internal/dtoa.h [new file with mode: 0644]
core/deps/rapidjson/internal/ieee754.h [new file with mode: 0644]
core/deps/rapidjson/internal/itoa.h [new file with mode: 0644]
core/deps/rapidjson/internal/meta.h [new file with mode: 0644]
core/deps/rapidjson/internal/pow10.h [new file with mode: 0644]
core/deps/rapidjson/internal/regex.h [new file with mode: 0644]
core/deps/rapidjson/internal/stack.h [new file with mode: 0644]
core/deps/rapidjson/internal/strfunc.h [new file with mode: 0644]
core/deps/rapidjson/internal/strtod.h [new file with mode: 0644]
core/deps/rapidjson/internal/swap.h [new file with mode: 0644]
core/deps/rapidjson/istreamwrapper.h [new file with mode: 0644]
core/deps/rapidjson/memorybuffer.h [new file with mode: 0644]
core/deps/rapidjson/memorystream.h [new file with mode: 0644]
core/deps/rapidjson/msinttypes/inttypes.h [new file with mode: 0644]
core/deps/rapidjson/msinttypes/stdint.h [new file with mode: 0644]
core/deps/rapidjson/ostreamwrapper.h [new file with mode: 0644]
core/deps/rapidjson/pointer.h [new file with mode: 0644]
core/deps/rapidjson/prettywriter.h [new file with mode: 0644]
core/deps/rapidjson/rapidjson.h [new file with mode: 0644]
core/deps/rapidjson/reader.h [new file with mode: 0644]
core/deps/rapidjson/schema.h [new file with mode: 0644]
core/deps/rapidjson/stream.h [new file with mode: 0644]
core/deps/rapidjson/stringbuffer.h [new file with mode: 0644]
core/deps/rapidjson/writer.h [new file with mode: 0644]
core/deps/sdf/sdf.h [new file with mode: 0644]
core/deps/stb/stb_easy_font.h [new file with mode: 0644]
core/deps/stb/stb_image.h [new file with mode: 0644]
core/generated/.gitkeep [new file with mode: 0644]
core/include/tangram/data/clientGeoJsonSource.h [new file with mode: 0644]
core/include/tangram/data/properties.h [new file with mode: 0644]
core/include/tangram/data/propertyItem.h [new file with mode: 0644]
core/include/tangram/data/tileSource.h [new file with mode: 0644]
core/include/tangram/log.h [new file with mode: 0644]
core/include/tangram/platform.h [new file with mode: 0644]
core/include/tangram/tangram.h [new file with mode: 0644]
core/include/tangram/tile/tileID.h [new file with mode: 0644]
core/include/tangram/tile/tileTask.h [new file with mode: 0644]
core/include/tangram/util/types.h [new file with mode: 0644]
core/include/tangram/util/url.h [new file with mode: 0644]
core/include/tangram/util/variant.h [new file with mode: 0644]
core/shaders/ambientLight.glsl [new file with mode: 0644]
core/shaders/debug.fs [new file with mode: 0644]
core/shaders/debug.vs [new file with mode: 0644]
core/shaders/debugPrimitive.fs [new file with mode: 0644]
core/shaders/debugPrimitive.vs [new file with mode: 0644]
core/shaders/debugTexture.fs [new file with mode: 0644]
core/shaders/debugTexture.vs [new file with mode: 0644]
core/shaders/directionalLight.glsl [new file with mode: 0644]
core/shaders/lights.glsl [new file with mode: 0644]
core/shaders/material.glsl [new file with mode: 0644]
core/shaders/point.fs [new file with mode: 0644]
core/shaders/point.vs [new file with mode: 0644]
core/shaders/pointLight.glsl [new file with mode: 0644]
core/shaders/polygon.fs [new file with mode: 0644]
core/shaders/polygon.vs [new file with mode: 0644]
core/shaders/polyline.fs [new file with mode: 0644]
core/shaders/polyline.vs [new file with mode: 0644]
core/shaders/rasters.glsl [new file with mode: 0644]
core/shaders/sdf.fs [new file with mode: 0644]
core/shaders/selection.fs [new file with mode: 0644]
core/shaders/spotLight.glsl [new file with mode: 0644]
core/shaders/text.fs [new file with mode: 0644]
core/src/data/clientGeoJsonSource.cpp [new file with mode: 0644]
core/src/data/formats/geoJson.cpp [new file with mode: 0644]
core/src/data/formats/geoJson.h [new file with mode: 0644]
core/src/data/formats/mvt.cpp [new file with mode: 0644]
core/src/data/formats/mvt.h [new file with mode: 0644]
core/src/data/formats/topoJson.cpp [new file with mode: 0644]
core/src/data/formats/topoJson.h [new file with mode: 0644]
core/src/data/mbtilesDataSource.cpp [new file with mode: 0644]
core/src/data/mbtilesDataSource.h [new file with mode: 0644]
core/src/data/memoryCacheDataSource.cpp [new file with mode: 0644]
core/src/data/memoryCacheDataSource.h [new file with mode: 0644]
core/src/data/networkDataSource.cpp [new file with mode: 0644]
core/src/data/networkDataSource.h [new file with mode: 0644]
core/src/data/properties.cpp [new file with mode: 0644]
core/src/data/rasterSource.cpp [new file with mode: 0644]
core/src/data/rasterSource.h [new file with mode: 0644]
core/src/data/tileData.h [new file with mode: 0644]
core/src/data/tileSource.cpp [new file with mode: 0644]
core/src/debug/frameInfo.cpp [new file with mode: 0644]
core/src/debug/frameInfo.h [new file with mode: 0644]
core/src/debug/textDisplay.cpp [new file with mode: 0644]
core/src/debug/textDisplay.h [new file with mode: 0644]
core/src/gl.h [new file with mode: 0644]
core/src/gl/disposer.cpp [new file with mode: 0644]
core/src/gl/disposer.h [new file with mode: 0644]
core/src/gl/dynamicQuadMesh.h [new file with mode: 0644]
core/src/gl/framebuffer.cpp [new file with mode: 0644]
core/src/gl/framebuffer.h [new file with mode: 0644]
core/src/gl/glError.cpp [new file with mode: 0644]
core/src/gl/glError.h [new file with mode: 0644]
core/src/gl/hardware.cpp [new file with mode: 0644]
core/src/gl/hardware.h [new file with mode: 0644]
core/src/gl/mesh.cpp [new file with mode: 0644]
core/src/gl/mesh.h [new file with mode: 0644]
core/src/gl/primitives.cpp [new file with mode: 0644]
core/src/gl/primitives.h [new file with mode: 0644]
core/src/gl/renderState.cpp [new file with mode: 0644]
core/src/gl/renderState.h [new file with mode: 0644]
core/src/gl/shaderProgram.cpp [new file with mode: 0644]
core/src/gl/shaderProgram.h [new file with mode: 0644]
core/src/gl/shaderSource.cpp [new file with mode: 0644]
core/src/gl/shaderSource.h [new file with mode: 0644]
core/src/gl/texture.cpp [new file with mode: 0644]
core/src/gl/texture.h [new file with mode: 0644]
core/src/gl/uniform.h [new file with mode: 0644]
core/src/gl/vao.cpp [new file with mode: 0644]
core/src/gl/vao.h [new file with mode: 0644]
core/src/gl/vertexLayout.cpp [new file with mode: 0644]
core/src/gl/vertexLayout.h [new file with mode: 0644]
core/src/labels/curvedLabel.cpp [new file with mode: 0644]
core/src/labels/curvedLabel.h [new file with mode: 0644]
core/src/labels/fadeEffect.h [new file with mode: 0644]
core/src/labels/label.cpp [new file with mode: 0644]
core/src/labels/label.h [new file with mode: 0644]
core/src/labels/labelCollider.cpp [new file with mode: 0644]
core/src/labels/labelCollider.h [new file with mode: 0644]
core/src/labels/labelProperty.cpp [new file with mode: 0644]
core/src/labels/labelProperty.h [new file with mode: 0644]
core/src/labels/labelSet.cpp [new file with mode: 0644]
core/src/labels/labelSet.h [new file with mode: 0644]
core/src/labels/labels.cpp [new file with mode: 0644]
core/src/labels/labels.h [new file with mode: 0644]
core/src/labels/obbBuffer.h [new file with mode: 0644]
core/src/labels/screenTransform.h [new file with mode: 0644]
core/src/labels/spriteLabel.cpp [new file with mode: 0644]
core/src/labels/spriteLabel.h [new file with mode: 0644]
core/src/labels/textLabel.cpp [new file with mode: 0644]
core/src/labels/textLabel.h [new file with mode: 0644]
core/src/labels/textLabels.h [new file with mode: 0644]
core/src/marker/marker.cpp [new file with mode: 0644]
core/src/marker/marker.h [new file with mode: 0644]
core/src/marker/markerManager.cpp [new file with mode: 0644]
core/src/marker/markerManager.h [new file with mode: 0644]
core/src/platform.cpp [new file with mode: 0644]
core/src/scene/ambientLight.cpp [new file with mode: 0644]
core/src/scene/ambientLight.h [new file with mode: 0644]
core/src/scene/asset.cpp [new file with mode: 0644]
core/src/scene/asset.h [new file with mode: 0644]
core/src/scene/dataLayer.cpp [new file with mode: 0644]
core/src/scene/dataLayer.h [new file with mode: 0644]
core/src/scene/directionalLight.cpp [new file with mode: 0644]
core/src/scene/directionalLight.h [new file with mode: 0644]
core/src/scene/drawRule.cpp [new file with mode: 0644]
core/src/scene/drawRule.h [new file with mode: 0644]
core/src/scene/drawRuleWarnings.h [new file with mode: 0644]
core/src/scene/filters.cpp [new file with mode: 0644]
core/src/scene/filters.h [new file with mode: 0644]
core/src/scene/importer.cpp [new file with mode: 0644]
core/src/scene/importer.h [new file with mode: 0644]
core/src/scene/light.cpp [new file with mode: 0644]
core/src/scene/light.h [new file with mode: 0644]
core/src/scene/lights.h [new file with mode: 0644]
core/src/scene/pointLight.cpp [new file with mode: 0644]
core/src/scene/pointLight.h [new file with mode: 0644]
core/src/scene/scene.cpp [new file with mode: 0644]
core/src/scene/scene.h [new file with mode: 0644]
core/src/scene/sceneLayer.cpp [new file with mode: 0644]
core/src/scene/sceneLayer.h [new file with mode: 0644]
core/src/scene/sceneLoader.cpp [new file with mode: 0644]
core/src/scene/sceneLoader.h [new file with mode: 0644]
core/src/scene/spotLight.cpp [new file with mode: 0644]
core/src/scene/spotLight.h [new file with mode: 0644]
core/src/scene/spriteAtlas.cpp [new file with mode: 0644]
core/src/scene/spriteAtlas.h [new file with mode: 0644]
core/src/scene/stops.cpp [new file with mode: 0644]
core/src/scene/stops.h [new file with mode: 0644]
core/src/scene/styleContext.cpp [new file with mode: 0644]
core/src/scene/styleContext.h [new file with mode: 0644]
core/src/scene/styleMixer.cpp [new file with mode: 0644]
core/src/scene/styleMixer.h [new file with mode: 0644]
core/src/scene/styleParam.cpp [new file with mode: 0644]
core/src/scene/styleParam.h [new file with mode: 0644]
core/src/selection/featureSelection.cpp [new file with mode: 0644]
core/src/selection/featureSelection.h [new file with mode: 0644]
core/src/selection/selectionQuery.cpp [new file with mode: 0644]
core/src/selection/selectionQuery.h [new file with mode: 0644]
core/src/style/debugStyle.cpp [new file with mode: 0644]
core/src/style/debugStyle.h [new file with mode: 0644]
core/src/style/debugTextStyle.cpp [new file with mode: 0644]
core/src/style/debugTextStyle.h [new file with mode: 0644]
core/src/style/material.cpp [new file with mode: 0644]
core/src/style/material.h [new file with mode: 0644]
core/src/style/pointStyle.cpp [new file with mode: 0644]
core/src/style/pointStyle.h [new file with mode: 0644]
core/src/style/pointStyleBuilder.cpp [new file with mode: 0644]
core/src/style/pointStyleBuilder.h [new file with mode: 0644]
core/src/style/polygonStyle.cpp [new file with mode: 0644]
core/src/style/polygonStyle.h [new file with mode: 0644]
core/src/style/polylineStyle.cpp [new file with mode: 0644]
core/src/style/polylineStyle.h [new file with mode: 0644]
core/src/style/rasterStyle.cpp [new file with mode: 0644]
core/src/style/rasterStyle.h [new file with mode: 0644]
core/src/style/style.cpp [new file with mode: 0644]
core/src/style/style.h [new file with mode: 0644]
core/src/style/textStyle.cpp [new file with mode: 0644]
core/src/style/textStyle.h [new file with mode: 0644]
core/src/style/textStyleBuilder.cpp [new file with mode: 0644]
core/src/style/textStyleBuilder.h [new file with mode: 0644]
core/src/tangram.cpp [new file with mode: 0644]
core/src/text/fontContext.cpp [new file with mode: 0644]
core/src/text/fontContext.h [new file with mode: 0644]
core/src/text/textUtil.cpp [new file with mode: 0644]
core/src/text/textUtil.h [new file with mode: 0644]
core/src/tile/tile.cpp [new file with mode: 0644]
core/src/tile/tile.h [new file with mode: 0644]
core/src/tile/tileBuilder.cpp [new file with mode: 0644]
core/src/tile/tileBuilder.h [new file with mode: 0644]
core/src/tile/tileCache.h [new file with mode: 0644]
core/src/tile/tileHash.h [new file with mode: 0644]
core/src/tile/tileManager.cpp [new file with mode: 0644]
core/src/tile/tileManager.h [new file with mode: 0644]
core/src/tile/tileTask.cpp [new file with mode: 0644]
core/src/tile/tileWorker.cpp [new file with mode: 0644]
core/src/tile/tileWorker.h [new file with mode: 0644]
core/src/util/asyncWorker.h [new file with mode: 0644]
core/src/util/base64.h [new file with mode: 0644]
core/src/util/builders.cpp [new file with mode: 0644]
core/src/util/builders.h [new file with mode: 0644]
core/src/util/color.h [new file with mode: 0644]
core/src/util/dashArray.cpp [new file with mode: 0644]
core/src/util/dashArray.h [new file with mode: 0644]
core/src/util/ease.h [new file with mode: 0644]
core/src/util/extrude.cpp [new file with mode: 0644]
core/src/util/extrude.h [new file with mode: 0644]
core/src/util/fastmap.h [new file with mode: 0644]
core/src/util/floatFormatter.cpp [new file with mode: 0644]
core/src/util/floatFormatter.h [new file with mode: 0644]
core/src/util/geom.cpp [new file with mode: 0644]
core/src/util/geom.h [new file with mode: 0644]
core/src/util/hash.h [new file with mode: 0644]
core/src/util/inputHandler.cpp [new file with mode: 0644]
core/src/util/inputHandler.h [new file with mode: 0644]
core/src/util/jobQueue.cpp [new file with mode: 0644]
core/src/util/jobQueue.h [new file with mode: 0644]
core/src/util/json.cpp [new file with mode: 0644]
core/src/util/json.h [new file with mode: 0644]
core/src/util/lineSampler.h [new file with mode: 0644]
core/src/util/mapProjection.cpp [new file with mode: 0644]
core/src/util/mapProjection.h [new file with mode: 0644]
core/src/util/rasterize.cpp [new file with mode: 0644]
core/src/util/rasterize.h [new file with mode: 0644]
core/src/util/topologicalSort.h [new file with mode: 0644]
core/src/util/url.cpp [new file with mode: 0644]
core/src/util/util.h [new file with mode: 0644]
core/src/util/yamlHelper.cpp [new file with mode: 0644]
core/src/util/yamlHelper.h [new file with mode: 0644]
core/src/util/zlibHelper.cpp [new file with mode: 0644]
core/src/util/zlibHelper.h [new file with mode: 0644]
core/src/view/view.cpp [new file with mode: 0644]
core/src/view/view.h [new file with mode: 0644]
core/src/view/viewConstraint.cpp [new file with mode: 0644]
core/src/view/viewConstraint.h [new file with mode: 0644]
images/clion-tangram-target.png [new file with mode: 0644]
images/default-point.png [new file with mode: 0644]
images/screenshot.png [new file with mode: 0644]
package-submodules.sh [new file with mode: 0755]
packaging/tangram-es.spec [new file with mode: 0644]
platforms/android/.gitignore [new file with mode: 0644]
platforms/android/README.md [new file with mode: 0644]
platforms/android/build.gradle [new file with mode: 0644]
platforms/android/demo/build.gradle [new file with mode: 0644]
platforms/android/demo/proguard-project.txt [new file with mode: 0644]
platforms/android/demo/src/main/AndroidManifest.xml [new file with mode: 0644]
platforms/android/demo/src/main/java/com/mapzen/tangram/android/MainActivity.java [new file with mode: 0644]
platforms/android/demo/src/main/java/com/mapzen/tangram/android/PresetSelectionTextView.java [new file with mode: 0644]
platforms/android/demo/src/main/res/drawable-hdpi/ic_launcher.png [new file with mode: 0644]
platforms/android/demo/src/main/res/drawable-ldpi/ic_launcher.png [new file with mode: 0644]
platforms/android/demo/src/main/res/drawable-mdpi/ic_launcher.png [new file with mode: 0644]
platforms/android/demo/src/main/res/drawable-xhdpi/ic_launcher.png [new file with mode: 0644]
platforms/android/demo/src/main/res/layout/main.xml [new file with mode: 0644]
platforms/android/demo/src/main/res/values/strings.xml [new file with mode: 0644]
platforms/android/gradle.properties [new file with mode: 0644]
platforms/android/gradle/wrapper/gradle-wrapper.jar [new file with mode: 0644]
platforms/android/gradle/wrapper/gradle-wrapper.properties [new file with mode: 0644]
platforms/android/gradlew [new file with mode: 0755]
platforms/android/release-checklist.md [new file with mode: 0644]
platforms/android/run.sh [new file with mode: 0755]
platforms/android/settings.gradle [new file with mode: 0644]
platforms/android/tangram/build.gradle [new file with mode: 0644]
platforms/android/tangram/gradle-mvn-push.gradle [new file with mode: 0644]
platforms/android/tangram/gradle.properties [new file with mode: 0644]
platforms/android/tangram/src/main/AndroidManifest.xml [new file with mode: 0644]
platforms/android/tangram/src/main/cpp/jniExports.cpp [new file with mode: 0644]
platforms/android/tangram/src/main/cpp/platform_android.cpp [new file with mode: 0644]
platforms/android/tangram/src/main/cpp/platform_android.h [new file with mode: 0644]
platforms/android/tangram/src/main/cpp/sqlite3ndk.cpp [new file with mode: 0755]
platforms/android/tangram/src/main/cpp/sqlite3ndk.h [new file with mode: 0755]
platforms/android/tangram/src/main/java/com/almeros/android/multitouch/BaseGestureDetector.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/almeros/android/multitouch/MoveGestureDetector.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/almeros/android/multitouch/RotateGestureDetector.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/almeros/android/multitouch/ShoveGestureDetector.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/almeros/android/multitouch/TwoFingerGestureDetector.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/ConfigChooser.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/FontFileParser.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/HttpHandler.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/LabelPickResult.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/LngLat.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/MapController.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/MapView.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/Marker.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/MarkerPickResult.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdate.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdateError.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/TouchInput.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Point.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polygon.java [new file with mode: 0644]
platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java [new file with mode: 0644]
platforms/android/tangram/versioning.gradle [new file with mode: 0644]
platforms/common/glfwApp.cpp [new file with mode: 0644]
platforms/common/glfwApp.h [new file with mode: 0644]
platforms/common/platform_gl.cpp [new file with mode: 0644]
platforms/common/platform_gl.h [new file with mode: 0644]
platforms/common/urlClient.cpp [new file with mode: 0644]
platforms/common/urlClient.h [new file with mode: 0644]
platforms/ios/README.md [new file with mode: 0644]
platforms/ios/demo/Config.plist.in [new file with mode: 0644]
platforms/ios/demo/Info.plist [new file with mode: 0644]
platforms/ios/demo/resources/LaunchScreen.xib [new file with mode: 0644]
platforms/ios/demo/resources/Main_iPad.storyboard [new file with mode: 0644]
platforms/ios/demo/resources/Main_iPhone.storyboard [new file with mode: 0644]
platforms/ios/demo/src/AppDelegate.h [new file with mode: 0644]
platforms/ios/demo/src/AppDelegate.m [new file with mode: 0644]
platforms/ios/demo/src/MapViewController.h [new file with mode: 0644]
platforms/ios/demo/src/MapViewController.m [new file with mode: 0644]
platforms/ios/demo/src/main.m [new file with mode: 0644]
platforms/ios/framework/Info.plist [new file with mode: 0644]
platforms/ios/framework/Modules/module.modulemap [new file with mode: 0644]
platforms/ios/framework/TangramMap.h [new file with mode: 0644]
platforms/ios/jazzy.yml [new file with mode: 0644]
platforms/ios/release-checklist.md [new file with mode: 0644]
platforms/ios/src/TangramMap/TGFontConverter.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGFontConverter.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGGeoPoint.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGGeoPolygon.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGGeoPolygon.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGGeoPolyline.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGGeoPolyline.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGHelpers.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGHelpers.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGHttpHandler.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGHttpHandler.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGLabelPickResult+Internal.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGLabelPickResult.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGLabelPickResult.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapData+Internal.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapData.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapData.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapViewController+Internal.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapViewController.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMapViewController.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarker+Internal.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarker.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarker.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarkerPickResult+Internal.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarkerPickResult.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGMarkerPickResult.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGSceneUpdate.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGSceneUpdate.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/TGTypes.h [new file with mode: 0644]
platforms/ios/src/TangramMap/TGTypes.mm [new file with mode: 0644]
platforms/ios/src/TangramMap/platform_ios.h [new file with mode: 0644]
platforms/ios/src/TangramMap/platform_ios.mm [new file with mode: 0644]
platforms/linux/README.md [new file with mode: 0644]
platforms/linux/src/main.cpp [new file with mode: 0644]
platforms/linux/src/platform_linux.cpp [new file with mode: 0644]
platforms/linux/src/platform_linux.h [new file with mode: 0644]
platforms/osx/Info.plist [new file with mode: 0644]
platforms/osx/README.md [new file with mode: 0644]
platforms/osx/src/main.mm [new file with mode: 0644]
platforms/osx/src/platform_osx.h [new file with mode: 0644]
platforms/osx/src/platform_osx.mm [new file with mode: 0644]
platforms/rpi/README.md [new file with mode: 0644]
platforms/rpi/src/context.cpp [new file with mode: 0644]
platforms/rpi/src/context.h [new file with mode: 0644]
platforms/rpi/src/main.cpp [new file with mode: 0644]
platforms/tizen/src/platform_tizen.cpp [new file with mode: 0644]
platforms/tizen/src/platform_tizen.h [new file with mode: 0644]
platforms/tizen/src/tizen_gl.cpp [new file with mode: 0644]
platforms/tizen/src/tizen_gl.h [new file with mode: 0644]
proxy.py [new file with mode: 0644]
scenes/fonts/DroidSansFallback.ttf [new file with mode: 0755]
scenes/fonts/DroidSansJapanese.ttf [new file with mode: 0755]
scenes/fonts/NotoNaskh-Regular.ttf [new file with mode: 0644]
scenes/fonts/NotoSans-Regular.ttf [new file with mode: 0644]
scenes/fonts/NotoSansHebrew-Regular.ttf [new file with mode: 0644]
scenes/fonts/firasans-medium.ttf [new file with mode: 0644]
scenes/fonts/roboto-regular.ttf [new file with mode: 0755]
scenes/img/arrow-3.png [new file with mode: 0644]
scenes/img/cross.png [new file with mode: 0644]
scenes/img/cubemap.png [new file with mode: 0644]
scenes/img/grid.jpg [new file with mode: 0644]
scenes/img/mapzen-logo.png [new file with mode: 0644]
scenes/img/normals.jpg [new file with mode: 0644]
scenes/img/poi_icons_32.png [new file with mode: 0644]
scenes/img/sem.jpg [new file with mode: 0644]
scenes/import.yaml [new file with mode: 0644]
scenes/import/test.yaml [new file with mode: 0644]
scenes/raster-double.yaml [new file with mode: 0644]
scenes/raster-simple.yaml [new file with mode: 0644]
scenes/raster-terrain.yaml [new file with mode: 0644]
scenes/scene.yaml [new file with mode: 0644]
scripts/incbin.sh [new file with mode: 0755]
scripts/travis/android-sdk-license [new file with mode: 0644]
scripts/travis/before_install.sh [new file with mode: 0755]
scripts/travis/script_build.sh [new file with mode: 0755]
scripts/travis/script_build_bench.sh [new file with mode: 0644]
scripts/travis/script_build_tests.sh [new file with mode: 0755]
scripts/travis/script_deploy_android_demo.sh [new file with mode: 0755]
scripts/travis/script_deploy_android_snapshot.sh [new file with mode: 0755]
scripts/travis/script_run_bench.sh [new file with mode: 0755]
scripts/travis/script_run_tests.sh [new file with mode: 0755]
tangram-es.manifest [new file with mode: 0644]
tests/CMakeLists.txt [new file with mode: 0644]
tests/catch/catch.hpp [new file with mode: 0644]
tests/src/catch.cpp [new file with mode: 0644]
tests/src/gl_mock.cpp [new file with mode: 0644]
tests/src/platform_mock.cpp [new file with mode: 0644]
tests/src/platform_mock.h [new file with mode: 0644]
tests/unit/curlTests.cpp [new file with mode: 0644]
tests/unit/drawRuleTests.cpp [new file with mode: 0644]
tests/unit/dukTests.cpp [new file with mode: 0644]
tests/unit/fileTests.cpp [new file with mode: 0644]
tests/unit/labelTests.cpp [new file with mode: 0644]
tests/unit/labelsTests.cpp [new file with mode: 0644]
tests/unit/layerTests.cpp [new file with mode: 0644]
tests/unit/lineWrapTests.cpp [new file with mode: 0644]
tests/unit/mercProjTests.cpp [new file with mode: 0644]
tests/unit/meshTests.cpp [new file with mode: 0644]
tests/unit/sceneImportTests.cpp [new file with mode: 0644]
tests/unit/sceneLoaderTests.cpp [new file with mode: 0644]
tests/unit/sceneUpdateTests.cpp [new file with mode: 0644]
tests/unit/stopsTests.cpp [new file with mode: 0644]
tests/unit/styleMixerTests.cpp [new file with mode: 0644]
tests/unit/styleSortingTests.cpp [new file with mode: 0644]
tests/unit/styleUniformsTests.cpp [new file with mode: 0644]
tests/unit/textureTests.cpp [new file with mode: 0644]
tests/unit/tileIDTests.cpp [new file with mode: 0644]
tests/unit/tileManagerTests.cpp [new file with mode: 0644]
tests/unit/urlTests.cpp [new file with mode: 0644]
tests/unit/yamlFilterTests.cpp [new file with mode: 0644]
toolchains/android.cmake [new file with mode: 0644]
toolchains/darwin.cmake [new file with mode: 0644]
toolchains/iOS.cmake [new file with mode: 0644]
toolchains/iOS.framework.cmake [new file with mode: 0644]
toolchains/iOS.toolchain.cmake [new file with mode: 0644]
toolchains/linux.cmake [new file with mode: 0644]
toolchains/raspberrypi.cmake [new file with mode: 0644]
toolchains/tizen-lib.cmake [new file with mode: 0644]
toolchains/tizen.cmake [new file with mode: 0644]
toolchains/tizen.toolchain.cmake [new file with mode: 0644]
toolchains/utils.cmake [new file with mode: 0644]

diff --git a/.clang-format b/.clang-format
new file mode 100644 (file)
index 0000000..409201d
--- /dev/null
@@ -0,0 +1,64 @@
+---
+Language: Cpp
+AccessModifierOffset: -4
+AlignAfterOpenBracket: true
+AlignEscapedNewlinesLeft: false
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: true
+AllowShortCaseLabelsOnASingleLine: true
+AllowShortIfStatementsOnASingleLine: true
+AllowShortLoopsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: All
+AlwaysBreakAfterDefinitionReturnType: false
+AlwaysBreakTemplateDeclarations: false
+AlwaysBreakBeforeMultilineStrings: false
+BreakBeforeBinaryOperators: None
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BinPackParameters: true
+BinPackArguments: true
+ColumnLimit: 120
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
+ConstructorInitializerIndentWidth: 4
+DerivePointerAlignment: false
+ExperimentalAutoDetectBinPacking: false
+IndentCaseLabels: false
+IndentWrappedFunctionNames: false
+IndentFunctionDeclarationAfterType: false
+MaxEmptyLinesToKeep: 2
+KeepEmptyLinesAtTheStartOfBlocks: true
+NamespaceIndentation: None
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
+PenaltyBreakComment: 300
+PenaltyBreakString: 1000
+PenaltyBreakFirstLessLess: 120
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Left
+SpacesBeforeTrailingComments: 1
+Cpp11BracedListStyle: true
+Standard: Cpp11
+IndentWidth: 4
+TabWidth: 4
+UseTab: Never
+BreakBeforeBraces: Attach
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpacesInAngles: false
+SpaceInEmptyParentheses: false
+SpacesInCStyleCastParentheses: false
+SpaceAfterCStyleCast: false
+SpacesInContainerLiterals: true
+SpaceBeforeAssignmentOperators: true
+ContinuationIndentWidth: 4
+CommentPragmas: '^ IWYU pragma:'
+ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+SpaceBeforeParens: ControlStatements
+DisableFormat: false
+---
+
diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3ed6317
--- /dev/null
@@ -0,0 +1,151 @@
+# Created by http://www.gitignore.io
+
+### OSX ###
+.DS_Store
+.AppleDouble
+.LSOverride
+
+# Icon must end with two \r
+Icon
+
+
+# Thumbnails
+._*
+
+# proxy.py cache
+.tiles
+
+# Files that might appear on external disk
+.Spotlight-V100
+.Trashes
+
+# Directories potentially created on remote AFP share
+.AppleDB
+.AppleDesktop
+Network Trash Folder
+Temporary Items
+.apdisk
+
+
+### Android ###
+# Built application files
+*.apk
+*.ap_
+
+# Files for the Dalvik VM
+*.dex
+
+# Java class files
+*.class
+
+# Generated files
+bin/
+gen/
+*.o.d
+
+# Gradle files
+.gradle/
+*.externalNativeBuild
+
+# Local configuration file (sdk path, etc)
+local.properties
+
+# Proguard folder generated by Eclipse
+proguard/
+
+# Log Files
+*.log
+
+*.externalNativeBuild
+
+### Xcode ###
+*.pbxuser
+!default.pbxuser
+*.mode1v3
+!default.mode1v3
+*.mode2v3
+!default.mode2v3
+*.perspectivev3
+!default.perspectivev3
+xcuserdata
+*.xccheckout
+*.moved-aside
+DerivedData
+*.xcuserstate
+
+### Intellij ###
+
+*.iml
+
+## Directory-based project format:
+.idea/
+
+## File-based project format:
+*.ipr
+*.iws
+
+### C++ ###
+# Compiled Object files
+*.slo
+*.lo
+*.o
+*.obj
+
+# Compiled Dynamic libraries
+*.so
+*.dylib
+*.dll
+
+# Fortran module files
+*.mod
+
+# Compiled Static libraries
+*.lai
+*.la
+*.a
+*.lib
+
+# Executables
+*.exe
+*.out
+*.app
+
+#Keep specific precompiled static libraries
+!**/precompiled/**/*.a
+!**/precompiled/**/*.dylib
+
+# CMake files
+CMakeCache.txt
+CMakeScripts
+CMakeFiles
+build
+build/**/Makefile
+cmake_install.cmake
+install_manifest.txt
+
+# Android debugging
+platforms/android/demo/jni
+platforms/android/*/libs
+platforms/android/*/obj
+*.mk
+
+# Android gradle
+platforms/android/demo/gradle
+platforms/android/demo/gradlew*
+
+# iOS generated plist configuration
+platforms/ios/demo/resources/Config.plist
+
+# vim
+*.swp
+*.swo
+
+# perf files
+perf.data
+
+# generated headers
+core/generated/*.h
+
+# CLion build directories
+/cmake-build-debug/
+/cmake-build-release/
diff --git a/.gitmodules b/.gitmodules
new file mode 100644 (file)
index 0000000..050c1de
--- /dev/null
@@ -0,0 +1,36 @@
+[submodule "core/include/isect2d"]
+       path = core/deps/isect2d
+       url = https://github.com/tangrams/isect2d.git
+[submodule "core/dependencies/csscolorparser"]
+       path = core/deps/css-color-parser-cpp
+       url = https://github.com/tangrams/css-color-parser-cpp
+[submodule "core/include/variant"]
+       path = core/deps/variant
+       url = https://github.com/tangrams/variant
+[submodule "core/include/earcut.hpp"]
+       path = core/deps/earcut
+       url = https://github.com/tangrams/earcut.hpp
+[submodule "core/dependencies/geojson-vt-cpp"]
+       path = core/deps/geojson-vt-cpp
+       url = https://github.com/tangrams/geojson-vt-cpp.git
+[submodule "external/duktape"]
+       path = core/deps/duktape
+       url = https://github.com/tangrams/duktape.git
+[submodule "external/yaml-cpp"]
+       path = core/deps/yaml-cpp
+       url = https://github.com/tangrams/yaml-cpp
+[submodule "external/glfw"]
+       path = platforms/common/glfw
+       url = https://github.com/glfw/glfw
+[submodule "external/benchmark"]
+       path = bench/benchmark
+       url = https://github.com/google/benchmark
+[submodule "external/alfons"]
+       path = core/deps/alfons
+       url = https://github.com/hjanetzek/alfons
+[submodule "external/harfbuzz-icu-freetype"]
+       path = core/deps/harfbuzz-icu-freetype
+       url = https://github.com/tangrams/harfbuzz-icu-freetype.git
+[submodule "external/SQLiteCpp"]
+       path = core/deps/SQLiteCpp
+       url = https://github.com/SRombauts/SQLiteCpp.git
diff --git a/.travis.yml b/.travis.yml
new file mode 100644 (file)
index 0000000..ea1e800
--- /dev/null
@@ -0,0 +1,45 @@
+language: android
+
+sudo: enabled
+
+branches:
+    only:
+        - master
+
+matrix:
+    include:
+        - os: linux
+          env: PLATFORM=linux CXX=g++-4.9 CC=gcc-4.9
+          addons:
+            apt:
+              sources: [ 'ubuntu-toolchain-r-test', 'george-edison55-precise-backports' ]
+              packages: [ 'cmake', 'cmake-data', 'gcc-4.9', 'g++-4.9', 'xorg-dev', 'libglu1-mesa-dev' ]
+        - os: linux
+          env: PLATFORM=android
+          addons:
+            apt:
+              sources: [ 'ubuntu-toolchain-r-test' ]
+              packages: [ 'libstdc++6', 's3cmd' ]
+          android:
+            components: [ 'tools', 'build-tools-25.0.0', 'extra-android-m2repository', 'android-25' ]
+          jdk: oraclejdk8
+
+before_install:
+    - git submodule update --init
+    - source ./scripts/travis/before_install.sh
+
+install: ulimit -c
+
+before_script:
+    # Set the core file limit to unlimited so a core file is generated upon crash
+    - ulimit -c unlimited -S
+
+# build test project
+script:
+    - source ./scripts/travis/script_build.sh
+    - source ./scripts/travis/script_run_tests.sh
+    - source ./scripts/travis/script_run_bench.sh
+
+after_success:
+    - source ./scripts/travis/script_deploy_android_snapshot.sh
+    - source ./scripts/travis/script_deploy_android_demo.sh
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644 (file)
index 0000000..403bbef
--- /dev/null
@@ -0,0 +1,101 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+project(tangram)
+
+# Options
+option(USE_SYSTEM_FONT_LIBS "Use system libraries Freetype, ICU and Harfbuzz via pkgconfig" OFF)
+option(USE_SYSTEM_GLFW_LIBS "Use system libraries for GLFW3 via pkgconfig" OFF)
+
+if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "")
+    message(STATUS "Build type configuration " ${CMAKE_BUILD_TYPE})
+else()
+    set(CMAKE_BUILD_TYPE Release)
+endif()
+
+#if(NOT EXISTS "${PROJECT_SOURCE_DIR}/core/deps/harfbuzz-icu-freetype/harfbuzz/README")
+#    message(SEND_ERROR "Missing submodules - Please run:\n 'git submodule update --init'")
+#    return()
+#endif()
+
+set(APPLICATION ON)
+
+if(NOT CMAKE_BUILD_TYPE)
+  set(CMAKE_BUILD_TYPE Release)
+endif()
+
+include(${PROJECT_SOURCE_DIR}/toolchains/utils.cmake)
+
+# platform lookup
+set(SUPPORTED_TARGETS darwin ios android raspberrypi linux tizen tizen-lib ios.framework)
+
+if(NOT PLATFORM_TARGET)
+    string(TOLOWER "${CMAKE_SYSTEM_NAME}" varplatform)
+    string(TOUPPER "${CMAKE_SYSTEM_NAME}" VARPLATFORM)
+
+    message(STATUS "No target defined (give as parameter -DPLATFORM_TARGET=platform_name).")
+    message(STATUS "Targets available: ${SUPPORTED_TARGETS}.")
+    message(STATUS "Will use your OS: ${varplatform}.")
+
+    set(PLATFORM_TARGET ${varplatform})
+else()
+    string(TOLOWER "${PLATFORM_TARGET}" varplatform)
+    string(TOUPPER "${PLATFORM_TARGET}" VARPLATFORM)
+
+    message(STATUS "Platform chosen : ${VARPLATFORM}")
+endif()
+
+list(FIND SUPPORTED_TARGETS ${varplatform} target_in_list)
+
+if(target_in_list EQUAL -1)
+    message(SEND_ERROR "${varplatform} not in supported targets: ${SUPPORTED_TARGETS}")
+    return()
+endif()
+
+# setting up cache variable platform
+set(PLATFORM ${varplatform} CACHE INTERNAL "platform" FORCE)
+
+# cmake output configuration
+if(NOT ${PLATFORM_TARGET} STREQUAL android)
+    set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+    set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
+    set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
+endif()
+
+# cmake inclusions and definitions
+set(CMAKE_TARGET_FILE ${PROJECT_SOURCE_DIR}/toolchains/${PLATFORM_TARGET}.cmake)
+
+message(STATUS "Including ${varplatform} dependent cmake file : ${CMAKE_TARGET_FILE}")
+
+
+## set platform configuration, build library and application.
+# adds targets:
+# - core
+# - tangram
+# - copy_resources
+include(${CMAKE_TARGET_FILE})
+
+if(BENCHMARK OR UNIT_TESTS)
+    add_library(platform_mock
+        ${PROJECT_SOURCE_DIR}/tests/src/platform_mock.cpp
+        ${PROJECT_SOURCE_DIR}/tests/src/gl_mock.cpp)
+
+    target_include_directories(platform_mock
+        PUBLIC ${CORE_LIBRARIES_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR}/tests/src)
+
+    target_compile_definitions(platform_mock
+        PUBLIC -DUNIT_TESTS)
+
+    target_link_libraries(platform_mock
+        PUBLIC core)
+
+endif()
+
+if(UNIT_TESTS)
+    message(STATUS "Build with tests")
+    add_subdirectory(${PROJECT_SOURCE_DIR}/tests)
+endif()
+
+if(BENCHMARK)
+    message(STATUS "Build with benchmarks")
+    add_subdirectory(${PROJECT_SOURCE_DIR}/bench)
+endif()
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
new file mode 100644 (file)
index 0000000..226145a
--- /dev/null
@@ -0,0 +1,49 @@
+# Contributing to Tangram ES
+
+The easiest way to help out is to submit bug reports and feature requests on our [issues](https://github.com/tangrams/tangram-es/issues) page.
+
+When submitting a bug report, please include:
+
+ - The device and operating system version that produced the bug
+ - The version or commit of Tangram ES that produced the bug
+ - Steps required to recreate the issue
+ - What happened
+ - What you expected to happen
+
+Thanks!
+
+## Building
+
+If you'd like to contribute code to the project or just make changes for fun, you'll need to make sure your development environment is set up correctly.
+
+ - [Developing for Mac OS X](platforms/osx/README.md#setup)
+ - [Developing for Ubuntu Linux](platforms/linux/README.md#setup)
+ - [Developing for Android](platforms/android/README.md#setup)
+ - [Developing for iOS](platforms/ios/README.md#setup)
+ - [Developing for Raspberry Pi](platforms/rpi/README.md#setup)
+
+## Development
+
+The tangram-es project is divided into two parts: a portable C++14 [core library](core) and the various [platform interfaces](platforms).
+
+To develop for the core library, it is usually easiest to build and test your changes using either the Mac OS X or Ubuntu desktop targets. These targets are the fastest and easiest to deploy and debug.
+
+## Code Style
+
+In general, code changes should follow the style of the surrounding code.
+
+When in doubt, you can use the provided clang-format style file for automatic styling.
+
+Install clang-format (available through brew or apt-get):
+```
+brew install clang-format
+```
+or
+```
+sudo apt-get install clang-format
+```
+
+Run clang-format with specified style (use -i to modify the contents of the specified file):
+```
+clang-format -i -style=file [file]
+```
diff --git a/ISSUE_TEMPLATE.md b/ISSUE_TEMPLATE.md
new file mode 100644 (file)
index 0000000..d05d1e3
--- /dev/null
@@ -0,0 +1,24 @@
+**TO REPRODUCE THE ISSUE, FOLLOW THESE STEPS:**
+
+ - List the steps you used
+ - To produce the result here
+ - Don't leave any out
+
+**RESULT:**
+
+Describe the result here.
+
+**EXPECTED RESULT:**
+
+Describe what you expected to see here.
+
+**ENVIRONMENT:**
+
+ - What operating system and device did you produce this issue on?
+ - If you used a released version, what is the version number?
+
+**OTHER:**
+
+Any additional notes, comments, tips, tricks, gifs, suggestions, poetry, recipes, jokes
+
+If you are able to record the log output from tangram-es, please attach it as a text file or share it using a site like https://hastebin.com/
diff --git a/LICENSE b/LICENSE
new file mode 100644 (file)
index 0000000..f94b6af
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,20 @@
+The MIT License (MIT)
+
+Copyright (c) 2014 Mapzen 
+
+Permission is hereby granted, free of charge, to any person obtaining a copy of
+this software and associated documentation files (the "Software"), to deal in
+the Software without restriction, including without limitation the rights to
+use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
+the Software, and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
+FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
+COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..2306693
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,389 @@
+all: android osx ios
+
+.PHONY: clean
+.PHONY: clean-android
+.PHONY: clean-osx
+.PHONY: clean-xcode
+.PHONY: clean-ios
+.PHONY: clean-rpi
+.PHONY: clean-linux
+.PHONY: clean-benchmark
+.PHONY: clean-shaders
+.PHONY: clean-tizen-arm
+.PHONY: clean-tizen-x86
+.PHONY: clean-ios-framework
+.PHONY: clean-ios-framework-sim
+.PHONY: android
+.PHONY: osx
+.PHONY: xcode
+.PHONY: ios
+.PHONY: rpi
+.PHONY: linux
+.PHONY: benchmark
+.PHONY: ios-framework
+.PHONY: ios-framework-universal
+.PHONY: check-ndk
+.PHONY: cmake-osx
+.PHONY: cmake-xcode
+.PHONY: cmake-ios
+.PHONY: cmake-ios-framework
+.PHONY: cmake-ios-framework-sim
+.PHONY: cmake-rpi
+.PHONY: cmake-linux
+.PHONY: install-android
+.PHONY: ios-docs
+
+ANDROID_BUILD_DIR = platforms/android/tangram/build
+OSX_BUILD_DIR = build/osx
+OSX_XCODE_BUILD_DIR = build/xcode
+IOS_BUILD_DIR = build/ios
+IOS_FRAMEWORK_BUILD_DIR = build/ios-framework
+IOS_FRAMEWORK_SIM_BUILD_DIR = build/ios-framework-sim
+IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR = build/ios-framework-universal
+IOS_SIM_BUILD_DIR = build/ios-sim
+IOS_DOCS_BUILD_DIR = build/ios-docs
+RPI_BUILD_DIR = build/rpi
+LINUX_BUILD_DIR = build/linux
+TESTS_BUILD_DIR = build/tests
+BENCH_BUILD_DIR = build/bench
+TIZEN_ARM_BUILD_DIR = build/tizen-arm
+TIZEN_X86_BUILD_DIR = build/tizen-x86
+
+TOOLCHAIN_DIR = toolchains
+OSX_TARGET = tangram
+IOS_TARGET = tangram
+IOS_FRAMEWORK_TARGET = TangramMap
+OSX_XCODE_PROJ = tangram.xcodeproj
+IOS_XCODE_PROJ = tangram.xcodeproj
+IOS_FRAMEWORK_XCODE_PROJ = tangram.xcodeproj
+
+XCPRETTY = $(shell command -v xcpretty 2> /dev/null)
+
+# Default build type is Release
+CONFIG = Release
+ifdef DEBUG
+       CONFIG = Debug
+endif
+
+ifdef DEBUG
+       BUILD_TYPE = -DCMAKE_BUILD_TYPE=Debug
+endif
+ifdef RELEASE
+       BUILD_TYPE = -DCMAKE_BUILD_TYPE=Release
+endif
+
+ifndef TANGRAM_CMAKE_OPTIONS
+       TANGRAM_CMAKE_OPTIONS = \
+               -DBENCHMARK=0 \
+               -DUNIT_TESTS=0
+endif
+
+# Build for iOS simulator architecture only
+ifdef TANGRAM_IOS_FRAMEWORK_SLIM
+       IOS_FRAMEWORK_PATH = ${IOS_FRAMEWORK_SIM_BUILD_DIR}/lib/${CONFIG}/TangramMap.framework
+       IOS_FRAMEWORK_DEVICE_ARCHS = ''
+       IOS_FRAMEWORK_SIM_ARCHS = 'x86_64'
+else
+       IOS_FRAMEWORK_PATH = ${IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR}/${CONFIG}/TangramMap.framework
+       IOS_FRAMEWORK_DEVICE_ARCHS = 'armv7 armv7s arm64'
+       IOS_FRAMEWORK_SIM_ARCHS = 'i386 x86_64'
+endif
+
+BENCH_CMAKE_PARAMS = \
+       -DBENCHMARK=1 \
+       -DAPPLICATION=0 \
+       -DCMAKE_BUILD_TYPE=Release
+
+UNIT_TESTS_CMAKE_PARAMS = \
+       -DUNIT_TESTS=1 \
+       -DAPPLICATION=0 \
+       -DCMAKE_BUILD_TYPE=Debug
+
+IOS_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=ios \
+       -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_DIR}/iOS.toolchain.cmake \
+       -DTANGRAM_FRAMEWORK=${IOS_FRAMEWORK_PATH} \
+       -G Xcode
+
+IOS_FRAMEWORK_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=ios.framework \
+       -DIOS_SIMULATOR_ARCHS=${IOS_FRAMEWORK_SIM_ARCHS} \
+       -DIOS_DEVICE_ARCHS=${IOS_FRAMEWORK_DEVICE_ARCHS} \
+       -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_DIR}/iOS.toolchain.cmake \
+       -G Xcode
+
+DARWIN_XCODE_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=darwin \
+       -DCMAKE_OSX_DEPLOYMENT_TARGET:STRING="10.9" \
+       -G Xcode
+
+DARWIN_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=darwin \
+       -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
+
+RPI_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=raspberrypi \
+       -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
+
+LINUX_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DPLATFORM_TARGET=linux \
+       -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
+
+ifndef TIZEN_PROFILE
+       TIZEN_PROFILE=mobile
+endif
+
+ifndef TIZEN_VERSION
+       TIZEN_VERSION=4.0
+endif
+
+ifndef TIZEN_ARCH
+       TIZEN_ARCH=arm
+endif
+
+TIZEN_ARM_CMAKE_PARAMS = \
+        ${BUILD_TYPE} \
+        ${CMAKE_OPTIONS} \
+       -DTIZEN_SDK=$$TIZEN_SDK \
+       -DTIZEN_ARCH=${TIZEN_ARCH} \
+       -DTIZEN_SYSROOT=$$TIZEN_SDK/platforms/tizen-${TIZEN_VERSION}/${TIZEN_PROFILE}/rootstraps/${TIZEN_PROFILE}-${TIZEN_VERSION}-device.core \
+       -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_DIR}/tizen.toolchain.cmake \
+       -DPLATFORM_TARGET=tizen \
+       -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
+
+TIZEN_X86_CMAKE_PARAMS = \
+       ${BUILD_TYPE} \
+       ${CMAKE_OPTIONS} \
+       -DTIZEN_SDK=$$TIZEN_SDK \
+       -DTIZEN_ARCH=${TIZEN_ARCH} \
+       -DTIZEN_SYSROOT=$$TIZEN_SDK/platforms/tizen-${TIZEN_VERSION}/${TIZEN_PROFILE}/rootstraps/${TIZEN_PROFILE}-${TIZEN_VERSION}-emulator.core \
+       -DCMAKE_TOOLCHAIN_FILE=${TOOLCHAIN_DIR}/tizen.toolchain.cmake \
+       -DPLATFORM_TARGET=tizen \
+       -DCMAKE_EXPORT_COMPILE_COMMANDS=TRUE
+
+clean: clean-android clean-osx clean-ios clean-rpi clean-tests clean-xcode clean-linux clean-shaders \
+       clean-tizen-arm clean-tizen-x86
+
+clean-android:
+       rm -rf platforms/android/build
+       rm -rf platforms/android/tangram/build
+       rm -rf platforms/android/tangram/.externalNativeBuild
+       rm -rf platforms/android/demo/build
+
+clean-osx:
+       rm -rf ${OSX_BUILD_DIR}
+
+clean-ios: clean-ios-framework clean-ios-framework-sim clean-ios-framework-universal
+       rm -rf ${IOS_BUILD_DIR}
+
+clean-rpi:
+       rm -rf ${RPI_BUILD_DIR}
+
+clean-linux:
+       rm -rf ${LINUX_BUILD_DIR}
+
+clean-xcode:
+       rm -rf ${OSX_XCODE_BUILD_DIR}
+
+clean-tests:
+       rm -rf ${TESTS_BUILD_DIR}
+
+clean-benchmark:
+       rm -rf ${BENCH_BUILD_DIR}
+
+clean-shaders:
+       rm -rf core/include/shaders/*.h
+
+clean-tizen-arm:
+       rm -rf ${TIZEN_ARM_BUILD_DIR}
+
+clean-tizen-x86:
+       rm -rf ${TIZEN_X86_BUILD_DIR}
+
+clean-ios-framework:
+       rm -rf ${IOS_FRAMEWORK_BUILD_DIR}
+
+clean-ios-framework-sim:
+       rm -rf ${IOS_FRAMEWORK_SIM_BUILD_DIR}
+
+clean-ios-framework-universal:
+       rm -rf ${IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR}
+
+android: android-demo
+       @echo "run: 'adb install -r android/demo/build/outputs/apk/demo-debug.apk'"
+
+android-sdk:
+       @cd platforms/android/ && \
+       ./gradlew tangram:assembleFullRelease
+
+android-demo:
+       @cd platforms/android/ && \
+       ./gradlew demo:assembleDebug
+
+osx: ${OSX_BUILD_DIR}/Makefile
+       @cd ${OSX_BUILD_DIR} && \
+       ${MAKE}
+
+${OSX_BUILD_DIR}/Makefile: cmake-osx
+
+OSX_BUILD = \
+       xcodebuild -target ${OSX_TARGET} -project ${OSX_XCODE_BUILD_DIR}/${OSX_XCODE_PROJ} -configuration ${CONFIG}
+
+xcode: ${OSX_XCODE_BUILD_DIR}/${OSX_XCODE_PROJ}
+ifeq (, $(shell which xcpretty))
+       ${OSX_BUILD}
+else
+       ${OSX_BUILD} | ${XCPRETTY}
+endif
+
+${OSX_XCODE_BUILD_DIR}/${OSX_XCODE_PROJ}: cmake-xcode
+
+cmake-xcode:
+       @mkdir -p ${OSX_XCODE_BUILD_DIR}
+       @cd ${OSX_XCODE_BUILD_DIR} && \
+       cmake ../.. ${DARWIN_XCODE_CMAKE_PARAMS}
+
+cmake-osx:
+       @mkdir -p ${OSX_BUILD_DIR}
+       @cd ${OSX_BUILD_DIR} && \
+       cmake ../.. ${DARWIN_CMAKE_PARAMS}
+
+IOS_BUILD = \
+       xcodebuild -target ${IOS_TARGET} ARCHS=${IOS_FRAMEWORK_SIM_ARCHS} ONLY_ACTIVE_ARCH=NO -sdk iphonesimulator -project ${IOS_BUILD_DIR}/${IOS_XCODE_PROJ} -configuration ${CONFIG}
+
+ios: ${IOS_BUILD_DIR}/${IOS_XCODE_PROJ}
+ifeq (, $(shell which xcpretty))
+       ${IOS_BUILD}
+else
+       ${IOS_BUILD} | ${XCPRETTY}
+endif
+
+ios-docs:
+ifeq (, $(shell which jazzy))
+       $(error "Please install jazzy by running 'gem install jazzy'")
+endif
+       @mkdir -p ${IOS_DOCS_BUILD_DIR}
+       @cd platforms/ios && \
+       jazzy --config jazzy.yml
+
+${IOS_BUILD_DIR}/${IOS_XCODE_PROJ}: cmake-ios
+
+cmake-ios: ios-framework-universal
+       @mkdir -p ${IOS_BUILD_DIR}
+       @cd ${IOS_BUILD_DIR} && \
+       cmake ../.. ${IOS_CMAKE_PARAMS}
+
+cmake-ios-framework:
+ifndef TANGRAM_IOS_FRAMEWORK_SLIM
+       @mkdir -p ${IOS_FRAMEWORK_BUILD_DIR}
+       @cd ${IOS_FRAMEWORK_BUILD_DIR} && \
+       cmake ../.. ${IOS_FRAMEWORK_CMAKE_PARAMS} -DBUILD_IOS_FRAMEWORK=TRUE
+endif
+
+cmake-ios-framework-sim:
+       @mkdir -p ${IOS_FRAMEWORK_SIM_BUILD_DIR}
+       @cd ${IOS_FRAMEWORK_SIM_BUILD_DIR} && \
+       cmake ../.. ${IOS_FRAMEWORK_CMAKE_PARAMS} -DIOS_PLATFORM=SIMULATOR -DBUILD_IOS_FRAMEWORK=TRUE
+
+IOS_FRAMEWORK_BUILD = \
+       xcodebuild -target ${IOS_FRAMEWORK_TARGET} -project ${IOS_FRAMEWORK_BUILD_DIR}/${IOS_FRAMEWORK_XCODE_PROJ} -configuration ${CONFIG}
+
+ios-framework: cmake-ios-framework
+ifndef TANGRAM_IOS_FRAMEWORK_SLIM
+ifeq (, $(shell which xcpretty))
+       ${IOS_FRAMEWORK_BUILD}
+else
+       ${IOS_FRAMEWORK_BUILD} | ${XCPRETTY}
+endif
+endif
+
+IOS_FRAMEWORK_SIM_BUILD = \
+       xcodebuild -target ${IOS_FRAMEWORK_TARGET} -project ${IOS_FRAMEWORK_SIM_BUILD_DIR}/${IOS_FRAMEWORK_XCODE_PROJ} -configuration ${CONFIG}
+
+ios-framework-sim: cmake-ios-framework-sim
+ifeq (, $(shell which xcpretty))
+       ${IOS_FRAMEWORK_SIM_BUILD}
+else
+       ${IOS_FRAMEWORK_SIM_BUILD} | ${XCPRETTY}
+endif
+
+ios-framework-universal: ios-framework ios-framework-sim
+ifndef TANGRAM_IOS_FRAMEWORK_SLIM
+       @mkdir -p ${IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR}/${CONFIG}
+       @cp -r ${IOS_FRAMEWORK_BUILD_DIR}/lib/${CONFIG}/TangramMap.framework ${IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR}/${CONFIG}
+       lipo ${IOS_FRAMEWORK_BUILD_DIR}/lib/${CONFIG}/TangramMap.framework/TangramMap \
+               ${IOS_FRAMEWORK_SIM_BUILD_DIR}/lib/${CONFIG}/TangramMap.framework/TangramMap \
+               -create -output ${IOS_FRAMEWORK_UNIVERSAL_BUILD_DIR}/${CONFIG}/TangramMap.framework/TangramMap
+endif
+
+rpi: cmake-rpi
+       @cd ${RPI_BUILD_DIR} && \
+       ${MAKE}
+
+cmake-rpi:
+       @mkdir -p ${RPI_BUILD_DIR}
+       @cd ${RPI_BUILD_DIR} && \
+       cmake ../.. ${RPI_CMAKE_PARAMS}
+
+linux: cmake-linux
+       cd ${LINUX_BUILD_DIR} && \
+       ${MAKE}
+
+cmake-linux:
+       mkdir -p ${LINUX_BUILD_DIR}
+       cd ${LINUX_BUILD_DIR} &&\
+       cmake ../.. ${LINUX_CMAKE_PARAMS}
+
+tizen-arm: cmake-tizen-arm
+       cd ${TIZEN_ARM_BUILD_DIR} && \
+       ${MAKE}
+
+cmake-tizen-arm:
+       mkdir -p ${TIZEN_ARM_BUILD_DIR}
+       cd ${TIZEN_ARM_BUILD_DIR} &&\
+       cmake ../.. ${TIZEN_ARM_CMAKE_PARAMS}
+
+tizen-x86: cmake-tizen-x86
+       cd ${TIZEN_X86_BUILD_DIR} && \
+       ${MAKE}
+
+cmake-tizen-x86:
+       mkdir -p ${TIZEN_X86_BUILD_DIR}
+       cd ${TIZEN_X86_BUILD_DIR} && \
+       cmake ../.. ${TIZEN_X86_CMAKE_PARAMS}
+
+tests: unit-tests
+
+unit-tests:
+       @mkdir -p ${TESTS_BUILD_DIR}
+       @cd ${TESTS_BUILD_DIR} && \
+       cmake ../.. ${UNIT_TESTS_CMAKE_PARAMS} && \
+       ${MAKE}
+
+benchmark:
+       @mkdir -p ${BENCH_BUILD_DIR}
+       @cd ${BENCH_BUILD_DIR} && \
+       cmake ../../ ${BENCH_CMAKE_PARAMS} && \
+       ${MAKE}
+
+format:
+       @for file in `git diff --diff-filter=ACMRTUXB --name-only -- '*.cpp' '*.h'`; do \
+               if [[ -e $$file ]]; then clang-format -i $$file; fi \
+       done
+       @echo "format done on `git diff --diff-filter=ACMRTUXB --name-only -- '*.cpp' '*.h'`"
+
+### Android Helpers
+android-install:
+       @adb install -r platforms/android/demo/build/outputs/apk/demo-debug.apk
diff --git a/README.md b/README.md
new file mode 100644 (file)
index 0000000..d791f38
--- /dev/null
+++ b/README.md
@@ -0,0 +1,32 @@
+Tangram ES
+==========
+
+Tangram ES is a C++ library for rendering 2D and 3D maps from vector data using OpenGL ES. It is a counterpart to [Tangram](https://github.com/tangrams/tangram) that targets mobile and embedded devices.
+
+This repository contains both the core rendering library and sample applications that use the library on Android, iOS, Mac OS X, Ubuntu, and Raspberry Pi.
+
+![screenshot](images/screenshot.png)
+
+## Platform Targets
+
+For more information about building Tangram ES or using it in your project, see the individual platform pages below:
+
+| Platform                                | Build status                       |
+| --------------------------------------- | ---------------------------------- |
+| [Android](platforms/android) | [![Travis CI BuildStatus](https://travis-ci.org/tangrams/tangram-es.svg?branch=master)](https://travis-ci.org/tangrams/tangram-es/builds) |
+| [iOS](platforms/ios) | [![CircleCI](https://circleci.com/gh/tangrams/tangram-es.svg?style=shield&circle-token=741ff7f06a008b6eb491680c2d47968a7c4eaa3a)](https://circleci.com/gh/tangrams/tangram-es) |
+| [Mac OS X](platforms/osx) | |
+| [Ubuntu Linux](platforms/linux) | [![Travis CI BuildStatus](https://travis-ci.org/tangrams/tangram-es.svg?branch=master)](https://travis-ci.org/tangrams/tangram-es/builds) |
+| [Raspberry Pi](platforms/rpi) | |
+
+## Support
+
+For concept overviews and technical reference, see the [Tangram Documentation](https://mapzen.com/documentation/tangram).
+
+You can also find us in the tangram-chat gitter chat room: https://gitter.im/tangrams/tangram-chat
+
+## Contributions Welcome
+
+We gladly appreciate feedback, feature requests, and contributions. For information and instructions, see [CONTRIBUTING.md](CONTRIBUTING.md).
+
+Tangram ES is an open-source project sponsored by [Mapzen](https://mapzen.com).
diff --git a/bench/CMakeLists.txt b/bench/CMakeLists.txt
new file mode 100644 (file)
index 0000000..32aadc7
--- /dev/null
@@ -0,0 +1,35 @@
+# Build Google Benchmark library.
+set(BENCHMARK_ENABLE_TESTING OFF CACHE BOOL "")
+set(BENCHMARK_ENABLE_LTO OFF CACHE BOOL "")
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/benchmark)
+target_compile_options(benchmark PRIVATE -O3 -DNDEBUG)
+
+file(GLOB BENCH_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp)
+
+# create an executable per bench
+foreach(_src_file_path ${BENCH_SOURCES})
+    string(REPLACE ".cpp" "" bench ${_src_file_path})
+    string(REGEX MATCH "([^/]*)$" bench_name ${bench})
+
+    set(EXECUTABLE_NAME "${bench_name}.out")
+
+    add_executable(${EXECUTABLE_NAME} ${_src_file_path})
+
+    target_include_directories(${EXECUTABLE_NAME}
+        PUBLIC
+        ${CMAKE_CURRENT_SOURCE_DIR}/benchmark/include)
+
+    target_link_libraries(${EXECUTABLE_NAME}
+        ${CORE_LIBRARY}
+        benchmark
+        platform_mock
+        -lpthread)
+
+    set_target_properties(${EXECUTABLE_NAME}
+        PROPERTIES
+        RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/bench")
+
+    add_resources(${EXECUTABLE_NAME} "${PROJECT_SOURCE_DIR}/scenes")
+
+endforeach()
+
diff --git a/bench/src/builders.cpp b/bench/src/builders.cpp
new file mode 100644 (file)
index 0000000..d20c4e7
--- /dev/null
@@ -0,0 +1,61 @@
+#include "tangram.h"
+#include "gl.h"
+
+#include "util/builders.h"
+#include "glm/glm.hpp"
+#include <vector>
+
+#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
+
+using namespace Tangram;
+
+std::vector<glm::vec3> line = {
+    {0.0, 0.0, 0.0},
+    {1.0, 0.0, 0.0},
+    {1.0, 1.0, 0.0},
+    {0.0, 1.0, 0.0},
+};
+
+struct PosNormEnormColVertex {
+    glm::vec3 pos;
+    glm::vec2 texcoord;
+    glm::vec2 enorm;
+    GLfloat ewidth;
+    GLuint abgr;
+    GLfloat layer;
+};
+
+static void BM_Tangram_BuildButtMiterLine(benchmark::State& state) {
+    while(state.KeepRunning()) {
+        std::vector<PosNormEnormColVertex> vertices;
+        PolyLineBuilder builder {
+            [&](const glm::vec3& coord, const glm::vec2& normal, const glm::vec2& uv) {
+                vertices.push_back({ coord, uv, normal, 0.5f, 0xffffff, 0.f });
+            },
+            CapTypes::butt,
+            JoinTypes::miter
+        };
+
+        Builders::buildPolyLine(line, builder);
+    }
+}
+BENCHMARK(BM_Tangram_BuildButtMiterLine);
+
+static void BM_Tangram_BuildRoundRoundLine(benchmark::State& state) {
+    while(state.KeepRunning()) {
+        std::vector<PosNormEnormColVertex> vertices;
+        PolyLineBuilder builder {
+            [&](const glm::vec3& coord, const glm::vec2& normal, const glm::vec2& uv) {
+                vertices.push_back({ coord, uv, normal, 0.5f, 0xffffff, 0.f });
+            },
+            CapTypes::round,
+            JoinTypes::round
+        };
+
+        Builders::buildPolyLine(line, builder);
+    }
+}
+BENCHMARK(BM_Tangram_BuildRoundRoundLine);
+
+BENCHMARK_MAIN();
diff --git a/bench/src/tileLoading.cpp b/bench/src/tileLoading.cpp
new file mode 100644 (file)
index 0000000..30a14d2
--- /dev/null
@@ -0,0 +1,130 @@
+#include "tangram.h"
+#include "gl.h"
+#include "platform_mock.h"
+#include "log.h"
+#include "data/tileSource.h"
+#include "scene/sceneLoader.h"
+#include "scene/scene.h"
+#include "style/style.h"
+#include "scene/importer.h"
+#include "scene/styleContext.h"
+#include "util/mapProjection.h"
+#include "tile/tile.h"
+#include "tile/tileBuilder.h"
+#include "tile/tileTask.h"
+#include "text/fontContext.h"
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+
+#include "benchmark/benchmark_api.h"
+#include "benchmark/benchmark.h"
+
+using namespace Tangram;
+
+struct TestContext {
+
+    MercatorProjection s_projection;
+    const char* sceneFile = "scene.yaml";
+
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+
+    std::shared_ptr<Scene> scene;
+    StyleContext styleContext;
+
+    std::shared_ptr<TileSource> source;
+
+    std::vector<char> rawTileData;
+
+    std::shared_ptr<TileData> tileData;
+
+    std::unique_ptr<TileBuilder> tileBuilder;
+
+    void loadScene(const char* sceneFile) {
+
+        Importer sceneImporter;
+        scene = std::make_shared<Scene>(platform, sceneFile);
+
+        try {
+            scene->config() = sceneImporter.applySceneImports(platform, scene);
+        }
+        catch (YAML::ParserException e) {
+            LOGE("Parsing scene config '%s'", e.what());
+            return;
+        }
+        SceneLoader::applyConfig(platform, scene);
+
+        scene->fontContext()->loadFonts();
+
+        styleContext.initFunctions(*scene);
+        styleContext.setKeywordZoom(0);
+
+        source = *scene->tileSources().begin();
+        tileBuilder = std::make_unique<TileBuilder>(scene);
+    }
+
+    void loadTile(const char* path){
+        std::ifstream resource(path, std::ifstream::ate | std::ifstream::binary);
+        if(!resource.is_open()) {
+            LOGE("Failed to read file at path: %s", path.c_str());
+            return;
+        }
+
+        size_t _size = resource.tellg();
+        resource.seekg(std::ifstream::beg);
+
+        rawTileData.resize(_size);
+
+        resource.read(&rawTileData[0], _size);
+        resource.close();
+    }
+
+    void parseTile() {
+        Tile tile({0,0,10,10,0}, s_projection);
+        source = *scene->tileSources().begin();
+        auto task = source->createTask(tile.getID());
+        auto& t = dynamic_cast<BinaryTileTask&>(*task);
+        t.rawTileData = std::make_shared<std::vector<char>>(rawTileData);
+
+        tileData = source->parse(*task, s_projection);
+    }
+};
+
+class TileLoadingFixture : public benchmark::Fixture {
+public:
+    TestContext ctx;
+    MercatorProjection s_projection;
+    const char* sceneFile = "scene.yaml";
+
+    std::shared_ptr<Tile> result;
+
+    void SetUp() override {
+        LOG("SETUP");
+        ctx.loadScene(sceneFile);
+        ctx.loadTile("tile.mvt");
+        ctx.parseTile();
+        LOG("Ready");
+    }
+    void TearDown() override {
+        result.reset();
+        LOG("TEARDOWN");
+    }
+};
+
+BENCHMARK_DEFINE_F(TileLoadingFixture, BuildTest)(benchmark::State& st) {
+#if 0
+    while (st.KeepRunning()) {
+        ctx.parseTile();
+        result = ctx.tileBuilder->build({0,0,10,10,0}, *ctx.tileData, *ctx.source);
+
+        LOG("ok %d / bytes - %d", bool(result), result->getMemoryUsage());
+    }
+#endif
+}
+
+BENCHMARK_REGISTER_F(TileLoadingFixture, BuildTest);
+
+
+
+BENCHMARK_MAIN();
diff --git a/circle.yml b/circle.yml
new file mode 100644 (file)
index 0000000..89877ef
--- /dev/null
@@ -0,0 +1,21 @@
+machine:
+  xcode:
+    version: 8.1
+  environment:
+    # Dummy values, Circle won't run without a project and scheme.
+    XCODE_PROJECT: build/tangram.xcodeproj
+    XCODE_SCHEME: phony
+checkout:
+  post:
+    - git submodule sync
+    - git submodule update --init
+    - gem install jazzy
+test:
+  override:
+    - if [ $CIRCLE_BRANCH = 'master' ]; then make ios; else make ios TANGRAM_IOS_FRAMEWORK_SLIM=1; fi
+    - make ios-docs
+  post:
+    - if [ $CIRCLE_BRANCH = 'master' ]; then cd build/ios-framework-universal/Release &&
+      zip -r ${CIRCLE_ARTIFACTS}/framework.zip TangramMap.framework; fi
+    - if [ $CIRCLE_BRANCH = 'master' ]; then cd build/ &&
+      zip -r ${CIRCLE_ARTIFACTS}/docs.zip ios-docs; fi
diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt
new file mode 100644 (file)
index 0000000..71e7c45
--- /dev/null
@@ -0,0 +1,134 @@
+# Defines the following cached variables
+#   - CORE_INCLUDE_DIRS, the path where to CORE headers are located
+#   - CORE_LIBRARY, the core library name
+
+project(core)
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+    # using regular Clang or AppleClang
+    list(APPEND CORE_CXX_FLAGS -Wno-gnu-anonymous-struct)
+    list(APPEND CORE_CXX_FLAGS -Wno-nested-anon-types)
+    list(APPEND CORE_CXX_FLAGS -Wno-gnu-zero-variadic-macro-arguments)
+endif()
+
+set(SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/src)
+set(INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/include/tangram)
+set(DEPS_DIR ${CMAKE_CURRENT_SOURCE_DIR}/deps)
+set(GENERATED_DIR ${CMAKE_CURRENT_SOURCE_DIR}/generated)
+
+set(CORE_LIBRARY core CACHE INTERNAL "core library name" FORCE)
+
+if (CMAKE_BUILD_TYPE MATCHES Debug)
+  add_definitions(-DDEBUG)
+  add_definitions(-DLOG_LEVEL=3)
+else()
+  add_definitions(-DLOG_LEVEL=2)
+endif()
+
+if (TANGRAM_WARN_ON_RULE_CONFLICT)
+  add_definitions(-DTANGRAM_WARN_ON_RULE_CONFLICT)
+endif()
+
+file(GLOB_RECURSE FOUND_SOURCES "${SOURCE_DIR}/*.cpp")
+file(GLOB_RECURSE FOUND_HEADERS "${SOURCE_DIR}/*.h")
+
+set(CORE_INCLUDE_DIRS
+  ${SOURCE_DIR}
+  ${INCLUDE_DIR}
+  ${GENERATED_DIR}
+  ${DEPS_DIR}
+  ${DEPS_DIR}/glm
+  ${DEPS_DIR}/earcut/include
+  ${DEPS_DIR}/isect2d/include
+  ${DEPS_DIR}/hash-library
+  ${DEPS_DIR}/mapbox
+  ${DEPS_DIR}/pbf
+  ${DEPS_DIR}/rapidjson
+  ${DEPS_DIR}/sdf
+  ${DEPS_DIR}/SQLiteCpp
+  ${DEPS_DIR}/stb
+  ${DEPS_DIR}/miniz
+  ${DEPS_DIR}/geojson-vt-cpp/geometry.hpp/include
+  ${DEPS_DIR}/geojson-vt-cpp/geojson.hpp/include
+  ${DEPS_DIR}/geojson-vt-cpp/include
+  ${DEPS_DIR}/double-conversion/include
+  CACHE INTERNAL "core include directories" FORCE)
+list(REMOVE_DUPLICATES CORE_INCLUDE_DIRS)
+
+add_library(${CORE_LIBRARY} ${FOUND_SOURCES} ${FOUND_HEADERS})
+
+# Build core library dependencies.
+add_subdirectory(${DEPS_DIR})
+
+# Link core library dependencies.
+set(LINK_LIBRARIES
+    ${CORE_LIBRARY}
+    PUBLIC
+    duktape
+    css-color-parser-cpp
+    yaml-cpp
+    alfons
+    SQLiteCpp
+    sqlite3
+    double-conversion
+    miniz
+    z)
+
+if (UNIX AND NOT APPLE)
+  # SQLite needs dl dynamic library loader when Linux
+  target_link_libraries(${LINK_LIBRARIES} dl)
+else()
+  target_link_libraries(${LINK_LIBRARIES})
+endif ()
+
+target_include_directories(${CORE_LIBRARY}
+  PUBLIC
+  ${CORE_INCLUDE_DIRS})
+
+target_compile_options(${CORE_LIBRARY}
+  PUBLIC
+  ${CORE_CXX_FLAGS})
+
+target_compile_definitions(${CORE_LIBRARY}
+  PUBLIC
+  ${CORE_COMPILE_DEFS})
+
+# make groups for xcode
+group_recursive_sources(src "src")
+
+# add compile shader targets
+file(GLOB_RECURSE SHADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/shaders/*")
+set(SHADER_OUTPUT_DIRECTORY ${GENERATED_DIR})
+foreach(_shader ${SHADER_FILES})
+    get_filename_component(_shader_name ${_shader} NAME_WE)
+    get_filename_component(_shader_ext ${_shader} EXT)
+    string(REGEX REPLACE "\\." "" _shader_ext ${_shader_ext})
+    if(${_shader_ext} STREQUAL "fs" OR ${_shader_ext} STREQUAL "glsl" OR ${_shader_ext} STREQUAL "vs")
+        set(_shader_name ${_shader_name}_${_shader_ext})
+        set(SHADER_OUTPUT ${SHADER_OUTPUT_DIRECTORY}/${_shader_name}.h)
+        add_custom_target(
+            ${_shader_name}
+            DEPENDS ${SHADER_OUTPUT})
+        add_custom_command(
+            OUTPUT ${SHADER_OUTPUT}
+            WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/..
+            MAIN_DEPENDENCY ${_shader}
+            COMMAND ${PROJECT_SOURCE_DIR}/../scripts/incbin.sh
+                ${_shader}
+                core/generated/${_shader_name}.h
+                ${_shader_name})
+        add_dependencies(${CORE_LIBRARY} ${_shader_name})
+    endif()
+endforeach()
+
+# add target to transform the default point texture into a data header
+set(DEFAULT_POINT_TEXTURE_IMAGE ${CMAKE_CURRENT_SOURCE_DIR}/../images/default-point.png)
+set(DEFAULT_POINT_TEXTURE_HEADER ${GENERATED_DIR}/defaultPointTextureData.h)
+add_custom_target(default_point_texture DEPENDS ${DEFAULT_POINT_TEXTURE_HEADER})
+add_custom_command(
+  OUTPUT ${DEFAULT_POINT_TEXTURE_HEADER}
+  WORKING_DIRECTORY ${PROJECT_SOURCE_DIR}/..
+  MAIN_DEPENDENCY ${DEFAULT_POINT_TEXTURE_IMAGE}
+  COMMAND ${PROJECT_SOURCE_DIR}/../scripts/incbin.sh ${DEFAULT_POINT_TEXTURE_IMAGE} ${DEFAULT_POINT_TEXTURE_HEADER} default_point_texture
+  )
+add_dependencies(${CORE_LIBRARY} default_point_texture)
diff --git a/core/deps/CMakeLists.txt b/core/deps/CMakeLists.txt
new file mode 100644 (file)
index 0000000..3d09bc9
--- /dev/null
@@ -0,0 +1,83 @@
+cmake_minimum_required(VERSION 2.8.12)
+
+## yaml-cpp ##
+##############
+set(YAML_CPP_BUILD_TOOLS OFF CACHE BOOL "")
+set(YAML_CPP_BUILD_CONTRIB OFF CACHE BOOL "")
+set(YAML_CPP_INSTALL OFF CACHE BOOL "")
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp)
+
+target_include_directories(yaml-cpp
+  PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}/yaml-cpp/include
+)
+
+## css-color-parser-cpp ##
+##########################
+add_library(css-color-parser-cpp
+  ${CMAKE_CURRENT_SOURCE_DIR}/css-color-parser-cpp/csscolorparser.cpp)
+
+target_include_directories(css-color-parser-cpp
+  PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}/css-color-parser-cpp)
+
+## duktape ##
+#############
+add_library(duktape
+  ${CMAKE_CURRENT_SOURCE_DIR}/duktape/duktape.c)
+
+target_compile_options(duktape PRIVATE
+  -fstrict-aliasing
+  -fomit-frame-pointer
+  -std=c99
+  -Wall)
+
+target_include_directories(duktape
+  PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}/duktape)
+
+## miniz ##
+###########
+add_library(miniz
+    ${CMAKE_CURRENT_SOURCE_DIR}/miniz/miniz.c)
+
+target_include_directories(miniz
+  PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}/miniz)
+
+
+
+if(NOT USE_SYSTEM_FONT_LIBS)
+  ## Harfbuzz - ICU-Common - UCDN - Freetype2 ##
+  ##############################################
+  set(HARFBUZZ_BUILD_ICU ON CACHE BOOL "Enable building of ICU")
+  set(HARFBUZZ_BUILD_UCDN ON CACHE BOOL "Enable building of UCDN")
+  add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/harfbuzz-icu-freetype)
+
+  message(STATUS "harfbuzz" ${HARFBUZZ_LIBRARIES})
+
+  set(ALFONS_DEPS_LIBRARIES
+    ${ALFONS_DEPS_LIBRARIES}
+    harfbuzz ${HARFBUZZ_LIBRARIES}
+    CACHE INTERNAL "alfons-libs" FORCE)
+endif()
+
+## alfons ##
+############
+set(GLM_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/glm)
+add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/alfons)
+
+## SQLiteCpp ##
+###############
+set(SQLITECPP_RUN_CPPLINT OFF CACHE BOOL "")
+set(SQLITECPP_RUN_CPPCHECK OFF CACHE BOOL "")
+set(SQLITE_ENABLE_COLUMN_METADATA OFF CACHE BOOL "")
+
+add_subdirectory(SQLiteCpp)
+
+# Extensions aren't needed for MBTiles and aren't available in older versions of sqlite3.
+target_compile_definitions(SQLiteCpp PRIVATE SQLITE_OMIT_LOAD_EXTENSION)
+
+## double-conversion ##
+#######################
+add_subdirectory(double-conversion)
diff --git a/core/deps/double-conversion/CMakeLists.txt b/core/deps/double-conversion/CMakeLists.txt
new file mode 100644 (file)
index 0000000..eb48f4d
--- /dev/null
@@ -0,0 +1,17 @@
+project(double-conversion)
+
+add_library(double-conversion
+  src/bignum-dtoa.cc
+  src/bignum.cc
+  src/cached-powers.cc
+  src/diy-fp.cc
+  src/double-conversion.cc
+  src/fast-dtoa.cc
+  src/fixed-dtoa.cc
+  src/strtod.cc)
+
+target_include_directories(double-conversion
+  PUBLIC
+  ${CMAKE_CURRENT_SOURCE_DIR}/include
+  PRIVATE
+  ${CMAKE_CURRENT_SOURCE_DIR}/src)
diff --git a/core/deps/double-conversion/include/double-conversion.h b/core/deps/double-conversion/include/double-conversion.h
new file mode 100644 (file)
index 0000000..db9de6f
--- /dev/null
@@ -0,0 +1,538 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+#define DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
+
+#include "../src/utils.h"
+
+namespace double_conversion {
+
+class StringBuilder;
+
+class DoubleToStringConverter {
+ public:
+  // When calling ToFixed with a double > 10^kMaxFixedDigitsBeforePoint
+  // or a requested_digits parameter > kMaxFixedDigitsAfterPoint then the
+  // function returns false.
+  static const int kMaxFixedDigitsBeforePoint = 60;
+  static const int kMaxFixedDigitsAfterPoint = 60;
+
+  // When calling ToExponential with a requested_digits
+  // parameter > kMaxExponentialDigits then the function returns false.
+  static const int kMaxExponentialDigits = 120;
+
+  // When calling ToPrecision with a requested_digits
+  // parameter < kMinPrecisionDigits or requested_digits > kMaxPrecisionDigits
+  // then the function returns false.
+  static const int kMinPrecisionDigits = 1;
+  static const int kMaxPrecisionDigits = 120;
+
+  enum Flags {
+    NO_FLAGS = 0,
+    EMIT_POSITIVE_EXPONENT_SIGN = 1,
+    EMIT_TRAILING_DECIMAL_POINT = 2,
+    EMIT_TRAILING_ZERO_AFTER_POINT = 4,
+    UNIQUE_ZERO = 8
+  };
+
+  // Flags should be a bit-or combination of the possible Flags-enum.
+  //  - NO_FLAGS: no special flags.
+  //  - EMIT_POSITIVE_EXPONENT_SIGN: when the number is converted into exponent
+  //    form, emits a '+' for positive exponents. Example: 1.2e+2.
+  //  - EMIT_TRAILING_DECIMAL_POINT: when the input number is an integer and is
+  //    converted into decimal format then a trailing decimal point is appended.
+  //    Example: 2345.0 is converted to "2345.".
+  //  - EMIT_TRAILING_ZERO_AFTER_POINT: in addition to a trailing decimal point
+  //    emits a trailing '0'-character. This flag requires the
+  //    EXMIT_TRAILING_DECIMAL_POINT flag.
+  //    Example: 2345.0 is converted to "2345.0".
+  //  - UNIQUE_ZERO: "-0.0" is converted to "0.0".
+  //
+  // Infinity symbol and nan_symbol provide the string representation for these
+  // special values. If the string is NULL and the special value is encountered
+  // then the conversion functions return false.
+  //
+  // The exponent_character is used in exponential representations. It is
+  // usually 'e' or 'E'.
+  //
+  // When converting to the shortest representation the converter will
+  // represent input numbers in decimal format if they are in the interval
+  // [10^decimal_in_shortest_low; 10^decimal_in_shortest_high[
+  //    (lower boundary included, greater boundary excluded).
+  // Example: with decimal_in_shortest_low = -6 and
+  //               decimal_in_shortest_high = 21:
+  //   ToShortest(0.000001)  -> "0.000001"
+  //   ToShortest(0.0000001) -> "1e-7"
+  //   ToShortest(111111111111111111111.0)  -> "111111111111111110000"
+  //   ToShortest(100000000000000000000.0)  -> "100000000000000000000"
+  //   ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+  //
+  // When converting to precision mode the converter may add
+  // max_leading_padding_zeroes before returning the number in exponential
+  // format.
+  // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+  //   ToPrecision(0.0000012345, 2) -> "0.0000012"
+  //   ToPrecision(0.00000012345, 2) -> "1.2e-7"
+  // Similarily the converter may add up to
+  // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+  // returning an exponential representation. A zero added by the
+  // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+  // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+  //   ToPrecision(230.0, 2) -> "230"
+  //   ToPrecision(230.0, 2) -> "230."  with EMIT_TRAILING_DECIMAL_POINT.
+  //   ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+  DoubleToStringConverter(int flags,
+                          const char* infinity_symbol,
+                          const char* nan_symbol,
+                          char exponent_character,
+                          int decimal_in_shortest_low,
+                          int decimal_in_shortest_high,
+                          int max_leading_padding_zeroes_in_precision_mode,
+                          int max_trailing_padding_zeroes_in_precision_mode)
+      : flags_(flags),
+        infinity_symbol_(infinity_symbol),
+        nan_symbol_(nan_symbol),
+        exponent_character_(exponent_character),
+        decimal_in_shortest_low_(decimal_in_shortest_low),
+        decimal_in_shortest_high_(decimal_in_shortest_high),
+        max_leading_padding_zeroes_in_precision_mode_(
+            max_leading_padding_zeroes_in_precision_mode),
+        max_trailing_padding_zeroes_in_precision_mode_(
+            max_trailing_padding_zeroes_in_precision_mode) {
+    // When 'trailing zero after the point' is set, then 'trailing point'
+    // must be set too.
+    ASSERT(((flags & EMIT_TRAILING_DECIMAL_POINT) != 0) ||
+        !((flags & EMIT_TRAILING_ZERO_AFTER_POINT) != 0));
+  }
+
+  // Returns a converter following the EcmaScript specification.
+  static const DoubleToStringConverter& EcmaScriptConverter();
+
+  // Computes the shortest string of digits that correctly represent the input
+  // number. Depending on decimal_in_shortest_low and decimal_in_shortest_high
+  // (see constructor) it then either returns a decimal representation, or an
+  // exponential representation.
+  // Example with decimal_in_shortest_low = -6,
+  //              decimal_in_shortest_high = 21,
+  //              EMIT_POSITIVE_EXPONENT_SIGN activated, and
+  //              EMIT_TRAILING_DECIMAL_POINT deactived:
+  //   ToShortest(0.000001)  -> "0.000001"
+  //   ToShortest(0.0000001) -> "1e-7"
+  //   ToShortest(111111111111111111111.0)  -> "111111111111111110000"
+  //   ToShortest(100000000000000000000.0)  -> "100000000000000000000"
+  //   ToShortest(1111111111111111111111.0) -> "1.1111111111111111e+21"
+  //
+  // Note: the conversion may round the output if the returned string
+  // is accurate enough to uniquely identify the input-number.
+  // For example the most precise representation of the double 9e59 equals
+  // "899999999999999918767229449717619953810131273674690656206848", but
+  // the converter will return the shorter (but still correct) "9e59".
+  //
+  // Returns true if the conversion succeeds. The conversion always succeeds
+  // except when the input value is special and no infinity_symbol or
+  // nan_symbol has been given to the constructor.
+  bool ToShortest(double value, StringBuilder* result_builder) const {
+    return ToShortestIeeeNumber(value, result_builder, SHORTEST);
+  }
+
+  // Same as ToShortest, but for single-precision floats.
+  bool ToShortestSingle(float value, StringBuilder* result_builder) const {
+    return ToShortestIeeeNumber(value, result_builder, SHORTEST_SINGLE);
+  }
+
+
+  // Computes a decimal representation with a fixed number of digits after the
+  // decimal point. The last emitted digit is rounded.
+  //
+  // Examples:
+  //   ToFixed(3.12, 1) -> "3.1"
+  //   ToFixed(3.1415, 3) -> "3.142"
+  //   ToFixed(1234.56789, 4) -> "1234.5679"
+  //   ToFixed(1.23, 5) -> "1.23000"
+  //   ToFixed(0.1, 4) -> "0.1000"
+  //   ToFixed(1e30, 2) -> "1000000000000000019884624838656.00"
+  //   ToFixed(0.1, 30) -> "0.100000000000000005551115123126"
+  //   ToFixed(0.1, 17) -> "0.10000000000000001"
+  //
+  // If requested_digits equals 0, then the tail of the result depends on
+  // the EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT.
+  // Examples, for requested_digits == 0,
+  //   let EMIT_TRAILING_DECIMAL_POINT and EMIT_TRAILING_ZERO_AFTER_POINT be
+  //    - false and false: then 123.45 -> 123
+  //                             0.678 -> 1
+  //    - true and false: then 123.45 -> 123.
+  //                            0.678 -> 1.
+  //    - true and true: then 123.45 -> 123.0
+  //                           0.678 -> 1.0
+  //
+  // Returns true if the conversion succeeds. The conversion always succeeds
+  // except for the following cases:
+  //   - the input value is special and no infinity_symbol or nan_symbol has
+  //     been provided to the constructor,
+  //   - 'value' > 10^kMaxFixedDigitsBeforePoint, or
+  //   - 'requested_digits' > kMaxFixedDigitsAfterPoint.
+  // The last two conditions imply that the result will never contain more than
+  // 1 + kMaxFixedDigitsBeforePoint + 1 + kMaxFixedDigitsAfterPoint characters
+  // (one additional character for the sign, and one for the decimal point).
+  bool ToFixed(double value,
+               int requested_digits,
+               StringBuilder* result_builder) const;
+
+  // Computes a representation in exponential format with requested_digits
+  // after the decimal point. The last emitted digit is rounded.
+  // If requested_digits equals -1, then the shortest exponential representation
+  // is computed.
+  //
+  // Examples with EMIT_POSITIVE_EXPONENT_SIGN deactivated, and
+  //               exponent_character set to 'e'.
+  //   ToExponential(3.12, 1) -> "3.1e0"
+  //   ToExponential(5.0, 3) -> "5.000e0"
+  //   ToExponential(0.001, 2) -> "1.00e-3"
+  //   ToExponential(3.1415, -1) -> "3.1415e0"
+  //   ToExponential(3.1415, 4) -> "3.1415e0"
+  //   ToExponential(3.1415, 3) -> "3.142e0"
+  //   ToExponential(123456789000000, 3) -> "1.235e14"
+  //   ToExponential(1000000000000000019884624838656.0, -1) -> "1e30"
+  //   ToExponential(1000000000000000019884624838656.0, 32) ->
+  //                     "1.00000000000000001988462483865600e30"
+  //   ToExponential(1234, 0) -> "1e3"
+  //
+  // Returns true if the conversion succeeds. The conversion always succeeds
+  // except for the following cases:
+  //   - the input value is special and no infinity_symbol or nan_symbol has
+  //     been provided to the constructor,
+  //   - 'requested_digits' > kMaxExponentialDigits.
+  // The last condition implies that the result will never contain more than
+  // kMaxExponentialDigits + 8 characters (the sign, the digit before the
+  // decimal point, the decimal point, the exponent character, the
+  // exponent's sign, and at most 3 exponent digits).
+  bool ToExponential(double value,
+                     int requested_digits,
+                     StringBuilder* result_builder) const;
+
+  // Computes 'precision' leading digits of the given 'value' and returns them
+  // either in exponential or decimal format, depending on
+  // max_{leading|trailing}_padding_zeroes_in_precision_mode (given to the
+  // constructor).
+  // The last computed digit is rounded.
+  //
+  // Example with max_leading_padding_zeroes_in_precision_mode = 6.
+  //   ToPrecision(0.0000012345, 2) -> "0.0000012"
+  //   ToPrecision(0.00000012345, 2) -> "1.2e-7"
+  // Similarily the converter may add up to
+  // max_trailing_padding_zeroes_in_precision_mode in precision mode to avoid
+  // returning an exponential representation. A zero added by the
+  // EMIT_TRAILING_ZERO_AFTER_POINT flag is counted for this limit.
+  // Examples for max_trailing_padding_zeroes_in_precision_mode = 1:
+  //   ToPrecision(230.0, 2) -> "230"
+  //   ToPrecision(230.0, 2) -> "230."  with EMIT_TRAILING_DECIMAL_POINT.
+  //   ToPrecision(230.0, 2) -> "2.3e2" with EMIT_TRAILING_ZERO_AFTER_POINT.
+  // Examples for max_trailing_padding_zeroes_in_precision_mode = 3, and no
+  //    EMIT_TRAILING_ZERO_AFTER_POINT:
+  //   ToPrecision(123450.0, 6) -> "123450"
+  //   ToPrecision(123450.0, 5) -> "123450"
+  //   ToPrecision(123450.0, 4) -> "123500"
+  //   ToPrecision(123450.0, 3) -> "123000"
+  //   ToPrecision(123450.0, 2) -> "1.2e5"
+  //
+  // Returns true if the conversion succeeds. The conversion always succeeds
+  // except for the following cases:
+  //   - the input value is special and no infinity_symbol or nan_symbol has
+  //     been provided to the constructor,
+  //   - precision < kMinPericisionDigits
+  //   - precision > kMaxPrecisionDigits
+  // The last condition implies that the result will never contain more than
+  // kMaxPrecisionDigits + 7 characters (the sign, the decimal point, the
+  // exponent character, the exponent's sign, and at most 3 exponent digits).
+  bool ToPrecision(double value,
+                   int precision,
+                   StringBuilder* result_builder) const;
+
+  enum DtoaMode {
+    // Produce the shortest correct representation.
+    // For example the output of 0.299999999999999988897 is (the less accurate
+    // but correct) 0.3.
+    SHORTEST,
+    // Same as SHORTEST, but for single-precision floats.
+    SHORTEST_SINGLE,
+    // Produce a fixed number of digits after the decimal point.
+    // For instance fixed(0.1, 4) becomes 0.1000
+    // If the input number is big, the output will be big.
+    FIXED,
+    // Fixed number of digits (independent of the decimal point).
+    PRECISION
+  };
+
+  // The maximal number of digits that are needed to emit a double in base 10.
+  // A higher precision can be achieved by using more digits, but the shortest
+  // accurate representation of any double will never use more digits than
+  // kBase10MaximalLength.
+  // Note that DoubleToAscii null-terminates its input. So the given buffer
+  // should be at least kBase10MaximalLength + 1 characters long.
+  static const int kBase10MaximalLength = 17;
+
+  // Converts the given double 'v' to ascii. 'v' must not be NaN, +Infinity, or
+  // -Infinity. In SHORTEST_SINGLE-mode this restriction also applies to 'v'
+  // after it has been casted to a single-precision float. That is, in this
+  // mode static_cast<float>(v) must not be NaN, +Infinity or -Infinity.
+  //
+  // The result should be interpreted as buffer * 10^(point-length).
+  //
+  // The output depends on the given mode:
+  //  - SHORTEST: produce the least amount of digits for which the internal
+  //   identity requirement is still satisfied. If the digits are printed
+  //   (together with the correct exponent) then reading this number will give
+  //   'v' again. The buffer will choose the representation that is closest to
+  //   'v'. If there are two at the same distance, than the one farther away
+  //   from 0 is chosen (halfway cases - ending with 5 - are rounded up).
+  //   In this mode the 'requested_digits' parameter is ignored.
+  //  - SHORTEST_SINGLE: same as SHORTEST but with single-precision.
+  //  - FIXED: produces digits necessary to print a given number with
+  //   'requested_digits' digits after the decimal point. The produced digits
+  //   might be too short in which case the caller has to fill the remainder
+  //   with '0's.
+  //   Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+  //   Halfway cases are rounded towards +/-Infinity (away from 0). The call
+  //   toFixed(0.15, 2) thus returns buffer="2", point=0.
+  //   The returned buffer may contain digits that would be truncated from the
+  //   shortest representation of the input.
+  //  - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+  //   Even though the length of produced digits usually equals
+  //   'requested_digits', the function is allowed to return fewer digits, in
+  //   which case the caller has to fill the missing digits with '0's.
+  //   Halfway cases are again rounded away from 0.
+  // DoubleToAscii expects the given buffer to be big enough to hold all
+  // digits and a terminating null-character. In SHORTEST-mode it expects a
+  // buffer of at least kBase10MaximalLength + 1. In all other modes the
+  // requested_digits parameter and the padding-zeroes limit the size of the
+  // output. Don't forget the decimal point, the exponent character and the
+  // terminating null-character when computing the maximal output size.
+  // The given length is only used in debug mode to ensure the buffer is big
+  // enough.
+  static void DoubleToAscii(double v,
+                            DtoaMode mode,
+                            int requested_digits,
+                            char* buffer,
+                            int buffer_length,
+                            bool* sign,
+                            int* length,
+                            int* point);
+
+ private:
+  // Implementation for ToShortest and ToShortestSingle.
+  bool ToShortestIeeeNumber(double value,
+                            StringBuilder* result_builder,
+                            DtoaMode mode) const;
+
+  // If the value is a special value (NaN or Infinity) constructs the
+  // corresponding string using the configured infinity/nan-symbol.
+  // If either of them is NULL or the value is not special then the
+  // function returns false.
+  bool HandleSpecialValues(double value, StringBuilder* result_builder) const;
+  // Constructs an exponential representation (i.e. 1.234e56).
+  // The given exponent assumes a decimal point after the first decimal digit.
+  void CreateExponentialRepresentation(const char* decimal_digits,
+                                       int length,
+                                       int exponent,
+                                       StringBuilder* result_builder) const;
+  // Creates a decimal representation (i.e 1234.5678).
+  void CreateDecimalRepresentation(const char* decimal_digits,
+                                   int length,
+                                   int decimal_point,
+                                   int digits_after_point,
+                                   StringBuilder* result_builder) const;
+
+  const int flags_;
+  const char* const infinity_symbol_;
+  const char* const nan_symbol_;
+  const char exponent_character_;
+  const int decimal_in_shortest_low_;
+  const int decimal_in_shortest_high_;
+  const int max_leading_padding_zeroes_in_precision_mode_;
+  const int max_trailing_padding_zeroes_in_precision_mode_;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(DoubleToStringConverter);
+};
+
+
+class StringToDoubleConverter {
+ public:
+  // Enumeration for allowing octals and ignoring junk when converting
+  // strings to numbers.
+  enum Flags {
+    NO_FLAGS = 0,
+    ALLOW_HEX = 1,
+    ALLOW_OCTALS = 2,
+    ALLOW_TRAILING_JUNK = 4,
+    ALLOW_LEADING_SPACES = 8,
+    ALLOW_TRAILING_SPACES = 16,
+    ALLOW_SPACES_AFTER_SIGN = 32
+  };
+
+  // Flags should be a bit-or combination of the possible Flags-enum.
+  //  - NO_FLAGS: no special flags.
+  //  - ALLOW_HEX: recognizes the prefix "0x". Hex numbers may only be integers.
+  //      Ex: StringToDouble("0x1234") -> 4660.0
+  //          In StringToDouble("0x1234.56") the characters ".56" are trailing
+  //          junk. The result of the call is hence dependent on
+  //          the ALLOW_TRAILING_JUNK flag and/or the junk value.
+  //      With this flag "0x" is a junk-string. Even with ALLOW_TRAILING_JUNK,
+  //      the string will not be parsed as "0" followed by junk.
+  //
+  //  - ALLOW_OCTALS: recognizes the prefix "0" for octals:
+  //      If a sequence of octal digits starts with '0', then the number is
+  //      read as octal integer. Octal numbers may only be integers.
+  //      Ex: StringToDouble("01234") -> 668.0
+  //          StringToDouble("012349") -> 12349.0  // Not a sequence of octal
+  //                                               // digits.
+  //          In StringToDouble("01234.56") the characters ".56" are trailing
+  //          junk. The result of the call is hence dependent on
+  //          the ALLOW_TRAILING_JUNK flag and/or the junk value.
+  //          In StringToDouble("01234e56") the characters "e56" are trailing
+  //          junk, too.
+  //  - ALLOW_TRAILING_JUNK: ignore trailing characters that are not part of
+  //      a double literal.
+  //  - ALLOW_LEADING_SPACES: skip over leading spaces.
+  //  - ALLOW_TRAILING_SPACES: ignore trailing spaces.
+  //  - ALLOW_SPACES_AFTER_SIGN: ignore spaces after the sign.
+  //       Ex: StringToDouble("-   123.2") -> -123.2.
+  //           StringToDouble("+   123.2") -> 123.2
+  //
+  // empty_string_value is returned when an empty string is given as input.
+  // If ALLOW_LEADING_SPACES or ALLOW_TRAILING_SPACES are set, then a string
+  // containing only spaces is converted to the 'empty_string_value', too.
+  //
+  // junk_string_value is returned when
+  //  a) ALLOW_TRAILING_JUNK is not set, and a junk character (a character not
+  //     part of a double-literal) is found.
+  //  b) ALLOW_TRAILING_JUNK is set, but the string does not start with a
+  //     double literal.
+  //
+  // infinity_symbol and nan_symbol are strings that are used to detect
+  // inputs that represent infinity and NaN. They can be null, in which case
+  // they are ignored.
+  // The conversion routine first reads any possible signs. Then it compares the
+  // following character of the input-string with the first character of
+  // the infinity, and nan-symbol. If either matches, the function assumes, that
+  // a match has been found, and expects the following input characters to match
+  // the remaining characters of the special-value symbol.
+  // This means that the following restrictions apply to special-value symbols:
+  //  - they must not start with signs ('+', or '-'),
+  //  - they must not have the same first character.
+  //  - they must not start with digits.
+  //
+  // Examples:
+  //  flags = ALLOW_HEX | ALLOW_TRAILING_JUNK,
+  //  empty_string_value = 0.0,
+  //  junk_string_value = NaN,
+  //  infinity_symbol = "infinity",
+  //  nan_symbol = "nan":
+  //    StringToDouble("0x1234") -> 4660.0.
+  //    StringToDouble("0x1234K") -> 4660.0.
+  //    StringToDouble("") -> 0.0  // empty_string_value.
+  //    StringToDouble(" ") -> NaN  // junk_string_value.
+  //    StringToDouble(" 1") -> NaN  // junk_string_value.
+  //    StringToDouble("0x") -> NaN  // junk_string_value.
+  //    StringToDouble("-123.45") -> -123.45.
+  //    StringToDouble("--123.45") -> NaN  // junk_string_value.
+  //    StringToDouble("123e45") -> 123e45.
+  //    StringToDouble("123E45") -> 123e45.
+  //    StringToDouble("123e+45") -> 123e45.
+  //    StringToDouble("123E-45") -> 123e-45.
+  //    StringToDouble("123e") -> 123.0  // trailing junk ignored.
+  //    StringToDouble("123e-") -> 123.0  // trailing junk ignored.
+  //    StringToDouble("+NaN") -> NaN  // NaN string literal.
+  //    StringToDouble("-infinity") -> -inf.  // infinity literal.
+  //    StringToDouble("Infinity") -> NaN  // junk_string_value.
+  //
+  //  flags = ALLOW_OCTAL | ALLOW_LEADING_SPACES,
+  //  empty_string_value = 0.0,
+  //  junk_string_value = NaN,
+  //  infinity_symbol = NULL,
+  //  nan_symbol = NULL:
+  //    StringToDouble("0x1234") -> NaN  // junk_string_value.
+  //    StringToDouble("01234") -> 668.0.
+  //    StringToDouble("") -> 0.0  // empty_string_value.
+  //    StringToDouble(" ") -> 0.0  // empty_string_value.
+  //    StringToDouble(" 1") -> 1.0
+  //    StringToDouble("0x") -> NaN  // junk_string_value.
+  //    StringToDouble("0123e45") -> NaN  // junk_string_value.
+  //    StringToDouble("01239E45") -> 1239e45.
+  //    StringToDouble("-infinity") -> NaN  // junk_string_value.
+  //    StringToDouble("NaN") -> NaN  // junk_string_value.
+  StringToDoubleConverter(int flags,
+                          double empty_string_value,
+                          double junk_string_value,
+                          const char* infinity_symbol,
+                          const char* nan_symbol)
+      : flags_(flags),
+        empty_string_value_(empty_string_value),
+        junk_string_value_(junk_string_value),
+        infinity_symbol_(infinity_symbol),
+        nan_symbol_(nan_symbol) {
+  }
+
+  // Performs the conversion.
+  // The output parameter 'processed_characters_count' is set to the number
+  // of characters that have been processed to read the number.
+  // Spaces than are processed with ALLOW_{LEADING|TRAILING}_SPACES are included
+  // in the 'processed_characters_count'. Trailing junk is never included.
+  double StringToDouble(const char* buffer,
+                        int length,
+                        int* processed_characters_count) const {
+    return StringToIeee(buffer, length, processed_characters_count, true);
+  }
+
+  // Same as StringToDouble but reads a float.
+  // Note that this is not equivalent to static_cast<float>(StringToDouble(...))
+  // due to potential double-rounding.
+  float StringToFloat(const char* buffer,
+                      int length,
+                      int* processed_characters_count) const {
+    return static_cast<float>(StringToIeee(buffer, length,
+                                           processed_characters_count, false));
+  }
+
+ private:
+  const int flags_;
+  const double empty_string_value_;
+  const double junk_string_value_;
+  const char* const infinity_symbol_;
+  const char* const nan_symbol_;
+
+  double StringToIeee(const char* buffer,
+                      int length,
+                      int* processed_characters_count,
+                      bool read_as_double) const;
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringToDoubleConverter);
+};
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_DOUBLE_CONVERSION_H_
diff --git a/core/deps/double-conversion/src/bignum-dtoa.cc b/core/deps/double-conversion/src/bignum-dtoa.cc
new file mode 100644 (file)
index 0000000..f1ad7a5
--- /dev/null
@@ -0,0 +1,641 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 <math.h>
+
+#include "bignum-dtoa.h"
+
+#include "bignum.h"
+#include "ieee.h"
+
+namespace double_conversion {
+
+static int NormalizedExponent(uint64_t significand, int exponent) {
+  ASSERT(significand != 0);
+  while ((significand & Double::kHiddenBit) == 0) {
+    significand = significand << 1;
+    exponent = exponent - 1;
+  }
+  return exponent;
+}
+
+
+// Forward declarations:
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k.
+static int EstimatePower(int exponent);
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator.
+static void InitialScaledStartValues(uint64_t significand,
+                                     int exponent,
+                                     bool lower_boundary_is_closer,
+                                     int estimated_power,
+                                     bool need_boundary_deltas,
+                                     Bignum* numerator,
+                                     Bignum* denominator,
+                                     Bignum* delta_minus,
+                                     Bignum* delta_plus);
+// Multiplies numerator/denominator so that its values lies in the range 1-10.
+// Returns decimal_point s.t.
+//  v = numerator'/denominator' * 10^(decimal_point-1)
+//     where numerator' and denominator' are the values of numerator and
+//     denominator after the call to this function.
+static void FixupMultiply10(int estimated_power, bool is_even,
+                            int* decimal_point,
+                            Bignum* numerator, Bignum* denominator,
+                            Bignum* delta_minus, Bignum* delta_plus);
+// Generates digits from the left to the right and stops when the generated
+// digits yield the shortest decimal representation of v.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+                                   Bignum* delta_minus, Bignum* delta_plus,
+                                   bool is_even,
+                                   Vector<char> buffer, int* length);
+// Generates 'requested_digits' after the decimal point.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+                          Bignum* numerator, Bignum* denominator,
+                          Vector<char>(buffer), int* length);
+// Generates 'count' digits of numerator/denominator.
+// Once 'count' digits have been produced rounds the result depending on the
+// remainder (remainders of exactly .5 round upwards). Might update the
+// decimal_point when rounding up (for example for 0.9999).
+static void GenerateCountedDigits(int count, int* decimal_point,
+                                  Bignum* numerator, Bignum* denominator,
+                                  Vector<char>(buffer), int* length);
+
+
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+                Vector<char> buffer, int* length, int* decimal_point) {
+  ASSERT(v > 0);
+  ASSERT(!Double(v).IsSpecial());
+  uint64_t significand;
+  int exponent;
+  bool lower_boundary_is_closer;
+  if (mode == BIGNUM_DTOA_SHORTEST_SINGLE) {
+    float f = static_cast<float>(v);
+    ASSERT(f == v);
+    significand = Single(f).Significand();
+    exponent = Single(f).Exponent();
+    lower_boundary_is_closer = Single(f).LowerBoundaryIsCloser();
+  } else {
+    significand = Double(v).Significand();
+    exponent = Double(v).Exponent();
+    lower_boundary_is_closer = Double(v).LowerBoundaryIsCloser();
+  }
+  bool need_boundary_deltas =
+      (mode == BIGNUM_DTOA_SHORTEST || mode == BIGNUM_DTOA_SHORTEST_SINGLE);
+
+  bool is_even = (significand & 1) == 0;
+  int normalized_exponent = NormalizedExponent(significand, exponent);
+  // estimated_power might be too low by 1.
+  int estimated_power = EstimatePower(normalized_exponent);
+
+  // Shortcut for Fixed.
+  // The requested digits correspond to the digits after the point. If the
+  // number is much too small, then there is no need in trying to get any
+  // digits.
+  if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) {
+    buffer[0] = '\0';
+    *length = 0;
+    // Set decimal-point to -requested_digits. This is what Gay does.
+    // Note that it should not have any effect anyways since the string is
+    // empty.
+    *decimal_point = -requested_digits;
+    return;
+  }
+
+  Bignum numerator;
+  Bignum denominator;
+  Bignum delta_minus;
+  Bignum delta_plus;
+  // Make sure the bignum can grow large enough. The smallest double equals
+  // 4e-324. In this case the denominator needs fewer than 324*4 binary digits.
+  // The maximum double is 1.7976931348623157e308 which needs fewer than
+  // 308*4 binary digits.
+  ASSERT(Bignum::kMaxSignificantBits >= 324*4);
+  InitialScaledStartValues(significand, exponent, lower_boundary_is_closer,
+                           estimated_power, need_boundary_deltas,
+                           &numerator, &denominator,
+                           &delta_minus, &delta_plus);
+  // We now have v = (numerator / denominator) * 10^estimated_power.
+  FixupMultiply10(estimated_power, is_even, decimal_point,
+                  &numerator, &denominator,
+                  &delta_minus, &delta_plus);
+  // We now have v = (numerator / denominator) * 10^(decimal_point-1), and
+  //  1 <= (numerator + delta_plus) / denominator < 10
+  switch (mode) {
+    case BIGNUM_DTOA_SHORTEST:
+    case BIGNUM_DTOA_SHORTEST_SINGLE:
+      GenerateShortestDigits(&numerator, &denominator,
+                             &delta_minus, &delta_plus,
+                             is_even, buffer, length);
+      break;
+    case BIGNUM_DTOA_FIXED:
+      BignumToFixed(requested_digits, decimal_point,
+                    &numerator, &denominator,
+                    buffer, length);
+      break;
+    case BIGNUM_DTOA_PRECISION:
+      GenerateCountedDigits(requested_digits, decimal_point,
+                            &numerator, &denominator,
+                            buffer, length);
+      break;
+    default:
+      UNREACHABLE();
+  }
+  buffer[*length] = '\0';
+}
+
+
+// The procedure starts generating digits from the left to the right and stops
+// when the generated digits yield the shortest decimal representation of v. A
+// decimal representation of v is a number lying closer to v than to any other
+// double, so it converts to v when read.
+//
+// This is true if d, the decimal representation, is between m- and m+, the
+// upper and lower boundaries. d must be strictly between them if !is_even.
+//           m- := (numerator - delta_minus) / denominator
+//           m+ := (numerator + delta_plus) / denominator
+//
+// Precondition: 0 <= (numerator+delta_plus) / denominator < 10.
+//   If 1 <= (numerator+delta_plus) / denominator < 10 then no leading 0 digit
+//   will be produced. This should be the standard precondition.
+static void GenerateShortestDigits(Bignum* numerator, Bignum* denominator,
+                                   Bignum* delta_minus, Bignum* delta_plus,
+                                   bool is_even,
+                                   Vector<char> buffer, int* length) {
+  // Small optimization: if delta_minus and delta_plus are the same just reuse
+  // one of the two bignums.
+  if (Bignum::Equal(*delta_minus, *delta_plus)) {
+    delta_plus = delta_minus;
+  }
+  *length = 0;
+  for (;;) {
+    uint16_t digit;
+    digit = numerator->DivideModuloIntBignum(*denominator);
+    ASSERT(digit <= 9);  // digit is a uint16_t and therefore always positive.
+    // digit = numerator / denominator (integer division).
+    // numerator = numerator % denominator.
+    buffer[(*length)++] = static_cast<char>(digit + '0');
+
+    // Can we stop already?
+    // If the remainder of the division is less than the distance to the lower
+    // boundary we can stop. In this case we simply round down (discarding the
+    // remainder).
+    // Similarly we test if we can round up (using the upper boundary).
+    bool in_delta_room_minus;
+    bool in_delta_room_plus;
+    if (is_even) {
+      in_delta_room_minus = Bignum::LessEqual(*numerator, *delta_minus);
+    } else {
+      in_delta_room_minus = Bignum::Less(*numerator, *delta_minus);
+    }
+    if (is_even) {
+      in_delta_room_plus =
+          Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+    } else {
+      in_delta_room_plus =
+          Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+    }
+    if (!in_delta_room_minus && !in_delta_room_plus) {
+      // Prepare for next iteration.
+      numerator->Times10();
+      delta_minus->Times10();
+      // We optimized delta_plus to be equal to delta_minus (if they share the
+      // same value). So don't multiply delta_plus if they point to the same
+      // object.
+      if (delta_minus != delta_plus) {
+        delta_plus->Times10();
+      }
+    } else if (in_delta_room_minus && in_delta_room_plus) {
+      // Let's see if 2*numerator < denominator.
+      // If yes, then the next digit would be < 5 and we can round down.
+      int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator);
+      if (compare < 0) {
+        // Remaining digits are less than .5. -> Round down (== do nothing).
+      } else if (compare > 0) {
+        // Remaining digits are more than .5 of denominator. -> Round up.
+        // Note that the last digit could not be a '9' as otherwise the whole
+        // loop would have stopped earlier.
+        // We still have an assert here in case the preconditions were not
+        // satisfied.
+        ASSERT(buffer[(*length) - 1] != '9');
+        buffer[(*length) - 1]++;
+      } else {
+        // Halfway case.
+        // TODO(floitsch): need a way to solve half-way cases.
+        //   For now let's round towards even (since this is what Gay seems to
+        //   do).
+
+        if ((buffer[(*length) - 1] - '0') % 2 == 0) {
+          // Round down => Do nothing.
+        } else {
+          ASSERT(buffer[(*length) - 1] != '9');
+          buffer[(*length) - 1]++;
+        }
+      }
+      return;
+    } else if (in_delta_room_minus) {
+      // Round down (== do nothing).
+      return;
+    } else {  // in_delta_room_plus
+      // Round up.
+      // Note again that the last digit could not be '9' since this would have
+      // stopped the loop earlier.
+      // We still have an ASSERT here, in case the preconditions were not
+      // satisfied.
+      ASSERT(buffer[(*length) -1] != '9');
+      buffer[(*length) - 1]++;
+      return;
+    }
+  }
+}
+
+
+// Let v = numerator / denominator < 10.
+// Then we generate 'count' digits of d = x.xxxxx... (without the decimal point)
+// from left to right. Once 'count' digits have been produced we decide wether
+// to round up or down. Remainders of exactly .5 round upwards. Numbers such
+// as 9.999999 propagate a carry all the way, and change the
+// exponent (decimal_point), when rounding upwards.
+static void GenerateCountedDigits(int count, int* decimal_point,
+                                  Bignum* numerator, Bignum* denominator,
+                                  Vector<char> buffer, int* length) {
+  ASSERT(count >= 0);
+  for (int i = 0; i < count - 1; ++i) {
+    uint16_t digit;
+    digit = numerator->DivideModuloIntBignum(*denominator);
+    ASSERT(digit <= 9);  // digit is a uint16_t and therefore always positive.
+    // digit = numerator / denominator (integer division).
+    // numerator = numerator % denominator.
+    buffer[i] = static_cast<char>(digit + '0');
+    // Prepare for next iteration.
+    numerator->Times10();
+  }
+  // Generate the last digit.
+  uint16_t digit;
+  digit = numerator->DivideModuloIntBignum(*denominator);
+  if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+    digit++;
+  }
+  ASSERT(digit <= 10);
+  buffer[count - 1] = static_cast<char>(digit + '0');
+  // Correct bad digits (in case we had a sequence of '9's). Propagate the
+  // carry until we hat a non-'9' or til we reach the first digit.
+  for (int i = count - 1; i > 0; --i) {
+    if (buffer[i] != '0' + 10) break;
+    buffer[i] = '0';
+    buffer[i - 1]++;
+  }
+  if (buffer[0] == '0' + 10) {
+    // Propagate a carry past the top place.
+    buffer[0] = '1';
+    (*decimal_point)++;
+  }
+  *length = count;
+}
+
+
+// Generates 'requested_digits' after the decimal point. It might omit
+// trailing '0's. If the input number is too small then no digits at all are
+// generated (ex.: 2 fixed digits for 0.00001).
+//
+// Input verifies:  1 <= (numerator + delta) / denominator < 10.
+static void BignumToFixed(int requested_digits, int* decimal_point,
+                          Bignum* numerator, Bignum* denominator,
+                          Vector<char>(buffer), int* length) {
+  // Note that we have to look at more than just the requested_digits, since
+  // a number could be rounded up. Example: v=0.5 with requested_digits=0.
+  // Even though the power of v equals 0 we can't just stop here.
+  if (-(*decimal_point) > requested_digits) {
+    // The number is definitively too small.
+    // Ex: 0.001 with requested_digits == 1.
+    // Set decimal-point to -requested_digits. This is what Gay does.
+    // Note that it should not have any effect anyways since the string is
+    // empty.
+    *decimal_point = -requested_digits;
+    *length = 0;
+    return;
+  } else if (-(*decimal_point) == requested_digits) {
+    // We only need to verify if the number rounds down or up.
+    // Ex: 0.04 and 0.06 with requested_digits == 1.
+    ASSERT(*decimal_point == -requested_digits);
+    // Initially the fraction lies in range (1, 10]. Multiply the denominator
+    // by 10 so that we can compare more easily.
+    denominator->Times10();
+    if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) {
+      // If the fraction is >= 0.5 then we have to include the rounded
+      // digit.
+      buffer[0] = '1';
+      *length = 1;
+      (*decimal_point)++;
+    } else {
+      // Note that we caught most of similar cases earlier.
+      *length = 0;
+    }
+    return;
+  } else {
+    // The requested digits correspond to the digits after the point.
+    // The variable 'needed_digits' includes the digits before the point.
+    int needed_digits = (*decimal_point) + requested_digits;
+    GenerateCountedDigits(needed_digits, decimal_point,
+                          numerator, denominator,
+                          buffer, length);
+  }
+}
+
+
+// Returns an estimation of k such that 10^(k-1) <= v < 10^k where
+// v = f * 2^exponent and 2^52 <= f < 2^53.
+// v is hence a normalized double with the given exponent. The output is an
+// approximation for the exponent of the decimal approimation .digits * 10^k.
+//
+// The result might undershoot by 1 in which case 10^k <= v < 10^k+1.
+// Note: this property holds for v's upper boundary m+ too.
+//    10^k <= m+ < 10^k+1.
+//   (see explanation below).
+//
+// Examples:
+//  EstimatePower(0)   => 16
+//  EstimatePower(-52) => 0
+//
+// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0.
+static int EstimatePower(int exponent) {
+  // This function estimates log10 of v where v = f*2^e (with e == exponent).
+  // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)).
+  // Note that f is bounded by its container size. Let p = 53 (the double's
+  // significand size). Then 2^(p-1) <= f < 2^p.
+  //
+  // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close
+  // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)).
+  // The computed number undershoots by less than 0.631 (when we compute log3
+  // and not log10).
+  //
+  // Optimization: since we only need an approximated result this computation
+  // can be performed on 64 bit integers. On x86/x64 architecture the speedup is
+  // not really measurable, though.
+  //
+  // Since we want to avoid overshooting we decrement by 1e10 so that
+  // floating-point imprecisions don't affect us.
+  //
+  // Explanation for v's boundary m+: the computation takes advantage of
+  // the fact that 2^(p-1) <= f < 2^p. Boundaries still satisfy this requirement
+  // (even for denormals where the delta can be much more important).
+
+  const double k1Log10 = 0.30102999566398114;  // 1/lg(10)
+
+  // For doubles len(f) == 53 (don't forget the hidden bit).
+  const int kSignificandSize = Double::kSignificandSize;
+  double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10);
+  return static_cast<int>(estimate);
+}
+
+
+// See comments for InitialScaledStartValues.
+static void InitialScaledStartValuesPositiveExponent(
+    uint64_t significand, int exponent,
+    int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  // A positive exponent implies a positive power.
+  ASSERT(estimated_power >= 0);
+  // Since the estimated_power is positive we simply multiply the denominator
+  // by 10^estimated_power.
+
+  // numerator = v.
+  numerator->AssignUInt64(significand);
+  numerator->ShiftLeft(exponent);
+  // denominator = 10^estimated_power.
+  denominator->AssignPowerUInt16(10, estimated_power);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    denominator->ShiftLeft(1);
+    numerator->ShiftLeft(1);
+    // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+    // denominator (of 2) delta_plus equals 2^e.
+    delta_plus->AssignUInt16(1);
+    delta_plus->ShiftLeft(exponent);
+    // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+    delta_minus->AssignUInt16(1);
+    delta_minus->ShiftLeft(exponent);
+  }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentPositivePower(
+    uint64_t significand, int exponent,
+    int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  // v = f * 2^e with e < 0, and with estimated_power >= 0.
+  // This means that e is close to 0 (have a look at how estimated_power is
+  // computed).
+
+  // numerator = significand
+  //  since v = significand * 2^exponent this is equivalent to
+  //  numerator = v * / 2^-exponent
+  numerator->AssignUInt64(significand);
+  // denominator = 10^estimated_power * 2^-exponent (with exponent < 0)
+  denominator->AssignPowerUInt16(10, estimated_power);
+  denominator->ShiftLeft(-exponent);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    denominator->ShiftLeft(1);
+    numerator->ShiftLeft(1);
+    // Let v = f * 2^e, then m+ - v = 1/2 * 2^e; With the common
+    // denominator (of 2) delta_plus equals 2^e.
+    // Given that the denominator already includes v's exponent the distance
+    // to the boundaries is simply 1.
+    delta_plus->AssignUInt16(1);
+    // Same for delta_minus. The adjustments if f == 2^p-1 are done later.
+    delta_minus->AssignUInt16(1);
+  }
+}
+
+
+// See comments for InitialScaledStartValues
+static void InitialScaledStartValuesNegativeExponentNegativePower(
+    uint64_t significand, int exponent,
+    int estimated_power, bool need_boundary_deltas,
+    Bignum* numerator, Bignum* denominator,
+    Bignum* delta_minus, Bignum* delta_plus) {
+  // Instead of multiplying the denominator with 10^estimated_power we
+  // multiply all values (numerator and deltas) by 10^-estimated_power.
+
+  // Use numerator as temporary container for power_ten.
+  Bignum* power_ten = numerator;
+  power_ten->AssignPowerUInt16(10, -estimated_power);
+
+  if (need_boundary_deltas) {
+    // Since power_ten == numerator we must make a copy of 10^estimated_power
+    // before we complete the computation of the numerator.
+    // delta_plus = delta_minus = 10^estimated_power
+    delta_plus->AssignBignum(*power_ten);
+    delta_minus->AssignBignum(*power_ten);
+  }
+
+  // numerator = significand * 2 * 10^-estimated_power
+  //  since v = significand * 2^exponent this is equivalent to
+  // numerator = v * 10^-estimated_power * 2 * 2^-exponent.
+  // Remember: numerator has been abused as power_ten. So no need to assign it
+  //  to itself.
+  ASSERT(numerator == power_ten);
+  numerator->MultiplyByUInt64(significand);
+
+  // denominator = 2 * 2^-exponent with exponent < 0.
+  denominator->AssignUInt16(1);
+  denominator->ShiftLeft(-exponent);
+
+  if (need_boundary_deltas) {
+    // Introduce a common denominator so that the deltas to the boundaries are
+    // integers.
+    numerator->ShiftLeft(1);
+    denominator->ShiftLeft(1);
+    // With this shift the boundaries have their correct value, since
+    // delta_plus = 10^-estimated_power, and
+    // delta_minus = 10^-estimated_power.
+    // These assignments have been done earlier.
+    // The adjustments if f == 2^p-1 (lower boundary is closer) are done later.
+  }
+}
+
+
+// Let v = significand * 2^exponent.
+// Computes v / 10^estimated_power exactly, as a ratio of two bignums, numerator
+// and denominator. The functions GenerateShortestDigits and
+// GenerateCountedDigits will then convert this ratio to its decimal
+// representation d, with the required accuracy.
+// Then d * 10^estimated_power is the representation of v.
+// (Note: the fraction and the estimated_power might get adjusted before
+// generating the decimal representation.)
+//
+// The initial start values consist of:
+//  - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power.
+//  - a scaled (common) denominator.
+//  optionally (used by GenerateShortestDigits to decide if it has the shortest
+//  decimal converting back to v):
+//  - v - m-: the distance to the lower boundary.
+//  - m+ - v: the distance to the upper boundary.
+//
+// v, m+, m-, and therefore v - m- and m+ - v all share the same denominator.
+//
+// Let ep == estimated_power, then the returned values will satisfy:
+//  v / 10^ep = numerator / denominator.
+//  v's boundarys m- and m+:
+//    m- / 10^ep == v / 10^ep - delta_minus / denominator
+//    m+ / 10^ep == v / 10^ep + delta_plus / denominator
+//  Or in other words:
+//    m- == v - delta_minus * 10^ep / denominator;
+//    m+ == v + delta_plus * 10^ep / denominator;
+//
+// Since 10^(k-1) <= v < 10^k    (with k == estimated_power)
+//  or       10^k <= v < 10^(k+1)
+//  we then have 0.1 <= numerator/denominator < 1
+//           or    1 <= numerator/denominator < 10
+//
+// It is then easy to kickstart the digit-generation routine.
+//
+// The boundary-deltas are only filled if the mode equals BIGNUM_DTOA_SHORTEST
+// or BIGNUM_DTOA_SHORTEST_SINGLE.
+
+static void InitialScaledStartValues(uint64_t significand,
+                                     int exponent,
+                                     bool lower_boundary_is_closer,
+                                     int estimated_power,
+                                     bool need_boundary_deltas,
+                                     Bignum* numerator,
+                                     Bignum* denominator,
+                                     Bignum* delta_minus,
+                                     Bignum* delta_plus) {
+  if (exponent >= 0) {
+    InitialScaledStartValuesPositiveExponent(
+        significand, exponent, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  } else if (estimated_power >= 0) {
+    InitialScaledStartValuesNegativeExponentPositivePower(
+        significand, exponent, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  } else {
+    InitialScaledStartValuesNegativeExponentNegativePower(
+        significand, exponent, estimated_power, need_boundary_deltas,
+        numerator, denominator, delta_minus, delta_plus);
+  }
+
+  if (need_boundary_deltas && lower_boundary_is_closer) {
+    // The lower boundary is closer at half the distance of "normal" numbers.
+    // Increase the common denominator and adapt all but the delta_minus.
+    denominator->ShiftLeft(1);  // *2
+    numerator->ShiftLeft(1);    // *2
+    delta_plus->ShiftLeft(1);   // *2
+  }
+}
+
+
+// This routine multiplies numerator/denominator so that its values lies in the
+// range 1-10. That is after a call to this function we have:
+//    1 <= (numerator + delta_plus) /denominator < 10.
+// Let numerator the input before modification and numerator' the argument
+// after modification, then the output-parameter decimal_point is such that
+//  numerator / denominator * 10^estimated_power ==
+//    numerator' / denominator' * 10^(decimal_point - 1)
+// In some cases estimated_power was too low, and this is already the case. We
+// then simply adjust the power so that 10^(k-1) <= v < 10^k (with k ==
+// estimated_power) but do not touch the numerator or denominator.
+// Otherwise the routine multiplies the numerator and the deltas by 10.
+static void FixupMultiply10(int estimated_power, bool is_even,
+                            int* decimal_point,
+                            Bignum* numerator, Bignum* denominator,
+                            Bignum* delta_minus, Bignum* delta_plus) {
+  bool in_range;
+  if (is_even) {
+    // For IEEE doubles half-way cases (in decimal system numbers ending with 5)
+    // are rounded to the closest floating-point number with even significand.
+    in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) >= 0;
+  } else {
+    in_range = Bignum::PlusCompare(*numerator, *delta_plus, *denominator) > 0;
+  }
+  if (in_range) {
+    // Since numerator + delta_plus >= denominator we already have
+    // 1 <= numerator/denominator < 10. Simply update the estimated_power.
+    *decimal_point = estimated_power + 1;
+  } else {
+    *decimal_point = estimated_power;
+    numerator->Times10();
+    if (Bignum::Equal(*delta_minus, *delta_plus)) {
+      delta_minus->Times10();
+      delta_plus->AssignBignum(*delta_minus);
+    } else {
+      delta_minus->Times10();
+      delta_plus->Times10();
+    }
+  }
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/bignum-dtoa.h b/core/deps/double-conversion/src/bignum-dtoa.h
new file mode 100644 (file)
index 0000000..34b9619
--- /dev/null
@@ -0,0 +1,84 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+#define DOUBLE_CONVERSION_BIGNUM_DTOA_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+enum BignumDtoaMode {
+  // Return the shortest correct representation.
+  // For example the output of 0.299999999999999988897 is (the less accurate but
+  // correct) 0.3.
+  BIGNUM_DTOA_SHORTEST,
+  // Same as BIGNUM_DTOA_SHORTEST but for single-precision floats.
+  BIGNUM_DTOA_SHORTEST_SINGLE,
+  // Return a fixed number of digits after the decimal point.
+  // For instance fixed(0.1, 4) becomes 0.1000
+  // If the input number is big, the output will be big.
+  BIGNUM_DTOA_FIXED,
+  // Return a fixed number of digits, no matter what the exponent is.
+  BIGNUM_DTOA_PRECISION
+};
+
+// Converts the given double 'v' to ascii.
+// The result should be interpreted as buffer * 10^(point-length).
+// The buffer will be null-terminated.
+//
+// The input v must be > 0 and different from NaN, and Infinity.
+//
+// The output depends on the given mode:
+//  - SHORTEST: produce the least amount of digits for which the internal
+//   identity requirement is still satisfied. If the digits are printed
+//   (together with the correct exponent) then reading this number will give
+//   'v' again. The buffer will choose the representation that is closest to
+//   'v'. If there are two at the same distance, than the number is round up.
+//   In this mode the 'requested_digits' parameter is ignored.
+//  - FIXED: produces digits necessary to print a given number with
+//   'requested_digits' digits after the decimal point. The produced digits
+//   might be too short in which case the caller has to fill the gaps with '0's.
+//   Example: toFixed(0.001, 5) is allowed to return buffer="1", point=-2.
+//   Halfway cases are rounded up. The call toFixed(0.15, 2) thus returns
+//     buffer="2", point=0.
+//   Note: the length of the returned buffer has no meaning wrt the significance
+//   of its digits. That is, just because it contains '0's does not mean that
+//   any other digit would not satisfy the internal identity requirement.
+//  - PRECISION: produces 'requested_digits' where the first digit is not '0'.
+//   Even though the length of produced digits usually equals
+//   'requested_digits', the function is allowed to return fewer digits, in
+//   which case the caller has to fill the missing digits with '0's.
+//   Halfway cases are again rounded up.
+// 'BignumDtoa' expects the given buffer to be big enough to hold all digits
+// and a terminating null-character.
+void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits,
+                Vector<char> buffer, int* length, int* point);
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_BIGNUM_DTOA_H_
diff --git a/core/deps/double-conversion/src/bignum.cc b/core/deps/double-conversion/src/bignum.cc
new file mode 100644 (file)
index 0000000..2743d67
--- /dev/null
@@ -0,0 +1,766 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 "bignum.h"
+#include "utils.h"
+
+namespace double_conversion {
+
+Bignum::Bignum()
+    : bigits_(bigits_buffer_, kBigitCapacity), used_digits_(0), exponent_(0) {
+  for (int i = 0; i < kBigitCapacity; ++i) {
+    bigits_[i] = 0;
+  }
+}
+
+
+template<typename S>
+static int BitSize(S value) {
+  (void) value;  // Mark variable as used.
+  return 8 * sizeof(value);
+}
+
+// Guaranteed to lie in one Bigit.
+void Bignum::AssignUInt16(uint16_t value) {
+  ASSERT(kBigitSize >= BitSize(value));
+  Zero();
+  if (value == 0) return;
+
+  EnsureCapacity(1);
+  bigits_[0] = value;
+  used_digits_ = 1;
+}
+
+
+void Bignum::AssignUInt64(uint64_t value) {
+  const int kUInt64Size = 64;
+
+  Zero();
+  if (value == 0) return;
+
+  int needed_bigits = kUInt64Size / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  for (int i = 0; i < needed_bigits; ++i) {
+    bigits_[i] = value & kBigitMask;
+    value = value >> kBigitSize;
+  }
+  used_digits_ = needed_bigits;
+  Clamp();
+}
+
+
+void Bignum::AssignBignum(const Bignum& other) {
+  exponent_ = other.exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    bigits_[i] = other.bigits_[i];
+  }
+  // Clear the excess digits (if there were any).
+  for (int i = other.used_digits_; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = other.used_digits_;
+}
+
+
+static uint64_t ReadUInt64(Vector<const char> buffer,
+                           int from,
+                           int digits_to_read) {
+  uint64_t result = 0;
+  for (int i = from; i < from + digits_to_read; ++i) {
+    int digit = buffer[i] - '0';
+    ASSERT(0 <= digit && digit <= 9);
+    result = result * 10 + digit;
+  }
+  return result;
+}
+
+
+void Bignum::AssignDecimalString(Vector<const char> value) {
+  // 2^64 = 18446744073709551616 > 10^19
+  const int kMaxUint64DecimalDigits = 19;
+  Zero();
+  int length = value.length();
+  int pos = 0;
+  // Let's just say that each digit needs 4 bits.
+  while (length >= kMaxUint64DecimalDigits) {
+    uint64_t digits = ReadUInt64(value, pos, kMaxUint64DecimalDigits);
+    pos += kMaxUint64DecimalDigits;
+    length -= kMaxUint64DecimalDigits;
+    MultiplyByPowerOfTen(kMaxUint64DecimalDigits);
+    AddUInt64(digits);
+  }
+  uint64_t digits = ReadUInt64(value, pos, length);
+  MultiplyByPowerOfTen(length);
+  AddUInt64(digits);
+  Clamp();
+}
+
+
+static int HexCharValue(char c) {
+  if ('0' <= c && c <= '9') return c - '0';
+  if ('a' <= c && c <= 'f') return 10 + c - 'a';
+  ASSERT('A' <= c && c <= 'F');
+  return 10 + c - 'A';
+}
+
+
+void Bignum::AssignHexString(Vector<const char> value) {
+  Zero();
+  int length = value.length();
+
+  int needed_bigits = length * 4 / kBigitSize + 1;
+  EnsureCapacity(needed_bigits);
+  int string_index = length - 1;
+  for (int i = 0; i < needed_bigits - 1; ++i) {
+    // These bigits are guaranteed to be "full".
+    Chunk current_bigit = 0;
+    for (int j = 0; j < kBigitSize / 4; j++) {
+      current_bigit += HexCharValue(value[string_index--]) << (j * 4);
+    }
+    bigits_[i] = current_bigit;
+  }
+  used_digits_ = needed_bigits - 1;
+
+  Chunk most_significant_bigit = 0;  // Could be = 0;
+  for (int j = 0; j <= string_index; ++j) {
+    most_significant_bigit <<= 4;
+    most_significant_bigit += HexCharValue(value[j]);
+  }
+  if (most_significant_bigit != 0) {
+    bigits_[used_digits_] = most_significant_bigit;
+    used_digits_++;
+  }
+  Clamp();
+}
+
+
+void Bignum::AddUInt64(uint64_t operand) {
+  if (operand == 0) return;
+  Bignum other;
+  other.AssignUInt64(operand);
+  AddBignum(other);
+}
+
+
+void Bignum::AddBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+
+  // If this has a greater exponent than other append zero-bigits to this.
+  // After this call exponent_ <= other.exponent_.
+  Align(other);
+
+  // There are two possibilities:
+  //   aaaaaaaaaaa 0000  (where the 0s represent a's exponent)
+  //     bbbbb 00000000
+  //   ----------------
+  //   ccccccccccc 0000
+  // or
+  //    aaaaaaaaaa 0000
+  //  bbbbbbbbb 0000000
+  //  -----------------
+  //  cccccccccccc 0000
+  // In both cases we might need a carry bigit.
+
+  EnsureCapacity(1 + Max(BigitLength(), other.BigitLength()) - exponent_);
+  Chunk carry = 0;
+  int bigit_pos = other.exponent_ - exponent_;
+  ASSERT(bigit_pos >= 0);
+  for (int i = 0; i < other.used_digits_; ++i) {
+    Chunk sum = bigits_[bigit_pos] + other.bigits_[i] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+
+  while (carry != 0) {
+    Chunk sum = bigits_[bigit_pos] + carry;
+    bigits_[bigit_pos] = sum & kBigitMask;
+    carry = sum >> kBigitSize;
+    bigit_pos++;
+  }
+  used_digits_ = Max(bigit_pos, used_digits_);
+  ASSERT(IsClamped());
+}
+
+
+void Bignum::SubtractBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  // We require this to be bigger than other.
+  ASSERT(LessEqual(other, *this));
+
+  Align(other);
+
+  int offset = other.exponent_ - exponent_;
+  Chunk borrow = 0;
+  int i;
+  for (i = 0; i < other.used_digits_; ++i) {
+    ASSERT((borrow == 0) || (borrow == 1));
+    Chunk difference = bigits_[i + offset] - other.bigits_[i] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+  }
+  while (borrow != 0) {
+    Chunk difference = bigits_[i + offset] - borrow;
+    bigits_[i + offset] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+    ++i;
+  }
+  Clamp();
+}
+
+
+void Bignum::ShiftLeft(int shift_amount) {
+  if (used_digits_ == 0) return;
+  exponent_ += shift_amount / kBigitSize;
+  int local_shift = shift_amount % kBigitSize;
+  EnsureCapacity(used_digits_ + 1);
+  BigitsShiftLeft(local_shift);
+}
+
+
+void Bignum::MultiplyByUInt32(uint32_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  if (used_digits_ == 0) return;
+
+  // The product of a bigit with the factor is of size kBigitSize + 32.
+  // Assert that this number + 1 (for the carry) fits into double chunk.
+  ASSERT(kDoubleChunkSize >= kBigitSize + 32 + 1);
+  DoubleChunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * bigits_[i] + carry;
+    bigits_[i] = static_cast<Chunk>(product & kBigitMask);
+    carry = (product >> kBigitSize);
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByUInt64(uint64_t factor) {
+  if (factor == 1) return;
+  if (factor == 0) {
+    Zero();
+    return;
+  }
+  ASSERT(kBigitSize < 32);
+  uint64_t carry = 0;
+  uint64_t low = factor & 0xFFFFFFFF;
+  uint64_t high = factor >> 32;
+  for (int i = 0; i < used_digits_; ++i) {
+    uint64_t product_low = low * bigits_[i];
+    uint64_t product_high = high * bigits_[i];
+    uint64_t tmp = (carry & kBigitMask) + product_low;
+    bigits_[i] = tmp & kBigitMask;
+    carry = (carry >> kBigitSize) + (tmp >> kBigitSize) +
+        (product_high << (32 - kBigitSize));
+  }
+  while (carry != 0) {
+    EnsureCapacity(used_digits_ + 1);
+    bigits_[used_digits_] = carry & kBigitMask;
+    used_digits_++;
+    carry >>= kBigitSize;
+  }
+}
+
+
+void Bignum::MultiplyByPowerOfTen(int exponent) {
+  const uint64_t kFive27 = UINT64_2PART_C(0x6765c793, fa10079d);
+  const uint16_t kFive1 = 5;
+  const uint16_t kFive2 = kFive1 * 5;
+  const uint16_t kFive3 = kFive2 * 5;
+  const uint16_t kFive4 = kFive3 * 5;
+  const uint16_t kFive5 = kFive4 * 5;
+  const uint16_t kFive6 = kFive5 * 5;
+  const uint32_t kFive7 = kFive6 * 5;
+  const uint32_t kFive8 = kFive7 * 5;
+  const uint32_t kFive9 = kFive8 * 5;
+  const uint32_t kFive10 = kFive9 * 5;
+  const uint32_t kFive11 = kFive10 * 5;
+  const uint32_t kFive12 = kFive11 * 5;
+  const uint32_t kFive13 = kFive12 * 5;
+  const uint32_t kFive1_to_12[] =
+      { kFive1, kFive2, kFive3, kFive4, kFive5, kFive6,
+        kFive7, kFive8, kFive9, kFive10, kFive11, kFive12 };
+
+  ASSERT(exponent >= 0);
+  if (exponent == 0) return;
+  if (used_digits_ == 0) return;
+
+  // We shift by exponent at the end just before returning.
+  int remaining_exponent = exponent;
+  while (remaining_exponent >= 27) {
+    MultiplyByUInt64(kFive27);
+    remaining_exponent -= 27;
+  }
+  while (remaining_exponent >= 13) {
+    MultiplyByUInt32(kFive13);
+    remaining_exponent -= 13;
+  }
+  if (remaining_exponent > 0) {
+    MultiplyByUInt32(kFive1_to_12[remaining_exponent - 1]);
+  }
+  ShiftLeft(exponent);
+}
+
+
+void Bignum::Square() {
+  ASSERT(IsClamped());
+  int product_length = 2 * used_digits_;
+  EnsureCapacity(product_length);
+
+  // Comba multiplication: compute each column separately.
+  // Example: r = a2a1a0 * b2b1b0.
+  //    r =  1    * a0b0 +
+  //        10    * (a1b0 + a0b1) +
+  //        100   * (a2b0 + a1b1 + a0b2) +
+  //        1000  * (a2b1 + a1b2) +
+  //        10000 * a2b2
+  //
+  // In the worst case we have to accumulate nb-digits products of digit*digit.
+  //
+  // Assert that the additional number of bits in a DoubleChunk are enough to
+  // sum up used_digits of Bigit*Bigit.
+  if ((1 << (2 * (kChunkSize - kBigitSize))) <= used_digits_) {
+    UNIMPLEMENTED();
+  }
+  DoubleChunk accumulator = 0;
+  // First shift the digits so we don't overwrite them.
+  int copy_offset = used_digits_;
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[copy_offset + i] = bigits_[i];
+  }
+  // We have two loops to avoid some 'if's in the loop.
+  for (int i = 0; i < used_digits_; ++i) {
+    // Process temporary digit i with power i.
+    // The sum of the two indices must be equal to i.
+    int bigit_index1 = i;
+    int bigit_index2 = 0;
+    // Sum all of the sub-products.
+    while (bigit_index1 >= 0) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  for (int i = used_digits_; i < product_length; ++i) {
+    int bigit_index1 = used_digits_ - 1;
+    int bigit_index2 = i - bigit_index1;
+    // Invariant: sum of both indices is again equal to i.
+    // Inner loop runs 0 times on last iteration, emptying accumulator.
+    while (bigit_index2 < used_digits_) {
+      Chunk chunk1 = bigits_[copy_offset + bigit_index1];
+      Chunk chunk2 = bigits_[copy_offset + bigit_index2];
+      accumulator += static_cast<DoubleChunk>(chunk1) * chunk2;
+      bigit_index1--;
+      bigit_index2++;
+    }
+    // The overwritten bigits_[i] will never be read in further loop iterations,
+    // because bigit_index1 and bigit_index2 are always greater
+    // than i - used_digits_.
+    bigits_[i] = static_cast<Chunk>(accumulator) & kBigitMask;
+    accumulator >>= kBigitSize;
+  }
+  // Since the result was guaranteed to lie inside the number the
+  // accumulator must be 0 now.
+  ASSERT(accumulator == 0);
+
+  // Don't forget to update the used_digits and the exponent.
+  used_digits_ = product_length;
+  exponent_ *= 2;
+  Clamp();
+}
+
+
+void Bignum::AssignPowerUInt16(uint16_t base, int power_exponent) {
+  ASSERT(base != 0);
+  ASSERT(power_exponent >= 0);
+  if (power_exponent == 0) {
+    AssignUInt16(1);
+    return;
+  }
+  Zero();
+  int shifts = 0;
+  // We expect base to be in range 2-32, and most often to be 10.
+  // It does not make much sense to implement different algorithms for counting
+  // the bits.
+  while ((base & 1) == 0) {
+    base >>= 1;
+    shifts++;
+  }
+  int bit_size = 0;
+  int tmp_base = base;
+  while (tmp_base != 0) {
+    tmp_base >>= 1;
+    bit_size++;
+  }
+  int final_size = bit_size * power_exponent;
+  // 1 extra bigit for the shifting, and one for rounded final_size.
+  EnsureCapacity(final_size / kBigitSize + 2);
+
+  // Left to Right exponentiation.
+  int mask = 1;
+  while (power_exponent >= mask) mask <<= 1;
+
+  // The mask is now pointing to the bit above the most significant 1-bit of
+  // power_exponent.
+  // Get rid of first 1-bit;
+  mask >>= 2;
+  uint64_t this_value = base;
+
+  bool delayed_multipliciation = false;
+  const uint64_t max_32bits = 0xFFFFFFFF;
+  while (mask != 0 && this_value <= max_32bits) {
+    this_value = this_value * this_value;
+    // Verify that there is enough space in this_value to perform the
+    // multiplication.  The first bit_size bits must be 0.
+    if ((power_exponent & mask) != 0) {
+      uint64_t base_bits_mask =
+          ~((static_cast<uint64_t>(1) << (64 - bit_size)) - 1);
+      bool high_bits_zero = (this_value & base_bits_mask) == 0;
+      if (high_bits_zero) {
+        this_value *= base;
+      } else {
+        delayed_multipliciation = true;
+      }
+    }
+    mask >>= 1;
+  }
+  AssignUInt64(this_value);
+  if (delayed_multipliciation) {
+    MultiplyByUInt32(base);
+  }
+
+  // Now do the same thing as a bignum.
+  while (mask != 0) {
+    Square();
+    if ((power_exponent & mask) != 0) {
+      MultiplyByUInt32(base);
+    }
+    mask >>= 1;
+  }
+
+  // And finally add the saved shifts.
+  ShiftLeft(shifts * power_exponent);
+}
+
+
+// Precondition: this/other < 16bit.
+uint16_t Bignum::DivideModuloIntBignum(const Bignum& other) {
+  ASSERT(IsClamped());
+  ASSERT(other.IsClamped());
+  ASSERT(other.used_digits_ > 0);
+
+  // Easy case: if we have less digits than the divisor than the result is 0.
+  // Note: this handles the case where this == 0, too.
+  if (BigitLength() < other.BigitLength()) {
+    return 0;
+  }
+
+  Align(other);
+
+  uint16_t result = 0;
+
+  // Start by removing multiples of 'other' until both numbers have the same
+  // number of digits.
+  while (BigitLength() > other.BigitLength()) {
+    // This naive approach is extremely inefficient if `this` divided by other
+    // is big. This function is implemented for doubleToString where
+    // the result should be small (less than 10).
+    ASSERT(other.bigits_[other.used_digits_ - 1] >= ((1 << kBigitSize) / 16));
+    ASSERT(bigits_[used_digits_ - 1] < 0x10000);
+    // Remove the multiples of the first digit.
+    // Example this = 23 and other equals 9. -> Remove 2 multiples.
+    result += static_cast<uint16_t>(bigits_[used_digits_ - 1]);
+    SubtractTimes(other, bigits_[used_digits_ - 1]);
+  }
+
+  ASSERT(BigitLength() == other.BigitLength());
+
+  // Both bignums are at the same length now.
+  // Since other has more than 0 digits we know that the access to
+  // bigits_[used_digits_ - 1] is safe.
+  Chunk this_bigit = bigits_[used_digits_ - 1];
+  Chunk other_bigit = other.bigits_[other.used_digits_ - 1];
+
+  if (other.used_digits_ == 1) {
+    // Shortcut for easy (and common) case.
+    int quotient = this_bigit / other_bigit;
+    bigits_[used_digits_ - 1] = this_bigit - other_bigit * quotient;
+    ASSERT(quotient < 0x10000);
+    result += static_cast<uint16_t>(quotient);
+    Clamp();
+    return result;
+  }
+
+  int division_estimate = this_bigit / (other_bigit + 1);
+  ASSERT(division_estimate < 0x10000);
+  result += static_cast<uint16_t>(division_estimate);
+  SubtractTimes(other, division_estimate);
+
+  if (other_bigit * (division_estimate + 1) > this_bigit) {
+    // No need to even try to subtract. Even if other's remaining digits were 0
+    // another subtraction would be too much.
+    return result;
+  }
+
+  while (LessEqual(other, *this)) {
+    SubtractBignum(other);
+    result++;
+  }
+  return result;
+}
+
+
+template<typename S>
+static int SizeInHexChars(S number) {
+  ASSERT(number > 0);
+  int result = 0;
+  while (number != 0) {
+    number >>= 4;
+    result++;
+  }
+  return result;
+}
+
+
+static char HexCharOfValue(int value) {
+  ASSERT(0 <= value && value <= 16);
+  if (value < 10) return static_cast<char>(value + '0');
+  return static_cast<char>(value - 10 + 'A');
+}
+
+
+bool Bignum::ToHexString(char* buffer, int buffer_size) const {
+  ASSERT(IsClamped());
+  // Each bigit must be printable as separate hex-character.
+  ASSERT(kBigitSize % 4 == 0);
+  const int kHexCharsPerBigit = kBigitSize / 4;
+
+  if (used_digits_ == 0) {
+    if (buffer_size < 2) return false;
+    buffer[0] = '0';
+    buffer[1] = '\0';
+    return true;
+  }
+  // We add 1 for the terminating '\0' character.
+  int needed_chars = (BigitLength() - 1) * kHexCharsPerBigit +
+      SizeInHexChars(bigits_[used_digits_ - 1]) + 1;
+  if (needed_chars > buffer_size) return false;
+  int string_index = needed_chars - 1;
+  buffer[string_index--] = '\0';
+  for (int i = 0; i < exponent_; ++i) {
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = '0';
+    }
+  }
+  for (int i = 0; i < used_digits_ - 1; ++i) {
+    Chunk current_bigit = bigits_[i];
+    for (int j = 0; j < kHexCharsPerBigit; ++j) {
+      buffer[string_index--] = HexCharOfValue(current_bigit & 0xF);
+      current_bigit >>= 4;
+    }
+  }
+  // And finally the last bigit.
+  Chunk most_significant_bigit = bigits_[used_digits_ - 1];
+  while (most_significant_bigit != 0) {
+    buffer[string_index--] = HexCharOfValue(most_significant_bigit & 0xF);
+    most_significant_bigit >>= 4;
+  }
+  return true;
+}
+
+
+Bignum::Chunk Bignum::BigitAt(int index) const {
+  if (index >= BigitLength()) return 0;
+  if (index < exponent_) return 0;
+  return bigits_[index - exponent_];
+}
+
+
+int Bignum::Compare(const Bignum& a, const Bignum& b) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  int bigit_length_a = a.BigitLength();
+  int bigit_length_b = b.BigitLength();
+  if (bigit_length_a < bigit_length_b) return -1;
+  if (bigit_length_a > bigit_length_b) return +1;
+  for (int i = bigit_length_a - 1; i >= Min(a.exponent_, b.exponent_); --i) {
+    Chunk bigit_a = a.BigitAt(i);
+    Chunk bigit_b = b.BigitAt(i);
+    if (bigit_a < bigit_b) return -1;
+    if (bigit_a > bigit_b) return +1;
+    // Otherwise they are equal up to this digit. Try the next digit.
+  }
+  return 0;
+}
+
+
+int Bignum::PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c) {
+  ASSERT(a.IsClamped());
+  ASSERT(b.IsClamped());
+  ASSERT(c.IsClamped());
+  if (a.BigitLength() < b.BigitLength()) {
+    return PlusCompare(b, a, c);
+  }
+  if (a.BigitLength() + 1 < c.BigitLength()) return -1;
+  if (a.BigitLength() > c.BigitLength()) return +1;
+  // The exponent encodes 0-bigits. So if there are more 0-digits in 'a' than
+  // 'b' has digits, then the bigit-length of 'a'+'b' must be equal to the one
+  // of 'a'.
+  if (a.exponent_ >= b.BigitLength() && a.BigitLength() < c.BigitLength()) {
+    return -1;
+  }
+
+  Chunk borrow = 0;
+  // Starting at min_exponent all digits are == 0. So no need to compare them.
+  int min_exponent = Min(Min(a.exponent_, b.exponent_), c.exponent_);
+  for (int i = c.BigitLength() - 1; i >= min_exponent; --i) {
+    Chunk chunk_a = a.BigitAt(i);
+    Chunk chunk_b = b.BigitAt(i);
+    Chunk chunk_c = c.BigitAt(i);
+    Chunk sum = chunk_a + chunk_b;
+    if (sum > chunk_c + borrow) {
+      return +1;
+    } else {
+      borrow = chunk_c + borrow - sum;
+      if (borrow > 1) return -1;
+      borrow <<= kBigitSize;
+    }
+  }
+  if (borrow == 0) return 0;
+  return -1;
+}
+
+
+void Bignum::Clamp() {
+  while (used_digits_ > 0 && bigits_[used_digits_ - 1] == 0) {
+    used_digits_--;
+  }
+  if (used_digits_ == 0) {
+    // Zero.
+    exponent_ = 0;
+  }
+}
+
+
+bool Bignum::IsClamped() const {
+  return used_digits_ == 0 || bigits_[used_digits_ - 1] != 0;
+}
+
+
+void Bignum::Zero() {
+  for (int i = 0; i < used_digits_; ++i) {
+    bigits_[i] = 0;
+  }
+  used_digits_ = 0;
+  exponent_ = 0;
+}
+
+
+void Bignum::Align(const Bignum& other) {
+  if (exponent_ > other.exponent_) {
+    // If "X" represents a "hidden" digit (by the exponent) then we are in the
+    // following case (a == this, b == other):
+    // a:  aaaaaaXXXX   or a:   aaaaaXXX
+    // b:     bbbbbbX      b: bbbbbbbbXX
+    // We replace some of the hidden digits (X) of a with 0 digits.
+    // a:  aaaaaa000X   or a:   aaaaa0XX
+    int zero_digits = exponent_ - other.exponent_;
+    EnsureCapacity(used_digits_ + zero_digits);
+    for (int i = used_digits_ - 1; i >= 0; --i) {
+      bigits_[i + zero_digits] = bigits_[i];
+    }
+    for (int i = 0; i < zero_digits; ++i) {
+      bigits_[i] = 0;
+    }
+    used_digits_ += zero_digits;
+    exponent_ -= zero_digits;
+    ASSERT(used_digits_ >= 0);
+    ASSERT(exponent_ >= 0);
+  }
+}
+
+
+void Bignum::BigitsShiftLeft(int shift_amount) {
+  ASSERT(shift_amount < kBigitSize);
+  ASSERT(shift_amount >= 0);
+  Chunk carry = 0;
+  for (int i = 0; i < used_digits_; ++i) {
+    Chunk new_carry = bigits_[i] >> (kBigitSize - shift_amount);
+    bigits_[i] = ((bigits_[i] << shift_amount) + carry) & kBigitMask;
+    carry = new_carry;
+  }
+  if (carry != 0) {
+    bigits_[used_digits_] = carry;
+    used_digits_++;
+  }
+}
+
+
+void Bignum::SubtractTimes(const Bignum& other, int factor) {
+  ASSERT(exponent_ <= other.exponent_);
+  if (factor < 3) {
+    for (int i = 0; i < factor; ++i) {
+      SubtractBignum(other);
+    }
+    return;
+  }
+  Chunk borrow = 0;
+  int exponent_diff = other.exponent_ - exponent_;
+  for (int i = 0; i < other.used_digits_; ++i) {
+    DoubleChunk product = static_cast<DoubleChunk>(factor) * other.bigits_[i];
+    DoubleChunk remove = borrow + product;
+    Chunk difference = bigits_[i + exponent_diff] - (remove & kBigitMask);
+    bigits_[i + exponent_diff] = difference & kBigitMask;
+    borrow = static_cast<Chunk>((difference >> (kChunkSize - 1)) +
+                                (remove >> kBigitSize));
+  }
+  for (int i = other.used_digits_ + exponent_diff; i < used_digits_; ++i) {
+    if (borrow == 0) return;
+    Chunk difference = bigits_[i] - borrow;
+    bigits_[i] = difference & kBigitMask;
+    borrow = difference >> (kChunkSize - 1);
+  }
+  Clamp();
+}
+
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/bignum.h b/core/deps/double-conversion/src/bignum.h
new file mode 100644 (file)
index 0000000..5ec3544
--- /dev/null
@@ -0,0 +1,145 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_BIGNUM_H_
+#define DOUBLE_CONVERSION_BIGNUM_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+class Bignum {
+ public:
+  // 3584 = 128 * 28. We can represent 2^3584 > 10^1000 accurately.
+  // This bignum can encode much bigger numbers, since it contains an
+  // exponent.
+  static const int kMaxSignificantBits = 3584;
+
+  Bignum();
+  void AssignUInt16(uint16_t value);
+  void AssignUInt64(uint64_t value);
+  void AssignBignum(const Bignum& other);
+
+  void AssignDecimalString(Vector<const char> value);
+  void AssignHexString(Vector<const char> value);
+
+  void AssignPowerUInt16(uint16_t base, int exponent);
+
+  void AddUInt16(uint16_t operand);
+  void AddUInt64(uint64_t operand);
+  void AddBignum(const Bignum& other);
+  // Precondition: this >= other.
+  void SubtractBignum(const Bignum& other);
+
+  void Square();
+  void ShiftLeft(int shift_amount);
+  void MultiplyByUInt32(uint32_t factor);
+  void MultiplyByUInt64(uint64_t factor);
+  void MultiplyByPowerOfTen(int exponent);
+  void Times10() { return MultiplyByUInt32(10); }
+  // Pseudocode:
+  //  int result = this / other;
+  //  this = this % other;
+  // In the worst case this function is in O(this/other).
+  uint16_t DivideModuloIntBignum(const Bignum& other);
+
+  bool ToHexString(char* buffer, int buffer_size) const;
+
+  // Returns
+  //  -1 if a < b,
+  //   0 if a == b, and
+  //  +1 if a > b.
+  static int Compare(const Bignum& a, const Bignum& b);
+  static bool Equal(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) == 0;
+  }
+  static bool LessEqual(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) <= 0;
+  }
+  static bool Less(const Bignum& a, const Bignum& b) {
+    return Compare(a, b) < 0;
+  }
+  // Returns Compare(a + b, c);
+  static int PlusCompare(const Bignum& a, const Bignum& b, const Bignum& c);
+  // Returns a + b == c
+  static bool PlusEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) == 0;
+  }
+  // Returns a + b <= c
+  static bool PlusLessEqual(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) <= 0;
+  }
+  // Returns a + b < c
+  static bool PlusLess(const Bignum& a, const Bignum& b, const Bignum& c) {
+    return PlusCompare(a, b, c) < 0;
+  }
+ private:
+  typedef uint32_t Chunk;
+  typedef uint64_t DoubleChunk;
+
+  static const int kChunkSize = sizeof(Chunk) * 8;
+  static const int kDoubleChunkSize = sizeof(DoubleChunk) * 8;
+  // With bigit size of 28 we loose some bits, but a double still fits easily
+  // into two chunks, and more importantly we can use the Comba multiplication.
+  static const int kBigitSize = 28;
+  static const Chunk kBigitMask = (1 << kBigitSize) - 1;
+  // Every instance allocates kBigitLength chunks on the stack. Bignums cannot
+  // grow. There are no checks if the stack-allocated space is sufficient.
+  static const int kBigitCapacity = kMaxSignificantBits / kBigitSize;
+
+  void EnsureCapacity(int size) {
+    if (size > kBigitCapacity) {
+      UNREACHABLE();
+    }
+  }
+  void Align(const Bignum& other);
+  void Clamp();
+  bool IsClamped() const;
+  void Zero();
+  // Requires this to have enough capacity (no tests done).
+  // Updates used_digits_ if necessary.
+  // shift_amount must be < kBigitSize.
+  void BigitsShiftLeft(int shift_amount);
+  // BigitLength includes the "hidden" digits encoded in the exponent.
+  int BigitLength() const { return used_digits_ + exponent_; }
+  Chunk BigitAt(int index) const;
+  void SubtractTimes(const Bignum& other, int factor);
+
+  Chunk bigits_buffer_[kBigitCapacity];
+  // A vector backed by bigits_buffer_. This way accesses to the array are
+  // checked for out-of-bounds errors.
+  Vector<Chunk> bigits_;
+  int used_digits_;
+  // The Bignum's value equals value(bigits_) * 2^(exponent_ * kBigitSize).
+  int exponent_;
+
+  DISALLOW_COPY_AND_ASSIGN(Bignum);
+};
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_BIGNUM_H_
diff --git a/core/deps/double-conversion/src/cached-powers.cc b/core/deps/double-conversion/src/cached-powers.cc
new file mode 100644 (file)
index 0000000..d1359ff
--- /dev/null
@@ -0,0 +1,176 @@
+// Copyright 2006-2008 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 <stdarg.h>
+#include <limits.h>
+#include <math.h>
+
+#include "utils.h"
+
+#include "cached-powers.h"
+
+namespace double_conversion {
+
+struct CachedPower {
+  uint64_t significand;
+  int16_t binary_exponent;
+  int16_t decimal_exponent;
+};
+
+static const CachedPower kCachedPowers[] = {
+  {UINT64_2PART_C(0xfa8fd5a0, 081c0288), -1220, -348},
+  {UINT64_2PART_C(0xbaaee17f, a23ebf76), -1193, -340},
+  {UINT64_2PART_C(0x8b16fb20, 3055ac76), -1166, -332},
+  {UINT64_2PART_C(0xcf42894a, 5dce35ea), -1140, -324},
+  {UINT64_2PART_C(0x9a6bb0aa, 55653b2d), -1113, -316},
+  {UINT64_2PART_C(0xe61acf03, 3d1a45df), -1087, -308},
+  {UINT64_2PART_C(0xab70fe17, c79ac6ca), -1060, -300},
+  {UINT64_2PART_C(0xff77b1fc, bebcdc4f), -1034, -292},
+  {UINT64_2PART_C(0xbe5691ef, 416bd60c), -1007, -284},
+  {UINT64_2PART_C(0x8dd01fad, 907ffc3c), -980, -276},
+  {UINT64_2PART_C(0xd3515c28, 31559a83), -954, -268},
+  {UINT64_2PART_C(0x9d71ac8f, ada6c9b5), -927, -260},
+  {UINT64_2PART_C(0xea9c2277, 23ee8bcb), -901, -252},
+  {UINT64_2PART_C(0xaecc4991, 4078536d), -874, -244},
+  {UINT64_2PART_C(0x823c1279, 5db6ce57), -847, -236},
+  {UINT64_2PART_C(0xc2109436, 4dfb5637), -821, -228},
+  {UINT64_2PART_C(0x9096ea6f, 3848984f), -794, -220},
+  {UINT64_2PART_C(0xd77485cb, 25823ac7), -768, -212},
+  {UINT64_2PART_C(0xa086cfcd, 97bf97f4), -741, -204},
+  {UINT64_2PART_C(0xef340a98, 172aace5), -715, -196},
+  {UINT64_2PART_C(0xb23867fb, 2a35b28e), -688, -188},
+  {UINT64_2PART_C(0x84c8d4df, d2c63f3b), -661, -180},
+  {UINT64_2PART_C(0xc5dd4427, 1ad3cdba), -635, -172},
+  {UINT64_2PART_C(0x936b9fce, bb25c996), -608, -164},
+  {UINT64_2PART_C(0xdbac6c24, 7d62a584), -582, -156},
+  {UINT64_2PART_C(0xa3ab6658, 0d5fdaf6), -555, -148},
+  {UINT64_2PART_C(0xf3e2f893, dec3f126), -529, -140},
+  {UINT64_2PART_C(0xb5b5ada8, aaff80b8), -502, -132},
+  {UINT64_2PART_C(0x87625f05, 6c7c4a8b), -475, -124},
+  {UINT64_2PART_C(0xc9bcff60, 34c13053), -449, -116},
+  {UINT64_2PART_C(0x964e858c, 91ba2655), -422, -108},
+  {UINT64_2PART_C(0xdff97724, 70297ebd), -396, -100},
+  {UINT64_2PART_C(0xa6dfbd9f, b8e5b88f), -369, -92},
+  {UINT64_2PART_C(0xf8a95fcf, 88747d94), -343, -84},
+  {UINT64_2PART_C(0xb9447093, 8fa89bcf), -316, -76},
+  {UINT64_2PART_C(0x8a08f0f8, bf0f156b), -289, -68},
+  {UINT64_2PART_C(0xcdb02555, 653131b6), -263, -60},
+  {UINT64_2PART_C(0x993fe2c6, d07b7fac), -236, -52},
+  {UINT64_2PART_C(0xe45c10c4, 2a2b3b06), -210, -44},
+  {UINT64_2PART_C(0xaa242499, 697392d3), -183, -36},
+  {UINT64_2PART_C(0xfd87b5f2, 8300ca0e), -157, -28},
+  {UINT64_2PART_C(0xbce50864, 92111aeb), -130, -20},
+  {UINT64_2PART_C(0x8cbccc09, 6f5088cc), -103, -12},
+  {UINT64_2PART_C(0xd1b71758, e219652c), -77, -4},
+  {UINT64_2PART_C(0x9c400000, 00000000), -50, 4},
+  {UINT64_2PART_C(0xe8d4a510, 00000000), -24, 12},
+  {UINT64_2PART_C(0xad78ebc5, ac620000), 3, 20},
+  {UINT64_2PART_C(0x813f3978, f8940984), 30, 28},
+  {UINT64_2PART_C(0xc097ce7b, c90715b3), 56, 36},
+  {UINT64_2PART_C(0x8f7e32ce, 7bea5c70), 83, 44},
+  {UINT64_2PART_C(0xd5d238a4, abe98068), 109, 52},
+  {UINT64_2PART_C(0x9f4f2726, 179a2245), 136, 60},
+  {UINT64_2PART_C(0xed63a231, d4c4fb27), 162, 68},
+  {UINT64_2PART_C(0xb0de6538, 8cc8ada8), 189, 76},
+  {UINT64_2PART_C(0x83c7088e, 1aab65db), 216, 84},
+  {UINT64_2PART_C(0xc45d1df9, 42711d9a), 242, 92},
+  {UINT64_2PART_C(0x924d692c, a61be758), 269, 100},
+  {UINT64_2PART_C(0xda01ee64, 1a708dea), 295, 108},
+  {UINT64_2PART_C(0xa26da399, 9aef774a), 322, 116},
+  {UINT64_2PART_C(0xf209787b, b47d6b85), 348, 124},
+  {UINT64_2PART_C(0xb454e4a1, 79dd1877), 375, 132},
+  {UINT64_2PART_C(0x865b8692, 5b9bc5c2), 402, 140},
+  {UINT64_2PART_C(0xc83553c5, c8965d3d), 428, 148},
+  {UINT64_2PART_C(0x952ab45c, fa97a0b3), 455, 156},
+  {UINT64_2PART_C(0xde469fbd, 99a05fe3), 481, 164},
+  {UINT64_2PART_C(0xa59bc234, db398c25), 508, 172},
+  {UINT64_2PART_C(0xf6c69a72, a3989f5c), 534, 180},
+  {UINT64_2PART_C(0xb7dcbf53, 54e9bece), 561, 188},
+  {UINT64_2PART_C(0x88fcf317, f22241e2), 588, 196},
+  {UINT64_2PART_C(0xcc20ce9b, d35c78a5), 614, 204},
+  {UINT64_2PART_C(0x98165af3, 7b2153df), 641, 212},
+  {UINT64_2PART_C(0xe2a0b5dc, 971f303a), 667, 220},
+  {UINT64_2PART_C(0xa8d9d153, 5ce3b396), 694, 228},
+  {UINT64_2PART_C(0xfb9b7cd9, a4a7443c), 720, 236},
+  {UINT64_2PART_C(0xbb764c4c, a7a44410), 747, 244},
+  {UINT64_2PART_C(0x8bab8eef, b6409c1a), 774, 252},
+  {UINT64_2PART_C(0xd01fef10, a657842c), 800, 260},
+  {UINT64_2PART_C(0x9b10a4e5, e9913129), 827, 268},
+  {UINT64_2PART_C(0xe7109bfb, a19c0c9d), 853, 276},
+  {UINT64_2PART_C(0xac2820d9, 623bf429), 880, 284},
+  {UINT64_2PART_C(0x80444b5e, 7aa7cf85), 907, 292},
+  {UINT64_2PART_C(0xbf21e440, 03acdd2d), 933, 300},
+  {UINT64_2PART_C(0x8e679c2f, 5e44ff8f), 960, 308},
+  {UINT64_2PART_C(0xd433179d, 9c8cb841), 986, 316},
+  {UINT64_2PART_C(0x9e19db92, b4e31ba9), 1013, 324},
+  {UINT64_2PART_C(0xeb96bf6e, badf77d9), 1039, 332},
+  {UINT64_2PART_C(0xaf87023b, 9bf0ee6b), 1066, 340},
+};
+
+static const int kCachedPowersLength = ARRAY_SIZE(kCachedPowers);
+static const int kCachedPowersOffset = 348;  // -1 * the first decimal_exponent.
+static const double kD_1_LOG2_10 = 0.30102999566398114;  //  1 / lg(10)
+// Difference between the decimal exponents in the table above.
+const int PowersOfTenCache::kDecimalExponentDistance = 8;
+const int PowersOfTenCache::kMinDecimalExponent = -348;
+const int PowersOfTenCache::kMaxDecimalExponent = 340;
+
+void PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+    int min_exponent,
+    int max_exponent,
+    DiyFp* power,
+    int* decimal_exponent) {
+  int kQ = DiyFp::kSignificandSize;
+  double k = ceil((min_exponent + kQ - 1) * kD_1_LOG2_10);
+  int foo = kCachedPowersOffset;
+  int index =
+      (foo + static_cast<int>(k) - 1) / kDecimalExponentDistance + 1;
+  ASSERT(0 <= index && index < kCachedPowersLength);
+  CachedPower cached_power = kCachedPowers[index];
+  ASSERT(min_exponent <= cached_power.binary_exponent);
+  (void) max_exponent;  // Mark variable as used.
+  ASSERT(cached_power.binary_exponent <= max_exponent);
+  *decimal_exponent = cached_power.decimal_exponent;
+  *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+}
+
+
+void PowersOfTenCache::GetCachedPowerForDecimalExponent(int requested_exponent,
+                                                        DiyFp* power,
+                                                        int* found_exponent) {
+  ASSERT(kMinDecimalExponent <= requested_exponent);
+  ASSERT(requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance);
+  int index =
+      (requested_exponent + kCachedPowersOffset) / kDecimalExponentDistance;
+  CachedPower cached_power = kCachedPowers[index];
+  *power = DiyFp(cached_power.significand, cached_power.binary_exponent);
+  *found_exponent = cached_power.decimal_exponent;
+  ASSERT(*found_exponent <= requested_exponent);
+  ASSERT(requested_exponent < *found_exponent + kDecimalExponentDistance);
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/cached-powers.h b/core/deps/double-conversion/src/cached-powers.h
new file mode 100644 (file)
index 0000000..61a5061
--- /dev/null
@@ -0,0 +1,64 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_CACHED_POWERS_H_
+#define DOUBLE_CONVERSION_CACHED_POWERS_H_
+
+#include "diy-fp.h"
+
+namespace double_conversion {
+
+class PowersOfTenCache {
+ public:
+
+  // Not all powers of ten are cached. The decimal exponent of two neighboring
+  // cached numbers will differ by kDecimalExponentDistance.
+  static const int kDecimalExponentDistance;
+
+  static const int kMinDecimalExponent;
+  static const int kMaxDecimalExponent;
+
+  // Returns a cached power-of-ten with a binary exponent in the range
+  // [min_exponent; max_exponent] (boundaries included).
+  static void GetCachedPowerForBinaryExponentRange(int min_exponent,
+                                                   int max_exponent,
+                                                   DiyFp* power,
+                                                   int* decimal_exponent);
+
+  // Returns a cached power of ten x ~= 10^k such that
+  //   k <= decimal_exponent < k + kCachedPowersDecimalDistance.
+  // The given decimal_exponent must satisfy
+  //   kMinDecimalExponent <= requested_exponent, and
+  //   requested_exponent < kMaxDecimalExponent + kDecimalExponentDistance.
+  static void GetCachedPowerForDecimalExponent(int requested_exponent,
+                                               DiyFp* power,
+                                               int* found_exponent);
+};
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_CACHED_POWERS_H_
diff --git a/core/deps/double-conversion/src/diy-fp.cc b/core/deps/double-conversion/src/diy-fp.cc
new file mode 100644 (file)
index 0000000..ddd1891
--- /dev/null
@@ -0,0 +1,57 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 "diy-fp.h"
+#include "utils.h"
+
+namespace double_conversion {
+
+void DiyFp::Multiply(const DiyFp& other) {
+  // Simply "emulates" a 128 bit multiplication.
+  // However: the resulting number only contains 64 bits. The least
+  // significant 64 bits are only used for rounding the most significant 64
+  // bits.
+  const uint64_t kM32 = 0xFFFFFFFFU;
+  uint64_t a = f_ >> 32;
+  uint64_t b = f_ & kM32;
+  uint64_t c = other.f_ >> 32;
+  uint64_t d = other.f_ & kM32;
+  uint64_t ac = a * c;
+  uint64_t bc = b * c;
+  uint64_t ad = a * d;
+  uint64_t bd = b * d;
+  uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32);
+  // By adding 1U << 31 to tmp we round the final result.
+  // Halfway cases will be round up.
+  tmp += 1U << 31;
+  uint64_t result_f = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32);
+  e_ += other.e_ + 64;
+  f_ = result_f;
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/diy-fp.h b/core/deps/double-conversion/src/diy-fp.h
new file mode 100644 (file)
index 0000000..63f914e
--- /dev/null
@@ -0,0 +1,118 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_DIY_FP_H_
+#define DOUBLE_CONVERSION_DIY_FP_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+// This "Do It Yourself Floating Point" class implements a floating-point number
+// with a uint64 significand and an int exponent. Normalized DiyFp numbers will
+// have the most significant bit of the significand set.
+// Multiplication and Subtraction do not normalize their results.
+// DiyFp are not designed to contain special doubles (NaN and Infinity).
+class DiyFp {
+ public:
+  static const int kSignificandSize = 64;
+
+  DiyFp() : f_(0), e_(0) {}
+  DiyFp(uint64_t significant, int exponent) : f_(significant), e_(exponent) {}
+
+  // this = this - other.
+  // The exponents of both numbers must be the same and the significand of this
+  // must be bigger than the significand of other.
+  // The result will not be normalized.
+  void Subtract(const DiyFp& other) {
+    ASSERT(e_ == other.e_);
+    ASSERT(f_ >= other.f_);
+    f_ -= other.f_;
+  }
+
+  // Returns a - b.
+  // The exponents of both numbers must be the same and this must be bigger
+  // than other. The result will not be normalized.
+  static DiyFp Minus(const DiyFp& a, const DiyFp& b) {
+    DiyFp result = a;
+    result.Subtract(b);
+    return result;
+  }
+
+
+  // this = this * other.
+  void Multiply(const DiyFp& other);
+
+  // returns a * b;
+  static DiyFp Times(const DiyFp& a, const DiyFp& b) {
+    DiyFp result = a;
+    result.Multiply(b);
+    return result;
+  }
+
+  void Normalize() {
+    ASSERT(f_ != 0);
+    uint64_t significant = f_;
+    int exponent = e_;
+
+    // This method is mainly called for normalizing boundaries. In general
+    // boundaries need to be shifted by 10 bits. We thus optimize for this case.
+    const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000);
+    while ((significant & k10MSBits) == 0) {
+      significant <<= 10;
+      exponent -= 10;
+    }
+    while ((significant & kUint64MSB) == 0) {
+      significant <<= 1;
+      exponent--;
+    }
+    f_ = significant;
+    e_ = exponent;
+  }
+
+  static DiyFp Normalize(const DiyFp& a) {
+    DiyFp result = a;
+    result.Normalize();
+    return result;
+  }
+
+  uint64_t f() const { return f_; }
+  int e() const { return e_; }
+
+  void set_f(uint64_t new_value) { f_ = new_value; }
+  void set_e(int new_value) { e_ = new_value; }
+
+ private:
+  static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000);
+
+  uint64_t f_;
+  int e_;
+};
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_DIY_FP_H_
diff --git a/core/deps/double-conversion/src/double-conversion.cc b/core/deps/double-conversion/src/double-conversion.cc
new file mode 100644 (file)
index 0000000..a929375
--- /dev/null
@@ -0,0 +1,911 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 <limits.h>
+#include <math.h>
+
+#include "double-conversion.h"
+
+#include "bignum-dtoa.h"
+#include "fast-dtoa.h"
+#include "fixed-dtoa.h"
+#include "ieee.h"
+#include "strtod.h"
+#include "utils.h"
+
+namespace double_conversion {
+
+const DoubleToStringConverter& DoubleToStringConverter::EcmaScriptConverter() {
+  int flags = UNIQUE_ZERO | EMIT_POSITIVE_EXPONENT_SIGN;
+  static DoubleToStringConverter converter(flags,
+                                           "Infinity",
+                                           "NaN",
+                                           'e',
+                                           -6, 21,
+                                           6, 0);
+  return converter;
+}
+
+
+bool DoubleToStringConverter::HandleSpecialValues(
+    double value,
+    StringBuilder* result_builder) const {
+  Double double_inspect(value);
+  if (double_inspect.IsInfinite()) {
+    if (infinity_symbol_ == NULL) return false;
+    if (value < 0) {
+      result_builder->AddCharacter('-');
+    }
+    result_builder->AddString(infinity_symbol_);
+    return true;
+  }
+  if (double_inspect.IsNan()) {
+    if (nan_symbol_ == NULL) return false;
+    result_builder->AddString(nan_symbol_);
+    return true;
+  }
+  return false;
+}
+
+
+void DoubleToStringConverter::CreateExponentialRepresentation(
+    const char* decimal_digits,
+    int length,
+    int exponent,
+    StringBuilder* result_builder) const {
+  ASSERT(length != 0);
+  result_builder->AddCharacter(decimal_digits[0]);
+  if (length != 1) {
+    result_builder->AddCharacter('.');
+    result_builder->AddSubstring(&decimal_digits[1], length-1);
+  }
+  result_builder->AddCharacter(exponent_character_);
+  if (exponent < 0) {
+    result_builder->AddCharacter('-');
+    exponent = -exponent;
+  } else {
+    if ((flags_ & EMIT_POSITIVE_EXPONENT_SIGN) != 0) {
+      result_builder->AddCharacter('+');
+    }
+  }
+  if (exponent == 0) {
+    result_builder->AddCharacter('0');
+    return;
+  }
+  ASSERT(exponent < 1e4);
+  const int kMaxExponentLength = 5;
+  char buffer[kMaxExponentLength + 1];
+  buffer[kMaxExponentLength] = '\0';
+  int first_char_pos = kMaxExponentLength;
+  while (exponent > 0) {
+    buffer[--first_char_pos] = '0' + (exponent % 10);
+    exponent /= 10;
+  }
+  result_builder->AddSubstring(&buffer[first_char_pos],
+                               kMaxExponentLength - first_char_pos);
+}
+
+
+void DoubleToStringConverter::CreateDecimalRepresentation(
+    const char* decimal_digits,
+    int length,
+    int decimal_point,
+    int digits_after_point,
+    StringBuilder* result_builder) const {
+  // Create a representation that is padded with zeros if needed.
+  if (decimal_point <= 0) {
+      // "0.00000decimal_rep".
+    result_builder->AddCharacter('0');
+    if (digits_after_point > 0) {
+      result_builder->AddCharacter('.');
+      result_builder->AddPadding('0', -decimal_point);
+      ASSERT(length <= digits_after_point - (-decimal_point));
+      result_builder->AddSubstring(decimal_digits, length);
+      int remaining_digits = digits_after_point - (-decimal_point) - length;
+      result_builder->AddPadding('0', remaining_digits);
+    }
+  } else if (decimal_point >= length) {
+    // "decimal_rep0000.00000" or "decimal_rep.0000"
+    result_builder->AddSubstring(decimal_digits, length);
+    result_builder->AddPadding('0', decimal_point - length);
+    if (digits_after_point > 0) {
+      result_builder->AddCharacter('.');
+      result_builder->AddPadding('0', digits_after_point);
+    }
+  } else {
+    // "decima.l_rep000"
+    ASSERT(digits_after_point > 0);
+    result_builder->AddSubstring(decimal_digits, decimal_point);
+    result_builder->AddCharacter('.');
+    ASSERT(length - decimal_point <= digits_after_point);
+    result_builder->AddSubstring(&decimal_digits[decimal_point],
+                                 length - decimal_point);
+    int remaining_digits = digits_after_point - (length - decimal_point);
+    result_builder->AddPadding('0', remaining_digits);
+  }
+  if (digits_after_point == 0) {
+    if ((flags_ & EMIT_TRAILING_DECIMAL_POINT) != 0) {
+      result_builder->AddCharacter('.');
+    }
+    if ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) {
+      result_builder->AddCharacter('0');
+    }
+  }
+}
+
+
+bool DoubleToStringConverter::ToShortestIeeeNumber(
+    double value,
+    StringBuilder* result_builder,
+    DoubleToStringConverter::DtoaMode mode) const {
+  ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE);
+  if (Double(value).IsSpecial()) {
+    return HandleSpecialValues(value, result_builder);
+  }
+
+  int decimal_point;
+  bool sign;
+  const int kDecimalRepCapacity = kBase10MaximalLength + 1;
+  char decimal_rep[kDecimalRepCapacity];
+  int decimal_rep_length;
+
+  DoubleToAscii(value, mode, 0, decimal_rep, kDecimalRepCapacity,
+                &sign, &decimal_rep_length, &decimal_point);
+
+  bool unique_zero = (flags_ & UNIQUE_ZERO) != 0;
+  if (sign && (value != 0.0 || !unique_zero)) {
+    result_builder->AddCharacter('-');
+  }
+
+  int exponent = decimal_point - 1;
+  if ((decimal_in_shortest_low_ <= exponent) &&
+      (exponent < decimal_in_shortest_high_)) {
+    CreateDecimalRepresentation(decimal_rep, decimal_rep_length,
+                                decimal_point,
+                                Max(0, decimal_rep_length - decimal_point),
+                                result_builder);
+  } else {
+    CreateExponentialRepresentation(decimal_rep, decimal_rep_length, exponent,
+                                    result_builder);
+  }
+  return true;
+}
+
+
+bool DoubleToStringConverter::ToFixed(double value,
+                                      int requested_digits,
+                                      StringBuilder* result_builder) const {
+  ASSERT(kMaxFixedDigitsBeforePoint == 60);
+  const double kFirstNonFixed = 1e60;
+
+  if (Double(value).IsSpecial()) {
+    return HandleSpecialValues(value, result_builder);
+  }
+
+  if (requested_digits > kMaxFixedDigitsAfterPoint) return false;
+  if (value >= kFirstNonFixed || value <= -kFirstNonFixed) return false;
+
+  // Find a sufficiently precise decimal representation of n.
+  int decimal_point;
+  bool sign;
+  // Add space for the '\0' byte.
+  const int kDecimalRepCapacity =
+      kMaxFixedDigitsBeforePoint + kMaxFixedDigitsAfterPoint + 1;
+  char decimal_rep[kDecimalRepCapacity];
+  int decimal_rep_length;
+  DoubleToAscii(value, FIXED, requested_digits,
+                decimal_rep, kDecimalRepCapacity,
+                &sign, &decimal_rep_length, &decimal_point);
+
+  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+  if (sign && (value != 0.0 || !unique_zero)) {
+    result_builder->AddCharacter('-');
+  }
+
+  CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+                              requested_digits, result_builder);
+  return true;
+}
+
+
+bool DoubleToStringConverter::ToExponential(
+    double value,
+    int requested_digits,
+    StringBuilder* result_builder) const {
+  if (Double(value).IsSpecial()) {
+    return HandleSpecialValues(value, result_builder);
+  }
+
+  if (requested_digits < -1) return false;
+  if (requested_digits > kMaxExponentialDigits) return false;
+
+  int decimal_point;
+  bool sign;
+  // Add space for digit before the decimal point and the '\0' character.
+  const int kDecimalRepCapacity = kMaxExponentialDigits + 2;
+  ASSERT(kDecimalRepCapacity > kBase10MaximalLength);
+  char decimal_rep[kDecimalRepCapacity];
+  int decimal_rep_length;
+
+  if (requested_digits == -1) {
+    DoubleToAscii(value, SHORTEST, 0,
+                  decimal_rep, kDecimalRepCapacity,
+                  &sign, &decimal_rep_length, &decimal_point);
+  } else {
+    DoubleToAscii(value, PRECISION, requested_digits + 1,
+                  decimal_rep, kDecimalRepCapacity,
+                  &sign, &decimal_rep_length, &decimal_point);
+    ASSERT(decimal_rep_length <= requested_digits + 1);
+
+    for (int i = decimal_rep_length; i < requested_digits + 1; ++i) {
+      decimal_rep[i] = '0';
+    }
+    decimal_rep_length = requested_digits + 1;
+  }
+
+  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+  if (sign && (value != 0.0 || !unique_zero)) {
+    result_builder->AddCharacter('-');
+  }
+
+  int exponent = decimal_point - 1;
+  CreateExponentialRepresentation(decimal_rep,
+                                  decimal_rep_length,
+                                  exponent,
+                                  result_builder);
+  return true;
+}
+
+
+bool DoubleToStringConverter::ToPrecision(double value,
+                                          int precision,
+                                          StringBuilder* result_builder) const {
+  if (Double(value).IsSpecial()) {
+    return HandleSpecialValues(value, result_builder);
+  }
+
+  if (precision < kMinPrecisionDigits || precision > kMaxPrecisionDigits) {
+    return false;
+  }
+
+  // Find a sufficiently precise decimal representation of n.
+  int decimal_point;
+  bool sign;
+  // Add one for the terminating null character.
+  const int kDecimalRepCapacity = kMaxPrecisionDigits + 1;
+  char decimal_rep[kDecimalRepCapacity];
+  int decimal_rep_length;
+
+  DoubleToAscii(value, PRECISION, precision,
+                decimal_rep, kDecimalRepCapacity,
+                &sign, &decimal_rep_length, &decimal_point);
+  ASSERT(decimal_rep_length <= precision);
+
+  bool unique_zero = ((flags_ & UNIQUE_ZERO) != 0);
+  if (sign && (value != 0.0 || !unique_zero)) {
+    result_builder->AddCharacter('-');
+  }
+
+  // The exponent if we print the number as x.xxeyyy. That is with the
+  // decimal point after the first digit.
+  int exponent = decimal_point - 1;
+
+  int extra_zero = ((flags_ & EMIT_TRAILING_ZERO_AFTER_POINT) != 0) ? 1 : 0;
+  if ((-decimal_point + 1 > max_leading_padding_zeroes_in_precision_mode_) ||
+      (decimal_point - precision + extra_zero >
+       max_trailing_padding_zeroes_in_precision_mode_)) {
+    // Fill buffer to contain 'precision' digits.
+    // Usually the buffer is already at the correct length, but 'DoubleToAscii'
+    // is allowed to return less characters.
+    for (int i = decimal_rep_length; i < precision; ++i) {
+      decimal_rep[i] = '0';
+    }
+
+    CreateExponentialRepresentation(decimal_rep,
+                                    precision,
+                                    exponent,
+                                    result_builder);
+  } else {
+    CreateDecimalRepresentation(decimal_rep, decimal_rep_length, decimal_point,
+                                Max(0, precision - decimal_point),
+                                result_builder);
+  }
+  return true;
+}
+
+
+static BignumDtoaMode DtoaToBignumDtoaMode(
+    DoubleToStringConverter::DtoaMode dtoa_mode) {
+  switch (dtoa_mode) {
+    case DoubleToStringConverter::SHORTEST:  return BIGNUM_DTOA_SHORTEST;
+    case DoubleToStringConverter::SHORTEST_SINGLE:
+        return BIGNUM_DTOA_SHORTEST_SINGLE;
+    case DoubleToStringConverter::FIXED:     return BIGNUM_DTOA_FIXED;
+    case DoubleToStringConverter::PRECISION: return BIGNUM_DTOA_PRECISION;
+    default:
+      UNREACHABLE();
+         return BIGNUM_DTOA_SHORTEST;
+  }
+}
+
+
+void DoubleToStringConverter::DoubleToAscii(double v,
+                                            DtoaMode mode,
+                                            int requested_digits,
+                                            char* buffer,
+                                            int buffer_length,
+                                            bool* sign,
+                                            int* length,
+                                            int* point) {
+  Vector<char> vector(buffer, buffer_length);
+  ASSERT(!Double(v).IsSpecial());
+  ASSERT(mode == SHORTEST || mode == SHORTEST_SINGLE || requested_digits >= 0);
+
+  if (Double(v).Sign() < 0) {
+    *sign = true;
+    v = -v;
+  } else {
+    *sign = false;
+  }
+
+  if (mode == PRECISION && requested_digits == 0) {
+    vector[0] = '\0';
+    *length = 0;
+    return;
+  }
+
+  if (v == 0) {
+    vector[0] = '0';
+    vector[1] = '\0';
+    *length = 1;
+    *point = 1;
+    return;
+  }
+
+  bool fast_worked;
+  switch (mode) {
+    case SHORTEST:
+      fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST, 0, vector, length, point);
+      break;
+    case SHORTEST_SINGLE:
+      fast_worked = FastDtoa(v, FAST_DTOA_SHORTEST_SINGLE, 0,
+                             vector, length, point);
+      break;
+    case FIXED:
+      fast_worked = FastFixedDtoa(v, requested_digits, vector, length, point);
+      break;
+    case PRECISION:
+      fast_worked = FastDtoa(v, FAST_DTOA_PRECISION, requested_digits,
+                             vector, length, point);
+      break;
+    default:
+      fast_worked = false;
+      UNREACHABLE();
+  }
+  if (fast_worked) return;
+
+  // If the fast dtoa didn't succeed use the slower bignum version.
+  BignumDtoaMode bignum_mode = DtoaToBignumDtoaMode(mode);
+  BignumDtoa(v, bignum_mode, requested_digits, vector, length, point);
+  vector[*length] = '\0';
+}
+
+
+// Consumes the given substring from the iterator.
+// Returns false, if the substring does not match.
+static bool ConsumeSubString(const char** current,
+                             const char* end,
+                             const char* substring) {
+  ASSERT(**current == *substring);
+  for (substring++; *substring != '\0'; substring++) {
+    ++*current;
+    if (*current == end || **current != *substring) return false;
+  }
+  ++*current;
+  return true;
+}
+
+
+// Maximum number of significant digits in decimal representation.
+// The longest possible double in decimal representation is
+// (2^53 - 1) * 2 ^ -1074 that is (2 ^ 53 - 1) * 5 ^ 1074 / 10 ^ 1074
+// (768 digits). If we parse a number whose first digits are equal to a
+// mean of 2 adjacent doubles (that could have up to 769 digits) the result
+// must be rounded to the bigger one unless the tail consists of zeros, so
+// we don't need to preserve all the digits.
+const int kMaxSignificantDigits = 772;
+
+
+// Returns true if a nonspace found and false if the end has reached.
+static inline bool AdvanceToNonspace(const char** current, const char* end) {
+  while (*current != end) {
+    if (**current != ' ') return true;
+    ++*current;
+  }
+  return false;
+}
+
+
+static bool isDigit(int x, int radix) {
+  return (x >= '0' && x <= '9' && x < '0' + radix)
+      || (radix > 10 && x >= 'a' && x < 'a' + radix - 10)
+      || (radix > 10 && x >= 'A' && x < 'A' + radix - 10);
+}
+
+
+static double SignedZero(bool sign) {
+  return sign ? -0.0 : 0.0;
+}
+
+
+// Returns true if 'c' is a decimal digit that is valid for the given radix.
+//
+// The function is small and could be inlined, but VS2012 emitted a warning
+// because it constant-propagated the radix and concluded that the last
+// condition was always true. By moving it into a separate function the
+// compiler wouldn't warn anymore.
+static bool IsDecimalDigitForRadix(int c, int radix) {
+  return '0' <= c && c <= '9' && (c - '0') < radix;
+}
+
+// Returns true if 'c' is a character digit that is valid for the given radix.
+// The 'a_character' should be 'a' or 'A'.
+//
+// The function is small and could be inlined, but VS2012 emitted a warning
+// because it constant-propagated the radix and concluded that the first
+// condition was always false. By moving it into a separate function the
+// compiler wouldn't warn anymore.
+static bool IsCharacterDigitForRadix(int c, int radix, char a_character) {
+  return radix > 10 && c >= a_character && c < a_character + radix - 10;
+}
+
+
+// Parsing integers with radix 2, 4, 8, 16, 32. Assumes current != end.
+template <int radix_log_2>
+static double RadixStringToIeee(const char* current,
+                                const char* end,
+                                bool sign,
+                                bool allow_trailing_junk,
+                                double junk_string_value,
+                                bool read_as_double,
+                                const char** trailing_pointer) {
+  ASSERT(current != end);
+
+  const int kDoubleSize = Double::kSignificandSize;
+  const int kSingleSize = Single::kSignificandSize;
+  const int kSignificandSize = read_as_double? kDoubleSize: kSingleSize;
+
+  // Skip leading 0s.
+  while (*current == '0') {
+    ++current;
+    if (current == end) {
+      *trailing_pointer = end;
+      return SignedZero(sign);
+    }
+  }
+
+  int64_t number = 0;
+  int exponent = 0;
+  const int radix = (1 << radix_log_2);
+
+  do {
+    int digit;
+    if (IsDecimalDigitForRadix(*current, radix)) {
+      digit = static_cast<char>(*current) - '0';
+    } else if (IsCharacterDigitForRadix(*current, radix, 'a')) {
+      digit = static_cast<char>(*current) - 'a' + 10;
+    } else if (IsCharacterDigitForRadix(*current, radix, 'A')) {
+      digit = static_cast<char>(*current) - 'A' + 10;
+    } else {
+      if (allow_trailing_junk || !AdvanceToNonspace(&current, end)) {
+        break;
+      } else {
+        return junk_string_value;
+      }
+    }
+
+    number = number * radix + digit;
+    int overflow = static_cast<int>(number >> kSignificandSize);
+    if (overflow != 0) {
+      // Overflow occurred. Need to determine which direction to round the
+      // result.
+      int overflow_bits_count = 1;
+      while (overflow > 1) {
+        overflow_bits_count++;
+        overflow >>= 1;
+      }
+
+      int dropped_bits_mask = ((1 << overflow_bits_count) - 1);
+      int dropped_bits = static_cast<int>(number) & dropped_bits_mask;
+      number >>= overflow_bits_count;
+      exponent = overflow_bits_count;
+
+      bool zero_tail = true;
+      for (;;) {
+        ++current;
+        if (current == end || !isDigit(*current, radix)) break;
+        zero_tail = zero_tail && *current == '0';
+        exponent += radix_log_2;
+      }
+
+      if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+        return junk_string_value;
+      }
+
+      int middle_value = (1 << (overflow_bits_count - 1));
+      if (dropped_bits > middle_value) {
+        number++;  // Rounding up.
+      } else if (dropped_bits == middle_value) {
+        // Rounding to even to consistency with decimals: half-way case rounds
+        // up if significant part is odd and down otherwise.
+        if ((number & 1) != 0 || !zero_tail) {
+          number++;  // Rounding up.
+        }
+      }
+
+      // Rounding up may cause overflow.
+      if ((number & ((int64_t)1 << kSignificandSize)) != 0) {
+        exponent++;
+        number >>= 1;
+      }
+      break;
+    }
+    ++current;
+  } while (current != end);
+
+  ASSERT(number < ((int64_t)1 << kSignificandSize));
+  ASSERT(static_cast<int64_t>(static_cast<double>(number)) == number);
+
+  *trailing_pointer = current;
+
+  if (exponent == 0) {
+    if (sign) {
+      if (number == 0) return -0.0;
+      number = -number;
+    }
+    return static_cast<double>(number);
+  }
+
+  ASSERT(number != 0);
+  return Double(DiyFp(number, exponent)).value();
+}
+
+
+double StringToDoubleConverter::StringToIeee(
+    const char* input,
+    int length,
+    int* processed_characters_count,
+    bool read_as_double) const {
+  const char* current = input;
+  const char* end = input + length;
+
+  *processed_characters_count = 0;
+
+  const bool allow_trailing_junk = (flags_ & ALLOW_TRAILING_JUNK) != 0;
+  const bool allow_leading_spaces = (flags_ & ALLOW_LEADING_SPACES) != 0;
+  const bool allow_trailing_spaces = (flags_ & ALLOW_TRAILING_SPACES) != 0;
+  const bool allow_spaces_after_sign = (flags_ & ALLOW_SPACES_AFTER_SIGN) != 0;
+
+  // To make sure that iterator dereferencing is valid the following
+  // convention is used:
+  // 1. Each '++current' statement is followed by check for equality to 'end'.
+  // 2. If AdvanceToNonspace returned false then current == end.
+  // 3. If 'current' becomes equal to 'end' the function returns or goes to
+  // 'parsing_done'.
+  // 4. 'current' is not dereferenced after the 'parsing_done' label.
+  // 5. Code before 'parsing_done' may rely on 'current != end'.
+  if (current == end) return empty_string_value_;
+
+  if (allow_leading_spaces || allow_trailing_spaces) {
+    if (!AdvanceToNonspace(&current, end)) {
+      *processed_characters_count = static_cast<int>(current - input);
+      return empty_string_value_;
+    }
+    if (!allow_leading_spaces && (input != current)) {
+      // No leading spaces allowed, but AdvanceToNonspace moved forward.
+      return junk_string_value_;
+    }
+  }
+
+  // The longest form of simplified number is: "-<significant digits>.1eXXX\0".
+  const int kBufferSize = kMaxSignificantDigits + 10;
+  char buffer[kBufferSize];  // NOLINT: size is known at compile time.
+  int buffer_pos = 0;
+
+  // Exponent will be adjusted if insignificant digits of the integer part
+  // or insignificant leading zeros of the fractional part are dropped.
+  int exponent = 0;
+  int significant_digits = 0;
+  int insignificant_digits = 0;
+  bool nonzero_digit_dropped = false;
+
+  bool sign = false;
+
+  if (*current == '+' || *current == '-') {
+    sign = (*current == '-');
+    ++current;
+    const char* next_non_space = current;
+    // Skip following spaces (if allowed).
+    if (!AdvanceToNonspace(&next_non_space, end)) return junk_string_value_;
+    if (!allow_spaces_after_sign && (current != next_non_space)) {
+      return junk_string_value_;
+    }
+    current = next_non_space;
+  }
+
+  if (infinity_symbol_ != NULL) {
+    if (*current == infinity_symbol_[0]) {
+      if (!ConsumeSubString(&current, end, infinity_symbol_)) {
+        return junk_string_value_;
+      }
+
+      if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+        return junk_string_value_;
+      }
+      if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+        return junk_string_value_;
+      }
+
+      ASSERT(buffer_pos == 0);
+      *processed_characters_count = static_cast<int>(current - input);
+      return sign ? -Double::Infinity() : Double::Infinity();
+    }
+  }
+
+  if (nan_symbol_ != NULL) {
+    if (*current == nan_symbol_[0]) {
+      if (!ConsumeSubString(&current, end, nan_symbol_)) {
+        return junk_string_value_;
+      }
+
+      if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+        return junk_string_value_;
+      }
+      if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+        return junk_string_value_;
+      }
+
+      ASSERT(buffer_pos == 0);
+      *processed_characters_count = static_cast<int>(current - input);
+      return sign ? -Double::NaN() : Double::NaN();
+    }
+  }
+
+  bool leading_zero = false;
+  if (*current == '0') {
+    ++current;
+    if (current == end) {
+      *processed_characters_count = static_cast<int>(current - input);
+      return SignedZero(sign);
+    }
+
+    leading_zero = true;
+
+    // It could be hexadecimal value.
+    if ((flags_ & ALLOW_HEX) && (*current == 'x' || *current == 'X')) {
+      ++current;
+      if (current == end || !isDigit(*current, 16)) {
+        return junk_string_value_;  // "0x".
+      }
+
+      const char* tail_pointer = NULL;
+      double result = RadixStringToIeee<4>(current,
+                                           end,
+                                           sign,
+                                           allow_trailing_junk,
+                                           junk_string_value_,
+                                           read_as_double,
+                                           &tail_pointer);
+      if (tail_pointer != NULL) {
+        if (allow_trailing_spaces) AdvanceToNonspace(&tail_pointer, end);
+        *processed_characters_count = static_cast<int>(tail_pointer - input);
+      }
+      return result;
+    }
+
+    // Ignore leading zeros in the integer part.
+    while (*current == '0') {
+      ++current;
+      if (current == end) {
+        *processed_characters_count = static_cast<int>(current - input);
+        return SignedZero(sign);
+      }
+    }
+  }
+
+  bool octal = leading_zero && (flags_ & ALLOW_OCTALS) != 0;
+
+  // Copy significant digits of the integer part (if any) to the buffer.
+  while (*current >= '0' && *current <= '9') {
+    if (significant_digits < kMaxSignificantDigits) {
+      ASSERT(buffer_pos < kBufferSize);
+      buffer[buffer_pos++] = static_cast<char>(*current);
+      significant_digits++;
+      // Will later check if it's an octal in the buffer.
+    } else {
+      insignificant_digits++;  // Move the digit into the exponential part.
+      nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+    }
+    octal = octal && *current < '8';
+    ++current;
+    if (current == end) goto parsing_done;
+  }
+
+  if (significant_digits == 0) {
+    octal = false;
+  }
+
+  if (*current == '.') {
+    if (octal && !allow_trailing_junk) return junk_string_value_;
+    if (octal) goto parsing_done;
+
+    ++current;
+    if (current == end) {
+      if (significant_digits == 0 && !leading_zero) {
+        return junk_string_value_;
+      } else {
+        goto parsing_done;
+      }
+    }
+
+    if (significant_digits == 0) {
+      // octal = false;
+      // Integer part consists of 0 or is absent. Significant digits start after
+      // leading zeros (if any).
+      while (*current == '0') {
+        ++current;
+        if (current == end) {
+          *processed_characters_count = static_cast<int>(current - input);
+          return SignedZero(sign);
+        }
+        exponent--;  // Move this 0 into the exponent.
+      }
+    }
+
+    // There is a fractional part.
+    // We don't emit a '.', but adjust the exponent instead.
+    while (*current >= '0' && *current <= '9') {
+      if (significant_digits < kMaxSignificantDigits) {
+        ASSERT(buffer_pos < kBufferSize);
+        buffer[buffer_pos++] = static_cast<char>(*current);
+        significant_digits++;
+        exponent--;
+      } else {
+        // Ignore insignificant digits in the fractional part.
+        nonzero_digit_dropped = nonzero_digit_dropped || *current != '0';
+      }
+      ++current;
+      if (current == end) goto parsing_done;
+    }
+  }
+
+  if (!leading_zero && exponent == 0 && significant_digits == 0) {
+    // If leading_zeros is true then the string contains zeros.
+    // If exponent < 0 then string was [+-]\.0*...
+    // If significant_digits != 0 the string is not equal to 0.
+    // Otherwise there are no digits in the string.
+    return junk_string_value_;
+  }
+
+  // Parse exponential part.
+  if (*current == 'e' || *current == 'E') {
+    if (octal && !allow_trailing_junk) return junk_string_value_;
+    if (octal) goto parsing_done;
+    ++current;
+    if (current == end) {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return junk_string_value_;
+      }
+    }
+    char currentSign = '+';
+    if (*current == '+' || *current == '-') {
+      currentSign = static_cast<char>(*current);
+      ++current;
+      if (current == end) {
+        if (allow_trailing_junk) {
+          goto parsing_done;
+        } else {
+          return junk_string_value_;
+        }
+      }
+    }
+
+    if (current == end || *current < '0' || *current > '9') {
+      if (allow_trailing_junk) {
+        goto parsing_done;
+      } else {
+        return junk_string_value_;
+      }
+    }
+
+    const int max_exponent = INT_MAX / 2;
+    ASSERT(-max_exponent / 2 <= exponent && exponent <= max_exponent / 2);
+    int num = 0;
+    do {
+      // Check overflow.
+      int digit = *current - '0';
+      if (num >= max_exponent / 10
+          && !(num == max_exponent / 10 && digit <= max_exponent % 10)) {
+        num = max_exponent;
+      } else {
+        num = num * 10 + digit;
+      }
+      ++current;
+    } while (current != end && *current >= '0' && *current <= '9');
+
+    exponent += (currentSign == '-' ? -num : num);
+  }
+
+  if (!(allow_trailing_spaces || allow_trailing_junk) && (current != end)) {
+    return junk_string_value_;
+  }
+  if (!allow_trailing_junk && AdvanceToNonspace(&current, end)) {
+    return junk_string_value_;
+  }
+  if (allow_trailing_spaces) {
+    AdvanceToNonspace(&current, end);
+  }
+
+  parsing_done:
+  exponent += insignificant_digits;
+
+  if (octal) {
+    double result;
+    const char* tail_pointer = NULL;
+    result = RadixStringToIeee<3>(buffer,
+                                  buffer + buffer_pos,
+                                  sign,
+                                  allow_trailing_junk,
+                                  junk_string_value_,
+                                  read_as_double,
+                                  &tail_pointer);
+    ASSERT(tail_pointer != NULL);
+    *processed_characters_count = static_cast<int>(current - input);
+    return result;
+  }
+
+  if (nonzero_digit_dropped) {
+    buffer[buffer_pos++] = '1';
+    exponent--;
+  }
+
+  ASSERT(buffer_pos < kBufferSize);
+  buffer[buffer_pos] = '\0';
+
+  double converted;
+  if (read_as_double) {
+    converted = Strtod(Vector<const char>(buffer, buffer_pos), exponent);
+  } else {
+    converted = Strtof(Vector<const char>(buffer, buffer_pos), exponent);
+  }
+  *processed_characters_count = static_cast<int>(current - input);
+  return sign? -converted: converted;
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/fast-dtoa.cc b/core/deps/double-conversion/src/fast-dtoa.cc
new file mode 100644 (file)
index 0000000..6135038
--- /dev/null
@@ -0,0 +1,665 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 "fast-dtoa.h"
+
+#include "cached-powers.h"
+#include "diy-fp.h"
+#include "ieee.h"
+
+namespace double_conversion {
+
+// The minimal and maximal target exponent define the range of w's binary
+// exponent, where 'w' is the result of multiplying the input by a cached power
+// of ten.
+//
+// A different range might be chosen on a different platform, to optimize digit
+// generation, but a smaller range requires more powers of ten to be cached.
+static const int kMinimalTargetExponent = -60;
+static const int kMaximalTargetExponent = -32;
+
+
+// Adjusts the last digit of the generated number, and screens out generated
+// solutions that may be inaccurate. A solution may be inaccurate if it is
+// outside the safe interval, or if we cannot prove that it is closer to the
+// input than a neighboring representation of the same length.
+//
+// Input: * buffer containing the digits of too_high / 10^kappa
+//        * the buffer's length
+//        * distance_too_high_w == (too_high - w).f() * unit
+//        * unsafe_interval == (too_high - too_low).f() * unit
+//        * rest = (too_high - buffer * 10^kappa).f() * unit
+//        * ten_kappa = 10^kappa * unit
+//        * unit = the common multiplier
+// Output: returns true if the buffer is guaranteed to contain the closest
+//    representable number to the input.
+//  Modifies the generated digits in the buffer to approach (round towards) w.
+static bool RoundWeed(Vector<char> buffer,
+                      int length,
+                      uint64_t distance_too_high_w,
+                      uint64_t unsafe_interval,
+                      uint64_t rest,
+                      uint64_t ten_kappa,
+                      uint64_t unit) {
+  uint64_t small_distance = distance_too_high_w - unit;
+  uint64_t big_distance = distance_too_high_w + unit;
+  // Let w_low  = too_high - big_distance, and
+  //     w_high = too_high - small_distance.
+  // Note: w_low < w < w_high
+  //
+  // The real w (* unit) must lie somewhere inside the interval
+  // ]w_low; w_high[ (often written as "(w_low; w_high)")
+
+  // Basically the buffer currently contains a number in the unsafe interval
+  // ]too_low; too_high[ with too_low < w < too_high
+  //
+  //  too_high - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  //                     ^v 1 unit            ^      ^                 ^      ^
+  //  boundary_high ---------------------     .      .                 .      .
+  //                     ^v 1 unit            .      .                 .      .
+  //   - - - - - - - - - - - - - - - - - - -  +  - - + - - - - - -     .      .
+  //                                          .      .         ^       .      .
+  //                                          .  big_distance  .       .      .
+  //                                          .      .         .       .    rest
+  //                              small_distance     .         .       .      .
+  //                                          v      .         .       .      .
+  //  w_high - - - - - - - - - - - - - - - - - -     .         .       .      .
+  //                     ^v 1 unit                   .         .       .      .
+  //  w ----------------------------------------     .         .       .      .
+  //                     ^v 1 unit                   v         .       .      .
+  //  w_low  - - - - - - - - - - - - - - - - - - - - -         .       .      .
+  //                                                           .       .      v
+  //  buffer --------------------------------------------------+-------+--------
+  //                                                           .       .
+  //                                                  safe_interval    .
+  //                                                           v       .
+  //   - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -     .
+  //                     ^v 1 unit                                     .
+  //  boundary_low -------------------------                     unsafe_interval
+  //                     ^v 1 unit                                     v
+  //  too_low  - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+  //
+  //
+  // Note that the value of buffer could lie anywhere inside the range too_low
+  // to too_high.
+  //
+  // boundary_low, boundary_high and w are approximations of the real boundaries
+  // and v (the input number). They are guaranteed to be precise up to one unit.
+  // In fact the error is guaranteed to be strictly less than one unit.
+  //
+  // Anything that lies outside the unsafe interval is guaranteed not to round
+  // to v when read again.
+  // Anything that lies inside the safe interval is guaranteed to round to v
+  // when read again.
+  // If the number inside the buffer lies inside the unsafe interval but not
+  // inside the safe interval then we simply do not know and bail out (returning
+  // false).
+  //
+  // Similarly we have to take into account the imprecision of 'w' when finding
+  // the closest representation of 'w'. If we have two potential
+  // representations, and one is closer to both w_low and w_high, then we know
+  // it is closer to the actual value v.
+  //
+  // By generating the digits of too_high we got the largest (closest to
+  // too_high) buffer that is still in the unsafe interval. In the case where
+  // w_high < buffer < too_high we try to decrement the buffer.
+  // This way the buffer approaches (rounds towards) w.
+  // There are 3 conditions that stop the decrementation process:
+  //   1) the buffer is already below w_high
+  //   2) decrementing the buffer would make it leave the unsafe interval
+  //   3) decrementing the buffer would yield a number below w_high and farther
+  //      away than the current number. In other words:
+  //              (buffer{-1} < w_high) && w_high - buffer{-1} > buffer - w_high
+  // Instead of using the buffer directly we use its distance to too_high.
+  // Conceptually rest ~= too_high - buffer
+  // We need to do the following tests in this order to avoid over- and
+  // underflows.
+  ASSERT(rest <= unsafe_interval);
+  while (rest < small_distance &&  // Negated condition 1
+         unsafe_interval - rest >= ten_kappa &&  // Negated condition 2
+         (rest + ten_kappa < small_distance ||  // buffer{-1} > w_high
+          small_distance - rest >= rest + ten_kappa - small_distance)) {
+    buffer[length - 1]--;
+    rest += ten_kappa;
+  }
+
+  // We have approached w+ as much as possible. We now test if approaching w-
+  // would require changing the buffer. If yes, then we have two possible
+  // representations close to w, but we cannot decide which one is closer.
+  if (rest < big_distance &&
+      unsafe_interval - rest >= ten_kappa &&
+      (rest + ten_kappa < big_distance ||
+       big_distance - rest > rest + ten_kappa - big_distance)) {
+    return false;
+  }
+
+  // Weeding test.
+  //   The safe interval is [too_low + 2 ulp; too_high - 2 ulp]
+  //   Since too_low = too_high - unsafe_interval this is equivalent to
+  //      [too_high - unsafe_interval + 4 ulp; too_high - 2 ulp]
+  //   Conceptually we have: rest ~= too_high - buffer
+  return (2 * unit <= rest) && (rest <= unsafe_interval - 4 * unit);
+}
+
+
+// Rounds the buffer upwards if the result is closer to v by possibly adding
+// 1 to the buffer. If the precision of the calculation is not sufficient to
+// round correctly, return false.
+// The rounding might shift the whole buffer in which case the kappa is
+// adjusted. For example "99", kappa = 3 might become "10", kappa = 4.
+//
+// If 2*rest > ten_kappa then the buffer needs to be round up.
+// rest can have an error of +/- 1 unit. This function accounts for the
+// imprecision and returns false, if the rounding direction cannot be
+// unambiguously determined.
+//
+// Precondition: rest < ten_kappa.
+static bool RoundWeedCounted(Vector<char> buffer,
+                             int length,
+                             uint64_t rest,
+                             uint64_t ten_kappa,
+                             uint64_t unit,
+                             int* kappa) {
+  ASSERT(rest < ten_kappa);
+  // The following tests are done in a specific order to avoid overflows. They
+  // will work correctly with any uint64 values of rest < ten_kappa and unit.
+  //
+  // If the unit is too big, then we don't know which way to round. For example
+  // a unit of 50 means that the real number lies within rest +/- 50. If
+  // 10^kappa == 40 then there is no way to tell which way to round.
+  if (unit >= ten_kappa) return false;
+  // Even if unit is just half the size of 10^kappa we are already completely
+  // lost. (And after the previous test we know that the expression will not
+  // over/underflow.)
+  if (ten_kappa - unit <= unit) return false;
+  // If 2 * (rest + unit) <= 10^kappa we can safely round down.
+  if ((ten_kappa - rest > rest) && (ten_kappa - 2 * rest >= 2 * unit)) {
+    return true;
+  }
+  // If 2 * (rest - unit) >= 10^kappa, then we can safely round up.
+  if ((rest > unit) && (ten_kappa - (rest - unit) <= (rest - unit))) {
+    // Increment the last digit recursively until we find a non '9' digit.
+    buffer[length - 1]++;
+    for (int i = length - 1; i > 0; --i) {
+      if (buffer[i] != '0' + 10) break;
+      buffer[i] = '0';
+      buffer[i - 1]++;
+    }
+    // If the first digit is now '0'+ 10 we had a buffer with all '9's. With the
+    // exception of the first digit all digits are now '0'. Simply switch the
+    // first digit to '1' and adjust the kappa. Example: "99" becomes "10" and
+    // the power (the kappa) is increased.
+    if (buffer[0] == '0' + 10) {
+      buffer[0] = '1';
+      (*kappa) += 1;
+    }
+    return true;
+  }
+  return false;
+}
+
+// Returns the biggest power of ten that is less than or equal to the given
+// number. We furthermore receive the maximum number of bits 'number' has.
+//
+// Returns power == 10^(exponent_plus_one-1) such that
+//    power <= number < power * 10.
+// If number_bits == 0 then 0^(0-1) is returned.
+// The number of bits must be <= 32.
+// Precondition: number < (1 << (number_bits + 1)).
+
+// Inspired by the method for finding an integer log base 10 from here:
+// http://graphics.stanford.edu/~seander/bithacks.html#IntegerLog10
+static unsigned int const kSmallPowersOfTen[] =
+    {0, 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000,
+     1000000000};
+
+static void BiggestPowerTen(uint32_t number,
+                            int number_bits,
+                            uint32_t* power,
+                            int* exponent_plus_one) {
+  ASSERT(number < (1u << (number_bits + 1)));
+  // 1233/4096 is approximately 1/lg(10).
+  int exponent_plus_one_guess = ((number_bits + 1) * 1233 >> 12);
+  // We increment to skip over the first entry in the kPowersOf10 table.
+  // Note: kPowersOf10[i] == 10^(i-1).
+  exponent_plus_one_guess++;
+  // We don't have any guarantees that 2^number_bits <= number.
+  if (number < kSmallPowersOfTen[exponent_plus_one_guess]) {
+    exponent_plus_one_guess--;
+  }
+  *power = kSmallPowersOfTen[exponent_plus_one_guess];
+  *exponent_plus_one = exponent_plus_one_guess;
+}
+
+// Generates the digits of input number w.
+// w is a floating-point number (DiyFp), consisting of a significand and an
+// exponent. Its exponent is bounded by kMinimalTargetExponent and
+// kMaximalTargetExponent.
+//       Hence -60 <= w.e() <= -32.
+//
+// Returns false if it fails, in which case the generated digits in the buffer
+// should not be used.
+// Preconditions:
+//  * low, w and high are correct up to 1 ulp (unit in the last place). That
+//    is, their error must be less than a unit of their last digits.
+//  * low.e() == w.e() == high.e()
+//  * low < w < high, and taking into account their error: low~ <= high~
+//  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+// Postconditions: returns false if procedure fails.
+//   otherwise:
+//     * buffer is not null-terminated, but len contains the number of digits.
+//     * buffer contains the shortest possible decimal digit-sequence
+//       such that LOW < buffer * 10^kappa < HIGH, where LOW and HIGH are the
+//       correct values of low and high (without their error).
+//     * if more than one decimal representation gives the minimal number of
+//       decimal digits then the one closest to W (where W is the correct value
+//       of w) is chosen.
+// Remark: this procedure takes into account the imprecision of its input
+//   numbers. If the precision is not enough to guarantee all the postconditions
+//   then false is returned. This usually happens rarely (~0.5%).
+//
+// Say, for the sake of example, that
+//   w.e() == -48, and w.f() == 0x1234567890abcdef
+// w's value can be computed by w.f() * 2^w.e()
+// We can obtain w's integral digits by simply shifting w.f() by -w.e().
+//  -> w's integral part is 0x1234
+//  w's fractional part is therefore 0x567890abcdef.
+// Printing w's integral part is easy (simply print 0x1234 in decimal).
+// In order to print its fraction we repeatedly multiply the fraction by 10 and
+// get each digit. Example the first digit after the point would be computed by
+//   (0x567890abcdef * 10) >> 48. -> 3
+// The whole thing becomes slightly more complicated because we want to stop
+// once we have enough digits. That is, once the digits inside the buffer
+// represent 'w' we can stop. Everything inside the interval low - high
+// represents w. However we have to pay attention to low, high and w's
+// imprecision.
+static bool DigitGen(DiyFp low,
+                     DiyFp w,
+                     DiyFp high,
+                     Vector<char> buffer,
+                     int* length,
+                     int* kappa) {
+  ASSERT(low.e() == w.e() && w.e() == high.e());
+  ASSERT(low.f() + 1 <= high.f() - 1);
+  ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+  // low, w and high are imprecise, but by less than one ulp (unit in the last
+  // place).
+  // If we remove (resp. add) 1 ulp from low (resp. high) we are certain that
+  // the new numbers are outside of the interval we want the final
+  // representation to lie in.
+  // Inversely adding (resp. removing) 1 ulp from low (resp. high) would yield
+  // numbers that are certain to lie in the interval. We will use this fact
+  // later on.
+  // We will now start by generating the digits within the uncertain
+  // interval. Later we will weed out representations that lie outside the safe
+  // interval and thus _might_ lie outside the correct interval.
+  uint64_t unit = 1;
+  DiyFp too_low = DiyFp(low.f() - unit, low.e());
+  DiyFp too_high = DiyFp(high.f() + unit, high.e());
+  // too_low and too_high are guaranteed to lie outside the interval we want the
+  // generated number in.
+  DiyFp unsafe_interval = DiyFp::Minus(too_high, too_low);
+  // We now cut the input number into two parts: the integral digits and the
+  // fractionals. We will not write any decimal separator though, but adapt
+  // kappa instead.
+  // Reminder: we are currently computing the digits (stored inside the buffer)
+  // such that:   too_low < buffer * 10^kappa < too_high
+  // We use too_high for the digit_generation and stop as soon as possible.
+  // If we stop early we effectively round down.
+  DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+  // Division by one is a shift.
+  uint32_t integrals = static_cast<uint32_t>(too_high.f() >> -one.e());
+  // Modulo by one is an and.
+  uint64_t fractionals = too_high.f() & (one.f() - 1);
+  uint32_t divisor;
+  int divisor_exponent_plus_one;
+  BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+                  &divisor, &divisor_exponent_plus_one);
+  *kappa = divisor_exponent_plus_one;
+  *length = 0;
+  // Loop invariant: buffer = too_high / 10^kappa  (integer division)
+  // The invariant holds for the first iteration: kappa has been initialized
+  // with the divisor exponent + 1. And the divisor is the biggest power of ten
+  // that is smaller than integrals.
+  while (*kappa > 0) {
+    int digit = integrals / divisor;
+    ASSERT(digit <= 9);
+    buffer[*length] = static_cast<char>('0' + digit);
+    (*length)++;
+    integrals %= divisor;
+    (*kappa)--;
+    // Note that kappa now equals the exponent of the divisor and that the
+    // invariant thus holds again.
+    uint64_t rest =
+        (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+    // Invariant: too_high = buffer * 10^kappa + DiyFp(rest, one.e())
+    // Reminder: unsafe_interval.e() == one.e()
+    if (rest < unsafe_interval.f()) {
+      // Rounding down (by not emitting the remaining digits) yields a number
+      // that lies within the unsafe interval.
+      return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f(),
+                       unsafe_interval.f(), rest,
+                       static_cast<uint64_t>(divisor) << -one.e(), unit);
+    }
+    divisor /= 10;
+  }
+
+  // The integrals have been generated. We are at the point of the decimal
+  // separator. In the following loop we simply multiply the remaining digits by
+  // 10 and divide by one. We just need to pay attention to multiply associated
+  // data (like the interval or 'unit'), too.
+  // Note that the multiplication by 10 does not overflow, because w.e >= -60
+  // and thus one.e >= -60.
+  ASSERT(one.e() >= -60);
+  ASSERT(fractionals < one.f());
+  ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+  for (;;) {
+    fractionals *= 10;
+    unit *= 10;
+    unsafe_interval.set_f(unsafe_interval.f() * 10);
+    // Integer division by one.
+    int digit = static_cast<int>(fractionals >> -one.e());
+    ASSERT(digit <= 9);
+    buffer[*length] = static_cast<char>('0' + digit);
+    (*length)++;
+    fractionals &= one.f() - 1;  // Modulo by one.
+    (*kappa)--;
+    if (fractionals < unsafe_interval.f()) {
+      return RoundWeed(buffer, *length, DiyFp::Minus(too_high, w).f() * unit,
+                       unsafe_interval.f(), fractionals, one.f(), unit);
+    }
+  }
+}
+
+
+
+// Generates (at most) requested_digits digits of input number w.
+// w is a floating-point number (DiyFp), consisting of a significand and an
+// exponent. Its exponent is bounded by kMinimalTargetExponent and
+// kMaximalTargetExponent.
+//       Hence -60 <= w.e() <= -32.
+//
+// Returns false if it fails, in which case the generated digits in the buffer
+// should not be used.
+// Preconditions:
+//  * w is correct up to 1 ulp (unit in the last place). That
+//    is, its error must be strictly less than a unit of its last digit.
+//  * kMinimalTargetExponent <= w.e() <= kMaximalTargetExponent
+//
+// Postconditions: returns false if procedure fails.
+//   otherwise:
+//     * buffer is not null-terminated, but length contains the number of
+//       digits.
+//     * the representation in buffer is the most precise representation of
+//       requested_digits digits.
+//     * buffer contains at most requested_digits digits of w. If there are less
+//       than requested_digits digits then some trailing '0's have been removed.
+//     * kappa is such that
+//            w = buffer * 10^kappa + eps with |eps| < 10^kappa / 2.
+//
+// Remark: This procedure takes into account the imprecision of its input
+//   numbers. If the precision is not enough to guarantee all the postconditions
+//   then false is returned. This usually happens rarely, but the failure-rate
+//   increases with higher requested_digits.
+static bool DigitGenCounted(DiyFp w,
+                            int requested_digits,
+                            Vector<char> buffer,
+                            int* length,
+                            int* kappa) {
+  ASSERT(kMinimalTargetExponent <= w.e() && w.e() <= kMaximalTargetExponent);
+  ASSERT(kMinimalTargetExponent >= -60);
+  ASSERT(kMaximalTargetExponent <= -32);
+  // w is assumed to have an error less than 1 unit. Whenever w is scaled we
+  // also scale its error.
+  uint64_t w_error = 1;
+  // We cut the input number into two parts: the integral digits and the
+  // fractional digits. We don't emit any decimal separator, but adapt kappa
+  // instead. Example: instead of writing "1.2" we put "12" into the buffer and
+  // increase kappa by 1.
+  DiyFp one = DiyFp(static_cast<uint64_t>(1) << -w.e(), w.e());
+  // Division by one is a shift.
+  uint32_t integrals = static_cast<uint32_t>(w.f() >> -one.e());
+  // Modulo by one is an and.
+  uint64_t fractionals = w.f() & (one.f() - 1);
+  uint32_t divisor;
+  int divisor_exponent_plus_one;
+  BiggestPowerTen(integrals, DiyFp::kSignificandSize - (-one.e()),
+                  &divisor, &divisor_exponent_plus_one);
+  *kappa = divisor_exponent_plus_one;
+  *length = 0;
+
+  // Loop invariant: buffer = w / 10^kappa  (integer division)
+  // The invariant holds for the first iteration: kappa has been initialized
+  // with the divisor exponent + 1. And the divisor is the biggest power of ten
+  // that is smaller than 'integrals'.
+  while (*kappa > 0) {
+    int digit = integrals / divisor;
+    ASSERT(digit <= 9);
+    buffer[*length] = static_cast<char>('0' + digit);
+    (*length)++;
+    requested_digits--;
+    integrals %= divisor;
+    (*kappa)--;
+    // Note that kappa now equals the exponent of the divisor and that the
+    // invariant thus holds again.
+    if (requested_digits == 0) break;
+    divisor /= 10;
+  }
+
+  if (requested_digits == 0) {
+    uint64_t rest =
+        (static_cast<uint64_t>(integrals) << -one.e()) + fractionals;
+    return RoundWeedCounted(buffer, *length, rest,
+                            static_cast<uint64_t>(divisor) << -one.e(), w_error,
+                            kappa);
+  }
+
+  // The integrals have been generated. We are at the point of the decimal
+  // separator. In the following loop we simply multiply the remaining digits by
+  // 10 and divide by one. We just need to pay attention to multiply associated
+  // data (the 'unit'), too.
+  // Note that the multiplication by 10 does not overflow, because w.e >= -60
+  // and thus one.e >= -60.
+  ASSERT(one.e() >= -60);
+  ASSERT(fractionals < one.f());
+  ASSERT(UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF) / 10 >= one.f());
+  while (requested_digits > 0 && fractionals > w_error) {
+    fractionals *= 10;
+    w_error *= 10;
+    // Integer division by one.
+    int digit = static_cast<int>(fractionals >> -one.e());
+    ASSERT(digit <= 9);
+    buffer[*length] = static_cast<char>('0' + digit);
+    (*length)++;
+    requested_digits--;
+    fractionals &= one.f() - 1;  // Modulo by one.
+    (*kappa)--;
+  }
+  if (requested_digits != 0) return false;
+  return RoundWeedCounted(buffer, *length, fractionals, one.f(), w_error,
+                          kappa);
+}
+
+
+// Provides a decimal representation of v.
+// Returns true if it succeeds, otherwise the result cannot be trusted.
+// There will be *length digits inside the buffer (not null-terminated).
+// If the function returns true then
+//        v == (double) (buffer * 10^decimal_exponent).
+// The digits in the buffer are the shortest representation possible: no
+// 0.09999999999999999 instead of 0.1. The shorter representation will even be
+// chosen even if the longer one would be closer to v.
+// The last digit will be closest to the actual v. That is, even if several
+// digits might correctly yield 'v' when read again, the closest will be
+// computed.
+static bool Grisu3(double v,
+                   FastDtoaMode mode,
+                   Vector<char> buffer,
+                   int* length,
+                   int* decimal_exponent) {
+  DiyFp w = Double(v).AsNormalizedDiyFp();
+  // boundary_minus and boundary_plus are the boundaries between v and its
+  // closest floating-point neighbors. Any number strictly between
+  // boundary_minus and boundary_plus will round to v when convert to a double.
+  // Grisu3 will never output representations that lie exactly on a boundary.
+  DiyFp boundary_minus, boundary_plus;
+  if (mode == FAST_DTOA_SHORTEST) {
+    Double(v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+  } else {
+    ASSERT(mode == FAST_DTOA_SHORTEST_SINGLE);
+    float single_v = static_cast<float>(v);
+    Single(single_v).NormalizedBoundaries(&boundary_minus, &boundary_plus);
+  }
+  ASSERT(boundary_plus.e() == w.e());
+  DiyFp ten_mk;  // Cached power of ten: 10^-k
+  int mk;        // -k
+  int ten_mk_minimal_binary_exponent =
+     kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+  int ten_mk_maximal_binary_exponent =
+     kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+  PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+      ten_mk_minimal_binary_exponent,
+      ten_mk_maximal_binary_exponent,
+      &ten_mk, &mk);
+  ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+          DiyFp::kSignificandSize) &&
+         (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+          DiyFp::kSignificandSize));
+  // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+  // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+  // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+  // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+  // off by a small amount.
+  // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+  // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+  //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+  DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+  ASSERT(scaled_w.e() ==
+         boundary_plus.e() + ten_mk.e() + DiyFp::kSignificandSize);
+  // In theory it would be possible to avoid some recomputations by computing
+  // the difference between w and boundary_minus/plus (a power of 2) and to
+  // compute scaled_boundary_minus/plus by subtracting/adding from
+  // scaled_w. However the code becomes much less readable and the speed
+  // enhancements are not terriffic.
+  DiyFp scaled_boundary_minus = DiyFp::Times(boundary_minus, ten_mk);
+  DiyFp scaled_boundary_plus  = DiyFp::Times(boundary_plus,  ten_mk);
+
+  // DigitGen will generate the digits of scaled_w. Therefore we have
+  // v == (double) (scaled_w * 10^-mk).
+  // Set decimal_exponent == -mk and pass it to DigitGen. If scaled_w is not an
+  // integer than it will be updated. For instance if scaled_w == 1.23 then
+  // the buffer will be filled with "123" und the decimal_exponent will be
+  // decreased by 2.
+  int kappa;
+  bool result = DigitGen(scaled_boundary_minus, scaled_w, scaled_boundary_plus,
+                         buffer, length, &kappa);
+  *decimal_exponent = -mk + kappa;
+  return result;
+}
+
+
+// The "counted" version of grisu3 (see above) only generates requested_digits
+// number of digits. This version does not generate the shortest representation,
+// and with enough requested digits 0.1 will at some point print as 0.9999999...
+// Grisu3 is too imprecise for real halfway cases (1.5 will not work) and
+// therefore the rounding strategy for halfway cases is irrelevant.
+static bool Grisu3Counted(double v,
+                          int requested_digits,
+                          Vector<char> buffer,
+                          int* length,
+                          int* decimal_exponent) {
+  DiyFp w = Double(v).AsNormalizedDiyFp();
+  DiyFp ten_mk;  // Cached power of ten: 10^-k
+  int mk;        // -k
+  int ten_mk_minimal_binary_exponent =
+     kMinimalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+  int ten_mk_maximal_binary_exponent =
+     kMaximalTargetExponent - (w.e() + DiyFp::kSignificandSize);
+  PowersOfTenCache::GetCachedPowerForBinaryExponentRange(
+      ten_mk_minimal_binary_exponent,
+      ten_mk_maximal_binary_exponent,
+      &ten_mk, &mk);
+  ASSERT((kMinimalTargetExponent <= w.e() + ten_mk.e() +
+          DiyFp::kSignificandSize) &&
+         (kMaximalTargetExponent >= w.e() + ten_mk.e() +
+          DiyFp::kSignificandSize));
+  // Note that ten_mk is only an approximation of 10^-k. A DiyFp only contains a
+  // 64 bit significand and ten_mk is thus only precise up to 64 bits.
+
+  // The DiyFp::Times procedure rounds its result, and ten_mk is approximated
+  // too. The variable scaled_w (as well as scaled_boundary_minus/plus) are now
+  // off by a small amount.
+  // In fact: scaled_w - w*10^k < 1ulp (unit in the last place) of scaled_w.
+  // In other words: let f = scaled_w.f() and e = scaled_w.e(), then
+  //           (f-1) * 2^e < w*10^k < (f+1) * 2^e
+  DiyFp scaled_w = DiyFp::Times(w, ten_mk);
+
+  // We now have (double) (scaled_w * 10^-mk).
+  // DigitGen will generate the first requested_digits digits of scaled_w and
+  // return together with a kappa such that scaled_w ~= buffer * 10^kappa. (It
+  // will not always be exactly the same since DigitGenCounted only produces a
+  // limited number of digits.)
+  int kappa;
+  bool result = DigitGenCounted(scaled_w, requested_digits,
+                                buffer, length, &kappa);
+  *decimal_exponent = -mk + kappa;
+  return result;
+}
+
+
+bool FastDtoa(double v,
+              FastDtoaMode mode,
+              int requested_digits,
+              Vector<char> buffer,
+              int* length,
+              int* decimal_point) {
+  ASSERT(v > 0);
+  ASSERT(!Double(v).IsSpecial());
+
+  bool result = false;
+  int decimal_exponent = 0;
+  switch (mode) {
+    case FAST_DTOA_SHORTEST:
+    case FAST_DTOA_SHORTEST_SINGLE:
+      result = Grisu3(v, mode, buffer, length, &decimal_exponent);
+      break;
+    case FAST_DTOA_PRECISION:
+      result = Grisu3Counted(v, requested_digits,
+                             buffer, length, &decimal_exponent);
+      break;
+    default:
+      UNREACHABLE();
+  }
+  if (result) {
+    *decimal_point = *length + decimal_exponent;
+    buffer[*length] = '\0';
+  }
+  return result;
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/fast-dtoa.h b/core/deps/double-conversion/src/fast-dtoa.h
new file mode 100644 (file)
index 0000000..5f1e8ee
--- /dev/null
@@ -0,0 +1,88 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_FAST_DTOA_H_
+#define DOUBLE_CONVERSION_FAST_DTOA_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+enum FastDtoaMode {
+  // Computes the shortest representation of the given input. The returned
+  // result will be the most accurate number of this length. Longer
+  // representations might be more accurate.
+  FAST_DTOA_SHORTEST,
+  // Same as FAST_DTOA_SHORTEST but for single-precision floats.
+  FAST_DTOA_SHORTEST_SINGLE,
+  // Computes a representation where the precision (number of digits) is
+  // given as input. The precision is independent of the decimal point.
+  FAST_DTOA_PRECISION
+};
+
+// FastDtoa will produce at most kFastDtoaMaximalLength digits. This does not
+// include the terminating '\0' character.
+static const int kFastDtoaMaximalLength = 17;
+// Same for single-precision numbers.
+static const int kFastDtoaMaximalSingleLength = 9;
+
+// Provides a decimal representation of v.
+// The result should be interpreted as buffer * 10^(point - length).
+//
+// Precondition:
+//   * v must be a strictly positive finite double.
+//
+// Returns true if it succeeds, otherwise the result can not be trusted.
+// There will be *length digits inside the buffer followed by a null terminator.
+// If the function returns true and mode equals
+//   - FAST_DTOA_SHORTEST, then
+//     the parameter requested_digits is ignored.
+//     The result satisfies
+//         v == (double) (buffer * 10^(point - length)).
+//     The digits in the buffer are the shortest representation possible. E.g.
+//     if 0.099999999999 and 0.1 represent the same double then "1" is returned
+//     with point = 0.
+//     The last digit will be closest to the actual v. That is, even if several
+//     digits might correctly yield 'v' when read again, the buffer will contain
+//     the one closest to v.
+//   - FAST_DTOA_PRECISION, then
+//     the buffer contains requested_digits digits.
+//     the difference v - (buffer * 10^(point-length)) is closest to zero for
+//     all possible representations of requested_digits digits.
+//     If there are two values that are equally close, then FastDtoa returns
+//     false.
+// For both modes the buffer must be large enough to hold the result.
+bool FastDtoa(double d,
+              FastDtoaMode mode,
+              int requested_digits,
+              Vector<char> buffer,
+              int* length,
+              int* decimal_point);
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_FAST_DTOA_H_
diff --git a/core/deps/double-conversion/src/fixed-dtoa.cc b/core/deps/double-conversion/src/fixed-dtoa.cc
new file mode 100644 (file)
index 0000000..aef65fd
--- /dev/null
@@ -0,0 +1,404 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 <math.h>
+
+#include "fixed-dtoa.h"
+#include "ieee.h"
+
+namespace double_conversion {
+
+// Represents a 128bit type. This class should be replaced by a native type on
+// platforms that support 128bit integers.
+class UInt128 {
+ public:
+  UInt128() : high_bits_(0), low_bits_(0) { }
+  UInt128(uint64_t high, uint64_t low) : high_bits_(high), low_bits_(low) { }
+
+  void Multiply(uint32_t multiplicand) {
+    uint64_t accumulator;
+
+    accumulator = (low_bits_ & kMask32) * multiplicand;
+    uint32_t part = static_cast<uint32_t>(accumulator & kMask32);
+    accumulator >>= 32;
+    accumulator = accumulator + (low_bits_ >> 32) * multiplicand;
+    low_bits_ = (accumulator << 32) + part;
+    accumulator >>= 32;
+    accumulator = accumulator + (high_bits_ & kMask32) * multiplicand;
+    part = static_cast<uint32_t>(accumulator & kMask32);
+    accumulator >>= 32;
+    accumulator = accumulator + (high_bits_ >> 32) * multiplicand;
+    high_bits_ = (accumulator << 32) + part;
+    ASSERT((accumulator >> 32) == 0);
+  }
+
+  void Shift(int shift_amount) {
+    ASSERT(-64 <= shift_amount && shift_amount <= 64);
+    if (shift_amount == 0) {
+      return;
+    } else if (shift_amount == -64) {
+      high_bits_ = low_bits_;
+      low_bits_ = 0;
+    } else if (shift_amount == 64) {
+      low_bits_ = high_bits_;
+      high_bits_ = 0;
+    } else if (shift_amount <= 0) {
+      high_bits_ <<= -shift_amount;
+      high_bits_ += low_bits_ >> (64 + shift_amount);
+      low_bits_ <<= -shift_amount;
+    } else {
+      low_bits_ >>= shift_amount;
+      low_bits_ += high_bits_ << (64 - shift_amount);
+      high_bits_ >>= shift_amount;
+    }
+  }
+
+  // Modifies *this to *this MOD (2^power).
+  // Returns *this DIV (2^power).
+  int DivModPowerOf2(int power) {
+    if (power >= 64) {
+      int result = static_cast<int>(high_bits_ >> (power - 64));
+      high_bits_ -= static_cast<uint64_t>(result) << (power - 64);
+      return result;
+    } else {
+      uint64_t part_low = low_bits_ >> power;
+      uint64_t part_high = high_bits_ << (64 - power);
+      int result = static_cast<int>(part_low + part_high);
+      high_bits_ = 0;
+      low_bits_ -= part_low << power;
+      return result;
+    }
+  }
+
+  bool IsZero() const {
+    return high_bits_ == 0 && low_bits_ == 0;
+  }
+
+  int BitAt(int position) {
+    if (position >= 64) {
+      return static_cast<int>(high_bits_ >> (position - 64)) & 1;
+    } else {
+      return static_cast<int>(low_bits_ >> position) & 1;
+    }
+  }
+
+ private:
+  static const uint64_t kMask32 = 0xFFFFFFFF;
+  // Value == (high_bits_ << 64) + low_bits_
+  uint64_t high_bits_;
+  uint64_t low_bits_;
+};
+
+
+static const int kDoubleSignificandSize = 53;  // Includes the hidden bit.
+
+
+static void FillDigits32FixedLength(uint32_t number, int requested_length,
+                                    Vector<char> buffer, int* length) {
+  for (int i = requested_length - 1; i >= 0; --i) {
+    buffer[(*length) + i] = '0' + number % 10;
+    number /= 10;
+  }
+  *length += requested_length;
+}
+
+
+static void FillDigits32(uint32_t number, Vector<char> buffer, int* length) {
+  int number_length = 0;
+  // We fill the digits in reverse order and exchange them afterwards.
+  while (number != 0) {
+    int digit = number % 10;
+    number /= 10;
+    buffer[(*length) + number_length] = static_cast<char>('0' + digit);
+    number_length++;
+  }
+  // Exchange the digits.
+  int i = *length;
+  int j = *length + number_length - 1;
+  while (i < j) {
+    char tmp = buffer[i];
+    buffer[i] = buffer[j];
+    buffer[j] = tmp;
+    i++;
+    j--;
+  }
+  *length += number_length;
+}
+
+
+static void FillDigits64FixedLength(uint64_t number,
+                                    Vector<char> buffer, int* length) {
+  const uint32_t kTen7 = 10000000;
+  // For efficiency cut the number into 3 uint32_t parts, and print those.
+  uint32_t part2 = static_cast<uint32_t>(number % kTen7);
+  number /= kTen7;
+  uint32_t part1 = static_cast<uint32_t>(number % kTen7);
+  uint32_t part0 = static_cast<uint32_t>(number / kTen7);
+
+  FillDigits32FixedLength(part0, 3, buffer, length);
+  FillDigits32FixedLength(part1, 7, buffer, length);
+  FillDigits32FixedLength(part2, 7, buffer, length);
+}
+
+
+static void FillDigits64(uint64_t number, Vector<char> buffer, int* length) {
+  const uint32_t kTen7 = 10000000;
+  // For efficiency cut the number into 3 uint32_t parts, and print those.
+  uint32_t part2 = static_cast<uint32_t>(number % kTen7);
+  number /= kTen7;
+  uint32_t part1 = static_cast<uint32_t>(number % kTen7);
+  uint32_t part0 = static_cast<uint32_t>(number / kTen7);
+
+  if (part0 != 0) {
+    FillDigits32(part0, buffer, length);
+    FillDigits32FixedLength(part1, 7, buffer, length);
+    FillDigits32FixedLength(part2, 7, buffer, length);
+  } else if (part1 != 0) {
+    FillDigits32(part1, buffer, length);
+    FillDigits32FixedLength(part2, 7, buffer, length);
+  } else {
+    FillDigits32(part2, buffer, length);
+  }
+}
+
+
+static void RoundUp(Vector<char> buffer, int* length, int* decimal_point) {
+  // An empty buffer represents 0.
+  if (*length == 0) {
+    buffer[0] = '1';
+    *decimal_point = 1;
+    *length = 1;
+    return;
+  }
+  // Round the last digit until we either have a digit that was not '9' or until
+  // we reached the first digit.
+  buffer[(*length) - 1]++;
+  for (int i = (*length) - 1; i > 0; --i) {
+    if (buffer[i] != '0' + 10) {
+      return;
+    }
+    buffer[i] = '0';
+    buffer[i - 1]++;
+  }
+  // If the first digit is now '0' + 10, we would need to set it to '0' and add
+  // a '1' in front. However we reach the first digit only if all following
+  // digits had been '9' before rounding up. Now all trailing digits are '0' and
+  // we simply switch the first digit to '1' and update the decimal-point
+  // (indicating that the point is now one digit to the right).
+  if (buffer[0] == '0' + 10) {
+    buffer[0] = '1';
+    (*decimal_point)++;
+  }
+}
+
+
+// The given fractionals number represents a fixed-point number with binary
+// point at bit (-exponent).
+// Preconditions:
+//   -128 <= exponent <= 0.
+//   0 <= fractionals * 2^exponent < 1
+//   The buffer holds the result.
+// The function will round its result. During the rounding-process digits not
+// generated by this function might be updated, and the decimal-point variable
+// might be updated. If this function generates the digits 99 and the buffer
+// already contained "199" (thus yielding a buffer of "19999") then a
+// rounding-up will change the contents of the buffer to "20000".
+static void FillFractionals(uint64_t fractionals, int exponent,
+                            int fractional_count, Vector<char> buffer,
+                            int* length, int* decimal_point) {
+  ASSERT(-128 <= exponent && exponent <= 0);
+  // 'fractionals' is a fixed-point number, with binary point at bit
+  // (-exponent). Inside the function the non-converted remainder of fractionals
+  // is a fixed-point number, with binary point at bit 'point'.
+  if (-exponent <= 64) {
+    // One 64 bit number is sufficient.
+    ASSERT(fractionals >> 56 == 0);
+    int point = -exponent;
+    for (int i = 0; i < fractional_count; ++i) {
+      if (fractionals == 0) break;
+      // Instead of multiplying by 10 we multiply by 5 and adjust the point
+      // location. This way the fractionals variable will not overflow.
+      // Invariant at the beginning of the loop: fractionals < 2^point.
+      // Initially we have: point <= 64 and fractionals < 2^56
+      // After each iteration the point is decremented by one.
+      // Note that 5^3 = 125 < 128 = 2^7.
+      // Therefore three iterations of this loop will not overflow fractionals
+      // (even without the subtraction at the end of the loop body). At this
+      // time point will satisfy point <= 61 and therefore fractionals < 2^point
+      // and any further multiplication of fractionals by 5 will not overflow.
+      fractionals *= 5;
+      point--;
+      int digit = static_cast<int>(fractionals >> point);
+      ASSERT(digit <= 9);
+      buffer[*length] = static_cast<char>('0' + digit);
+      (*length)++;
+      fractionals -= static_cast<uint64_t>(digit) << point;
+    }
+    // If the first bit after the point is set we have to round up.
+    if (((fractionals >> (point - 1)) & 1) == 1) {
+      RoundUp(buffer, length, decimal_point);
+    }
+  } else {  // We need 128 bits.
+    ASSERT(64 < -exponent && -exponent <= 128);
+    UInt128 fractionals128 = UInt128(fractionals, 0);
+    fractionals128.Shift(-exponent - 64);
+    int point = 128;
+    for (int i = 0; i < fractional_count; ++i) {
+      if (fractionals128.IsZero()) break;
+      // As before: instead of multiplying by 10 we multiply by 5 and adjust the
+      // point location.
+      // This multiplication will not overflow for the same reasons as before.
+      fractionals128.Multiply(5);
+      point--;
+      int digit = fractionals128.DivModPowerOf2(point);
+      ASSERT(digit <= 9);
+      buffer[*length] = static_cast<char>('0' + digit);
+      (*length)++;
+    }
+    if (fractionals128.BitAt(point - 1) == 1) {
+      RoundUp(buffer, length, decimal_point);
+    }
+  }
+}
+
+
+// Removes leading and trailing zeros.
+// If leading zeros are removed then the decimal point position is adjusted.
+static void TrimZeros(Vector<char> buffer, int* length, int* decimal_point) {
+  while (*length > 0 && buffer[(*length) - 1] == '0') {
+    (*length)--;
+  }
+  int first_non_zero = 0;
+  while (first_non_zero < *length && buffer[first_non_zero] == '0') {
+    first_non_zero++;
+  }
+  if (first_non_zero != 0) {
+    for (int i = first_non_zero; i < *length; ++i) {
+      buffer[i - first_non_zero] = buffer[i];
+    }
+    *length -= first_non_zero;
+    *decimal_point -= first_non_zero;
+  }
+}
+
+
+bool FastFixedDtoa(double v,
+                   int fractional_count,
+                   Vector<char> buffer,
+                   int* length,
+                   int* decimal_point) {
+  const uint32_t kMaxUInt32 = 0xFFFFFFFF;
+  uint64_t significand = Double(v).Significand();
+  int exponent = Double(v).Exponent();
+  // v = significand * 2^exponent (with significand a 53bit integer).
+  // If the exponent is larger than 20 (i.e. we may have a 73bit number) then we
+  // don't know how to compute the representation. 2^73 ~= 9.5*10^21.
+  // If necessary this limit could probably be increased, but we don't need
+  // more.
+  if (exponent > 20) return false;
+  if (fractional_count > 20) return false;
+  *length = 0;
+  // At most kDoubleSignificandSize bits of the significand are non-zero.
+  // Given a 64 bit integer we have 11 0s followed by 53 potentially non-zero
+  // bits:  0..11*..0xxx..53*..xx
+  if (exponent + kDoubleSignificandSize > 64) {
+    // The exponent must be > 11.
+    //
+    // We know that v = significand * 2^exponent.
+    // And the exponent > 11.
+    // We simplify the task by dividing v by 10^17.
+    // The quotient delivers the first digits, and the remainder fits into a 64
+    // bit number.
+    // Dividing by 10^17 is equivalent to dividing by 5^17*2^17.
+    const uint64_t kFive17 = UINT64_2PART_C(0xB1, A2BC2EC5);  // 5^17
+    uint64_t divisor = kFive17;
+    int divisor_power = 17;
+    uint64_t dividend = significand;
+    uint32_t quotient;
+    uint64_t remainder;
+    // Let v = f * 2^e with f == significand and e == exponent.
+    // Then need q (quotient) and r (remainder) as follows:
+    //   v            = q * 10^17       + r
+    //   f * 2^e      = q * 10^17       + r
+    //   f * 2^e      = q * 5^17 * 2^17 + r
+    // If e > 17 then
+    //   f * 2^(e-17) = q * 5^17        + r/2^17
+    // else
+    //   f  = q * 5^17 * 2^(17-e) + r/2^e
+    if (exponent > divisor_power) {
+      // We only allow exponents of up to 20 and therefore (17 - e) <= 3
+      dividend <<= exponent - divisor_power;
+      quotient = static_cast<uint32_t>(dividend / divisor);
+      remainder = (dividend % divisor) << divisor_power;
+    } else {
+      divisor <<= divisor_power - exponent;
+      quotient = static_cast<uint32_t>(dividend / divisor);
+      remainder = (dividend % divisor) << exponent;
+    }
+    FillDigits32(quotient, buffer, length);
+    FillDigits64FixedLength(remainder, buffer, length);
+    *decimal_point = *length;
+  } else if (exponent >= 0) {
+    // 0 <= exponent <= 11
+    significand <<= exponent;
+    FillDigits64(significand, buffer, length);
+    *decimal_point = *length;
+  } else if (exponent > -kDoubleSignificandSize) {
+    // We have to cut the number.
+    uint64_t integrals = significand >> -exponent;
+    uint64_t fractionals = significand - (integrals << -exponent);
+    if (integrals > kMaxUInt32) {
+      FillDigits64(integrals, buffer, length);
+    } else {
+      FillDigits32(static_cast<uint32_t>(integrals), buffer, length);
+    }
+    *decimal_point = *length;
+    FillFractionals(fractionals, exponent, fractional_count,
+                    buffer, length, decimal_point);
+  } else if (exponent < -128) {
+    // This configuration (with at most 20 digits) means that all digits must be
+    // 0.
+    ASSERT(fractional_count <= 20);
+    buffer[0] = '\0';
+    *length = 0;
+    *decimal_point = -fractional_count;
+  } else {
+    *decimal_point = 0;
+    FillFractionals(significand, exponent, fractional_count,
+                    buffer, length, decimal_point);
+  }
+  TrimZeros(buffer, length, decimal_point);
+  buffer[*length] = '\0';
+  if ((*length) == 0) {
+    // The string is empty and the decimal_point thus has no importance. Mimick
+    // Gay's dtoa and and set it to -fractional_count.
+    *decimal_point = -fractional_count;
+  }
+  return true;
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/fixed-dtoa.h b/core/deps/double-conversion/src/fixed-dtoa.h
new file mode 100644 (file)
index 0000000..3bdd08e
--- /dev/null
@@ -0,0 +1,56 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_FIXED_DTOA_H_
+#define DOUBLE_CONVERSION_FIXED_DTOA_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+// Produces digits necessary to print a given number with
+// 'fractional_count' digits after the decimal point.
+// The buffer must be big enough to hold the result plus one terminating null
+// character.
+//
+// The produced digits might be too short in which case the caller has to fill
+// the gaps with '0's.
+// Example: FastFixedDtoa(0.001, 5, ...) is allowed to return buffer = "1", and
+// decimal_point = -2.
+// Halfway cases are rounded towards +/-Infinity (away from 0). The call
+// FastFixedDtoa(0.15, 2, ...) thus returns buffer = "2", decimal_point = 0.
+// The returned buffer may contain digits that would be truncated from the
+// shortest representation of the input.
+//
+// This method only works for some parameters. If it can't handle the input it
+// returns false. The output is null-terminated when the function succeeds.
+bool FastFixedDtoa(double v, int fractional_count,
+                   Vector<char> buffer, int* length, int* decimal_point);
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_FIXED_DTOA_H_
diff --git a/core/deps/double-conversion/src/ieee.h b/core/deps/double-conversion/src/ieee.h
new file mode 100644 (file)
index 0000000..661141d
--- /dev/null
@@ -0,0 +1,402 @@
+// Copyright 2012 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_DOUBLE_H_
+#define DOUBLE_CONVERSION_DOUBLE_H_
+
+#include "diy-fp.h"
+
+namespace double_conversion {
+
+// We assume that doubles and uint64_t have the same endianness.
+static uint64_t double_to_uint64(double d) { return BitCast<uint64_t>(d); }
+static double uint64_to_double(uint64_t d64) { return BitCast<double>(d64); }
+static uint32_t float_to_uint32(float f) { return BitCast<uint32_t>(f); }
+static float uint32_to_float(uint32_t d32) { return BitCast<float>(d32); }
+
+// Helper functions for doubles.
+class Double {
+ public:
+  static const uint64_t kSignMask = UINT64_2PART_C(0x80000000, 00000000);
+  static const uint64_t kExponentMask = UINT64_2PART_C(0x7FF00000, 00000000);
+  static const uint64_t kSignificandMask = UINT64_2PART_C(0x000FFFFF, FFFFFFFF);
+  static const uint64_t kHiddenBit = UINT64_2PART_C(0x00100000, 00000000);
+  static const int kPhysicalSignificandSize = 52;  // Excludes the hidden bit.
+  static const int kSignificandSize = 53;
+
+  Double() : d64_(0) {}
+  explicit Double(double d) : d64_(double_to_uint64(d)) {}
+  explicit Double(uint64_t d64) : d64_(d64) {}
+  explicit Double(DiyFp diy_fp)
+    : d64_(DiyFpToUint64(diy_fp)) {}
+
+  // The value encoded by this Double must be greater or equal to +0.0.
+  // It must not be special (infinity, or NaN).
+  DiyFp AsDiyFp() const {
+    ASSERT(Sign() > 0);
+    ASSERT(!IsSpecial());
+    return DiyFp(Significand(), Exponent());
+  }
+
+  // The value encoded by this Double must be strictly greater than 0.
+  DiyFp AsNormalizedDiyFp() const {
+    ASSERT(value() > 0.0);
+    uint64_t f = Significand();
+    int e = Exponent();
+
+    // The current double could be a denormal.
+    while ((f & kHiddenBit) == 0) {
+      f <<= 1;
+      e--;
+    }
+    // Do the final shifts in one go.
+    f <<= DiyFp::kSignificandSize - kSignificandSize;
+    e -= DiyFp::kSignificandSize - kSignificandSize;
+    return DiyFp(f, e);
+  }
+
+  // Returns the double's bit as uint64.
+  uint64_t AsUint64() const {
+    return d64_;
+  }
+
+  // Returns the next greater double. Returns +infinity on input +infinity.
+  double NextDouble() const {
+    if (d64_ == kInfinity) return Double(kInfinity).value();
+    if (Sign() < 0 && Significand() == 0) {
+      // -0.0
+      return 0.0;
+    }
+    if (Sign() < 0) {
+      return Double(d64_ - 1).value();
+    } else {
+      return Double(d64_ + 1).value();
+    }
+  }
+
+  double PreviousDouble() const {
+    if (d64_ == (kInfinity | kSignMask)) return -Double::Infinity();
+    if (Sign() < 0) {
+      return Double(d64_ + 1).value();
+    } else {
+      if (Significand() == 0) return -0.0;
+      return Double(d64_ - 1).value();
+    }
+  }
+
+  int Exponent() const {
+    if (IsDenormal()) return kDenormalExponent;
+
+    uint64_t d64 = AsUint64();
+    int biased_e =
+        static_cast<int>((d64 & kExponentMask) >> kPhysicalSignificandSize);
+    return biased_e - kExponentBias;
+  }
+
+  uint64_t Significand() const {
+    uint64_t d64 = AsUint64();
+    uint64_t significand = d64 & kSignificandMask;
+    if (!IsDenormal()) {
+      return significand + kHiddenBit;
+    } else {
+      return significand;
+    }
+  }
+
+  // Returns true if the double is a denormal.
+  bool IsDenormal() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == 0;
+  }
+
+  // We consider denormals not to be special.
+  // Hence only Infinity and NaN are special.
+  bool IsSpecial() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kExponentMask) == kExponentMask;
+  }
+
+  bool IsNan() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) != 0);
+  }
+
+  bool IsInfinite() const {
+    uint64_t d64 = AsUint64();
+    return ((d64 & kExponentMask) == kExponentMask) &&
+        ((d64 & kSignificandMask) == 0);
+  }
+
+  int Sign() const {
+    uint64_t d64 = AsUint64();
+    return (d64 & kSignMask) == 0? 1: -1;
+  }
+
+  // Precondition: the value encoded by this Double must be greater or equal
+  // than +0.0.
+  DiyFp UpperBoundary() const {
+    ASSERT(Sign() > 0);
+    return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+  }
+
+  // Computes the two boundaries of this.
+  // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+  // exponent as m_plus.
+  // Precondition: the value encoded by this Double must be greater than 0.
+  void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+    ASSERT(value() > 0.0);
+    DiyFp v = this->AsDiyFp();
+    DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+    DiyFp m_minus;
+    if (LowerBoundaryIsCloser()) {
+      m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+    } else {
+      m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+    }
+    m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+    m_minus.set_e(m_plus.e());
+    *out_m_plus = m_plus;
+    *out_m_minus = m_minus;
+  }
+
+  bool LowerBoundaryIsCloser() const {
+    // The boundary is closer if the significand is of the form f == 2^p-1 then
+    // the lower boundary is closer.
+    // Think of v = 1000e10 and v- = 9999e9.
+    // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+    // at a distance of 1e8.
+    // The only exception is for the smallest normal: the largest denormal is
+    // at the same distance as its successor.
+    // Note: denormals have the same exponent as the smallest normals.
+    bool physical_significand_is_zero = ((AsUint64() & kSignificandMask) == 0);
+    return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+  }
+
+  double value() const { return uint64_to_double(d64_); }
+
+  // Returns the significand size for a given order of magnitude.
+  // If v = f*2^e with 2^p-1 <= f <= 2^p then p+e is v's order of magnitude.
+  // This function returns the number of significant binary digits v will have
+  // once it's encoded into a double. In almost all cases this is equal to
+  // kSignificandSize. The only exceptions are denormals. They start with
+  // leading zeroes and their effective significand-size is hence smaller.
+  static int SignificandSizeForOrderOfMagnitude(int order) {
+    if (order >= (kDenormalExponent + kSignificandSize)) {
+      return kSignificandSize;
+    }
+    if (order <= kDenormalExponent) return 0;
+    return order - kDenormalExponent;
+  }
+
+  static double Infinity() {
+    return Double(kInfinity).value();
+  }
+
+  static double NaN() {
+    return Double(kNaN).value();
+  }
+
+ private:
+  static const int kExponentBias = 0x3FF + kPhysicalSignificandSize;
+  static const int kDenormalExponent = -kExponentBias + 1;
+  static const int kMaxExponent = 0x7FF - kExponentBias;
+  static const uint64_t kInfinity = UINT64_2PART_C(0x7FF00000, 00000000);
+  static const uint64_t kNaN = UINT64_2PART_C(0x7FF80000, 00000000);
+
+  const uint64_t d64_;
+
+  static uint64_t DiyFpToUint64(DiyFp diy_fp) {
+    uint64_t significand = diy_fp.f();
+    int exponent = diy_fp.e();
+    while (significand > kHiddenBit + kSignificandMask) {
+      significand >>= 1;
+      exponent++;
+    }
+    if (exponent >= kMaxExponent) {
+      return kInfinity;
+    }
+    if (exponent < kDenormalExponent) {
+      return 0;
+    }
+    while (exponent > kDenormalExponent && (significand & kHiddenBit) == 0) {
+      significand <<= 1;
+      exponent--;
+    }
+    uint64_t biased_exponent;
+    if (exponent == kDenormalExponent && (significand & kHiddenBit) == 0) {
+      biased_exponent = 0;
+    } else {
+      biased_exponent = static_cast<uint64_t>(exponent + kExponentBias);
+    }
+    return (significand & kSignificandMask) |
+        (biased_exponent << kPhysicalSignificandSize);
+  }
+
+  DISALLOW_COPY_AND_ASSIGN(Double);
+};
+
+class Single {
+ public:
+  static const uint32_t kSignMask = 0x80000000;
+  static const uint32_t kExponentMask = 0x7F800000;
+  static const uint32_t kSignificandMask = 0x007FFFFF;
+  static const uint32_t kHiddenBit = 0x00800000;
+  static const int kPhysicalSignificandSize = 23;  // Excludes the hidden bit.
+  static const int kSignificandSize = 24;
+
+  Single() : d32_(0) {}
+  explicit Single(float f) : d32_(float_to_uint32(f)) {}
+  explicit Single(uint32_t d32) : d32_(d32) {}
+
+  // The value encoded by this Single must be greater or equal to +0.0.
+  // It must not be special (infinity, or NaN).
+  DiyFp AsDiyFp() const {
+    ASSERT(Sign() > 0);
+    ASSERT(!IsSpecial());
+    return DiyFp(Significand(), Exponent());
+  }
+
+  // Returns the single's bit as uint64.
+  uint32_t AsUint32() const {
+    return d32_;
+  }
+
+  int Exponent() const {
+    if (IsDenormal()) return kDenormalExponent;
+
+    uint32_t d32 = AsUint32();
+    int biased_e =
+        static_cast<int>((d32 & kExponentMask) >> kPhysicalSignificandSize);
+    return biased_e - kExponentBias;
+  }
+
+  uint32_t Significand() const {
+    uint32_t d32 = AsUint32();
+    uint32_t significand = d32 & kSignificandMask;
+    if (!IsDenormal()) {
+      return significand + kHiddenBit;
+    } else {
+      return significand;
+    }
+  }
+
+  // Returns true if the single is a denormal.
+  bool IsDenormal() const {
+    uint32_t d32 = AsUint32();
+    return (d32 & kExponentMask) == 0;
+  }
+
+  // We consider denormals not to be special.
+  // Hence only Infinity and NaN are special.
+  bool IsSpecial() const {
+    uint32_t d32 = AsUint32();
+    return (d32 & kExponentMask) == kExponentMask;
+  }
+
+  bool IsNan() const {
+    uint32_t d32 = AsUint32();
+    return ((d32 & kExponentMask) == kExponentMask) &&
+        ((d32 & kSignificandMask) != 0);
+  }
+
+  bool IsInfinite() const {
+    uint32_t d32 = AsUint32();
+    return ((d32 & kExponentMask) == kExponentMask) &&
+        ((d32 & kSignificandMask) == 0);
+  }
+
+  int Sign() const {
+    uint32_t d32 = AsUint32();
+    return (d32 & kSignMask) == 0? 1: -1;
+  }
+
+  // Computes the two boundaries of this.
+  // The bigger boundary (m_plus) is normalized. The lower boundary has the same
+  // exponent as m_plus.
+  // Precondition: the value encoded by this Single must be greater than 0.
+  void NormalizedBoundaries(DiyFp* out_m_minus, DiyFp* out_m_plus) const {
+    ASSERT(value() > 0.0);
+    DiyFp v = this->AsDiyFp();
+    DiyFp m_plus = DiyFp::Normalize(DiyFp((v.f() << 1) + 1, v.e() - 1));
+    DiyFp m_minus;
+    if (LowerBoundaryIsCloser()) {
+      m_minus = DiyFp((v.f() << 2) - 1, v.e() - 2);
+    } else {
+      m_minus = DiyFp((v.f() << 1) - 1, v.e() - 1);
+    }
+    m_minus.set_f(m_minus.f() << (m_minus.e() - m_plus.e()));
+    m_minus.set_e(m_plus.e());
+    *out_m_plus = m_plus;
+    *out_m_minus = m_minus;
+  }
+
+  // Precondition: the value encoded by this Single must be greater or equal
+  // than +0.0.
+  DiyFp UpperBoundary() const {
+    ASSERT(Sign() > 0);
+    return DiyFp(Significand() * 2 + 1, Exponent() - 1);
+  }
+
+  bool LowerBoundaryIsCloser() const {
+    // The boundary is closer if the significand is of the form f == 2^p-1 then
+    // the lower boundary is closer.
+    // Think of v = 1000e10 and v- = 9999e9.
+    // Then the boundary (== (v - v-)/2) is not just at a distance of 1e9 but
+    // at a distance of 1e8.
+    // The only exception is for the smallest normal: the largest denormal is
+    // at the same distance as its successor.
+    // Note: denormals have the same exponent as the smallest normals.
+    bool physical_significand_is_zero = ((AsUint32() & kSignificandMask) == 0);
+    return physical_significand_is_zero && (Exponent() != kDenormalExponent);
+  }
+
+  float value() const { return uint32_to_float(d32_); }
+
+  static float Infinity() {
+    return Single(kInfinity).value();
+  }
+
+  static float NaN() {
+    return Single(kNaN).value();
+  }
+
+ private:
+  static const int kExponentBias = 0x7F + kPhysicalSignificandSize;
+  static const int kDenormalExponent = -kExponentBias + 1;
+  static const int kMaxExponent = 0xFF - kExponentBias;
+  static const uint32_t kInfinity = 0x7F800000;
+  static const uint32_t kNaN = 0x7FC00000;
+
+  const uint32_t d32_;
+
+  DISALLOW_COPY_AND_ASSIGN(Single);
+};
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_DOUBLE_H_
diff --git a/core/deps/double-conversion/src/strtod.cc b/core/deps/double-conversion/src/strtod.cc
new file mode 100644 (file)
index 0000000..68d0217
--- /dev/null
@@ -0,0 +1,556 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 <stdarg.h>
+#include <limits.h>
+
+#include "strtod.h"
+#include "bignum.h"
+#include "cached-powers.h"
+#include "ieee.h"
+
+namespace double_conversion {
+
+// 2^53 = 9007199254740992.
+// Any integer with at most 15 decimal digits will hence fit into a double
+// (which has a 53bit significand) without loss of precision.
+static const int kMaxExactDoubleIntegerDecimalDigits = 15;
+// 2^64 = 18446744073709551616 > 10^19
+static const int kMaxUint64DecimalDigits = 19;
+
+// Max double: 1.7976931348623157 x 10^308
+// Min non-zero double: 4.9406564584124654 x 10^-324
+// Any x >= 10^309 is interpreted as +infinity.
+// Any x <= 10^-324 is interpreted as 0.
+// Note that 2.5e-324 (despite being smaller than the min double) will be read
+// as non-zero (equal to the min non-zero double).
+static const int kMaxDecimalPower = 309;
+static const int kMinDecimalPower = -324;
+
+// 2^64 = 18446744073709551616
+static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF);
+
+
+static const double exact_powers_of_ten[] = {
+  1.0,  // 10^0
+  10.0,
+  100.0,
+  1000.0,
+  10000.0,
+  100000.0,
+  1000000.0,
+  10000000.0,
+  100000000.0,
+  1000000000.0,
+  10000000000.0,  // 10^10
+  100000000000.0,
+  1000000000000.0,
+  10000000000000.0,
+  100000000000000.0,
+  1000000000000000.0,
+  10000000000000000.0,
+  100000000000000000.0,
+  1000000000000000000.0,
+  10000000000000000000.0,
+  100000000000000000000.0,  // 10^20
+  1000000000000000000000.0,
+  // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22
+  10000000000000000000000.0
+};
+static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten);
+
+// Maximum number of significant digits in the decimal representation.
+// In fact the value is 772 (see conversions.cc), but to give us some margin
+// we round up to 780.
+static const int kMaxSignificantDecimalDigits = 780;
+
+static Vector<const char> TrimLeadingZeros(Vector<const char> buffer) {
+  for (int i = 0; i < buffer.length(); i++) {
+    if (buffer[i] != '0') {
+      return buffer.SubVector(i, buffer.length());
+    }
+  }
+  return Vector<const char>(buffer.start(), 0);
+}
+
+
+static Vector<const char> TrimTrailingZeros(Vector<const char> buffer) {
+  for (int i = buffer.length() - 1; i >= 0; --i) {
+    if (buffer[i] != '0') {
+      return buffer.SubVector(0, i + 1);
+    }
+  }
+  return Vector<const char>(buffer.start(), 0);
+}
+
+
+static void CutToMaxSignificantDigits(Vector<const char> buffer,
+                                       int exponent,
+                                       char* significant_buffer,
+                                       int* significant_exponent) {
+  for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) {
+    significant_buffer[i] = buffer[i];
+  }
+  // The input buffer has been trimmed. Therefore the last digit must be
+  // different from '0'.
+  ASSERT(buffer[buffer.length() - 1] != '0');
+  // Set the last digit to be non-zero. This is sufficient to guarantee
+  // correct rounding.
+  significant_buffer[kMaxSignificantDecimalDigits - 1] = '1';
+  *significant_exponent =
+      exponent + (buffer.length() - kMaxSignificantDecimalDigits);
+}
+
+
+// Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits.
+// If possible the input-buffer is reused, but if the buffer needs to be
+// modified (due to cutting), then the input needs to be copied into the
+// buffer_copy_space.
+static void TrimAndCut(Vector<const char> buffer, int exponent,
+                       char* buffer_copy_space, int space_size,
+                       Vector<const char>* trimmed, int* updated_exponent) {
+  Vector<const char> left_trimmed = TrimLeadingZeros(buffer);
+  Vector<const char> right_trimmed = TrimTrailingZeros(left_trimmed);
+  exponent += left_trimmed.length() - right_trimmed.length();
+  if (right_trimmed.length() > kMaxSignificantDecimalDigits) {
+    (void) space_size;  // Mark variable as used.
+    ASSERT(space_size >= kMaxSignificantDecimalDigits);
+    CutToMaxSignificantDigits(right_trimmed, exponent,
+                              buffer_copy_space, updated_exponent);
+    *trimmed = Vector<const char>(buffer_copy_space,
+                                 kMaxSignificantDecimalDigits);
+  } else {
+    *trimmed = right_trimmed;
+    *updated_exponent = exponent;
+  }
+}
+
+
+// Reads digits from the buffer and converts them to a uint64.
+// Reads in as many digits as fit into a uint64.
+// When the string starts with "1844674407370955161" no further digit is read.
+// Since 2^64 = 18446744073709551616 it would still be possible read another
+// digit if it was less or equal than 6, but this would complicate the code.
+static uint64_t ReadUint64(Vector<const char> buffer,
+                           int* number_of_read_digits) {
+  uint64_t result = 0;
+  int i = 0;
+  while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) {
+    int digit = buffer[i++] - '0';
+    ASSERT(0 <= digit && digit <= 9);
+    result = 10 * result + digit;
+  }
+  *number_of_read_digits = i;
+  return result;
+}
+
+
+// Reads a DiyFp from the buffer.
+// The returned DiyFp is not necessarily normalized.
+// If remaining_decimals is zero then the returned DiyFp is accurate.
+// Otherwise it has been rounded and has error of at most 1/2 ulp.
+static void ReadDiyFp(Vector<const char> buffer,
+                      DiyFp* result,
+                      int* remaining_decimals) {
+  int read_digits;
+  uint64_t significand = ReadUint64(buffer, &read_digits);
+  if (buffer.length() == read_digits) {
+    *result = DiyFp(significand, 0);
+    *remaining_decimals = 0;
+  } else {
+    // Round the significand.
+    if (buffer[read_digits] >= '5') {
+      significand++;
+    }
+    // Compute the binary exponent.
+    int exponent = 0;
+    *result = DiyFp(significand, exponent);
+    *remaining_decimals = buffer.length() - read_digits;
+  }
+}
+
+
+static bool DoubleStrtod(Vector<const char> trimmed,
+                         int exponent,
+                         double* result) {
+#if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS)
+  // On x86 the floating-point stack can be 64 or 80 bits wide. If it is
+  // 80 bits wide (as is the case on Linux) then double-rounding occurs and the
+  // result is not accurate.
+  // We know that Windows32 uses 64 bits and is therefore accurate.
+  // Note that the ARM simulator is compiled for 32bits. It therefore exhibits
+  // the same problem.
+  return false;
+#endif
+  if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) {
+    int read_digits;
+    // The trimmed input fits into a double.
+    // If the 10^exponent (resp. 10^-exponent) fits into a double too then we
+    // can compute the result-double simply by multiplying (resp. dividing) the
+    // two numbers.
+    // This is possible because IEEE guarantees that floating-point operations
+    // return the best possible approximation.
+    if (exponent < 0 && -exponent < kExactPowersOfTenSize) {
+      // 10^-exponent fits into a double.
+      *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+      ASSERT(read_digits == trimmed.length());
+      *result /= exact_powers_of_ten[-exponent];
+      return true;
+    }
+    if (0 <= exponent && exponent < kExactPowersOfTenSize) {
+      // 10^exponent fits into a double.
+      *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+      ASSERT(read_digits == trimmed.length());
+      *result *= exact_powers_of_ten[exponent];
+      return true;
+    }
+    int remaining_digits =
+        kMaxExactDoubleIntegerDecimalDigits - trimmed.length();
+    if ((0 <= exponent) &&
+        (exponent - remaining_digits < kExactPowersOfTenSize)) {
+      // The trimmed string was short and we can multiply it with
+      // 10^remaining_digits. As a result the remaining exponent now fits
+      // into a double too.
+      *result = static_cast<double>(ReadUint64(trimmed, &read_digits));
+      ASSERT(read_digits == trimmed.length());
+      *result *= exact_powers_of_ten[remaining_digits];
+      *result *= exact_powers_of_ten[exponent - remaining_digits];
+      return true;
+    }
+  }
+  return false;
+}
+
+
+// Returns 10^exponent as an exact DiyFp.
+// The given exponent must be in the range [1; kDecimalExponentDistance[.
+static DiyFp AdjustmentPowerOfTen(int exponent) {
+  ASSERT(0 < exponent);
+  ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance);
+  // Simply hardcode the remaining powers for the given decimal exponent
+  // distance.
+  ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8);
+  switch (exponent) {
+    case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60);
+    case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57);
+    case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54);
+    case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50);
+    case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47);
+    case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44);
+    case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40);
+    default:
+      UNREACHABLE();
+      return DiyFp(0, 0);
+  }
+}
+
+
+// If the function returns true then the result is the correct double.
+// Otherwise it is either the correct double or the double that is just below
+// the correct double.
+static bool DiyFpStrtod(Vector<const char> buffer,
+                        int exponent,
+                        double* result) {
+  DiyFp input;
+  int remaining_decimals;
+  ReadDiyFp(buffer, &input, &remaining_decimals);
+  // Since we may have dropped some digits the input is not accurate.
+  // If remaining_decimals is different than 0 than the error is at most
+  // .5 ulp (unit in the last place).
+  // We don't want to deal with fractions and therefore keep a common
+  // denominator.
+  const int kDenominatorLog = 3;
+  const int kDenominator = 1 << kDenominatorLog;
+  // Move the remaining decimals into the exponent.
+  exponent += remaining_decimals;
+  int error = (remaining_decimals == 0 ? 0 : kDenominator / 2);
+
+  int old_e = input.e();
+  input.Normalize();
+  error <<= old_e - input.e();
+
+  ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent);
+  if (exponent < PowersOfTenCache::kMinDecimalExponent) {
+    *result = 0.0;
+    return true;
+  }
+  DiyFp cached_power;
+  int cached_decimal_exponent;
+  PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent,
+                                                     &cached_power,
+                                                     &cached_decimal_exponent);
+
+  if (cached_decimal_exponent != exponent) {
+    int adjustment_exponent = exponent - cached_decimal_exponent;
+    DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent);
+    input.Multiply(adjustment_power);
+    if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) {
+      // The product of input with the adjustment power fits into a 64 bit
+      // integer.
+      ASSERT(DiyFp::kSignificandSize == 64);
+    } else {
+      // The adjustment power is exact. There is hence only an error of 0.5.
+      error += kDenominator / 2;
+    }
+  }
+
+  input.Multiply(cached_power);
+  // The error introduced by a multiplication of a*b equals
+  //   error_a + error_b + error_a*error_b/2^64 + 0.5
+  // Substituting a with 'input' and b with 'cached_power' we have
+  //   error_b = 0.5  (all cached powers have an error of less than 0.5 ulp),
+  //   error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64
+  int error_b = kDenominator / 2;
+  int error_ab = (error == 0 ? 0 : 1);  // We round up to 1.
+  int fixed_error = kDenominator / 2;
+  error += error_b + error_ab + fixed_error;
+
+  old_e = input.e();
+  input.Normalize();
+  error <<= old_e - input.e();
+
+  // See if the double's significand changes if we add/subtract the error.
+  int order_of_magnitude = DiyFp::kSignificandSize + input.e();
+  int effective_significand_size =
+      Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude);
+  int precision_digits_count =
+      DiyFp::kSignificandSize - effective_significand_size;
+  if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) {
+    // This can only happen for very small denormals. In this case the
+    // half-way multiplied by the denominator exceeds the range of an uint64.
+    // Simply shift everything to the right.
+    int shift_amount = (precision_digits_count + kDenominatorLog) -
+        DiyFp::kSignificandSize + 1;
+    input.set_f(input.f() >> shift_amount);
+    input.set_e(input.e() + shift_amount);
+    // We add 1 for the lost precision of error, and kDenominator for
+    // the lost precision of input.f().
+    error = (error >> shift_amount) + 1 + kDenominator;
+    precision_digits_count -= shift_amount;
+  }
+  // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too.
+  ASSERT(DiyFp::kSignificandSize == 64);
+  ASSERT(precision_digits_count < 64);
+  uint64_t one64 = 1;
+  uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1;
+  uint64_t precision_bits = input.f() & precision_bits_mask;
+  uint64_t half_way = one64 << (precision_digits_count - 1);
+  precision_bits *= kDenominator;
+  half_way *= kDenominator;
+  DiyFp rounded_input(input.f() >> precision_digits_count,
+                      input.e() + precision_digits_count);
+  if (precision_bits >= half_way + error) {
+    rounded_input.set_f(rounded_input.f() + 1);
+  }
+  // If the last_bits are too close to the half-way case than we are too
+  // inaccurate and round down. In this case we return false so that we can
+  // fall back to a more precise algorithm.
+
+  *result = Double(rounded_input).value();
+  if (half_way - error < precision_bits && precision_bits < half_way + error) {
+    // Too imprecise. The caller will have to fall back to a slower version.
+    // However the returned number is guaranteed to be either the correct
+    // double, or the next-lower double.
+    return false;
+  } else {
+    return true;
+  }
+}
+
+
+// Returns
+//   - -1 if buffer*10^exponent < diy_fp.
+//   -  0 if buffer*10^exponent == diy_fp.
+//   - +1 if buffer*10^exponent > diy_fp.
+// Preconditions:
+//   buffer.length() + exponent <= kMaxDecimalPower + 1
+//   buffer.length() + exponent > kMinDecimalPower
+//   buffer.length() <= kMaxDecimalSignificantDigits
+static int CompareBufferWithDiyFp(Vector<const char> buffer,
+                                  int exponent,
+                                  DiyFp diy_fp) {
+  ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1);
+  ASSERT(buffer.length() + exponent > kMinDecimalPower);
+  ASSERT(buffer.length() <= kMaxSignificantDecimalDigits);
+  // Make sure that the Bignum will be able to hold all our numbers.
+  // Our Bignum implementation has a separate field for exponents. Shifts will
+  // consume at most one bigit (< 64 bits).
+  // ln(10) == 3.3219...
+  ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits);
+  Bignum buffer_bignum;
+  Bignum diy_fp_bignum;
+  buffer_bignum.AssignDecimalString(buffer);
+  diy_fp_bignum.AssignUInt64(diy_fp.f());
+  if (exponent >= 0) {
+    buffer_bignum.MultiplyByPowerOfTen(exponent);
+  } else {
+    diy_fp_bignum.MultiplyByPowerOfTen(-exponent);
+  }
+  if (diy_fp.e() > 0) {
+    diy_fp_bignum.ShiftLeft(diy_fp.e());
+  } else {
+    buffer_bignum.ShiftLeft(-diy_fp.e());
+  }
+  return Bignum::Compare(buffer_bignum, diy_fp_bignum);
+}
+
+
+// Returns true if the guess is the correct double.
+// Returns false, when guess is either correct or the next-lower double.
+static bool ComputeGuess(Vector<const char> trimmed, int exponent,
+                         double* guess) {
+  if (trimmed.length() == 0) {
+    *guess = 0.0;
+    return true;
+  }
+  if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) {
+    *guess = Double::Infinity();
+    return true;
+  }
+  if (exponent + trimmed.length() <= kMinDecimalPower) {
+    *guess = 0.0;
+    return true;
+  }
+
+  if (DoubleStrtod(trimmed, exponent, guess) ||
+      DiyFpStrtod(trimmed, exponent, guess)) {
+    return true;
+  }
+  if (*guess == Double::Infinity()) {
+    return true;
+  }
+  return false;
+}
+
+double Strtod(Vector<const char> buffer, int exponent) {
+  char copy_buffer[kMaxSignificantDecimalDigits];
+  Vector<const char> trimmed;
+  int updated_exponent;
+  TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+             &trimmed, &updated_exponent);
+  exponent = updated_exponent;
+
+  double guess;
+  bool is_correct = ComputeGuess(trimmed, exponent, &guess);
+  if (is_correct) return guess;
+
+  DiyFp upper_boundary = Double(guess).UpperBoundary();
+  int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
+  if (comparison < 0) {
+    return guess;
+  } else if (comparison > 0) {
+    return Double(guess).NextDouble();
+  } else if ((Double(guess).Significand() & 1) == 0) {
+    // Round towards even.
+    return guess;
+  } else {
+    return Double(guess).NextDouble();
+  }
+}
+
+float Strtof(Vector<const char> buffer, int exponent) {
+  char copy_buffer[kMaxSignificantDecimalDigits];
+  Vector<const char> trimmed;
+  int updated_exponent;
+  TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits,
+             &trimmed, &updated_exponent);
+  exponent = updated_exponent;
+
+  double double_guess;
+  bool is_correct = ComputeGuess(trimmed, exponent, &double_guess);
+
+  float float_guess = static_cast<float>(double_guess);
+  if (float_guess == double_guess) {
+    // This shortcut triggers for integer values.
+    return float_guess;
+  }
+
+  // We must catch double-rounding. Say the double has been rounded up, and is
+  // now a boundary of a float, and rounds up again. This is why we have to
+  // look at previous too.
+  // Example (in decimal numbers):
+  //    input: 12349
+  //    high-precision (4 digits): 1235
+  //    low-precision (3 digits):
+  //       when read from input: 123
+  //       when rounded from high precision: 124.
+  // To do this we simply look at the neigbors of the correct result and see
+  // if they would round to the same float. If the guess is not correct we have
+  // to look at four values (since two different doubles could be the correct
+  // double).
+
+  double double_next = Double(double_guess).NextDouble();
+  double double_previous = Double(double_guess).PreviousDouble();
+
+  float f1 = static_cast<float>(double_previous);
+  float f2 = float_guess;
+  float f3 = static_cast<float>(double_next);
+  float f4;
+  if (is_correct) {
+    f4 = f3;
+  } else {
+    double double_next2 = Double(double_next).NextDouble();
+    f4 = static_cast<float>(double_next2);
+  }
+  (void) f2;  // Mark variable as used.
+  ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4);
+
+  // If the guess doesn't lie near a single-precision boundary we can simply
+  // return its float-value.
+  if (f1 == f4) {
+    return float_guess;
+  }
+
+  ASSERT((f1 != f2 && f2 == f3 && f3 == f4) ||
+         (f1 == f2 && f2 != f3 && f3 == f4) ||
+         (f1 == f2 && f2 == f3 && f3 != f4));
+
+  // guess and next are the two possible canditates (in the same way that
+  // double_guess was the lower candidate for a double-precision guess).
+  float guess = f1;
+  float next = f4;
+  DiyFp upper_boundary;
+  if (guess == 0.0f) {
+    float min_float = 1e-45f;
+    upper_boundary = Double(static_cast<double>(min_float) / 2).AsDiyFp();
+  } else {
+    upper_boundary = Single(guess).UpperBoundary();
+  }
+  int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary);
+  if (comparison < 0) {
+    return guess;
+  } else if (comparison > 0) {
+    return next;
+  } else if ((Single(guess).Significand() & 1) == 0) {
+    // Round towards even.
+    return guess;
+  } else {
+    return next;
+  }
+}
+
+}  // namespace double_conversion
diff --git a/core/deps/double-conversion/src/strtod.h b/core/deps/double-conversion/src/strtod.h
new file mode 100644 (file)
index 0000000..ed0293b
--- /dev/null
@@ -0,0 +1,45 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_STRTOD_H_
+#define DOUBLE_CONVERSION_STRTOD_H_
+
+#include "utils.h"
+
+namespace double_conversion {
+
+// The buffer must only contain digits in the range [0-9]. It must not
+// contain a dot or a sign. It must not start with '0', and must not be empty.
+double Strtod(Vector<const char> buffer, int exponent);
+
+// The buffer must only contain digits in the range [0-9]. It must not
+// contain a dot or a sign. It must not start with '0', and must not be empty.
+float Strtof(Vector<const char> buffer, int exponent);
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_STRTOD_H_
diff --git a/core/deps/double-conversion/src/utils.h b/core/deps/double-conversion/src/utils.h
new file mode 100644 (file)
index 0000000..fd41f52
--- /dev/null
@@ -0,0 +1,324 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "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 THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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 DOUBLE_CONVERSION_UTILS_H_
+#define DOUBLE_CONVERSION_UTILS_H_
+
+#include <stdlib.h>
+#include <string.h>
+
+#include <assert.h>
+#ifndef ASSERT
+#define ASSERT(condition)         \
+    assert(condition);
+#endif
+#ifndef UNIMPLEMENTED
+#define UNIMPLEMENTED() (abort())
+#endif
+#ifndef UNREACHABLE
+#define UNREACHABLE()   (abort())
+#endif
+
+// Double operations detection based on target architecture.
+// Linux uses a 80bit wide floating point stack on x86. This induces double
+// rounding, which in turn leads to wrong results.
+// An easy way to test if the floating-point operations are correct is to
+// evaluate: 89255.0/1e22. If the floating-point stack is 64 bits wide then
+// the result is equal to 89255e-22.
+// The best way to test this, is to create a division-function and to compare
+// the output of the division with the expected result. (Inlining must be
+// disabled.)
+// On Linux,x86 89255e-22 != Div_double(89255.0/1e22)
+#if defined(_M_X64) || defined(__x86_64__) || \
+    defined(__ARMEL__) || defined(_M_ARM) || defined(__arm__) || defined(__arm64__) || \
+    defined(__avr32__) || \
+    defined(__hppa__) || defined(__ia64__) || \
+    defined(__mips__) || \
+    defined(__powerpc__) || defined(__ppc__) || defined(__ppc64__) || \
+    defined(__sparc__) || defined(__sparc) || defined(__s390__) || \
+    defined(__SH4__) || defined(__alpha__) || \
+    defined(_MIPS_ARCH_MIPS32R2) || \
+    defined(__AARCH64EL__) || \
+    defined(nios2) || defined(__nios2) || defined(__nios2__)
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#elif defined(_M_IX86) || defined(__i386__) || defined(__i386)
+#if defined(_WIN32)
+// Windows uses a 64bit wide floating point stack.
+#define DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS 1
+#else
+#undef DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS
+#endif  // _WIN32
+#else
+#error Target architecture was not detected as supported by Double-Conversion.
+#endif
+
+#if defined(__GNUC__)
+#define DOUBLE_CONVERSION_UNUSED __attribute__((unused))
+#else
+#define DOUBLE_CONVERSION_UNUSED
+#endif
+
+#if defined(_WIN32) && !defined(__MINGW32__)
+
+typedef signed char int8_t;
+typedef unsigned char uint8_t;
+typedef short int16_t;  // NOLINT
+typedef unsigned short uint16_t;  // NOLINT
+typedef int int32_t;
+typedef unsigned int uint32_t;
+typedef __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+// intptr_t and friends are defined in crtdefs.h through stdio.h.
+
+#else
+
+#include <stdint.h>
+
+#endif
+
+// The following macro works on both 32 and 64-bit platforms.
+// Usage: instead of writing 0x1234567890123456
+//      write UINT64_2PART_C(0x12345678,90123456);
+#define UINT64_2PART_C(a, b) (((static_cast<uint64_t>(a) << 32) + 0x##b##u))
+
+
+// The expression ARRAY_SIZE(a) is a compile-time constant of type
+// size_t which represents the number of elements of the given
+// array. You should only use ARRAY_SIZE on statically allocated
+// arrays.
+#ifndef ARRAY_SIZE
+#define ARRAY_SIZE(a)                                   \
+  ((sizeof(a) / sizeof(*(a))) /                         \
+  static_cast<size_t>(!(sizeof(a) % sizeof(*(a)))))
+#endif
+
+// A macro to disallow the evil copy constructor and operator= functions
+// This should be used in the private: declarations for a class
+#ifndef DISALLOW_COPY_AND_ASSIGN
+#define DISALLOW_COPY_AND_ASSIGN(TypeName)      \
+  TypeName(const TypeName&);                    \
+  void operator=(const TypeName&)
+#endif
+
+// A macro to disallow all the implicit constructors, namely the
+// default constructor, copy constructor and operator= functions.
+//
+// This should be used in the private: declarations for a class
+// that wants to prevent anyone from instantiating it. This is
+// especially useful for classes containing only static methods.
+#ifndef DISALLOW_IMPLICIT_CONSTRUCTORS
+#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \
+  TypeName();                                    \
+  DISALLOW_COPY_AND_ASSIGN(TypeName)
+#endif
+
+namespace double_conversion {
+
+static const int kCharSize = sizeof(char);
+
+// Returns the maximum of the two parameters.
+template <typename T>
+static T Max(T a, T b) {
+  return a < b ? b : a;
+}
+
+
+// Returns the minimum of the two parameters.
+template <typename T>
+static T Min(T a, T b) {
+  return a < b ? a : b;
+}
+
+
+inline int StrLength(const char* string) {
+  size_t length = strlen(string);
+  ASSERT(length == static_cast<size_t>(static_cast<int>(length)));
+  return static_cast<int>(length);
+}
+
+// This is a simplified version of V8's Vector class.
+template <typename T>
+class Vector {
+ public:
+  Vector() : start_(NULL), length_(0) {}
+  Vector(T* data, int size) : start_(data), length_(size) {
+    ASSERT(size == 0 || (size > 0 && data != NULL));
+  }
+
+  // Returns a vector using the same backing storage as this one,
+  // spanning from and including 'from', to but not including 'to'.
+  Vector<T> SubVector(int from, int to) {
+    ASSERT(to <= length_);
+    ASSERT(from < to);
+    ASSERT(0 <= from);
+    return Vector<T>(start() + from, to - from);
+  }
+
+  // Returns the length of the vector.
+  int length() const { return length_; }
+
+  // Returns whether or not the vector is empty.
+  bool is_empty() const { return length_ == 0; }
+
+  // Returns the pointer to the start of the data in the vector.
+  T* start() const { return start_; }
+
+  // Access individual vector elements - checks bounds in debug mode.
+  T& operator[](int index) const {
+    ASSERT(0 <= index && index < length_);
+    return start_[index];
+  }
+
+  T& first() { return start_[0]; }
+
+  T& last() { return start_[length_ - 1]; }
+
+ private:
+  T* start_;
+  int length_;
+};
+
+
+// Helper class for building result strings in a character buffer. The
+// purpose of the class is to use safe operations that checks the
+// buffer bounds on all operations in debug mode.
+class StringBuilder {
+ public:
+  StringBuilder(char* buffer, int length)
+      : buffer_(buffer, length), position_(0) { }
+
+  ~StringBuilder() { if (!is_finalized()) Finalize(); }
+
+  int size() const { return buffer_.length(); }
+
+  // Get the current position in the builder.
+  int position() const {
+    ASSERT(!is_finalized());
+    return position_;
+  }
+
+  // Reset the position.
+  void Reset() { position_ = 0; }
+
+  // Add a single character to the builder. It is not allowed to add
+  // 0-characters; use the Finalize() method to terminate the string
+  // instead.
+  void AddCharacter(char c) {
+    ASSERT(c != '\0');
+    ASSERT(!is_finalized() && position_ < buffer_.length());
+    buffer_[position_++] = c;
+  }
+
+  // Add an entire string to the builder. Uses strlen() internally to
+  // compute the length of the input string.
+  void AddString(const char* s) {
+    AddSubstring(s, StrLength(s));
+  }
+
+  // Add the first 'n' characters of the given string 's' to the
+  // builder. The input string must have enough characters.
+  void AddSubstring(const char* s, int n) {
+    ASSERT(!is_finalized() && position_ + n < buffer_.length());
+    ASSERT(static_cast<size_t>(n) <= strlen(s));
+    memmove(&buffer_[position_], s, n * kCharSize);
+    position_ += n;
+  }
+
+
+  // Add character padding to the builder. If count is non-positive,
+  // nothing is added to the builder.
+  void AddPadding(char c, int count) {
+    for (int i = 0; i < count; i++) {
+      AddCharacter(c);
+    }
+  }
+
+  // Finalize the string by 0-terminating it and returning the buffer.
+  char* Finalize() {
+    ASSERT(!is_finalized() && position_ < buffer_.length());
+    buffer_[position_] = '\0';
+    // Make sure nobody managed to add a 0-character to the
+    // buffer while building the string.
+    ASSERT(strlen(buffer_.start()) == static_cast<size_t>(position_));
+    position_ = -1;
+    ASSERT(is_finalized());
+    return buffer_.start();
+  }
+
+ private:
+  Vector<char> buffer_;
+  int position_;
+
+  bool is_finalized() const { return position_ < 0; }
+
+  DISALLOW_IMPLICIT_CONSTRUCTORS(StringBuilder);
+};
+
+// The type-based aliasing rule allows the compiler to assume that pointers of
+// different types (for some definition of different) never alias each other.
+// Thus the following code does not work:
+//
+// float f = foo();
+// int fbits = *(int*)(&f);
+//
+// The compiler 'knows' that the int pointer can't refer to f since the types
+// don't match, so the compiler may cache f in a register, leaving random data
+// in fbits.  Using C++ style casts makes no difference, however a pointer to
+// char data is assumed to alias any other pointer.  This is the 'memcpy
+// exception'.
+//
+// Bit_cast uses the memcpy exception to move the bits from a variable of one
+// type of a variable of another type.  Of course the end result is likely to
+// be implementation dependent.  Most compilers (gcc-4.2 and MSVC 2005)
+// will completely optimize BitCast away.
+//
+// There is an additional use for BitCast.
+// Recent gccs will warn when they see casts that may result in breakage due to
+// the type-based aliasing rule.  If you have checked that there is no breakage
+// you can use BitCast to cast one pointer type to another.  This confuses gcc
+// enough that it can no longer see that you have cast one pointer type to
+// another thus avoiding the warning.
+template <class Dest, class Source>
+inline Dest BitCast(const Source& source) {
+  // Compile time assertion: sizeof(Dest) == sizeof(Source)
+  // A compile error here means your Dest and Source have different sizes.
+  DOUBLE_CONVERSION_UNUSED
+      typedef char VerifySizesAreEqual[sizeof(Dest) == sizeof(Source) ? 1 : -1];
+
+  Dest dest;
+  memmove(&dest, &source, sizeof(dest));
+  return dest;
+}
+
+template <class Dest, class Source>
+inline Dest BitCast(Source* source) {
+  return BitCast<Dest>(reinterpret_cast<uintptr_t>(source));
+}
+
+}  // namespace double_conversion
+
+#endif  // DOUBLE_CONVERSION_UTILS_H_
diff --git a/core/deps/glm/copying.txt b/core/deps/glm/copying.txt
new file mode 100755 (executable)
index 0000000..7c20b4a
--- /dev/null
@@ -0,0 +1,54 @@
+================================================================================
+OpenGL Mathematics (GLM)
+--------------------------------------------------------------------------------
+GLM can be distributed and/or modified under the terms of either
+a) The Happy Bunny License, or b) the MIT License.
+
+================================================================================
+The Happy Bunny License (Modified MIT License)
+--------------------------------------------------------------------------------
+Copyright (c) 2005 - 2016 G-Truc Creation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+Restrictions: By making use of the Software for military purposes, you choose
+to make a Bunny unhappy.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
+
+================================================================================
+The MIT License
+--------------------------------------------------------------------------------
+Copyright (c) 2005 - 2016 G-Truc Creation
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/core/deps/glm/glm/CMakeLists.txt b/core/deps/glm/glm/CMakeLists.txt
new file mode 100755 (executable)
index 0000000..d60a887
--- /dev/null
@@ -0,0 +1,67 @@
+file(GLOB ROOT_SOURCE *.cpp)
+file(GLOB ROOT_INLINE *.inl)
+file(GLOB ROOT_HEADER *.hpp)
+file(GLOB ROOT_TEXT ../*.txt)
+file(GLOB ROOT_MD ../*.md)
+file(GLOB ROOT_NAT ../util/glm.natvis)
+
+file(GLOB_RECURSE CORE_SOURCE ./detail/*.cpp)
+file(GLOB_RECURSE CORE_INLINE ./detail/*.inl)
+file(GLOB_RECURSE CORE_HEADER ./detail/*.hpp)
+
+file(GLOB_RECURSE GTC_SOURCE ./gtc/*.cpp)
+file(GLOB_RECURSE GTC_INLINE ./gtc/*.inl)
+file(GLOB_RECURSE GTC_HEADER ./gtc/*.hpp)
+
+file(GLOB_RECURSE GTX_SOURCE ./gtx/*.cpp)
+file(GLOB_RECURSE GTX_INLINE ./gtx/*.inl)
+file(GLOB_RECURSE GTX_HEADER ./gtx/*.hpp)
+
+file(GLOB_RECURSE SIMD_SOURCE ./simd/*.cpp)
+file(GLOB_RECURSE SIMD_INLINE ./simd/*.inl)
+file(GLOB_RECURSE SIMD_HEADER ./simd/*.h)
+
+source_group("Text Files" FILES ${ROOT_TEXT} ${ROOT_MD})
+source_group("Core Files" FILES ${CORE_SOURCE})
+source_group("Core Files" FILES ${CORE_INLINE})
+source_group("Core Files" FILES ${CORE_HEADER})
+source_group("GTC Files" FILES ${GTC_SOURCE})
+source_group("GTC Files" FILES ${GTC_INLINE})
+source_group("GTC Files" FILES ${GTC_HEADER})
+source_group("GTX Files" FILES ${GTX_SOURCE})
+source_group("GTX Files" FILES ${GTX_INLINE})
+source_group("GTX Files" FILES ${GTX_HEADER})
+source_group("SIMD Files" FILES ${SIMD_SOURCE})
+source_group("SIMD Files" FILES ${SIMD_INLINE})
+source_group("SIMD Files" FILES ${SIMD_HEADER})
+
+include_directories(${CMAKE_CURRENT_SOURCE_DIR}/..)
+
+if(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE)
+       if(GLM_STATIC_LIBRARY_ENABLE)
+               add_library(glm_static STATIC ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT}
+                       ${ROOT_SOURCE}    ${ROOT_INLINE}    ${ROOT_HEADER}
+                       ${CORE_SOURCE}    ${CORE_INLINE}    ${CORE_HEADER}
+                       ${GTC_SOURCE}     ${GTC_INLINE}     ${GTC_HEADER}
+                       ${GTX_SOURCE}     ${GTX_INLINE}     ${GTX_HEADER}
+                       ${SIMD_SOURCE}    ${SIMD_INLINE}    ${SIMD_HEADER})
+       endif(GLM_STATIC_LIBRARY_ENABLE)
+
+       if(GLM_DYNAMIC_LIBRARY_ENABLE)
+               add_library(glm_shared SHARED ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT}
+                       ${ROOT_SOURCE}    ${ROOT_INLINE}    ${ROOT_HEADER}
+                       ${CORE_SOURCE}    ${CORE_INLINE}    ${CORE_HEADER}
+                       ${GTC_SOURCE}     ${GTC_INLINE}     ${GTC_HEADER}
+                       ${GTX_SOURCE}     ${GTX_INLINE}     ${GTX_HEADER}
+                       ${SIMD_SOURCE}    ${SIMD_INLINE}    ${SIMD_HEADER})
+       endif(GLM_DYNAMIC_LIBRARY_ENABLE)
+
+else(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE)
+       add_executable(glm_dummy ${ROOT_TEXT} ${ROOT_MD} ${ROOT_NAT}
+               ${ROOT_SOURCE}    ${ROOT_INLINE}    ${ROOT_HEADER}
+               ${CORE_SOURCE}    ${CORE_INLINE}    ${CORE_HEADER}
+               ${GTC_SOURCE}     ${GTC_INLINE}     ${GTC_HEADER}
+               ${GTX_SOURCE}     ${GTX_INLINE}     ${GTX_HEADER}
+               ${SIMD_SOURCE}    ${SIMD_INLINE}    ${SIMD_HEADER})
+
+endif(GLM_STATIC_LIBRARY_ENABLE OR GLM_DYNAMIC_LIBRARY_ENABLE)
diff --git a/core/deps/glm/glm/common.hpp b/core/deps/glm/glm/common.hpp
new file mode 100755 (executable)
index 0000000..f57e800
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/common.hpp
+
+#pragma once
+
+#include "detail/func_common.hpp"
diff --git a/core/deps/glm/glm/detail/_features.hpp b/core/deps/glm/glm/detail/_features.hpp
new file mode 100755 (executable)
index 0000000..97dd633
--- /dev/null
@@ -0,0 +1,399 @@
+/// @ref core
+/// @file glm/detail/_features.hpp
+
+#pragma once
+
+// #define GLM_CXX98_EXCEPTIONS
+// #define GLM_CXX98_RTTI
+
+// #define GLM_CXX11_RVALUE_REFERENCES
+// Rvalue references - GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2118.html
+
+// GLM_CXX11_TRAILING_RETURN
+// Rvalue references for *this - GCC not supported
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2439.htm
+
+// GLM_CXX11_NONSTATIC_MEMBER_INIT
+// Initialization of class objects by rvalues - GCC any
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1610.html
+
+// GLM_CXX11_NONSTATIC_MEMBER_INIT
+// Non-static data member initializers - GCC 4.7
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2008/n2756.htm
+
+// #define GLM_CXX11_VARIADIC_TEMPLATE
+// Variadic templates - GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2242.pdf
+
+// 
+// Extending variadic template template parameters - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2555.pdf
+
+// #define GLM_CXX11_GENERALIZED_INITIALIZERS
+// Initializer lists - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2672.htm
+
+// #define GLM_CXX11_STATIC_ASSERT 
+// Static assertions - GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1720.html
+
+// #define GLM_CXX11_AUTO_TYPE
+// auto-typed variables - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1984.pdf
+
+// #define GLM_CXX11_AUTO_TYPE
+// Multi-declarator auto - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1737.pdf
+
+// #define GLM_CXX11_AUTO_TYPE
+// Removal of auto as a storage-class specifier - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2546.htm
+
+// #define GLM_CXX11_AUTO_TYPE
+// New function declarator syntax - GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2541.htm
+
+// #define GLM_CXX11_LAMBDAS
+// New wording for C++0x lambdas - GCC 4.5
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2927.pdf
+
+// #define GLM_CXX11_DECLTYPE
+// Declared type of an expression - GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2343.pdf
+
+// 
+// Right angle brackets - GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1757.html
+
+// 
+// Default template arguments for function templates   DR226   GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/cwg_defects.html#226
+
+// 
+// Solving the SFINAE problem for expressions  DR339   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2634.html
+
+// #define GLM_CXX11_ALIAS_TEMPLATE
+// Template aliases    N2258   GCC 4.7
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf
+
+// 
+// Extern templates    N1987   Yes
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1987.htm
+
+// #define GLM_CXX11_NULLPTR
+// Null pointer constant       N2431   GCC 4.6
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2431.pdf
+
+// #define GLM_CXX11_STRONG_ENUMS
+// Strongly-typed enums        N2347   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2347.pdf
+
+// 
+// Forward declarations for enums      N2764   GCC 4.6
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2764.pdf
+
+// 
+// Generalized attributes      N2761   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2761.pdf
+
+// 
+// Generalized constant expressions    N2235   GCC 4.6
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2235.pdf
+
+// 
+// Alignment support   N2341   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf
+
+// #define GLM_CXX11_DELEGATING_CONSTRUCTORS
+// Delegating constructors     N1986   GCC 4.7
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1986.pdf
+
+// 
+// Inheriting constructors     N2540   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2540.htm
+
+// #define GLM_CXX11_EXPLICIT_CONVERSIONS
+// Explicit conversion operators       N2437   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf
+
+// 
+// New character types N2249   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2249.html
+
+// 
+// Unicode string literals     N2442   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
+
+// 
+// Raw string literals N2442   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2442.htm
+
+// 
+// Universal character name literals   N2170   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2170.html
+
+// #define GLM_CXX11_USER_LITERALS
+// User-defined literals               N2765   GCC 4.7
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2765.pdf
+
+// 
+// Standard Layout Types       N2342   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2342.htm
+
+// #define GLM_CXX11_DEFAULTED_FUNCTIONS
+// #define GLM_CXX11_DELETED_FUNCTIONS
+// Defaulted and deleted functions     N2346   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2346.htm
+
+// 
+// Extended friend declarations        N1791   GCC 4.7
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1791.pdf
+
+// 
+// Extending sizeof    N2253   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html
+
+// #define GLM_CXX11_INLINE_NAMESPACES
+// Inline namespaces   N2535   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2535.htm
+
+// #define GLM_CXX11_UNRESTRICTED_UNIONS
+// Unrestricted unions N2544   GCC 4.6
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+
+// #define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS
+// Local and unnamed types as template arguments       N2657   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2657.htm
+
+// #define GLM_CXX11_RANGE_FOR
+// Range-based for     N2930   GCC 4.6
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2930.html
+
+// #define GLM_CXX11_OVERRIDE_CONTROL
+// Explicit virtual overrides  N2928 N3206 N3272       GCC 4.7
+// http://www.open-std.org/JTC1/SC22/WG21/docs/papers/2009/n2928.htm
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3206.htm
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2011/n3272.htm
+
+// 
+// Minimal support for garbage collection and reachability-based leak detection        N2670   No
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2670.htm
+
+// #define GLM_CXX11_NOEXCEPT
+// Allowing move constructors to throw [noexcept]      N3050   GCC 4.6 (core language only)
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3050.html
+
+// 
+// Defining move special member functions      N3053   GCC 4.6
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2010/n3053.html
+
+// 
+// Sequence points     N2239   Yes
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html
+
+// 
+// Atomic operations   N2427   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2239.html
+
+// 
+// Strong Compare and Exchange N2748   GCC 4.5
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2427.html
+
+// 
+// Bidirectional Fences        N2752   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2752.htm
+
+// 
+// Memory model        N2429   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2429.htm
+
+// 
+// Data-dependency ordering: atomics and memory model  N2664   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2664.htm
+
+// 
+// Propagating exceptions      N2179   GCC 4.4
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2179.html
+
+// 
+// Abandoning a process and at_quick_exit      N2440   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2440.htm
+
+// 
+// Allow atomics use in signal handlers        N2547   Yes
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2547.htm
+
+// 
+// Thread-local storage        N2659   GCC 4.8
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2659.htm
+
+// 
+// Dynamic initialization and destruction with concurrency     N2660   GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2660.htm
+
+// 
+// __func__ predefined identifier      N2340   GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2340.htm
+
+// 
+// C99 preprocessor    N1653   GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2004/n1653.htm
+
+// 
+// long long   N1811   GCC 4.3
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1811.pdf
+
+// 
+// Extended integral types     N1988   Yes
+// http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1988.pdf
+
+#if(GLM_COMPILER & GLM_COMPILER_GCC)
+
+#      if(GLM_COMPILER >= GLM_COMPILER_GCC43)
+#              define GLM_CXX11_STATIC_ASSERT
+#      endif
+
+#elif(GLM_COMPILER & GLM_COMPILER_CLANG)
+#      if(__has_feature(cxx_exceptions))
+#              define GLM_CXX98_EXCEPTIONS
+#      endif
+
+#      if(__has_feature(cxx_rtti))
+#              define GLM_CXX98_RTTI
+#      endif
+
+#      if(__has_feature(cxx_access_control_sfinae))
+#              define GLM_CXX11_ACCESS_CONTROL_SFINAE
+#      endif
+
+#      if(__has_feature(cxx_alias_templates))
+#              define GLM_CXX11_ALIAS_TEMPLATE
+#      endif
+
+#      if(__has_feature(cxx_alignas))
+#              define GLM_CXX11_ALIGNAS
+#      endif
+
+#      if(__has_feature(cxx_attributes))
+#              define GLM_CXX11_ATTRIBUTES
+#      endif
+
+#      if(__has_feature(cxx_constexpr))
+#              define GLM_CXX11_CONSTEXPR
+#      endif
+
+#      if(__has_feature(cxx_decltype))
+#              define GLM_CXX11_DECLTYPE
+#      endif
+
+#      if(__has_feature(cxx_default_function_template_args))
+#              define GLM_CXX11_DEFAULT_FUNCTION_TEMPLATE_ARGS
+#      endif
+
+#      if(__has_feature(cxx_defaulted_functions))
+#              define GLM_CXX11_DEFAULTED_FUNCTIONS
+#      endif
+
+#      if(__has_feature(cxx_delegating_constructors))
+#              define GLM_CXX11_DELEGATING_CONSTRUCTORS
+#      endif
+
+#      if(__has_feature(cxx_deleted_functions))
+#              define GLM_CXX11_DELETED_FUNCTIONS
+#      endif
+
+#      if(__has_feature(cxx_explicit_conversions))
+#              define GLM_CXX11_EXPLICIT_CONVERSIONS
+#      endif
+
+#      if(__has_feature(cxx_generalized_initializers))
+#              define GLM_CXX11_GENERALIZED_INITIALIZERS
+#      endif
+
+#      if(__has_feature(cxx_implicit_moves))
+#              define GLM_CXX11_IMPLICIT_MOVES
+#      endif
+
+#      if(__has_feature(cxx_inheriting_constructors))
+#              define GLM_CXX11_INHERITING_CONSTRUCTORS
+#      endif
+
+#      if(__has_feature(cxx_inline_namespaces))
+#              define GLM_CXX11_INLINE_NAMESPACES
+#      endif
+
+#      if(__has_feature(cxx_lambdas))
+#              define GLM_CXX11_LAMBDAS
+#      endif
+
+#      if(__has_feature(cxx_local_type_template_args))
+#              define GLM_CXX11_LOCAL_TYPE_TEMPLATE_ARGS
+#      endif
+
+#      if(__has_feature(cxx_noexcept))
+#              define GLM_CXX11_NOEXCEPT
+#      endif
+
+#      if(__has_feature(cxx_nonstatic_member_init))
+#              define GLM_CXX11_NONSTATIC_MEMBER_INIT
+#      endif
+
+#      if(__has_feature(cxx_nullptr))
+#              define GLM_CXX11_NULLPTR
+#      endif
+
+#      if(__has_feature(cxx_override_control))
+#              define GLM_CXX11_OVERRIDE_CONTROL
+#      endif
+
+#      if(__has_feature(cxx_reference_qualified_functions))
+#              define GLM_CXX11_REFERENCE_QUALIFIED_FUNCTIONS
+#      endif
+
+#      if(__has_feature(cxx_range_for))
+#              define GLM_CXX11_RANGE_FOR
+#      endif
+
+#      if(__has_feature(cxx_raw_string_literals))
+#              define GLM_CXX11_RAW_STRING_LITERALS
+#      endif
+
+#      if(__has_feature(cxx_rvalue_references))
+#              define GLM_CXX11_RVALUE_REFERENCES
+#      endif
+
+#      if(__has_feature(cxx_static_assert))
+#              define GLM_CXX11_STATIC_ASSERT
+#      endif
+
+#      if(__has_feature(cxx_auto_type))
+#              define GLM_CXX11_AUTO_TYPE
+#      endif
+
+#      if(__has_feature(cxx_strong_enums))
+#              define GLM_CXX11_STRONG_ENUMS
+#      endif
+
+#      if(__has_feature(cxx_trailing_return))
+#              define GLM_CXX11_TRAILING_RETURN
+#      endif
+
+#      if(__has_feature(cxx_unicode_literals))
+#              define GLM_CXX11_UNICODE_LITERALS
+#      endif
+
+#      if(__has_feature(cxx_unrestricted_unions))
+#              define GLM_CXX11_UNRESTRICTED_UNIONS
+#      endif
+
+#      if(__has_feature(cxx_user_literals))
+#              define GLM_CXX11_USER_LITERALS
+#      endif
+
+#      if(__has_feature(cxx_variadic_templates))
+#              define GLM_CXX11_VARIADIC_TEMPLATES
+#      endif
+
+#endif//(GLM_COMPILER & GLM_COMPILER_CLANG)
diff --git a/core/deps/glm/glm/detail/_fixes.hpp b/core/deps/glm/glm/detail/_fixes.hpp
new file mode 100755 (executable)
index 0000000..c957562
--- /dev/null
@@ -0,0 +1,30 @@
+/// @ref core
+/// @file glm/detail/_fixes.hpp
+
+#include <cmath>
+
+//! Workaround for compatibility with other libraries
+#ifdef max
+#undef max
+#endif
+
+//! Workaround for compatibility with other libraries
+#ifdef min
+#undef min
+#endif
+
+//! Workaround for Android
+#ifdef isnan
+#undef isnan
+#endif
+
+//! Workaround for Android
+#ifdef isinf
+#undef isinf
+#endif
+
+//! Workaround for Chrone Native Client
+#ifdef log2
+#undef log2
+#endif
+
diff --git a/core/deps/glm/glm/detail/_noise.hpp b/core/deps/glm/glm/detail/_noise.hpp
new file mode 100755 (executable)
index 0000000..89403f4
--- /dev/null
@@ -0,0 +1,107 @@
+/// @ref core
+/// @file glm/detail/_noise.hpp
+
+#pragma once
+
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../common.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER T mod289(T const & x)
+       {
+               return x - floor(x * static_cast<T>(1.0) / static_cast<T>(289.0)) * static_cast<T>(289.0);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T permute(T const & x)
+       {
+               return mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> permute(tvec2<T, P> const & x)
+       {
+               return mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> permute(tvec3<T, P> const & x)
+       {
+               return mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> permute(tvec4<T, P> const & x)
+       {
+               return mod289(((x * static_cast<T>(34)) + static_cast<T>(1)) * x);
+       }
+/*
+       template <typename T, precision P, template<typename> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> permute(vecType<T, P> const & x)
+       {
+               return mod289(((x * T(34)) + T(1)) * x);
+       }
+*/
+       template <typename T>
+       GLM_FUNC_QUALIFIER T taylorInvSqrt(T const & r)
+       {
+               return T(1.79284291400159) - T(0.85373472095314) * r;
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> taylorInvSqrt(tvec2<T, P> const & r)
+       {
+               return T(1.79284291400159) - T(0.85373472095314) * r;
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> taylorInvSqrt(tvec3<T, P> const & r)
+       {
+               return T(1.79284291400159) - T(0.85373472095314) * r;
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> taylorInvSqrt(tvec4<T, P> const & r)
+       {
+               return T(1.79284291400159) - T(0.85373472095314) * r;
+       }
+/*
+       template <typename T, precision P, template<typename> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> taylorInvSqrt(vecType<T, P> const & r)
+       {
+               return T(1.79284291400159) - T(0.85373472095314) * r;
+       }
+*/
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> fade(tvec2<T, P> const & t)
+       {
+               return (t * t * t) * (t * (t * T(6) - T(15)) + T(10));
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> fade(tvec3<T, P> const & t)
+       {
+               return (t * t * t) * (t * (t * T(6) - T(15)) + T(10));
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> fade(tvec4<T, P> const & t)
+       {
+               return (t * t * t) * (t * (t * T(6) - T(15)) + T(10));
+       }
+/*
+       template <typename T, precision P, template <typename> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fade(vecType<T, P> const & t)
+       {
+               return (t * t * t) * (t * (t * T(6) - T(15)) + T(10));
+       }
+*/
+}//namespace detail
+}//namespace glm
+
diff --git a/core/deps/glm/glm/detail/_swizzle.hpp b/core/deps/glm/glm/detail/_swizzle.hpp
new file mode 100755 (executable)
index 0000000..8e134d9
--- /dev/null
@@ -0,0 +1,797 @@
+/// @ref core
+/// @file glm/detail/_swizzle.hpp
+
+#pragma once
+
+namespace glm{
+namespace detail
+{
+       // Internal class for implementing swizzle operators
+       template <typename T, int N>
+       struct _swizzle_base0
+       {
+       protected:
+               GLM_FUNC_QUALIFIER T& elem(size_t i){ return (reinterpret_cast<T*>(_buffer))[i]; }
+               GLM_FUNC_QUALIFIER T const& elem(size_t i) const{ return (reinterpret_cast<const T*>(_buffer))[i]; }
+
+               // Use an opaque buffer to *ensure* the compiler doesn't call a constructor.
+               // The size 1 buffer is assumed to aligned to the actual members so that the
+               // elem() 
+               char    _buffer[1];
+       };
+
+       template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3, bool Aligned>
+       struct _swizzle_base1 : public _swizzle_base0<T, N>
+       {
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, int E0, int E1, bool Aligned>
+       struct _swizzle_base1<2, T, P, vecType, E0,E1,-1,-2, Aligned> : public _swizzle_base0<T, 2>
+       {
+               GLM_FUNC_QUALIFIER vecType<T, P> operator ()()  const { return vecType<T, P>(this->elem(E0), this->elem(E1)); }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, bool Aligned>
+       struct _swizzle_base1<3, T, P, vecType, E0,E1,E2,-1, Aligned> : public _swizzle_base0<T, 3>
+       {
+               GLM_FUNC_QUALIFIER vecType<T, P> operator ()()  const { return vecType<T, P>(this->elem(E0), this->elem(E1), this->elem(E2)); }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3, bool Aligned>
+       struct _swizzle_base1<4, T, P, vecType, E0,E1,E2,E3, Aligned> : public _swizzle_base0<T, 4>
+       { 
+               GLM_FUNC_QUALIFIER vecType<T, P> operator ()()  const { return vecType<T, P>(this->elem(E0), this->elem(E1), this->elem(E2), this->elem(E3)); }
+       };
+
+       // Internal class for implementing swizzle operators
+       /*
+               Template parameters:
+
+               ValueType = type of scalar values (e.g. float, double)
+               VecType   = class the swizzle is applies to (e.g. tvec3<float>)
+               N         = number of components in the vector (e.g. 3)
+               E0...3    = what index the n-th element of this swizzle refers to in the unswizzled vec
+
+               DUPLICATE_ELEMENTS = 1 if there is a repeated element, 0 otherwise (used to specialize swizzles
+                       containing duplicate elements so that they cannot be used as r-values).            
+       */
+       template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3, int DUPLICATE_ELEMENTS>
+       struct _swizzle_base2 : public _swizzle_base1<N, T, P, vecType, E0,E1,E2,E3, detail::is_aligned<P>::value>
+       {
+               GLM_FUNC_QUALIFIER _swizzle_base2& operator= (const T& t)
+               {
+                       for (int i = 0; i < N; ++i)
+                               (*this)[i] = t;
+                       return *this;
+               }
+
+               GLM_FUNC_QUALIFIER _swizzle_base2& operator= (vecType<T, P> const& that)
+               {
+                       struct op { 
+                               GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e = t; } 
+                       };
+                       _apply_op(that, op());
+                       return *this;
+               }
+
+               GLM_FUNC_QUALIFIER void operator -= (vecType<T, P> const& that)
+               {
+                       struct op { 
+                               GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e -= t; } 
+                       };
+                       _apply_op(that, op());
+               }
+
+               GLM_FUNC_QUALIFIER void operator += (vecType<T, P> const& that)
+               {
+                       struct op { 
+                               GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e += t; } 
+                       };
+                       _apply_op(that, op());
+               }
+
+               GLM_FUNC_QUALIFIER void operator *= (vecType<T, P> const& that)
+               {
+                       struct op { 
+                               GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e *= t; } 
+                       };
+                       _apply_op(that, op());
+               }
+
+               GLM_FUNC_QUALIFIER void operator /= (vecType<T, P> const& that)
+               {
+                       struct op { 
+                               GLM_FUNC_QUALIFIER void operator() (T& e, T& t) { e /= t; } 
+                       };
+                       _apply_op(that, op());
+               }
+
+               GLM_FUNC_QUALIFIER T& operator[](size_t i)
+               {
+                       const int offset_dst[4] = { E0, E1, E2, E3 };
+                       return this->elem(offset_dst[i]);
+               }
+               GLM_FUNC_QUALIFIER T operator[](size_t i) const
+               {
+                       const int offset_dst[4] = { E0, E1, E2, E3 };
+                       return this->elem(offset_dst[i]);
+               }
+
+       protected:
+               template <typename U>
+               GLM_FUNC_QUALIFIER void _apply_op(vecType<T, P> const& that, U op)
+               {
+                       // Make a copy of the data in this == &that.
+                       // The copier should optimize out the copy in cases where the function is
+                       // properly inlined and the copy is not necessary.
+                       T t[N];
+                       for (int i = 0; i < N; ++i)
+                               t[i] = that[i];
+                       for (int i = 0; i < N; ++i)
+                               op( (*this)[i], t[i] );
+               }
+       };
+
+       // Specialization for swizzles containing duplicate elements.  These cannot be modified.
+       template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3>
+       struct _swizzle_base2<N, T, P, vecType, E0,E1,E2,E3, 1> : public _swizzle_base1<N, T, P, vecType, E0,E1,E2,E3, detail::is_aligned<P>::value>
+       {
+               struct Stub {};
+
+               GLM_FUNC_QUALIFIER _swizzle_base2& operator= (Stub const &) { return *this; }
+
+               GLM_FUNC_QUALIFIER T operator[]  (size_t i) const
+               {
+                       const int offset_dst[4] = { E0, E1, E2, E3 };
+                       return this->elem(offset_dst[i]);
+               }
+       };
+
+       template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3>
+       struct _swizzle : public _swizzle_base2<N, T, P, vecType, E0, E1, E2, E3, (E0 == E1 || E0 == E2 || E0 == E3 || E1 == E2 || E1 == E3 || E2 == E3)>
+       {
+               typedef _swizzle_base2<N, T, P, vecType, E0, E1, E2, E3, (E0 == E1 || E0 == E2 || E0 == E3 || E1 == E2 || E1 == E3 || E2 == E3)> base_type;
+
+               using base_type::operator=;
+
+               GLM_FUNC_QUALIFIER operator vecType<T, P> () const { return (*this)(); }
+       };
+
+//
+// To prevent the C++ syntax from getting entirely overwhelming, define some alias macros
+//
+#define _GLM_SWIZZLE_TEMPLATE1   template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3>
+#define _GLM_SWIZZLE_TEMPLATE2   template <int N, typename T, precision P, template <typename, precision> class vecType, int E0, int E1, int E2, int E3, int F0, int F1, int F2, int F3>
+#define _GLM_SWIZZLE_TYPE1       _swizzle<N, T, P, vecType, E0, E1, E2, E3>
+#define _GLM_SWIZZLE_TYPE2       _swizzle<N, T, P, vecType, F0, F1, F2, F3>
+
+//
+// Wrapper for a binary operator (e.g. u.yy + v.zy)
+//
+#define _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND)                 \
+       _GLM_SWIZZLE_TEMPLATE2                                                          \
+       GLM_FUNC_QUALIFIER vecType<T, P> operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b)  \
+       {                                                                               \
+               return a() OPERAND b();                                                     \
+       }                                                                               \
+       _GLM_SWIZZLE_TEMPLATE1                                                          \
+       GLM_FUNC_QUALIFIER vecType<T, P> operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const vecType<T, P>& b)                   \
+       {                                                                               \
+               return a() OPERAND b;                                                       \
+       }                                                                               \
+       _GLM_SWIZZLE_TEMPLATE1                                                          \
+       GLM_FUNC_QUALIFIER vecType<T, P> operator OPERAND ( const vecType<T, P>& a, const _GLM_SWIZZLE_TYPE1& b)                   \
+       {                                                                               \
+               return a OPERAND b();                                                       \
+       }
+
+//
+// Wrapper for a operand between a swizzle and a binary (e.g. 1.0f - u.xyz)
+//
+#define _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(OPERAND)                 \
+       _GLM_SWIZZLE_TEMPLATE1                                                          \
+       GLM_FUNC_QUALIFIER vecType<T, P> operator OPERAND ( const _GLM_SWIZZLE_TYPE1& a, const T& b)                   \
+       {                                                                               \
+               return a() OPERAND b;                                                       \
+       }                                                                               \
+       _GLM_SWIZZLE_TEMPLATE1                                                          \
+       GLM_FUNC_QUALIFIER vecType<T, P> operator OPERAND ( const T& a, const _GLM_SWIZZLE_TYPE1& b)                   \
+       {                                                                               \
+               return a OPERAND b();                                                       \
+       }
+
+//
+// Macro for wrapping a function taking one argument (e.g. abs())
+//
+#define _GLM_SWIZZLE_FUNCTION_1_ARGS(RETURN_TYPE,FUNCTION)                          \
+       _GLM_SWIZZLE_TEMPLATE1                                                          \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a)  \
+       {                                                                               \
+               return FUNCTION(a());                                                       \
+       }
+
+//
+// Macro for wrapping a function taking two vector arguments (e.g. dot()).
+//
+#define _GLM_SWIZZLE_FUNCTION_2_ARGS(RETURN_TYPE,FUNCTION)                                                      \
+       _GLM_SWIZZLE_TEMPLATE2                                                                                      \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b) \
+       {                                                                                                           \
+               return FUNCTION(a(), b());                                                                              \
+       }                                                                                                           \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                      \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE1& b) \
+       {                                                                                                           \
+               return FUNCTION(a(), b());                                                                              \
+       }                                                                                                           \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                      \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const typename V& b)         \
+       {                                                                                                           \
+               return FUNCTION(a(), b);                                                                                \
+       }                                                                                                           \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                      \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const V& a, const _GLM_SWIZZLE_TYPE1& b)                  \
+       {                                                                                                           \
+               return FUNCTION(a, b());                                                                                \
+       } 
+
+//
+// Macro for wrapping a function take 2 vec arguments followed by a scalar (e.g. mix()).
+//
+#define _GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(RETURN_TYPE,FUNCTION)                                                             \
+       _GLM_SWIZZLE_TEMPLATE2                                                                                                    \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE2& b, const T& c)   \
+       {                                                                                                                         \
+               return FUNCTION(a(), b(), c);                                                                                         \
+       }                                                                                                                         \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                                    \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const _GLM_SWIZZLE_TYPE1& b, const T& c)   \
+       {                                                                                                                         \
+               return FUNCTION(a(), b(), c);                                                                                         \
+       }                                                                                                                         \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                                    \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const _GLM_SWIZZLE_TYPE1& a, const typename S0::vec_type& b, const T& c)\
+       {                                                                                                                         \
+               return FUNCTION(a(), b, c);                                                                                           \
+       }                                                                                                                         \
+       _GLM_SWIZZLE_TEMPLATE1                                                                                                    \
+       GLM_FUNC_QUALIFIER typename _GLM_SWIZZLE_TYPE1::RETURN_TYPE FUNCTION(const typename V& a, const _GLM_SWIZZLE_TYPE1& b, const T& c)           \
+       {                                                                                                                         \
+               return FUNCTION(a, b(), c);                                                                                           \
+       } 
+}//namespace detail 
+}//namespace glm
+
+namespace glm
+{
+       namespace detail
+       {
+               _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(-)
+               _GLM_SWIZZLE_SCALAR_BINARY_OPERATOR_IMPLEMENTATION(*)
+               _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(+)
+               _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(-)
+               _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(*)
+               _GLM_SWIZZLE_VECTOR_BINARY_OPERATOR_IMPLEMENTATION(/)
+       }
+
+       //
+       // Swizzles are distinct types from the unswizzled type.  The below macros will
+       // provide template specializations for the swizzle types for the given functions
+       // so that the compiler does not have any ambiguity to choosing how to handle
+       // the function.
+       //
+       // The alternative is to use the operator()() when calling the function in order
+       // to explicitly convert the swizzled type to the unswizzled type.
+       //
+
+       //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    abs);
+       //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    acos);
+       //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    acosh);
+       //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    all);
+       //_GLM_SWIZZLE_FUNCTION_1_ARGS(vec_type,    any);
+
+       //_GLM_SWIZZLE_FUNCTION_2_ARGS(value_type,  dot);
+       //_GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type,    cross);
+       //_GLM_SWIZZLE_FUNCTION_2_ARGS(vec_type,    step);    
+       //_GLM_SWIZZLE_FUNCTION_2_ARGS_SCALAR(vec_type, mix);
+}
+
+#define _GLM_SWIZZLE2_2_MEMBERS(T, P, V, E0,E1) \
+       struct { detail::_swizzle<2, T, P, V, 0,0,-1,-2> E0 ## E0; }; \
+       struct { detail::_swizzle<2, T, P, V, 0,1,-1,-2> E0 ## E1; }; \
+       struct { detail::_swizzle<2, T, P, V, 1,0,-1,-2> E1 ## E0; }; \
+       struct { detail::_swizzle<2, T, P, V, 1,1,-1,-2> E1 ## E1; }; 
+
+#define _GLM_SWIZZLE2_3_MEMBERS(T, P, V, E0,E1) \
+       struct { detail::_swizzle<3,T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3,T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3,T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3,T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3,T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3,T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3,T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3,T, P, V, 1,1,1,-1> E1 ## E1 ## E1; };  
+
+#define _GLM_SWIZZLE2_4_MEMBERS(T, P, V, E0,E1) \
+       struct { detail::_swizzle<4,T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; };
+
+#define _GLM_SWIZZLE3_2_MEMBERS(T, P, V, E0,E1,E2) \
+       struct { detail::_swizzle<2,T, P, V, 0,0,-1,-2> E0 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 0,1,-1,-2> E0 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 0,2,-1,-2> E0 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,0,-1,-2> E1 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,1,-1,-2> E1 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,2,-1,-2> E1 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,0,-1,-2> E2 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,1,-1,-2> E2 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,2,-1,-2> E2 ## E2; };
+
+#define _GLM_SWIZZLE3_3_MEMBERS(T, P, V ,E0,E1,E2) \
+       struct { detail::_swizzle<3, T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,0,2,-1> E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,2,-1> E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,0,-1> E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,1,-1> E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,2,-1> E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,2,-1> E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,1,-1> E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,2,-1> E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,0,-1> E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,1,-1> E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,2,-1> E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,0,-1> E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,1,-1> E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,2,-1> E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,0,-1> E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,1,-1> E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,2,-1> E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,0,-1> E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,1,-1> E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,2,-1> E2 ## E2 ## E2; };
+
+#define _GLM_SWIZZLE3_4_MEMBERS(T, P, V, E0,E1,E2) \
+       struct { detail::_swizzle<4,T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4,T, P, V, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; 
+
+#define _GLM_SWIZZLE4_2_MEMBERS(T, P, V, E0,E1,E2,E3) \
+       struct { detail::_swizzle<2,T, P, V, 0,0,-1,-2> E0 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 0,1,-1,-2> E0 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 0,2,-1,-2> E0 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 0,3,-1,-2> E0 ## E3; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,0,-1,-2> E1 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,1,-1,-2> E1 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,2,-1,-2> E1 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 1,3,-1,-2> E1 ## E3; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,0,-1,-2> E2 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,1,-1,-2> E2 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,2,-1,-2> E2 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 2,3,-1,-2> E2 ## E3; }; \
+       struct { detail::_swizzle<2,T, P, V, 3,0,-1,-2> E3 ## E0; }; \
+       struct { detail::_swizzle<2,T, P, V, 3,1,-1,-2> E3 ## E1; }; \
+       struct { detail::_swizzle<2,T, P, V, 3,2,-1,-2> E3 ## E2; }; \
+       struct { detail::_swizzle<2,T, P, V, 3,3,-1,-2> E3 ## E3; }; 
+
+#define _GLM_SWIZZLE4_3_MEMBERS(T, P, V, E0,E1,E2,E3) \
+       struct { detail::_swizzle<3, T, P, V, 0,0,0,-1> E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,0,1,-1> E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,0,2,-1> E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,0,3,-1> E0 ## E0 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,0,-1> E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,1,-1> E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,2,-1> E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,1,3,-1> E0 ## E1 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,0,-1> E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,1,-1> E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,2,-1> E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,2,3,-1> E0 ## E2 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,3,0,-1> E0 ## E3 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,3,1,-1> E0 ## E3 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,3,2,-1> E0 ## E3 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 0,3,3,-1> E0 ## E3 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,0,-1> E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,1,-1> E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,2,-1> E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,0,3,-1> E1 ## E0 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,0,-1> E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,1,-1> E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,2,-1> E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,1,3,-1> E1 ## E1 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,0,-1> E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,1,-1> E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,2,-1> E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,2,3,-1> E1 ## E2 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,3,0,-1> E1 ## E3 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,3,1,-1> E1 ## E3 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,3,2,-1> E1 ## E3 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 1,3,3,-1> E1 ## E3 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,0,-1> E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,1,-1> E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,2,-1> E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,0,3,-1> E2 ## E0 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,0,-1> E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,1,-1> E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,2,-1> E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,1,3,-1> E2 ## E1 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,0,-1> E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,1,-1> E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,2,-1> E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,2,3,-1> E2 ## E2 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,3,0,-1> E2 ## E3 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,3,1,-1> E2 ## E3 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,3,2,-1> E2 ## E3 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 2,3,3,-1> E2 ## E3 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,0,0,-1> E3 ## E0 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,0,1,-1> E3 ## E0 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,0,2,-1> E3 ## E0 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,0,3,-1> E3 ## E0 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,1,0,-1> E3 ## E1 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,1,1,-1> E3 ## E1 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,1,2,-1> E3 ## E1 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,1,3,-1> E3 ## E1 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,2,0,-1> E3 ## E2 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,2,1,-1> E3 ## E2 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,2,2,-1> E3 ## E2 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,2,3,-1> E3 ## E2 ## E3; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,3,0,-1> E3 ## E3 ## E0; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,3,1,-1> E3 ## E3 ## E1; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,3,2,-1> E3 ## E3 ## E2; }; \
+       struct { detail::_swizzle<3, T, P, V, 3,3,3,-1> E3 ## E3 ## E3; };  
+
+#define _GLM_SWIZZLE4_4_MEMBERS(T, P, V, E0,E1,E2,E3) \
+       struct { detail::_swizzle<4, T, P, V, 0,0,0,0> E0 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,0,1> E0 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,0,2> E0 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,0,3> E0 ## E0 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,1,0> E0 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,1,1> E0 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,1,2> E0 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,1,3> E0 ## E0 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,2,0> E0 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,2,1> E0 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,2,2> E0 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,2,3> E0 ## E0 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,3,0> E0 ## E0 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,3,1> E0 ## E0 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,3,2> E0 ## E0 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,0,3,3> E0 ## E0 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,0,0> E0 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,0,1> E0 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,0,2> E0 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,0,3> E0 ## E1 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,1,0> E0 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,1,1> E0 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,1,2> E0 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,1,3> E0 ## E1 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,2,0> E0 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,2,1> E0 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,2,2> E0 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,2,3> E0 ## E1 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,3,0> E0 ## E1 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,3,1> E0 ## E1 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,3,2> E0 ## E1 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,1,3,3> E0 ## E1 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,0,0> E0 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,0,1> E0 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,0,2> E0 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,0,3> E0 ## E2 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,1,0> E0 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,1,1> E0 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,1,2> E0 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,1,3> E0 ## E2 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,2,0> E0 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,2,1> E0 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,2,2> E0 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,2,3> E0 ## E2 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,3,0> E0 ## E2 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,3,1> E0 ## E2 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,3,2> E0 ## E2 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,2,3,3> E0 ## E2 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,0,0> E0 ## E3 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,0,1> E0 ## E3 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,0,2> E0 ## E3 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,0,3> E0 ## E3 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,1,0> E0 ## E3 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,1,1> E0 ## E3 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,1,2> E0 ## E3 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,1,3> E0 ## E3 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,2,0> E0 ## E3 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,2,1> E0 ## E3 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,2,2> E0 ## E3 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,2,3> E0 ## E3 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,3,0> E0 ## E3 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,3,1> E0 ## E3 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,3,2> E0 ## E3 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 0,3,3,3> E0 ## E3 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,0,0> E1 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,0,1> E1 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,0,2> E1 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,0,3> E1 ## E0 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,1,0> E1 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,1,1> E1 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,1,2> E1 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,1,3> E1 ## E0 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,2,0> E1 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,2,1> E1 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,2,2> E1 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,2,3> E1 ## E0 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,3,0> E1 ## E0 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,3,1> E1 ## E0 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,3,2> E1 ## E0 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,0,3,3> E1 ## E0 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,0,0> E1 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,0,1> E1 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,0,2> E1 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,0,3> E1 ## E1 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,1,0> E1 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,1,1> E1 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,1,2> E1 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,1,3> E1 ## E1 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,2,0> E1 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,2,1> E1 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,2,2> E1 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,2,3> E1 ## E1 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,3,0> E1 ## E1 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,3,1> E1 ## E1 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,3,2> E1 ## E1 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,1,3,3> E1 ## E1 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,0,0> E1 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,0,1> E1 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,0,2> E1 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,0,3> E1 ## E2 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,1,0> E1 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,1,1> E1 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,1,2> E1 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,1,3> E1 ## E2 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,2,0> E1 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,2,1> E1 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,2,2> E1 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,2,3> E1 ## E2 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,3,0> E1 ## E2 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,3,1> E1 ## E2 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,3,2> E1 ## E2 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,2,3,3> E1 ## E2 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,0,0> E1 ## E3 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,0,1> E1 ## E3 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,0,2> E1 ## E3 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,0,3> E1 ## E3 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,1,0> E1 ## E3 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,1,1> E1 ## E3 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,1,2> E1 ## E3 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,1,3> E1 ## E3 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,2,0> E1 ## E3 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,2,1> E1 ## E3 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,2,2> E1 ## E3 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,2,3> E1 ## E3 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,3,0> E1 ## E3 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,3,1> E1 ## E3 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,3,2> E1 ## E3 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 1,3,3,3> E1 ## E3 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,0,0> E2 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,0,1> E2 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,0,2> E2 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,0,3> E2 ## E0 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,1,0> E2 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,1,1> E2 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,1,2> E2 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,1,3> E2 ## E0 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,2,0> E2 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,2,1> E2 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,2,2> E2 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,2,3> E2 ## E0 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,3,0> E2 ## E0 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,3,1> E2 ## E0 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,3,2> E2 ## E0 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,0,3,3> E2 ## E0 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,0,0> E2 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,0,1> E2 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,0,2> E2 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,0,3> E2 ## E1 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,1,0> E2 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,1,1> E2 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,1,2> E2 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,1,3> E2 ## E1 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,2,0> E2 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,2,1> E2 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,2,2> E2 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,2,3> E2 ## E1 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,3,0> E2 ## E1 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,3,1> E2 ## E1 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,3,2> E2 ## E1 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,1,3,3> E2 ## E1 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,0,0> E2 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,0,1> E2 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,0,2> E2 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,0,3> E2 ## E2 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,1,0> E2 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,1,1> E2 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,1,2> E2 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,1,3> E2 ## E2 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,2,0> E2 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,2,1> E2 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,2,2> E2 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,2,3> E2 ## E2 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,3,0> E2 ## E2 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,3,1> E2 ## E2 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,3,2> E2 ## E2 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,2,3,3> E2 ## E2 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,0,0> E2 ## E3 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,0,1> E2 ## E3 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,0,2> E2 ## E3 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,0,3> E2 ## E3 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,1,0> E2 ## E3 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,1,1> E2 ## E3 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,1,2> E2 ## E3 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,1,3> E2 ## E3 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,2,0> E2 ## E3 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,2,1> E2 ## E3 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,2,2> E2 ## E3 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,2,3> E2 ## E3 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,3,0> E2 ## E3 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,3,1> E2 ## E3 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,3,2> E2 ## E3 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 2,3,3,3> E2 ## E3 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,0,0> E3 ## E0 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,0,1> E3 ## E0 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,0,2> E3 ## E0 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,0,3> E3 ## E0 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,1,0> E3 ## E0 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,1,1> E3 ## E0 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,1,2> E3 ## E0 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,1,3> E3 ## E0 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,2,0> E3 ## E0 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,2,1> E3 ## E0 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,2,2> E3 ## E0 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,2,3> E3 ## E0 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,3,0> E3 ## E0 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,3,1> E3 ## E0 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,3,2> E3 ## E0 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,0,3,3> E3 ## E0 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,0,0> E3 ## E1 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,0,1> E3 ## E1 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,0,2> E3 ## E1 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,0,3> E3 ## E1 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,1,0> E3 ## E1 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,1,1> E3 ## E1 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,1,2> E3 ## E1 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,1,3> E3 ## E1 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,2,0> E3 ## E1 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,2,1> E3 ## E1 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,2,2> E3 ## E1 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,2,3> E3 ## E1 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,3,0> E3 ## E1 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,3,1> E3 ## E1 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,3,2> E3 ## E1 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,1,3,3> E3 ## E1 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,0,0> E3 ## E2 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,0,1> E3 ## E2 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,0,2> E3 ## E2 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,0,3> E3 ## E2 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,1,0> E3 ## E2 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,1,1> E3 ## E2 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,1,2> E3 ## E2 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,1,3> E3 ## E2 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,2,0> E3 ## E2 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,2,1> E3 ## E2 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,2,2> E3 ## E2 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,2,3> E3 ## E2 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,3,0> E3 ## E2 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,3,1> E3 ## E2 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,3,2> E3 ## E2 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,2,3,3> E3 ## E2 ## E3 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,0,0> E3 ## E3 ## E0 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,0,1> E3 ## E3 ## E0 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,0,2> E3 ## E3 ## E0 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,0,3> E3 ## E3 ## E0 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,1,0> E3 ## E3 ## E1 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,1,1> E3 ## E3 ## E1 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,1,2> E3 ## E3 ## E1 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,1,3> E3 ## E3 ## E1 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,2,0> E3 ## E3 ## E2 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,2,1> E3 ## E3 ## E2 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,2,2> E3 ## E3 ## E2 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,2,3> E3 ## E3 ## E2 ## E3; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,3,0> E3 ## E3 ## E3 ## E0; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,3,1> E3 ## E3 ## E3 ## E1; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,3,2> E3 ## E3 ## E3 ## E2; }; \
+       struct { detail::_swizzle<4, T, P, V, 3,3,3,3> E3 ## E3 ## E3 ## E3; };
diff --git a/core/deps/glm/glm/detail/_swizzle_func.hpp b/core/deps/glm/glm/detail/_swizzle_func.hpp
new file mode 100755 (executable)
index 0000000..4b37edb
--- /dev/null
@@ -0,0 +1,696 @@
+/// @ref core
+/// @file glm/detail/_swizzle_func.hpp
+
+#pragma once
+
+#define GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B)       \
+       SWIZZLED_TYPE<TMPL_TYPE, PRECISION> A ## B() CONST                                                                                              \
+       {                                                                                                                                                                                               \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B);                                                           \
+       }
+
+#define GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C)            \
+       SWIZZLED_TYPE<TMPL_TYPE, PRECISION> A ## B ## C() CONST                                                                                         \
+       {                                                                                                                                                                                                       \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B, this->C);                                                  \
+       }
+
+#define GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C, D) \
+       SWIZZLED_TYPE<TMPL_TYPE, PRECISION> A ## B ## C ## D() CONST                                                                            \
+       {                                                                                                                                                                                                       \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B, this->C, this->D);                                 \
+       }
+
+#define GLM_SWIZZLE_GEN_VEC2_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B)   \
+       template <typename TMPL_TYPE>                                                                                                                                           \
+       SWIZZLED_TYPE<TMPL_TYPE> CLASS_TYPE<TMPL_TYPE, PRECISION>::A ## B() CONST                                                       \
+       {                                                                                                                                                                                                       \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B);                                                                   \
+       }
+
+#define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C)                \
+       template <typename TMPL_TYPE>                                                                                                                                                   \
+       SWIZZLED_TYPE<TMPL_TYPE> CLASS_TYPE<TMPL_TYPE, PRECISION>::A ## B ## C() CONST                                                  \
+       {                                                                                                                                                                                                               \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B, this->C);                                                          \
+       }
+
+#define GLM_SWIZZLE_GEN_VEC4_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, CONST, A, B, C, D)     \
+       template <typename TMPL_TYPE>                                                                                                                                                   \
+       SWIZZLED_TYPE<TMPL_TYPE> CLASS_TYPE<TMPL_TYPE, PRECISION>::A ## B ## C ## D() CONST                                             \
+       {                                                                                                                                                                                                               \
+               return SWIZZLED_TYPE<TMPL_TYPE, PRECISION>(this->A, this->B, this->C, this->D);                                         \
+       }
+
+#define GLM_MUTABLE
+
+#define GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A)
+
+#define GLM_SWIZZLE_GEN_REF_FROM_VEC2(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE) \
+       GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, x, y) \
+       GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, r, g) \
+       GLM_SWIZZLE_GEN_REF2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, s, t)
+
+//GLM_SWIZZLE_GEN_REF_FROM_VEC2(valType, detail::vec2, detail::ref2)
+
+#define GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B)
+
+#define GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B, A)
+
+#define GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_REF3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_REF2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C)
+
+#define GLM_SWIZZLE_GEN_REF_FROM_VEC3(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, x, y, z) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, r, g, b) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, s, t, p)
+
+//GLM_SWIZZLE_GEN_REF_FROM_VEC3(valType, detail::vec3, detail::ref2, detail::ref3)
+
+#define GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, A, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, B, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, C, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, GLM_MUTABLE, D, C)
+
+#define GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, B)
+
+#define GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , B, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , C, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, , D, B, C, A)
+
+#define GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_REF2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_REF3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_REF4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D)
+
+#define GLM_SWIZZLE_GEN_REF_FROM_VEC4(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z, w) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b, a) \
+       GLM_SWIZZLE_GEN_REF_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p, q)
+
+//GLM_SWIZZLE_GEN_REF_FROM_VEC4(valType, detail::vec4, detail::ref2, detail::ref3, detail::ref4)
+
+#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B)
+
+#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B)
+
+#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_FROM_VEC2_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC2(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE)                    \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y)  \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g)  \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC2_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t)
+
+//GLM_SWIZZLE_GEN_VEC_FROM_VEC2(valType, detail::vec2, detail::vec2, detail::vec3, detail::vec4)
+
+#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C)
+
+#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C)
+
+#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, C)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_FROM_VEC3_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC3(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC3_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p)
+
+//GLM_SWIZZLE_GEN_VEC_FROM_VEC3(valType, detail::vec3, detail::vec2, detail::vec3, detail::vec4)
+
+#define GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C) \
+       GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D)
+
+#define GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C) \
+       GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D)
+
+#define GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, A, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, B, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, C, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, A, D, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, A, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, B, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, C, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, B, D, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, A, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, B, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, C, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, C, D, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, A, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, B, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, C, D, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, A, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, B, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, A) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, B) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, C) \
+       GLM_SWIZZLE_GEN_VEC4_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_TYPE, const, D, D, D, D)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC2_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC3_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC3_TYPE, A, B, C, D) \
+       GLM_SWIZZLE_GEN_VEC4_FROM_VEC4_SWIZZLE(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC4_TYPE, A, B, C, D)
+
+#define GLM_SWIZZLE_GEN_VEC_FROM_VEC4(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, x, y, z, w) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, r, g, b, a) \
+       GLM_SWIZZLE_GEN_VEC_FROM_VEC4_COMP(TMPL_TYPE, PRECISION, CLASS_TYPE, SWIZZLED_VEC2_TYPE, SWIZZLED_VEC3_TYPE, SWIZZLED_VEC4_TYPE, s, t, p, q)
+
+//GLM_SWIZZLE_GEN_VEC_FROM_VEC4(valType, detail::vec4, detail::vec2, detail::vec3, detail::vec4)
diff --git a/core/deps/glm/glm/detail/_vectorize.hpp b/core/deps/glm/glm/detail/_vectorize.hpp
new file mode 100755 (executable)
index 0000000..a08ed34
--- /dev/null
@@ -0,0 +1,131 @@
+/// @ref core
+/// @file glm/detail/_vectorize.hpp
+
+#pragma once
+
+#include "type_vec1.hpp"
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename R, typename T, precision P, template <typename, precision> class vecType>
+       struct functor1{};
+
+       template <typename R, typename T, precision P>
+       struct functor1<R, T, P, tvec1>
+       {
+               GLM_FUNC_QUALIFIER static tvec1<R, P> call(R (*Func) (T x), tvec1<T, P> const & v)
+               {
+                       return tvec1<R, P>(Func(v.x));
+               }
+       };
+
+       template <typename R, typename T, precision P>
+       struct functor1<R, T, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<R, P> call(R (*Func) (T x), tvec2<T, P> const & v)
+               {
+                       return tvec2<R, P>(Func(v.x), Func(v.y));
+               }
+       };
+
+       template <typename R, typename T, precision P>
+       struct functor1<R, T, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<R, P> call(R (*Func) (T x), tvec3<T, P> const & v)
+               {
+                       return tvec3<R, P>(Func(v.x), Func(v.y), Func(v.z));
+               }
+       };
+
+       template <typename R, typename T, precision P>
+       struct functor1<R, T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<R, P> call(R (*Func) (T x), tvec4<T, P> const & v)
+               {
+                       return tvec4<R, P>(Func(v.x), Func(v.y), Func(v.z), Func(v.w));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct functor2{};
+
+       template <typename T, precision P>
+       struct functor2<T, P, tvec1>
+       {
+               GLM_FUNC_QUALIFIER static tvec1<T, P> call(T (*Func) (T x, T y), tvec1<T, P> const & a, tvec1<T, P> const & b)
+               {
+                       return tvec1<T, P>(Func(a.x, b.x));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2<T, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<T, P> call(T (*Func) (T x, T y), tvec2<T, P> const & a, tvec2<T, P> const & b)
+               {
+                       return tvec2<T, P>(Func(a.x, b.x), Func(a.y, b.y));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2<T, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<T, P> call(T (*Func) (T x, T y), tvec3<T, P> const & a, tvec3<T, P> const & b)
+               {
+                       return tvec3<T, P>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(T (*Func) (T x, T y), tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(Func(a.x, b.x), Func(a.y, b.y), Func(a.z, b.z), Func(a.w, b.w));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct functor2_vec_sca{};
+
+       template <typename T, precision P>
+       struct functor2_vec_sca<T, P, tvec1>
+       {
+               GLM_FUNC_QUALIFIER static tvec1<T, P> call(T (*Func) (T x, T y), tvec1<T, P> const & a, T b)
+               {
+                       return tvec1<T, P>(Func(a.x, b));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2_vec_sca<T, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<T, P> call(T (*Func) (T x, T y), tvec2<T, P> const & a, T b)
+               {
+                       return tvec2<T, P>(Func(a.x, b), Func(a.y, b));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2_vec_sca<T, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<T, P> call(T (*Func) (T x, T y), tvec3<T, P> const & a, T b)
+               {
+                       return tvec3<T, P>(Func(a.x, b), Func(a.y, b), Func(a.z, b));
+               }
+       };
+
+       template <typename T, precision P>
+       struct functor2_vec_sca<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(T (*Func) (T x, T y), tvec4<T, P> const & a, T b)
+               {
+                       return tvec4<T, P>(Func(a.x, b), Func(a.y, b), Func(a.z, b), Func(a.w, b));
+               }
+       };
+}//namespace detail
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/dummy.cpp b/core/deps/glm/glm/detail/dummy.cpp
new file mode 100755 (executable)
index 0000000..a519a6d
--- /dev/null
@@ -0,0 +1,207 @@
+/// @ref core
+/// @file glm/core/dummy.cpp
+///
+/// GLM is a header only library. There is nothing to compile. 
+/// dummy.cpp exist only a wordaround for CMake file.
+
+/*
+#define GLM_MESSAGES
+#include <glm/glm.hpp>
+#include <glm/ext.hpp>
+#include <limits>
+
+struct material
+{
+       glm::vec4 emission; // Ecm
+       glm::vec4 ambient; // Acm
+       glm::vec4 diffuse; // Dcm
+       glm::vec4 specular; // Scm
+       float shininess; // Srm
+};
+
+struct light
+{
+       glm::vec4 ambient; // Acli
+       glm::vec4 diffuse; // Dcli
+       glm::vec4 specular; // Scli
+       glm::vec4 position; // Ppli
+       glm::vec4 halfVector; // Derived: Hi
+       glm::vec3 spotDirection; // Sdli
+       float spotExponent; // Srli
+       float spotCutoff; // Crli
+       // (range: [0.0,90.0], 180.0)
+       float spotCosCutoff; // Derived: cos(Crli)
+       // (range: [1.0,0.0],-1.0)
+       float constantAttenuation; // K0
+       float linearAttenuation; // K1
+       float quadraticAttenuation;// K2
+};
+
+
+// Sample 1
+#include <glm/vec3.hpp>// glm::vec3
+#include <glm/geometric.hpp>// glm::cross, glm::normalize
+
+glm::vec3 computeNormal
+(
+       glm::vec3 const & a,
+       glm::vec3 const & b,
+       glm::vec3 const & c
+)
+{
+       return glm::normalize(glm::cross(c - a, b - a));
+}
+
+typedef unsigned int GLuint;
+#define GL_FALSE 0
+void glUniformMatrix4fv(GLuint, int, int, float*){}
+
+// Sample 2
+#include <glm/vec3.hpp> // glm::vec3
+#include <glm/vec4.hpp> // glm::vec4, glm::ivec4
+#include <glm/mat4x4.hpp> // glm::mat4
+#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
+#include <glm/gtc/type_ptr.hpp> // glm::value_ptr
+void func(GLuint LocationMVP, float Translate, glm::vec2 const & Rotate)
+{
+       glm::mat4 Projection = glm::perspective(45.0f, 4.0f / 3.0f, 0.1f, 100.f);
+       glm::mat4 ViewTranslate = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
+       glm::mat4 ViewRotateX = glm::rotate(ViewTranslate, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
+       glm::mat4 View = glm::rotate(ViewRotateX, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
+       glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
+       glm::mat4 MVP = Projection * View * Model;
+       glUniformMatrix4fv(LocationMVP, 1, GL_FALSE, glm::value_ptr(MVP));
+}
+
+// Sample 3
+#include <glm/vec2.hpp>// glm::vec2
+#include <glm/packing.hpp>// glm::packUnorm2x16
+#include <glm/integer.hpp>// glm::uint
+#include <glm/gtc/type_precision.hpp>// glm::i8vec2, glm::i32vec2
+std::size_t const VertexCount = 4;
+// Float quad geometry
+std::size_t const PositionSizeF32 = VertexCount * sizeof(glm::vec2);
+glm::vec2 const PositionDataF32[VertexCount] =
+{
+       glm::vec2(-1.0f,-1.0f),
+       glm::vec2( 1.0f,-1.0f),
+       glm::vec2( 1.0f, 1.0f),
+       glm::vec2(-1.0f, 1.0f)
+       };
+// Half-float quad geometry
+std::size_t const PositionSizeF16 = VertexCount * sizeof(glm::uint);
+glm::uint const PositionDataF16[VertexCount] =
+{
+       glm::uint(glm::packUnorm2x16(glm::vec2(-1.0f, -1.0f))),
+       glm::uint(glm::packUnorm2x16(glm::vec2( 1.0f, -1.0f))),
+       glm::uint(glm::packUnorm2x16(glm::vec2( 1.0f, 1.0f))),
+       glm::uint(glm::packUnorm2x16(glm::vec2(-1.0f, 1.0f)))
+};
+// 8 bits signed integer quad geometry
+std::size_t const PositionSizeI8 = VertexCount * sizeof(glm::i8vec2);
+glm::i8vec2 const PositionDataI8[VertexCount] =
+{
+       glm::i8vec2(-1,-1),
+       glm::i8vec2( 1,-1),
+       glm::i8vec2( 1, 1),
+       glm::i8vec2(-1, 1)
+};
+// 32 bits signed integer quad geometry
+std::size_t const PositionSizeI32 = VertexCount * sizeof(glm::i32vec2);
+glm::i32vec2 const PositionDataI32[VertexCount] =
+{
+       glm::i32vec2 (-1,-1),
+       glm::i32vec2 ( 1,-1),
+       glm::i32vec2 ( 1, 1),
+       glm::i32vec2 (-1, 1)
+};
+
+struct intersection
+{
+       glm::vec4 position;
+       glm::vec3 normal;
+};
+*/
+
+
+/*
+// Sample 4
+#include <glm/vec3.hpp>// glm::vec3
+#include <glm/geometric.hpp>// glm::normalize, glm::dot, glm::reflect
+#include <glm/exponential.hpp>// glm::pow
+#include <glm/gtc/random.hpp>// glm::vecRand3
+glm::vec3 lighting
+(
+       intersection const & Intersection,
+       material const & Material,
+       light const & Light,
+       glm::vec3 const & View
+)
+{
+       glm::vec3 Color(0.0f);
+       glm::vec3 LightVertor(glm::normalize(
+               Light.position - Intersection.position +
+               glm::vecRand3(0.0f, Light.inaccuracy));
+
+       if(!shadow(Intersection.position, Light.position, LightVertor))
+       {
+               float Diffuse = glm::dot(Intersection.normal, LightVector);
+               if(Diffuse <= 0.0f)
+                       return Color;
+               if(Material.isDiffuse())
+                       Color += Light.color() * Material.diffuse * Diffuse;
+               if(Material.isSpecular())
+               {
+                       glm::vec3 Reflect(glm::reflect(
+                               glm::normalize(-LightVector),
+                               glm::normalize(Intersection.normal)));
+                       float Dot = glm::dot(Reflect, View);
+                       float Base = Dot > 0.0f ? Dot : 0.0f;
+                       float Specular = glm::pow(Base, Material.exponent);
+                       Color += Material.specular * Specular;
+               }
+       }
+       return Color;
+}
+*/
+
+/*
+template <typename T, glm::precision P, template<typename, glm::precision> class vecType>
+T normalizeDotA(vecType<T, P> const & x, vecType<T, P> const & y)
+{
+       return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y));
+}
+
+#define GLM_TEMPLATE_GENTYPE typename T, glm::precision P, template<typename, glm::precision> class
+
+template <GLM_TEMPLATE_GENTYPE vecType>
+T normalizeDotB(vecType<T, P> const & x, vecType<T, P> const & y)
+{
+       return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y));
+}
+
+template <typename vecType>
+typename vecType::value_type normalizeDotC(vecType const & a, vecType const & b)
+{
+       return glm::dot(a, b) * glm::inversesqrt(glm::dot(a, a) * glm::dot(b, b));
+}
+*/
+int main()
+{
+/*
+       glm::vec1 o(1);
+       glm::vec2 a(1);
+       glm::vec3 b(1);
+       glm::vec4 c(1);
+
+       glm::quat q;
+       glm::dualquat p;
+
+       glm::mat4 m(1);
+
+       float a0 = normalizeDotA(a, a);
+       float b0 = normalizeDotB(b, b);
+       float c0 = normalizeDotC(c, c);
+*/
+       return 0;
+}
diff --git a/core/deps/glm/glm/detail/func_common.hpp b/core/deps/glm/glm/detail/func_common.hpp
new file mode 100755 (executable)
index 0000000..871fed6
--- /dev/null
@@ -0,0 +1,427 @@
+/// @ref core
+/// @file glm/detail/func_common.hpp
+/// 
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+///
+/// @defgroup core_func_common Common functions
+/// @ingroup core
+/// 
+/// These all operate component-wise. The description is per component.
+
+#pragma once
+
+#include "setup.hpp"
+#include "precision.hpp"
+#include "type_int.hpp"
+#include "_fixes.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_common
+       /// @{
+
+       /// Returns x if x >= 0; otherwise, it returns -x.
+       /// 
+       /// @tparam genType floating-point or signed integer; scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/abs.xml">GLSL abs man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType abs(genType x);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> abs(vecType<T, P> const & x);
+
+       /// Returns 1.0 if x > 0, 0.0 if x == 0, or -1.0 if x < 0. 
+       /// 
+       /// @tparam genType Floating-point or signed integer; scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/sign.xml">GLSL sign man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> sign(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer that is less then or equal to x. 
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/floor.xml">GLSL floor man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> floor(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer to x
+       /// whose absolute value is not larger than the absolute value of x.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/trunc.xml">GLSL trunc man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> trunc(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer to x.
+       /// The fraction 0.5 will round in a direction chosen by the
+       /// implementation, presumably the direction that is fastest.
+       /// This includes the possibility that round(x) returns the
+       /// same value as roundEven(x) for all values of x.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml">GLSL round man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> round(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer to x.
+       /// A fractional part of 0.5 will round toward the nearest even
+       /// integer. (Both 3.5 and 4.5 for x will return 4.0.)
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/roundEven.xml">GLSL roundEven man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       /// @see <a href="http://developer.amd.com/documentation/articles/pages/New-Round-to-Even-Technique.aspx">New round to even technique</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> roundEven(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer
+       /// that is greater than or equal to x.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/ceil.xml">GLSL ceil man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> ceil(vecType<T, P> const & x);
+
+       /// Return x - floor(x).
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/fract.xml">GLSL fract man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType fract(genType x);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fract(vecType<T, P> const & x);
+
+       /// Modulus. Returns x - y * floor(x / y)
+       /// for each component in x using the floating point value y.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml">GLSL mod man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType mod(genType x, genType y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mod(vecType<T, P> const & x, T y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mod(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the fractional part of x and sets i to the integer
+       /// part (as a whole number floating point value). Both the
+       /// return value and the output parameter will have the same
+       /// sign as x.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/modf.xml">GLSL modf man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType modf(genType x, genType & i);
+
+       /// Returns y if y < x; otherwise, it returns x.
+       ///
+       /// @tparam genType Floating-point or integer; scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/min.xml">GLSL min man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType min(genType x, genType y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> min(vecType<T, P> const & x, T y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> min(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns y if x < y; otherwise, it returns x.
+       /// 
+       /// @tparam genType Floating-point or integer; scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/max.xml">GLSL max man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType max(genType x, genType y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> max(vecType<T, P> const & x, T y);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> max(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns min(max(x, minVal), maxVal) for each component in x 
+       /// using the floating-point values minVal and maxVal.
+       ///
+       /// @tparam genType Floating-point or integer; scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/clamp.xml">GLSL clamp man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType clamp(genType x, genType minVal, genType maxVal);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> clamp(vecType<T, P> const & x, T minVal, T maxVal);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> clamp(vecType<T, P> const & x, vecType<T, P> const & minVal, vecType<T, P> const & maxVal);
+
+       /// If genTypeU is a floating scalar or vector:
+       /// Returns x * (1.0 - a) + y * a, i.e., the linear blend of
+       /// x and y using the floating-point value a.
+       /// The value for a is not restricted to the range [0, 1].
+       /// 
+       /// If genTypeU is a boolean scalar or vector:
+       /// Selects which vector each returned component comes
+       /// from. For a component of <a> that is false, the
+       /// corresponding component of x is returned. For a
+       /// component of a that is true, the corresponding
+       /// component of y is returned. Components of x and y that
+       /// are not selected are allowed to be invalid floating point
+       /// values and will have no effect on the results. Thus, this
+       /// provides different functionality than
+       /// genType mix(genType x, genType y, genType(a))
+       /// where a is a Boolean vector.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mix.xml">GLSL mix man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       /// 
+       /// @param[in]  x Value to interpolate.
+       /// @param[in]  y Value to interpolate.
+       /// @param[in]  a Interpolant.
+       /// 
+       /// @tparam     genTypeT Floating point scalar or vector.
+       /// @tparam genTypeU Floating point or boolean scalar or vector. It can't be a vector if it is the length of genTypeT.
+       /// 
+       /// @code
+       /// #include <glm/glm.hpp>
+       /// ...
+       /// float a;
+       /// bool b;
+       /// glm::dvec3 e;
+       /// glm::dvec3 f;
+       /// glm::vec4 g;
+       /// glm::vec4 h;
+       /// ...
+       /// glm::vec4 r = glm::mix(g, h, a); // Interpolate with a floating-point scalar two vectors. 
+       /// glm::vec4 s = glm::mix(g, h, b); // Teturns g or h;
+       /// glm::dvec3 t = glm::mix(e, f, a); // Types of the third parameter is not required to match with the first and the second.
+       /// glm::vec4 u = glm::mix(g, h, r); // Interpolations can be perform per component with a vector for the last parameter.
+       /// @endcode
+       template <typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, vecType<U, P> const & a);
+
+       template <typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, U a);
+
+       template <typename genTypeT, typename genTypeU>
+       GLM_FUNC_DECL genTypeT mix(genTypeT x, genTypeT y, genTypeU a);
+
+       /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a genType.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml">GLSL step man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType step(genType edge, genType x);
+
+       /// Returns 0.0 if x < edge, otherwise it returns 1.0.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml">GLSL step man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, typename T, precision P>
+       GLM_FUNC_DECL vecType<T, P> step(T edge, vecType<T, P> const & x);
+
+       /// Returns 0.0 if x < edge, otherwise it returns 1.0.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/step.xml">GLSL step man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, typename T, precision P>
+       GLM_FUNC_DECL vecType<T, P> step(vecType<T, P> const & edge, vecType<T, P> const & x);
+
+       /// Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and
+       /// performs smooth Hermite interpolation between 0 and 1
+       /// when edge0 < x < edge1. This is useful in cases where
+       /// you would want a threshold function with a smooth
+       /// transition. This is equivalent to:
+       /// genType t;
+       /// t = clamp ((x - edge0) / (edge1 - edge0), 0, 1);
+       /// return t * t * (3 - 2 * t);
+       /// Results are undefined if edge0 >= edge1.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/smoothstep.xml">GLSL smoothstep man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType smoothstep(genType edge0, genType edge1, genType x);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> smoothstep(T edge0, T edge1, vecType<T, P> const & x);
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> smoothstep(vecType<T, P> const & edge0, vecType<T, P> const & edge1, vecType<T, P> const & x);
+
+       /// Returns true if x holds a NaN (not a number)
+       /// representation in the underlying implementation's set of
+       /// floating point representations. Returns false otherwise,
+       /// including for implementations with no NaN
+       /// representations.
+       /// 
+       /// /!\ When using compiler fast math, this function may fail.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/isnan.xml">GLSL isnan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isnan(vecType<T, P> const & x);
+
+       /// Returns true if x holds a positive infinity or negative
+       /// infinity representation in the underlying implementation's
+       /// set of floating point representations. Returns false
+       /// otherwise, including for implementations with no infinity
+       /// representations.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/isinf.xml">GLSL isinf man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isinf(vecType<T, P> const & x);
+
+       /// Returns a signed integer value representing
+       /// the encoding of a floating-point value. The floating-point
+       /// value's bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml">GLSL floatBitsToInt man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       GLM_FUNC_DECL int floatBitsToInt(float const & v);
+
+       /// Returns a signed integer value representing
+       /// the encoding of a floating-point value. The floatingpoint
+       /// value's bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToInt.xml">GLSL floatBitsToInt man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_DECL vecType<int, P> floatBitsToInt(vecType<float, P> const & v);
+
+       /// Returns a unsigned integer value representing
+       /// the encoding of a floating-point value. The floatingpoint
+       /// value's bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToUint.xml">GLSL floatBitsToUint man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       GLM_FUNC_DECL uint floatBitsToUint(float const & v);
+
+       /// Returns a unsigned integer value representing
+       /// the encoding of a floating-point value. The floatingpoint
+       /// value's bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/floatBitsToUint.xml">GLSL floatBitsToUint man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_DECL vecType<uint, P> floatBitsToUint(vecType<float, P> const & v);
+
+       /// Returns a floating-point value corresponding to a signed
+       /// integer encoding of a floating-point value.
+       /// If an inf or NaN is passed in, it will not signal, and the
+       /// resulting floating point value is unspecified. Otherwise,
+       /// the bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/intBitsToFloat.xml">GLSL intBitsToFloat man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       GLM_FUNC_DECL float intBitsToFloat(int const & v);
+
+       /// Returns a floating-point value corresponding to a signed
+       /// integer encoding of a floating-point value.
+       /// If an inf or NaN is passed in, it will not signal, and the
+       /// resulting floating point value is unspecified. Otherwise,
+       /// the bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/intBitsToFloat.xml">GLSL intBitsToFloat man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_DECL vecType<float, P> intBitsToFloat(vecType<int, P> const & v);
+
+       /// Returns a floating-point value corresponding to a
+       /// unsigned integer encoding of a floating-point value.
+       /// If an inf or NaN is passed in, it will not signal, and the
+       /// resulting floating point value is unspecified. Otherwise,
+       /// the bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/uintBitsToFloat.xml">GLSL uintBitsToFloat man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       GLM_FUNC_DECL float uintBitsToFloat(uint const & v);
+
+       /// Returns a floating-point value corresponding to a
+       /// unsigned integer encoding of a floating-point value.
+       /// If an inf or NaN is passed in, it will not signal, and the
+       /// resulting floating point value is unspecified. Otherwise,
+       /// the bit-level representation is preserved.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/uintBitsToFloat.xml">GLSL uintBitsToFloat man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_DECL vecType<float, P> uintBitsToFloat(vecType<uint, P> const & v);
+
+       /// Computes and returns a * b + c.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/fma.xml">GLSL fma man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType fma(genType const & a, genType const & b, genType const & c);
+
+       /// Splits x into a floating-point significand in the range
+       /// [0.5, 1.0) and an integral exponent of two, such that:
+       /// x = significand * exp(2, exponent)
+       /// 
+       /// The significand is returned by the function and the
+       /// exponent is returned in the parameter exp. For a
+       /// floating-point value of zero, the significant and exponent
+       /// are both zero. For a floating-point value that is an
+       /// infinity or is not a number, the results are undefined.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/frexp.xml">GLSL frexp man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType, typename genIType>
+       GLM_FUNC_DECL genType frexp(genType const & x, genIType & exp);
+
+       /// Builds a floating-point number from x and the
+       /// corresponding integral exponent of two in exp, returning:
+       /// significand * exp(2, exponent)
+       /// 
+       /// If this product is too large to be represented in the
+       /// floating-point type, the result is undefined.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///  
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/ldexp.xml">GLSL ldexp man page</a>; 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType, typename genIType>
+       GLM_FUNC_DECL genType ldexp(genType const & x, genIType const & exp);
+
+       /// @}
+}//namespace glm
+
+#include "func_common.inl"
+
diff --git a/core/deps/glm/glm/detail/func_common.inl b/core/deps/glm/glm/detail/func_common.inl
new file mode 100755 (executable)
index 0000000..327b058
--- /dev/null
@@ -0,0 +1,849 @@
+/// @ref core
+/// @file glm/detail/func_common.inl
+
+#include "func_vector_relational.hpp"
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+#include "_vectorize.hpp"
+#include <limits>
+
+namespace glm
+{
+       // min
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType min(genType x, genType y)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'min' only accept floating-point or integer inputs");
+               return x < y ? x : y;
+       }
+
+       // max
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType max(genType x, genType y)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'max' only accept floating-point or integer inputs");
+
+               return x > y ? x : y;
+       }
+
+       // abs
+       template <>
+       GLM_FUNC_QUALIFIER int32 abs(int32 x)
+       {
+               int32 const y = x >> 31;
+               return (x ^ y) - y;
+       }
+
+       // round
+#      if GLM_HAS_CXX11_STL
+               using ::std::round;
+#      else
+               template <typename genType>
+               GLM_FUNC_QUALIFIER genType round(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'round' only accept floating-point inputs");
+
+                       return x < static_cast<genType>(0) ? static_cast<genType>(int(x - static_cast<genType>(0.5))) : static_cast<genType>(int(x + static_cast<genType>(0.5)));
+               }
+#      endif
+
+       // trunc
+#      if GLM_HAS_CXX11_STL
+               using ::std::trunc;
+#      else
+               template <typename genType>
+               GLM_FUNC_QUALIFIER genType trunc(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'trunc' only accept floating-point inputs");
+
+                       return x < static_cast<genType>(0) ? -std::floor(-x) : std::floor(x);
+               }
+#      endif
+
+}//namespace glm
+
+namespace glm{
+namespace detail
+{
+       template <typename genFIType, bool /*signed*/>
+       struct compute_abs
+       {};
+
+       template <typename genFIType>
+       struct compute_abs<genFIType, true>
+       {
+               GLM_FUNC_QUALIFIER static genFIType call(genFIType x)
+               {
+                       GLM_STATIC_ASSERT(
+                               std::numeric_limits<genFIType>::is_iec559 || std::numeric_limits<genFIType>::is_signed || GLM_UNRESTRICTED_GENTYPE,
+                               "'abs' only accept floating-point and integer scalar or vector inputs");
+
+                       return x >= genFIType(0) ? x : -x;
+                       // TODO, perf comp with: *(((int *) &x) + 1) &= 0x7fffffff;
+               }
+       };
+
+       #if GLM_COMPILER & GLM_COMPILER_CUDA
+       template <>
+       struct compute_abs<float, true>
+       {
+               GLM_FUNC_QUALIFIER static float call(float x)
+               {
+                       return fabsf(x);
+               }
+       };
+       #endif
+
+       template <typename genFIType>
+       struct compute_abs<genFIType, false>
+       {
+               GLM_FUNC_QUALIFIER static genFIType call(genFIType x)
+               {
+                       GLM_STATIC_ASSERT(
+                               (!std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer) || GLM_UNRESTRICTED_GENTYPE,
+                               "'abs' only accept floating-point and integer scalar or vector inputs");
+                       return x;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_abs_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(abs, x);
+               }
+       };
+
+       template <typename T, typename U, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_mix_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, vecType<U, P> const & a)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
+
+                       return vecType<T, P>(vecType<U, P>(x) + a * vecType<U, P>(y - x));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_mix_vector<T, bool, P, vecType, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, vecType<bool, P> const & a)
+               {
+                       vecType<T, P> Result(uninitialize);
+                       for(length_t i = 0; i < x.length(); ++i)
+                               Result[i] = a[i] ? y[i] : x[i];
+                       return Result;
+               }
+       };
+
+       template <typename T, typename U, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_mix_scalar
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, U const & a)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
+
+                       return vecType<T, P>(vecType<U, P>(x) + a * vecType<U, P>(y - x));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_mix_scalar<T, bool, P, vecType, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y, bool const & a)
+               {
+                       return a ? y : x;
+               }
+       };
+
+       template <typename T, typename U>
+       struct compute_mix
+       {
+               GLM_FUNC_QUALIFIER static T call(T const & x, T const & y, U const & a)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<U>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'mix' only accept floating-point inputs for the interpolator a");
+
+                       return static_cast<T>(static_cast<U>(x) + a * static_cast<U>(y - x));
+               }
+       };
+
+       template <typename T>
+       struct compute_mix<T, bool>
+       {
+               GLM_FUNC_QUALIFIER static T call(T const & x, T const & y, bool const & a)
+               {
+                       return a ? y : x;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool isFloat, bool Aligned>
+       struct compute_sign
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return vecType<T, P>(glm::lessThan(vecType<T, P>(0), x)) - vecType<T, P>(glm::lessThan(x, vecType<T, P>(0)));
+               }
+       };
+
+#      if GLM_ARCH == GLM_ARCH_X86
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_sign<T, P, vecType, false, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       T const Shift(static_cast<T>(sizeof(T) * 8 - 1));
+                       vecType<T, P> const y(vecType<typename make_unsigned<T>::type, P>(-x) >> typename make_unsigned<T>::type(Shift));
+
+                       return (x >> Shift) | y;
+               }
+       };
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_floor
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(std::floor, x);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_ceil
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(std::ceil, x);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_fract
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return x - floor(x);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_trunc
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(trunc, x);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_round
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(round, x);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_mod
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & a, vecType<T, P> const & b)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'mod' only accept floating-point inputs. Include <glm/gtc/integer.hpp> for integer inputs.");
+                       return a - b * floor(a / b);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_min_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y)
+               {
+                       return detail::functor2<T, P, vecType>::call(min, x, y);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_max_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & y)
+               {
+                       return detail::functor2<T, P, vecType>::call(max, x, y);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_clamp_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, vecType<T, P> const & minVal, vecType<T, P> const & maxVal)
+               {
+                       return min(max(x, minVal), maxVal);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_step_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & edge, vecType<T, P> const & x)
+               {
+                       return mix(vecType<T, P>(1), vecType<T, P>(0), glm::lessThan(x, edge));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_smoothstep_vector
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & edge0, vecType<T, P> const & edge1, vecType<T, P> const & x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'step' only accept floating-point inputs");
+                       vecType<T, P> const tmp(clamp((x - edge0) / (edge1 - edge0), static_cast<T>(0), static_cast<T>(1)));
+                       return tmp * tmp * (static_cast<T>(3) - static_cast<T>(2) * tmp);
+               }
+       };
+}//namespace detail
+
+       template <typename genFIType>
+       GLM_FUNC_QUALIFIER genFIType abs(genFIType x)
+       {
+               return detail::compute_abs<genFIType, std::numeric_limits<genFIType>::is_signed>::call(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> abs(vecType<T, P> const & x)
+       {
+               return detail::compute_abs_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // sign
+       // fast and works for any type
+       template <typename genFIType> 
+       GLM_FUNC_QUALIFIER genFIType sign(genFIType x)
+       {
+               GLM_STATIC_ASSERT(
+                       std::numeric_limits<genFIType>::is_iec559 || (std::numeric_limits<genFIType>::is_signed && std::numeric_limits<genFIType>::is_integer),
+                       "'sign' only accept signed inputs");
+               
+               return detail::compute_sign<genFIType, defaultp, tvec1, std::numeric_limits<genFIType>::is_iec559, highp>::call(tvec1<genFIType>(x)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sign(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(
+                       std::numeric_limits<T>::is_iec559 || (std::numeric_limits<T>::is_signed && std::numeric_limits<T>::is_integer),
+                       "'sign' only accept signed inputs");
+
+               return detail::compute_sign<T, P, vecType, std::numeric_limits<T>::is_iec559, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // floor
+       using ::std::floor;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> floor(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'floor' only accept floating-point inputs.");
+               return detail::compute_floor<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> trunc(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'trunc' only accept floating-point inputs");
+               return detail::compute_trunc<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> round(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'round' only accept floating-point inputs");
+               return detail::compute_round<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+/*
+       // roundEven
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType roundEven(genType const& x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'roundEven' only accept floating-point inputs");
+
+               return genType(int(x + genType(int(x) % 2)));
+       }
+*/
+
+       // roundEven
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType roundEven(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'roundEven' only accept floating-point inputs");
+               
+               int Integer = static_cast<int>(x);
+               genType IntegerPart = static_cast<genType>(Integer);
+               genType FractionalPart = fract(x);
+
+               if(FractionalPart > static_cast<genType>(0.5) || FractionalPart < static_cast<genType>(0.5))
+               {
+                       return round(x);
+               }
+               else if((Integer % 2) == 0)
+               {
+                       return IntegerPart;
+               }
+               else if(x <= static_cast<genType>(0)) // Work around... 
+               {
+                       return IntegerPart - static_cast<genType>(1);
+               }
+               else
+               {
+                       return IntegerPart + static_cast<genType>(1);
+               }
+               //else // Bug on MinGW 4.5.2
+               //{
+               //      return mix(IntegerPart + genType(-1), IntegerPart + genType(1), x <= genType(0));
+               //}
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> roundEven(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'roundEven' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(roundEven, x);
+       }
+
+       // ceil
+       using ::std::ceil;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> ceil(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'ceil' only accept floating-point inputs");
+               return detail::compute_ceil<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // fract
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fract(genType x)
+       {
+               return fract(tvec1<genType>(x)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fract(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fract' only accept floating-point inputs");
+               return detail::compute_fract<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // mod
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType mod(genType x, genType y)
+       {
+#              if GLM_COMPILER & GLM_COMPILER_CUDA
+                       // Another Cuda compiler bug https://github.com/g-truc/glm/issues/530
+                       tvec1<genType, defaultp> Result(mod(tvec1<genType, defaultp>(x), y));
+                       return Result.x;
+#              else
+                       return mod(tvec1<genType, defaultp>(x), y).x;
+#              endif
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mod(vecType<T, P> const & x, T y)
+       {
+               return detail::compute_mod<T, P, vecType, detail::is_aligned<P>::value>::call(x, vecType<T, P>(y));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mod(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return detail::compute_mod<T, P, vecType, detail::is_aligned<P>::value>::call(x, y);
+       }
+
+       // modf
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType modf(genType x, genType & i)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'modf' only accept floating-point inputs");
+               return std::modf(x, &i);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> modf(tvec1<T, P> const & x, tvec1<T, P> & i)
+       {
+               return tvec1<T, P>(
+                       modf(x.x, i.x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> modf(tvec2<T, P> const & x, tvec2<T, P> & i)
+       {
+               return tvec2<T, P>(
+                       modf(x.x, i.x),
+                       modf(x.y, i.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> modf(tvec3<T, P> const & x, tvec3<T, P> & i)
+       {
+               return tvec3<T, P>(
+                       modf(x.x, i.x),
+                       modf(x.y, i.y),
+                       modf(x.z, i.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> modf(tvec4<T, P> const & x, tvec4<T, P> & i)
+       {
+               return tvec4<T, P>(
+                       modf(x.x, i.x),
+                       modf(x.y, i.y),
+                       modf(x.z, i.z),
+                       modf(x.w, i.w));
+       }
+
+       //// Only valid if (INT_MIN <= x-y <= INT_MAX)
+       //// min(x,y)
+       //r = y + ((x - y) & ((x - y) >> (sizeof(int) *
+       //CHAR_BIT - 1)));
+       //// max(x,y)
+       //r = x - ((x - y) & ((x - y) >> (sizeof(int) *
+       //CHAR_BIT - 1)));
+
+       // min
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> min(vecType<T, P> const & a, T b)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'min' only accept floating-point inputs for the interpolator a");
+               return detail::compute_min_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, vecType<T, P>(b));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> min(vecType<T, P> const & a, vecType<T, P> const & b)
+       {
+               return detail::compute_min_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, b);
+       }
+
+       // max
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> max(vecType<T, P> const & a, T b)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'max' only accept floating-point inputs for the interpolator a");
+               return detail::compute_max_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, vecType<T, P>(b));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> max(vecType<T, P> const & a, vecType<T, P> const & b)
+       {
+               return detail::compute_max_vector<T, P, vecType, detail::is_aligned<P>::value>::call(a, b);
+       }
+
+       // clamp
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType clamp(genType x, genType minVal, genType maxVal)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || std::numeric_limits<genType>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
+               return min(max(x, minVal), maxVal);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> clamp(vecType<T, P> const & x, T minVal, T maxVal)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
+               return detail::compute_clamp_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x, vecType<T, P>(minVal), vecType<T, P>(maxVal));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> clamp(vecType<T, P> const & x, vecType<T, P> const & minVal, vecType<T, P> const & maxVal)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || std::numeric_limits<T>::is_integer || GLM_UNRESTRICTED_GENTYPE, "'clamp' only accept floating-point or integer inputs");
+               return detail::compute_clamp_vector<T, P, vecType, detail::is_aligned<P>::value>::call(x, minVal, maxVal);
+       }
+
+       template <typename genTypeT, typename genTypeU>
+       GLM_FUNC_QUALIFIER genTypeT mix(genTypeT x, genTypeT y, genTypeU a)
+       {
+               return detail::compute_mix<genTypeT, genTypeU>::call(x, y, a);
+       }
+
+       template <typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, U a)
+       {
+               return detail::compute_mix_scalar<T, U, P, vecType, detail::is_aligned<P>::value>::call(x, y, a);
+       }
+       
+       template <typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mix(vecType<T, P> const & x, vecType<T, P> const & y, vecType<U, P> const & a)
+       {
+               return detail::compute_mix_vector<T, U, P, vecType, detail::is_aligned<P>::value>::call(x, y, a);
+       }
+
+       // step
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType step(genType edge, genType x)
+       {
+               return mix(static_cast<genType>(1), static_cast<genType>(0), glm::lessThan(x, edge));
+       }
+
+       template <template <typename, precision> class vecType, typename T, precision P>
+       GLM_FUNC_QUALIFIER vecType<T, P> step(T edge, vecType<T, P> const & x)
+       {
+               return detail::compute_step_vector<T, P, vecType, detail::is_aligned<P>::value>::call(vecType<T, P>(edge), x);
+       }
+
+       template <template <typename, precision> class vecType, typename T, precision P>
+       GLM_FUNC_QUALIFIER vecType<T, P> step(vecType<T, P> const & edge, vecType<T, P> const & x)
+       {
+               return detail::compute_step_vector<T, P, vecType, detail::is_aligned<P>::value>::call(edge, x);
+       }
+
+       // smoothstep
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType smoothstep(genType edge0, genType edge1, genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'smoothstep' only accept floating-point inputs");
+
+               genType const tmp(clamp((x - edge0) / (edge1 - edge0), genType(0), genType(1)));
+               return tmp * tmp * (genType(3) - genType(2) * tmp);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> smoothstep(T edge0, T edge1, vecType<T, P> const & x)
+       {
+               return detail::compute_smoothstep_vector<T, P, vecType, detail::is_aligned<P>::value>::call(vecType<T, P>(edge0), vecType<T, P>(edge1), x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> smoothstep(vecType<T, P> const & edge0, vecType<T, P> const & edge1, vecType<T, P> const & x)
+       {
+               return detail::compute_smoothstep_vector<T, P, vecType, detail::is_aligned<P>::value>::call(edge0, edge1, x);
+       }
+
+#      if GLM_HAS_CXX11_STL
+               using std::isnan;
+#      else
+               template <typename genType> 
+               GLM_FUNC_QUALIFIER bool isnan(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'isnan' only accept floating-point inputs");
+
+#                      if GLM_HAS_CXX11_STL
+                               return std::isnan(x);
+#                      elif GLM_COMPILER & GLM_COMPILER_VC
+                               return _isnan(x) != 0;
+#                      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#                              if GLM_PLATFORM & GLM_PLATFORM_WINDOWS
+                                       return _isnan(x) != 0;
+#                              else
+                                       return ::isnan(x) != 0;
+#                              endif
+#                      elif (GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)) && (GLM_PLATFORM & GLM_PLATFORM_ANDROID) && __cplusplus < 201103L
+                               return _isnan(x) != 0;
+#                      elif GLM_COMPILER & GLM_COMPILER_CUDA
+                               return isnan(x) != 0;
+#                      else
+                               return std::isnan(x);
+#                      endif
+               }
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isnan(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs");
+
+               return detail::functor1<bool, T, P, vecType>::call(isnan, x);
+       }
+
+#      if GLM_HAS_CXX11_STL
+               using std::isinf;
+#      else
+               template <typename genType> 
+               GLM_FUNC_QUALIFIER bool isinf(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'isinf' only accept floating-point inputs");
+
+#                      if GLM_HAS_CXX11_STL
+                               return std::isinf(x);
+#                      elif GLM_COMPILER & (GLM_COMPILER_INTEL | GLM_COMPILER_VC)
+#                              if(GLM_PLATFORM & GLM_PLATFORM_WINDOWS)
+                                       return _fpclass(x) == _FPCLASS_NINF || _fpclass(x) == _FPCLASS_PINF;
+#                              else
+                                       return ::isinf(x);
+#                              endif
+#                      elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)
+#                              if(GLM_PLATFORM & GLM_PLATFORM_ANDROID && __cplusplus < 201103L)
+                                       return _isinf(x) != 0;
+#                              else
+                                       return std::isinf(x);
+#                              endif
+#                      elif GLM_COMPILER & GLM_COMPILER_CUDA
+                               // http://developer.download.nvidia.com/compute/cuda/4_2/rel/toolkit/docs/online/group__CUDA__MATH__DOUBLE_g13431dd2b40b51f9139cbb7f50c18fab.html#g13431dd2b40b51f9139cbb7f50c18fab
+                               return isinf(double(x)) != 0;
+#                      else
+                               return std::isinf(x);
+#                      endif
+       }
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isinf(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs");
+
+               return detail::functor1<bool, T, P, vecType>::call(isinf, x);
+       }
+
+       GLM_FUNC_QUALIFIER int floatBitsToInt(float const & v)
+       {
+               return reinterpret_cast<int&>(const_cast<float&>(v));
+       }
+
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_QUALIFIER vecType<int, P> floatBitsToInt(vecType<float, P> const & v)
+       {
+               return reinterpret_cast<vecType<int, P>&>(const_cast<vecType<float, P>&>(v));
+       }
+
+       GLM_FUNC_QUALIFIER uint floatBitsToUint(float const & v)
+       {
+               return reinterpret_cast<uint&>(const_cast<float&>(v));
+       }
+
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_QUALIFIER vecType<uint, P> floatBitsToUint(vecType<float, P> const & v)
+       {
+               return reinterpret_cast<vecType<uint, P>&>(const_cast<vecType<float, P>&>(v));
+       }
+
+       GLM_FUNC_QUALIFIER float intBitsToFloat(int const & v)
+       {
+               return reinterpret_cast<float&>(const_cast<int&>(v));
+       }
+
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_QUALIFIER vecType<float, P> intBitsToFloat(vecType<int, P> const & v)
+       {
+               return reinterpret_cast<vecType<float, P>&>(const_cast<vecType<int, P>&>(v));
+       }
+
+       GLM_FUNC_QUALIFIER float uintBitsToFloat(uint const & v)
+       {
+               return reinterpret_cast<float&>(const_cast<uint&>(v));
+       }
+
+       template <template <typename, precision> class vecType, precision P>
+       GLM_FUNC_QUALIFIER vecType<float, P> uintBitsToFloat(vecType<uint, P> const & v)
+       {
+               return reinterpret_cast<vecType<float, P>&>(const_cast<vecType<uint, P>&>(v));
+       }
+       
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fma(genType const & a, genType const & b, genType const & c)
+       {
+               return a * b + c;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType frexp(genType x, int & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
+
+               return std::frexp(x, &exp);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> frexp(tvec1<T, P> const & x, tvec1<int, P> & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
+
+               return tvec1<T, P>(std::frexp(x.x, &exp.x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> frexp(tvec2<T, P> const & x, tvec2<int, P> & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
+
+               return tvec2<T, P>(
+                       frexp(x.x, exp.x),
+                       frexp(x.y, exp.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> frexp(tvec3<T, P> const & x, tvec3<int, P> & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
+
+               return tvec3<T, P>(
+                       frexp(x.x, exp.x),
+                       frexp(x.y, exp.y),
+                       frexp(x.z, exp.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> frexp(tvec4<T, P> const & x, tvec4<int, P> & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'frexp' only accept floating-point inputs");
+
+               return tvec4<T, P>(
+                       frexp(x.x, exp.x),
+                       frexp(x.y, exp.y),
+                       frexp(x.z, exp.z),
+                       frexp(x.w, exp.w));
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType ldexp(genType const & x, int const & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
+
+               return std::ldexp(x, exp);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> ldexp(tvec1<T, P> const & x, tvec1<int, P> const & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
+
+               return tvec1<T, P>(
+                       ldexp(x.x, exp.x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> ldexp(tvec2<T, P> const & x, tvec2<int, P> const & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
+
+               return tvec2<T, P>(
+                       ldexp(x.x, exp.x),
+                       ldexp(x.y, exp.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> ldexp(tvec3<T, P> const & x, tvec3<int, P> const & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
+
+               return tvec3<T, P>(
+                       ldexp(x.x, exp.x),
+                       ldexp(x.y, exp.y),
+                       ldexp(x.z, exp.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> ldexp(tvec4<T, P> const & x, tvec4<int, P> const & exp)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'ldexp' only accept floating-point inputs");
+
+               return tvec4<T, P>(
+                       ldexp(x.x, exp.x),
+                       ldexp(x.y, exp.y),
+                       ldexp(x.z, exp.z),
+                       ldexp(x.w, exp.w));
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_common_simd.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/func_common_simd.inl b/core/deps/glm/glm/detail/func_common_simd.inl
new file mode 100755 (executable)
index 0000000..c76f180
--- /dev/null
@@ -0,0 +1,231 @@
+/// @ref core
+/// @file glm/detail/func_common_simd.inl
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+#include "../simd/common.h"
+
+#include <immintrin.h>
+
+namespace glm{
+namespace detail
+{
+       template <precision P>
+       struct compute_abs_vector<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_abs(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_abs_vector<int, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<int, P> call(tvec4<int, P> const & v)
+               {
+                       tvec4<int, P> result(uninitialize);
+                       result.data = glm_ivec4_abs(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_floor<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_floor(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_ceil<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_ceil(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_fract<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_fract(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_round<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_round(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_mod<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & x, tvec4<float, P> const & y)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_mod(x.data, y.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_min_vector<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v1, tvec4<float, P> const & v2)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = _mm_min_ps(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_min_vector<int32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<int32, P> call(tvec4<int32, P> const & v1, tvec4<int32, P> const & v2)
+               {
+                       tvec4<int32, P> result(uninitialize);
+                       result.data = _mm_min_epi32(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_min_vector<uint32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<int32, P> call(tvec4<uint32, P> const & v1, tvec4<uint32, P> const & v2)
+               {
+                       tvec4<uint32, P> result(uninitialize);
+                       result.data = _mm_min_epu32(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_max_vector<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v1, tvec4<float, P> const & v2)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = _mm_max_ps(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_max_vector<int32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<int32, P> call(tvec4<int32, P> const & v1, tvec4<int32, P> const & v2)
+               {
+                       tvec4<int32, P> result(uninitialize);
+                       result.data = _mm_max_epi32(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_max_vector<uint32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint32, P> call(tvec4<uint32, P> const & v1, tvec4<uint32, P> const & v2)
+               {
+                       tvec4<uint32, P> result(uninitialize);
+                       result.data = _mm_max_epu32(v1.data, v2.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_clamp_vector<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & x, tvec4<float, P> const & minVal, tvec4<float, P> const & maxVal)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = _mm_min_ps(_mm_max_ps(x.data, minVal.data), maxVal.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_clamp_vector<int32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<int32, P> call(tvec4<int32, P> const & x, tvec4<int32, P> const & minVal, tvec4<int32, P> const & maxVal)
+               {
+                       tvec4<int32, P> result(uninitialize);
+                       result.data = _mm_min_epi32(_mm_max_epi32(x.data, minVal.data), maxVal.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_clamp_vector<uint32, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint32, P> call(tvec4<uint32, P> const & x, tvec4<uint32, P> const & minVal, tvec4<uint32, P> const & maxVal)
+               {
+                       tvec4<uint32, P> result(uninitialize);
+                       result.data = _mm_min_epu32(_mm_max_epu32(x.data, minVal.data), maxVal.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_mix_vector<float, bool, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & x, tvec4<float, P> const & y, tvec4<bool, P> const & a)
+               {
+                       __m128i const Load = _mm_set_epi32(-(int)a.w, -(int)a.z, -(int)a.y, -(int)a.x);
+                       __m128 const Mask = _mm_castsi128_ps(Load);
+
+                       tvec4<float, P> Result(uninitialize);
+#                      if 0 && GLM_ARCH & GLM_ARCH_AVX
+                               Result.data = _mm_blendv_ps(x.data, y.data, Mask);
+#                      else
+                               Result.data = _mm_or_ps(_mm_and_ps(Mask, y.data), _mm_andnot_ps(Mask, x.data));
+#                      endif
+                       return Result;
+               }
+       };
+/* FIXME
+       template <precision P>
+       struct compute_step_vector<float, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const& edge, tvec4<float, P> const& x)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_step(edge.data, x.data);
+                       return result;
+               }
+       };
+*/
+       template <precision P>
+       struct compute_smoothstep_vector<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const& edge0, tvec4<float, P> const& edge1, tvec4<float, P> const& x)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_smoothstep(edge0.data, edge1.data, x.data);
+                       return result;
+               }
+       };
+}//namespace detail
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/detail/func_exponential.hpp b/core/deps/glm/glm/detail/func_exponential.hpp
new file mode 100755 (executable)
index 0000000..a83de0b
--- /dev/null
@@ -0,0 +1,103 @@
+/// @ref core
+/// @file glm/detail/func_exponential.hpp
+/// 
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+///
+/// @defgroup core_func_exponential Exponential functions
+/// @ingroup core
+/// 
+/// These all operate component-wise. The description is per component.
+
+#pragma once
+
+#include "type_vec1.hpp"
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+#include <cmath>
+
+namespace glm
+{
+       /// @addtogroup core_func_exponential
+       /// @{
+
+       /// Returns 'base' raised to the power 'exponent'. 
+       ///
+       /// @param base Floating point value. pow function is defined for input values of 'base' defined in the range (inf-, inf+) in the limit of the type precision.
+       /// @param exponent Floating point value representing the 'exponent'.
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/pow.xml">GLSL pow man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> pow(vecType<T, P> const & base, vecType<T, P> const & exponent);
+
+       /// Returns the natural exponentiation of x, i.e., e^x.
+       ///
+       /// @param v exp function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/exp.xml">GLSL exp man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> exp(vecType<T, P> const & v);
+
+       /// Returns the natural logarithm of v, i.e., 
+       /// returns the value y which satisfies the equation x = e^y. 
+       /// Results are undefined if v <= 0.
+       ///
+       /// @param v log function is defined for input values of v defined in the range (0, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/log.xml">GLSL log man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> log(vecType<T, P> const & v);
+
+       /// Returns 2 raised to the v power.
+       /// 
+       /// @param v exp2 function is defined for input values of v defined in the range (inf-, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/exp2.xml">GLSL exp2 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> exp2(vecType<T, P> const & v);
+
+       /// Returns the base 2 log of x, i.e., returns the value y, 
+       /// which satisfies the equation x = 2 ^ y.
+       /// 
+       /// @param v log2 function is defined for input values of v defined in the range (0, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/log2.xml">GLSL log2 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> log2(vecType<T, P> const & v);
+
+       /// Returns the positive square root of v.
+       /// 
+       /// @param v sqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/sqrt.xml">GLSL sqrt man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       //template <typename genType>
+       //GLM_FUNC_DECL genType sqrt(genType const & x);
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> sqrt(vecType<T, P> const & v);
+       
+       /// Returns the reciprocal of the positive square root of v.
+       /// 
+       /// @param v inversesqrt function is defined for input values of v defined in the range [0, inf+) in the limit of the type precision.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/inversesqrt.xml">GLSL inversesqrt man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.2 Exponential Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> inversesqrt(vecType<T, P> const & v);
+
+       /// @}
+}//namespace glm
+
+#include "func_exponential.inl"
diff --git a/core/deps/glm/glm/detail/func_exponential.inl b/core/deps/glm/glm/detail/func_exponential.inl
new file mode 100755 (executable)
index 0000000..227fe91
--- /dev/null
@@ -0,0 +1,146 @@
+/// @ref core
+/// @file glm/detail/func_exponential.inl
+
+#include "func_vector_relational.hpp"
+#include "_vectorize.hpp"
+#include <limits>
+#include <cmath>
+#include <cassert>
+
+namespace glm{
+namespace detail
+{
+#      if GLM_HAS_CXX11_STL
+               using std::log2;
+#      else
+               template <typename genType>
+               genType log2(genType Value)
+               {
+                       return std::log(Value) * static_cast<genType>(1.4426950408889634073599246810019);
+               }
+#      endif
+
+       template <typename T, precision P, template <class, precision> class vecType, bool isFloat, bool Aligned>
+       struct compute_log2
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & vec)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(log2, vec);
+               }
+       };
+
+       template <template <class, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_sqrt
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return detail::functor1<T, T, P, vecType>::call(std::sqrt, x);
+               }
+       };
+
+       template <template <class, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_inversesqrt
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       return static_cast<T>(1) / sqrt(x);
+               }
+       };
+               
+       template <template <class, precision> class vecType, bool Aligned>
+       struct compute_inversesqrt<vecType, float, lowp, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static vecType<float, lowp> call(vecType<float, lowp> const & x)
+               {
+                       vecType<float, lowp> tmp(x);
+                       vecType<float, lowp> xhalf(tmp * 0.5f);
+                       vecType<uint, lowp>* p = reinterpret_cast<vecType<uint, lowp>*>(const_cast<vecType<float, lowp>*>(&x));
+                       vecType<uint, lowp> i = vecType<uint, lowp>(0x5f375a86) - (*p >> vecType<uint, lowp>(1));
+                       vecType<float, lowp>* ptmp = reinterpret_cast<vecType<float, lowp>*>(&i);
+                       tmp = *ptmp;
+                       tmp = tmp * (1.5f - xhalf * tmp * tmp);
+                       return tmp;
+               }
+       };
+}//namespace detail
+
+       // pow
+       using std::pow;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> pow(vecType<T, P> const & base, vecType<T, P> const & exponent)
+       {
+               return detail::functor2<T, P, vecType>::call(pow, base, exponent);
+       }
+
+       // exp
+       using std::exp;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> exp(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(exp, x);
+       }
+
+       // log
+       using std::log;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> log(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(log, x);
+       }
+
+       //exp2, ln2 = 0.69314718055994530941723212145818f
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType exp2(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'exp2' only accept floating-point inputs");
+
+               return std::exp(static_cast<genType>(0.69314718055994530941723212145818) * x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> exp2(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(exp2, x);
+       }
+
+       // log2, ln2 = 0.69314718055994530941723212145818f
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType log2(genType x)
+       {
+               return log2(tvec1<genType>(x)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> log2(vecType<T, P> const & x)
+       {
+               return detail::compute_log2<T, P, vecType, std::numeric_limits<T>::is_iec559, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // sqrt
+       using std::sqrt;
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sqrt(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'sqrt' only accept floating-point inputs");
+               return detail::compute_sqrt<vecType, T, P, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // inversesqrt
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType inversesqrt(genType x)
+       {
+               return static_cast<genType>(1) / sqrt(x);
+       }
+       
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> inversesqrt(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'inversesqrt' only accept floating-point inputs");
+               return detail::compute_inversesqrt<vecType, T, P, detail::is_aligned<P>::value>::call(x);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_exponential_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/detail/func_exponential_simd.inl b/core/deps/glm/glm/detail/func_exponential_simd.inl
new file mode 100755 (executable)
index 0000000..d7529ba
--- /dev/null
@@ -0,0 +1,35 @@
+/// @ref core
+/// @file glm/detail/func_exponential_simd.inl
+
+#include "../simd/exponential.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+namespace glm{
+namespace detail
+{
+       template <precision P>
+       struct compute_sqrt<tvec4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = _mm_sqrt_ps(v.data);
+                       return result;
+               }
+       };
+
+       template <>
+       struct compute_sqrt<tvec4, float, aligned_lowp, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, aligned_lowp> call(tvec4<float, aligned_lowp> const & v)
+               {
+                       tvec4<float, aligned_lowp> result(uninitialize);
+                       result.data = glm_vec4_sqrt_lowp(v.data);
+                       return result;
+               }
+       };
+}//namespace detail
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/detail/func_geometric.hpp b/core/deps/glm/glm/detail/func_geometric.hpp
new file mode 100755 (executable)
index 0000000..2f39bf5
--- /dev/null
@@ -0,0 +1,113 @@
+/// @ref core
+/// @file glm/detail/func_geometric.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+/// 
+/// @defgroup core_func_geometric Geometric functions
+/// @ingroup core
+/// 
+/// These operate on vectors as vectors, not component-wise.
+
+#pragma once
+
+#include "type_vec3.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_geometric
+       /// @{
+
+       /// Returns the length of x, i.e., sqrt(x * x).
+       /// 
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/length.xml">GLSL length man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T length(
+               vecType<T, P> const & x);
+
+       /// Returns the distance betwwen p0 and p1, i.e., length(p0 - p1).
+       ///
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/distance.xml">GLSL distance man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T distance(
+               vecType<T, P> const & p0,
+               vecType<T, P> const & p1);
+
+       /// Returns the dot product of x and y, i.e., result = x * y.
+       ///
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/dot.xml">GLSL dot man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T dot(
+               vecType<T, P> const & x,
+               vecType<T, P> const & y);
+
+       /// Returns the cross product of x and y.
+       ///
+       /// @tparam valType Floating-point scalar types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/cross.xml">GLSL cross man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> cross(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y);
+
+       /// Returns a vector in the same direction as x but with length of 1.
+       /// According to issue 10 GLSL 1.10 specification, if length(x) == 0 then result is undefined and generate an error.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/normalize.xml">GLSL normalize man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> normalize(
+               vecType<T, P> const & x);
+
+       /// If dot(Nref, I) < 0.0, return N, otherwise, return -N.
+       ///
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/faceforward.xml">GLSL faceforward man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> faceforward(
+               vecType<T, P> const & N,
+               vecType<T, P> const & I,
+               vecType<T, P> const & Nref);
+
+       /// For the incident vector I and surface orientation N, 
+       /// returns the reflection direction : result = I - 2.0 * dot(N, I) * N.
+       ///
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/reflect.xml">GLSL reflect man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL genType reflect(
+               genType const & I,
+               genType const & N);
+
+       /// For the incident vector I and surface normal N, 
+       /// and the ratio of indices of refraction eta, 
+       /// return the refraction vector.
+       ///
+       /// @tparam genType Floating-point vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/refract.xml">GLSL refract man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.5 Geometric Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> refract(
+               vecType<T, P> const & I,
+               vecType<T, P> const & N,
+               T eta);
+
+       /// @}
+}//namespace glm
+
+#include "func_geometric.inl"
diff --git a/core/deps/glm/glm/detail/func_geometric.inl b/core/deps/glm/glm/detail/func_geometric.inl
new file mode 100755 (executable)
index 0000000..07137c3
--- /dev/null
@@ -0,0 +1,247 @@
+/// @ref core
+/// @file glm/detail/func_geometric.inl
+
+#include "func_exponential.hpp"
+#include "func_common.hpp"
+#include "type_vec2.hpp"
+#include "type_vec4.hpp"
+#include "type_float.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <template <typename, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_length
+       {
+               GLM_FUNC_QUALIFIER static T call(vecType<T, P> const & v)
+               {
+                       return sqrt(dot(v, v));
+               }
+       };
+
+       template <template <typename, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_distance
+       {
+               GLM_FUNC_QUALIFIER static T call(vecType<T, P> const & p0, vecType<T, P> const & p1)
+               {
+                       return length(p1 - p0);
+               }
+       };
+
+       template <template <class, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_dot{};
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_dot<tvec1, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tvec1<T, P> const & a, tvec1<T, P> const & b)
+               {
+                       return a.x * b.x;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_dot<tvec2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tvec2<T, P> const & x, tvec2<T, P> const & y)
+               {
+                       tvec2<T, P> tmp(x * y);
+                       return tmp.x + tmp.y;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_dot<tvec3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tvec3<T, P> const & x, tvec3<T, P> const & y)
+               {
+                       tvec3<T, P> tmp(x * y);
+                       return tmp.x + tmp.y + tmp.z;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_dot<tvec4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tvec4<T, P> const & x, tvec4<T, P> const & y)
+               {
+                       tvec4<T, P> tmp(x * y);
+                       return (tmp.x + tmp.y) + (tmp.z + tmp.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_cross
+       {
+               GLM_FUNC_QUALIFIER static tvec3<T, P> call(tvec3<T, P> const & x, tvec3<T, P> const & y)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'cross' accepts only floating-point inputs");
+
+                       return tvec3<T, P>(
+                               x.y * y.z - y.y * x.z,
+                               x.z * y.x - y.z * x.x,
+                               x.x * y.y - y.x * x.y);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_normalize
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
+
+                       return v * inversesqrt(dot(v, v));
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_faceforward
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & N, vecType<T, P> const & I, vecType<T, P> const & Nref)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
+
+                       return dot(Nref, I) < static_cast<T>(0) ? N : -N;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_reflect
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & I, vecType<T, P> const & N)
+               {
+                       return I - N * dot(N, I) * static_cast<T>(2);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_refract
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & I, vecType<T, P> const & N, T eta)
+               {
+                       T const dotValue(dot(N, I));
+                       T const k(static_cast<T>(1) - eta * eta * (static_cast<T>(1) - dotValue * dotValue));
+                       return (eta * I - (eta * dotValue + std::sqrt(k)) * N) * static_cast<T>(k >= static_cast<T>(0));
+               }
+       };
+}//namespace detail
+
+       // length
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType length(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'length' accepts only floating-point inputs");
+
+               return abs(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T length(vecType<T, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length' accepts only floating-point inputs");
+
+               return detail::compute_length<vecType, T, P, detail::is_aligned<P>::value>::call(v);
+       }
+
+       // distance
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType distance(genType const & p0, genType const & p1)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'distance' accepts only floating-point inputs");
+
+               return length(p1 - p0);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T distance(vecType<T, P> const & p0, vecType<T, P> const & p1)
+       {
+               return detail::compute_distance<vecType, T, P, detail::is_aligned<P>::value>::call(p0, p1);
+       }
+
+       // dot
+       template <typename T>
+       GLM_FUNC_QUALIFIER T dot(T x, T y)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' accepts only floating-point inputs");
+               return x * y;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T dot(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'dot' accepts only floating-point inputs");
+               return detail::compute_dot<vecType, T, P, detail::is_aligned<P>::value>::call(x, y);
+       }
+
+       // cross
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> cross(tvec3<T, P> const & x, tvec3<T, P> const & y)
+       {
+               return detail::compute_cross<T, P, detail::is_aligned<P>::value>::call(x, y);
+       }
+
+       // normalize
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType normalize(genType const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'normalize' accepts only floating-point inputs");
+
+               return x < genType(0) ? genType(-1) : genType(1);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> normalize(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'normalize' accepts only floating-point inputs");
+
+               return detail::compute_normalize<T, P, vecType, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // faceforward
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType faceforward(genType const & N, genType const & I, genType const & Nref)
+       {
+               return dot(Nref, I) < static_cast<genType>(0) ? N : -N;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> faceforward(vecType<T, P> const & N, vecType<T, P> const & I, vecType<T, P> const & Nref)
+       {
+               return detail::compute_faceforward<T, P, vecType, detail::is_aligned<P>::value>::call(N, I, Nref);
+       }
+
+       // reflect
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType reflect(genType const & I, genType const & N)
+       {
+               return I - N * dot(N, I) * genType(2);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> reflect(vecType<T, P> const & I, vecType<T, P> const & N)
+       {
+               return detail::compute_reflect<T, P, vecType, detail::is_aligned<P>::value>::call(I, N);
+       }
+
+       // refract
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType refract(genType const & I, genType const & N, genType eta)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'refract' accepts only floating-point inputs");
+               genType const dotValue(dot(N, I));
+               genType const k(static_cast<genType>(1) - eta * eta * (static_cast<genType>(1) - dotValue * dotValue));
+               return (eta * I - (eta * dotValue + sqrt(k)) * N) * static_cast<genType>(k >= static_cast<genType>(0));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> refract(vecType<T, P> const & I, vecType<T, P> const & N, T eta)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'refract' accepts only floating-point inputs");
+               return detail::compute_refract<T, P, vecType, detail::is_aligned<P>::value>::call(I, N, eta);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_geometric_simd.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/func_geometric_simd.inl b/core/deps/glm/glm/detail/func_geometric_simd.inl
new file mode 100755 (executable)
index 0000000..f0d14a2
--- /dev/null
@@ -0,0 +1,99 @@
+/// @ref core
+/// @file glm/detail/func_geometric_simd.inl
+
+#include "../simd/geometric.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+namespace glm{
+namespace detail
+{
+       template <precision P>
+       struct compute_length<tvec4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static float call(tvec4<float, P> const & v)
+               {
+                       return _mm_cvtss_f32(glm_vec4_length(v.data));
+               }
+       };
+
+       template <precision P>
+       struct compute_distance<tvec4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static float call(tvec4<float, P> const & p0, tvec4<float, P> const & p1)
+               {
+                       return _mm_cvtss_f32(glm_vec4_distance(p0.data, p1.data));
+               }
+       };
+
+       template <precision P>
+       struct compute_dot<tvec4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static float call(tvec4<float, P> const& x, tvec4<float, P> const& y)
+               {
+                       return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data));
+               }
+       };
+
+       template <precision P>
+       struct compute_cross<float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<float, P> call(tvec3<float, P> const & a, tvec3<float, P> const & b)
+               {
+                       __m128 const set0 = _mm_set_ps(0.0f, a.z, a.y, a.x);
+                       __m128 const set1 = _mm_set_ps(0.0f, b.z, b.y, b.x);
+                       __m128 const xpd0 = glm_vec4_cross(set0, set1);
+
+                       tvec4<float, P> result(uninitialize);
+                       result.data = xpd0;
+                       return tvec3<float, P>(result);
+               }
+       };
+
+       template <precision P>
+       struct compute_normalize<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const & v)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_normalize(v.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_faceforward<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const& N, tvec4<float, P> const& I, tvec4<float, P> const& Nref)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_faceforward(N.data, I.data, Nref.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_reflect<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const& I, tvec4<float, P> const& N)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_reflect(I.data, N.data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_refract<float, P, tvec4, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<float, P> call(tvec4<float, P> const& I, tvec4<float, P> const& N, float eta)
+               {
+                       tvec4<float, P> result(uninitialize);
+                       result.data = glm_vec4_refract(I.data, N.data, _mm_set1_ps(eta));
+                       return result;
+               }
+       };
+}//namespace detail
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/detail/func_integer.hpp b/core/deps/glm/glm/detail/func_integer.hpp
new file mode 100755 (executable)
index 0000000..bd195a9
--- /dev/null
@@ -0,0 +1,203 @@
+/// @ref core
+/// @file glm/detail/func_integer.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+/// 
+/// @defgroup core_func_integer Integer functions
+/// @ingroup core
+/// 
+/// These all operate component-wise. The description is per component. 
+/// The notation [a, b] means the set of bits from bit-number a through bit-number 
+/// b, inclusive. The lowest-order bit is bit 0.
+
+#pragma once
+
+#include "setup.hpp"
+#include "precision.hpp"
+#include "func_common.hpp"
+#include "func_vector_relational.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_integer
+       /// @{
+
+       /// Adds 32-bit unsigned integer x and y, returning the sum
+       /// modulo pow(2, 32). The value carry is set to 0 if the sum was
+       /// less than pow(2, 32), or to 1 otherwise.
+       ///
+       /// @tparam genUType Unsigned integer scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/uaddCarry.xml">GLSL uaddCarry man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<uint, P> uaddCarry(
+               vecType<uint, P> const & x,
+               vecType<uint, P> const & y,
+               vecType<uint, P> & carry);
+
+       /// Subtracts the 32-bit unsigned integer y from x, returning
+       /// the difference if non-negative, or pow(2, 32) plus the difference
+       /// otherwise. The value borrow is set to 0 if x >= y, or to 1 otherwise.
+       ///
+       /// @tparam genUType Unsigned integer scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/usubBorrow.xml">GLSL usubBorrow man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<uint, P> usubBorrow(
+               vecType<uint, P> const & x,
+               vecType<uint, P> const & y,
+               vecType<uint, P> & borrow);
+
+       /// Multiplies 32-bit integers x and y, producing a 64-bit
+       /// result. The 32 least-significant bits are returned in lsb.
+       /// The 32 most-significant bits are returned in msb.
+       ///
+       /// @tparam genUType Unsigned integer scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/umulExtended.xml">GLSL umulExtended man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL void umulExtended(
+               vecType<uint, P> const & x,
+               vecType<uint, P> const & y,
+               vecType<uint, P> & msb,
+               vecType<uint, P> & lsb);
+               
+       /// Multiplies 32-bit integers x and y, producing a 64-bit
+       /// result. The 32 least-significant bits are returned in lsb.
+       /// The 32 most-significant bits are returned in msb.
+       /// 
+       /// @tparam genIType Signed integer scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/imulExtended.xml">GLSL imulExtended man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL void imulExtended(
+               vecType<int, P> const & x,
+               vecType<int, P> const & y,
+               vecType<int, P> & msb,
+               vecType<int, P> & lsb);
+
+       /// Extracts bits [offset, offset + bits - 1] from value,
+       /// returning them in the least significant bits of the result.
+       /// For unsigned data types, the most significant bits of the
+       /// result will be set to zero. For signed data types, the
+       /// most significant bits will be set to the value of bit offset + base - 1.
+       ///
+       /// If bits is zero, the result will be zero. The result will be
+       /// undefined if offset or bits is negative, or if the sum of
+       /// offset and bits is greater than the number of bits used
+       /// to store the operand.
+       ///
+       /// @tparam T Signed or unsigned integer scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldExtract.xml">GLSL bitfieldExtract man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldExtract(
+               vecType<T, P> const & Value,
+               int Offset,
+               int Bits);
+
+       /// Returns the insertion the bits least-significant bits of insert into base.
+       ///
+       /// The result will have bits [offset, offset + bits - 1] taken
+       /// from bits [0, bits - 1] of insert, and all other bits taken
+       /// directly from the corresponding bits of base. If bits is
+       /// zero, the result will simply be base. The result will be
+       /// undefined if offset or bits is negative, or if the sum of
+       /// offset and bits is greater than the number of bits used to
+       /// store the operand.
+       ///
+       /// @tparam T Signed or unsigned integer scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldInsert.xml">GLSL bitfieldInsert man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldInsert(
+               vecType<T, P> const & Base,
+               vecType<T, P> const & Insert,
+               int Offset,
+               int Bits);
+
+       /// Returns the reversal of the bits of value. 
+       /// The bit numbered n of the result will be taken from bit (bits - 1) - n of value, 
+       /// where bits is the total number of bits used to represent value.
+       ///
+       /// @tparam T Signed or unsigned integer scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/bitfieldReverse.xml">GLSL bitfieldReverse man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldReverse(vecType<T, P> const & v);
+
+       /// Returns the number of bits set to 1 in the binary representation of value.
+       ///
+       /// @tparam T Signed or unsigned integer scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/bitCount.xml">GLSL bitCount man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename genType>
+       GLM_FUNC_DECL int bitCount(genType v);
+
+       /// Returns the number of bits set to 1 in the binary representation of value.
+       ///
+       /// @tparam T Signed or unsigned integer scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/bitCount.xml">GLSL bitCount man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<int, P> bitCount(vecType<T, P> const & v);
+
+       /// Returns the bit number of the least significant bit set to
+       /// 1 in the binary representation of value. 
+       /// If value is zero, -1 will be returned.
+       ///
+       /// @tparam T Signed or unsigned integer scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/findLSB.xml">GLSL findLSB man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename genIUType>
+       GLM_FUNC_DECL int findLSB(genIUType x);
+
+       /// Returns the bit number of the least significant bit set to
+       /// 1 in the binary representation of value. 
+       /// If value is zero, -1 will be returned.
+       ///
+       /// @tparam T Signed or unsigned integer scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/findLSB.xml">GLSL findLSB man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<int, P> findLSB(vecType<T, P> const & v);
+
+       /// Returns the bit number of the most significant bit in the binary representation of value.
+       /// For positive integers, the result will be the bit number of the most significant bit set to 1. 
+       /// For negative integers, the result will be the bit number of the most significant
+       /// bit set to 0. For a value of zero or negative one, -1 will be returned.
+       ///
+       /// @tparam T Signed or unsigned integer scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/findMSB.xml">GLSL findMSB man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename genIUType>
+       GLM_FUNC_DECL int findMSB(genIUType x);
+
+       /// Returns the bit number of the most significant bit in the binary representation of value.
+       /// For positive integers, the result will be the bit number of the most significant bit set to 1. 
+       /// For negative integers, the result will be the bit number of the most significant
+       /// bit set to 0. For a value of zero or negative one, -1 will be returned.
+       ///
+       /// @tparam T Signed or unsigned integer scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/findMSB.xml">GLSL findMSB man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.8 Integer Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<int, P> findMSB(vecType<T, P> const & v);
+
+       /// @}
+}//namespace glm
+
+#include "func_integer.inl"
diff --git a/core/deps/glm/glm/detail/func_integer.inl b/core/deps/glm/glm/detail/func_integer.inl
new file mode 100755 (executable)
index 0000000..25910eb
--- /dev/null
@@ -0,0 +1,368 @@
+/// @ref core
+/// @file glm/detail/func_integer.inl
+
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+#include "type_int.hpp"
+#include "_vectorize.hpp"
+#if(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC)
+#      include <intrin.h>
+#      pragma intrinsic(_BitScanReverse)
+#endif//(GLM_ARCH & GLM_ARCH_X86 && GLM_COMPILER & GLM_COMPILER_VC)
+#include <limits>
+
+#if !GLM_HAS_EXTENDED_INTEGER_TYPE
+#      if GLM_COMPILER & GLM_COMPILER_GCC
+#              pragma GCC diagnostic ignored "-Wlong-long"
+#      endif
+#      if (GLM_COMPILER & GLM_COMPILER_CLANG)
+#              pragma clang diagnostic ignored "-Wc++11-long-long"
+#      endif
+#endif
+
+namespace glm{
+namespace detail
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER T mask(T Bits)
+       {
+               return Bits >= sizeof(T) * 8 ? ~static_cast<T>(0) : (static_cast<T>(1) << Bits) - static_cast<T>(1);
+       }
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType, bool Aligned, bool EXEC>
+       struct compute_bitfieldReverseStep
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T, T)
+               {
+                       return v;
+               }
+       };
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType, bool Aligned>
+       struct compute_bitfieldReverseStep<T, P, vecType, Aligned, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T Mask, T Shift)
+               {
+                       return (v & Mask) << Shift | (v & (~Mask)) >> Shift;
+               }
+       };
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType, bool Aligned, bool EXEC>
+       struct compute_bitfieldBitCountStep
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T, T)
+               {
+                       return v;
+               }
+       };
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType, bool Aligned>
+       struct compute_bitfieldBitCountStep<T, P, vecType, Aligned, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T Mask, T Shift)
+               {
+                       return (v & Mask) + ((v >> Shift) & Mask);
+               }
+       };
+
+       template <typename genIUType, size_t Bits>
+       struct compute_findLSB
+       {
+               GLM_FUNC_QUALIFIER static int call(genIUType Value)
+               {
+                       if(Value == 0)
+                               return -1;
+
+                       return glm::bitCount(~Value & (Value - static_cast<genIUType>(1)));
+               }
+       };
+
+#      if GLM_HAS_BITSCAN_WINDOWS
+               template <typename genIUType>
+               struct compute_findLSB<genIUType, 32>
+               {
+                       GLM_FUNC_QUALIFIER static int call(genIUType Value)
+                       {
+                               unsigned long Result(0);
+                               unsigned char IsNotNull = _BitScanForward(&Result, *reinterpret_cast<unsigned long*>(&Value));
+                               return IsNotNull ? int(Result) : -1;
+                       }
+               };
+
+#              if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32))
+               template <typename genIUType>
+               struct compute_findLSB<genIUType, 64>
+               {
+                       GLM_FUNC_QUALIFIER static int call(genIUType Value)
+                       {
+                               unsigned long Result(0);
+                               unsigned char IsNotNull = _BitScanForward64(&Result, *reinterpret_cast<unsigned __int64*>(&Value));
+                               return IsNotNull ? int(Result) : -1;
+                       }
+               };
+#              endif
+#      endif//GLM_HAS_BITSCAN_WINDOWS
+
+       template <typename T, glm::precision P, template <class, glm::precision> class vecType, bool EXEC = true>
+       struct compute_findMSB_step_vec
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, T Shift)
+               {
+                       return x | (x >> Shift);
+               }
+       };
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType>
+       struct compute_findMSB_step_vec<T, P, vecType, false>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x, T)
+               {
+                       return x;
+               }
+       };
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType, int>
+       struct compute_findMSB_vec
+       {
+               GLM_FUNC_QUALIFIER static vecType<int, P> call(vecType<T, P> const & vec)
+               {
+                       vecType<T, P> x(vec);
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 1));
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 2));
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >=  8>::call(x, static_cast<T>( 4));
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >= 16>::call(x, static_cast<T>( 8));
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >= 32>::call(x, static_cast<T>(16));
+                       x = compute_findMSB_step_vec<T, P, vecType, sizeof(T) * 8 >= 64>::call(x, static_cast<T>(32));
+                       return vecType<int, P>(sizeof(T) * 8 - 1) - glm::bitCount(~x);
+               }
+       };
+
+#      if GLM_HAS_BITSCAN_WINDOWS
+               template <typename genIUType>
+               GLM_FUNC_QUALIFIER int compute_findMSB_32(genIUType Value)
+               {
+                       unsigned long Result(0);
+                       unsigned char IsNotNull = _BitScanReverse(&Result, *reinterpret_cast<unsigned long*>(&Value));
+                       return IsNotNull ? int(Result) : -1;
+               }
+
+               template <typename T, glm::precision P, template<typename, glm::precision> class vecType>
+               struct compute_findMSB_vec<T, P, vecType, 32>
+               {
+                       GLM_FUNC_QUALIFIER static vecType<int, P> call(vecType<T, P> const & x)
+                       {
+                               return detail::functor1<int, T, P, vecType>::call(compute_findMSB_32, x);
+                       }
+               };
+
+#              if !((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_MODEL == GLM_MODEL_32))
+               template <typename genIUType>
+               GLM_FUNC_QUALIFIER int compute_findMSB_64(genIUType Value)
+               {
+                       unsigned long Result(0);
+                       unsigned char IsNotNull = _BitScanReverse64(&Result, *reinterpret_cast<unsigned __int64*>(&Value));
+                       return IsNotNull ? int(Result) : -1;
+               }
+
+               template <typename T, glm::precision P, template <class, glm::precision> class vecType>
+               struct compute_findMSB_vec<T, P, vecType, 64>
+               {
+                       GLM_FUNC_QUALIFIER static vecType<int, P> call(vecType<T, P> const & x)
+                       {
+                               return detail::functor1<int, T, P, vecType>::call(compute_findMSB_64, x);
+                       }
+               };
+#              endif
+#      endif//GLM_HAS_BITSCAN_WINDOWS
+}//namespace detail
+
+       // uaddCarry
+       GLM_FUNC_QUALIFIER uint uaddCarry(uint const & x, uint const & y, uint & Carry)
+       {
+               uint64 const Value64(static_cast<uint64>(x) + static_cast<uint64>(y));
+               uint64 const Max32((static_cast<uint64>(1) << static_cast<uint64>(32)) - static_cast<uint64>(1));
+               Carry = Value64 > Max32 ? 1u : 0u;
+               return static_cast<uint32>(Value64 % (Max32 + static_cast<uint64>(1)));
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uint, P> uaddCarry(vecType<uint, P> const & x, vecType<uint, P> const & y, vecType<uint, P> & Carry)
+       {
+               vecType<uint64, P> Value64(vecType<uint64, P>(x) + vecType<uint64, P>(y));
+               vecType<uint64, P> Max32((static_cast<uint64>(1) << static_cast<uint64>(32)) - static_cast<uint64>(1));
+               Carry = mix(vecType<uint32, P>(0), vecType<uint32, P>(1), greaterThan(Value64, Max32));
+               return vecType<uint32,P>(Value64 % (Max32 + static_cast<uint64>(1)));
+       }
+
+       // usubBorrow
+       GLM_FUNC_QUALIFIER uint usubBorrow(uint const & x, uint const & y, uint & Borrow)
+       {
+               GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch");
+
+               Borrow = x >= y ? static_cast<uint32>(0) : static_cast<uint32>(1);
+               if(y >= x)
+                       return y - x;
+               else
+                       return static_cast<uint32>((static_cast<int64>(1) << static_cast<int64>(32)) + (static_cast<int64>(y) - static_cast<int64>(x)));
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uint, P> usubBorrow(vecType<uint, P> const & x, vecType<uint, P> const & y, vecType<uint, P> & Borrow)
+       {
+               Borrow = mix(vecType<uint, P>(1), vecType<uint, P>(0), greaterThanEqual(x, y));
+               vecType<uint, P> const YgeX(y - x);
+               vecType<uint, P> const XgeY(vecType<uint32, P>((static_cast<int64>(1) << static_cast<int64>(32)) + (vecType<int64, P>(y) - vecType<int64, P>(x))));
+               return mix(XgeY, YgeX, greaterThanEqual(y, x));
+       }
+
+       // umulExtended
+       GLM_FUNC_QUALIFIER void umulExtended(uint const & x, uint const & y, uint & msb, uint & lsb)
+       {
+               GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch");
+
+               uint64 Value64 = static_cast<uint64>(x) * static_cast<uint64>(y);
+               msb = static_cast<uint>(Value64 >> static_cast<uint64>(32));
+               lsb = static_cast<uint>(Value64);
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER void umulExtended(vecType<uint, P> const & x, vecType<uint, P> const & y, vecType<uint, P> & msb, vecType<uint, P> & lsb)
+       {
+               GLM_STATIC_ASSERT(sizeof(uint) == sizeof(uint32), "uint and uint32 size mismatch");
+
+               vecType<uint64, P> Value64(vecType<uint64, P>(x) * vecType<uint64, P>(y));
+               msb = vecType<uint32, P>(Value64 >> static_cast<uint64>(32));
+               lsb = vecType<uint32, P>(Value64);
+       }
+
+       // imulExtended
+       GLM_FUNC_QUALIFIER void imulExtended(int x, int y, int & msb, int & lsb)
+       {
+               GLM_STATIC_ASSERT(sizeof(int) == sizeof(int32), "int and int32 size mismatch");
+
+               int64 Value64 = static_cast<int64>(x) * static_cast<int64>(y);
+               msb = static_cast<int>(Value64 >> static_cast<int64>(32));
+               lsb = static_cast<int>(Value64);
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER void imulExtended(vecType<int, P> const & x, vecType<int, P> const & y, vecType<int, P> & msb, vecType<int, P> & lsb)
+       {
+               GLM_STATIC_ASSERT(sizeof(int) == sizeof(int32), "int and int32 size mismatch");
+
+               vecType<int64, P> Value64(vecType<int64, P>(x) * vecType<int64, P>(y));
+               lsb = vecType<int32, P>(Value64 & static_cast<int64>(0xFFFFFFFF));
+               msb = vecType<int32, P>((Value64 >> static_cast<int64>(32)) & static_cast<int64>(0xFFFFFFFF));
+       }
+
+       // bitfieldExtract
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType bitfieldExtract(genIUType Value, int Offset, int Bits)
+       {
+               return bitfieldExtract(tvec1<genIUType>(Value), Offset, Bits).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldExtract(vecType<T, P> const & Value, int Offset, int Bits)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'bitfieldExtract' only accept integer inputs");
+
+               return (Value >> static_cast<T>(Offset)) & static_cast<T>(detail::mask(Bits));
+       }
+
+       // bitfieldInsert
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType bitfieldInsert(genIUType const & Base, genIUType const & Insert, int Offset, int Bits)
+       {
+               return bitfieldInsert(tvec1<genIUType>(Base), tvec1<genIUType>(Insert), Offset, Bits).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldInsert(vecType<T, P> const & Base, vecType<T, P> const & Insert, int Offset, int Bits)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'bitfieldInsert' only accept integer values");
+
+               T const Mask = static_cast<T>(detail::mask(Bits) << Offset);
+               return (Base & ~Mask) | (Insert & Mask);
+       }
+
+       // bitfieldReverse
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType bitfieldReverse(genType x)
+       {
+               return bitfieldReverse(glm::tvec1<genType, glm::defaultp>(x)).x;
+       }
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldReverse(vecType<T, P> const & v)
+       {
+               vecType<T, P> x(v);
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  2>::call(x, T(0x5555555555555555ull), static_cast<T>( 1));
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  4>::call(x, T(0x3333333333333333ull), static_cast<T>( 2));
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  8>::call(x, T(0x0F0F0F0F0F0F0F0Full), static_cast<T>( 4));
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 16>::call(x, T(0x00FF00FF00FF00FFull), static_cast<T>( 8));
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 32>::call(x, T(0x0000FFFF0000FFFFull), static_cast<T>(16));
+               x = detail::compute_bitfieldReverseStep<T, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 64>::call(x, T(0x00000000FFFFFFFFull), static_cast<T>(32));
+               return x;
+       }
+
+       // bitCount
+       template <typename genType>
+       GLM_FUNC_QUALIFIER int bitCount(genType x)
+       {
+               return bitCount(glm::tvec1<genType, glm::defaultp>(x)).x;
+       }
+
+       template <typename T, glm::precision P, template <typename, glm::precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<int, P> bitCount(vecType<T, P> const & v)
+       {
+               vecType<typename detail::make_unsigned<T>::type, P> x(*reinterpret_cast<vecType<typename detail::make_unsigned<T>::type, P> const *>(&v));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  2>::call(x, typename detail::make_unsigned<T>::type(0x5555555555555555ull), typename detail::make_unsigned<T>::type( 1));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  4>::call(x, typename detail::make_unsigned<T>::type(0x3333333333333333ull), typename detail::make_unsigned<T>::type( 2));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>=  8>::call(x, typename detail::make_unsigned<T>::type(0x0F0F0F0F0F0F0F0Full), typename detail::make_unsigned<T>::type( 4));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 16>::call(x, typename detail::make_unsigned<T>::type(0x00FF00FF00FF00FFull), typename detail::make_unsigned<T>::type( 8));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 32>::call(x, typename detail::make_unsigned<T>::type(0x0000FFFF0000FFFFull), typename detail::make_unsigned<T>::type(16));
+               x = detail::compute_bitfieldBitCountStep<typename detail::make_unsigned<T>::type, P, vecType, detail::is_aligned<P>::value, sizeof(T) * 8>= 64>::call(x, typename detail::make_unsigned<T>::type(0x00000000FFFFFFFFull), typename detail::make_unsigned<T>::type(32));
+               return vecType<int, P>(x);
+       }
+
+       // findLSB
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER int findLSB(genIUType Value)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findLSB' only accept integer values");
+
+               return detail::compute_findLSB<genIUType, sizeof(genIUType) * 8>::call(Value);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<int, P> findLSB(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'findLSB' only accept integer values");
+
+               return detail::functor1<int, T, P, vecType>::call(findLSB, x);
+       }
+
+       // findMSB
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER int findMSB(genIUType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'findMSB' only accept integer values");
+
+               return findMSB(tvec1<genIUType>(x)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<int, P> findMSB(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'findMSB' only accept integer values");
+
+               return detail::compute_findMSB_vec<T, P, vecType, sizeof(T) * 8>::call(x);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_integer_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/detail/func_integer_simd.inl b/core/deps/glm/glm/detail/func_integer_simd.inl
new file mode 100755 (executable)
index 0000000..6175860
--- /dev/null
@@ -0,0 +1,68 @@
+/// @ref core
+/// @file glm/detail/func_integer_simd.inl
+
+#include "../simd/integer.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+namespace glm{
+namespace detail
+{
+       template <glm::precision P>
+       struct compute_bitfieldReverseStep<uint32, P, tvec4, true, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint32, P> call(tvec4<uint32, P> const & v, uint32 Mask, uint32 Shift)
+               {
+                       __m128i const set0 = v.data;
+
+                       __m128i const set1 = _mm_set1_epi32(Mask);
+                       __m128i const and1 = _mm_and_si128(set0, set1);
+                       __m128i const sft1 = _mm_slli_epi32(and1, Shift);
+
+                       __m128i const set2 = _mm_andnot_si128(set0, _mm_set1_epi32(-1));
+                       __m128i const and2 = _mm_and_si128(set0, set2);
+                       __m128i const sft2 = _mm_srai_epi32(and2, Shift);
+               
+                       __m128i const or0 = _mm_or_si128(sft1, sft2);
+               
+                       return or0;
+               }
+       };
+
+       template <glm::precision P>
+       struct compute_bitfieldBitCountStep<uint32, P, tvec4, true, true>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint32, P> call(tvec4<uint32, P> const & v, uint32 Mask, uint32 Shift)
+               {
+                       __m128i const set0 = v.data;
+
+                       __m128i const set1 = _mm_set1_epi32(Mask);
+                       __m128i const and0 = _mm_and_si128(set0, set1);
+                       __m128i const sft0 = _mm_slli_epi32(set0, Shift);
+                       __m128i const and1 = _mm_and_si128(sft0, set1);
+                       __m128i const add0 = _mm_add_epi32(and0, and1);
+               
+                       return add0;
+               }
+       };
+}//namespace detail
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <>
+       GLM_FUNC_QUALIFIER int bitCount(uint32 x)
+       {
+               return _mm_popcnt_u32(x);
+       }
+
+#      if(GLM_MODEL == GLM_MODEL_64)
+       template <>
+       GLM_FUNC_QUALIFIER int bitCount(uint64 x)
+       {
+               return static_cast<int>(_mm_popcnt_u64(x));
+       }
+#      endif//GLM_MODEL
+#      endif//GLM_ARCH
+
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/detail/func_matrix.hpp b/core/deps/glm/glm/detail/func_matrix.hpp
new file mode 100755 (executable)
index 0000000..9be3449
--- /dev/null
@@ -0,0 +1,149 @@
+/// @ref core
+/// @file glm/detail/func_matrix.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>
+/// 
+/// @defgroup core_func_matrix Matrix functions
+/// @ingroup core
+/// 
+/// For each of the following built-in matrix functions, there is both a 
+/// single-precision floating point version, where all arguments and return values 
+/// are single precision, and a double-precision floating version, where all 
+/// arguments and return values are double precision. Only the single-precision 
+/// floating point version is shown.
+
+#pragma once
+
+// Dependencies
+#include "../detail/precision.hpp"
+#include "../detail/setup.hpp"
+#include "../detail/type_mat.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../mat2x2.hpp"
+#include "../mat2x3.hpp"
+#include "../mat2x4.hpp"
+#include "../mat3x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat3x4.hpp"
+#include "../mat4x2.hpp"
+#include "../mat4x3.hpp"
+#include "../mat4x4.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec2, tvec2>
+       {
+               typedef tmat2x2<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec2, tvec3>
+       {
+               typedef tmat3x2<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec2, tvec4>
+       {
+               typedef tmat4x2<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec3, tvec2>
+       {
+               typedef tmat2x3<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec3, tvec3>
+       {
+               typedef tmat3x3<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec3, tvec4>
+       {
+               typedef tmat4x3<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec4, tvec2>
+       {
+               typedef tmat2x4<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec4, tvec3>
+       {
+               typedef tmat3x4<T, P> type;
+       };
+
+       template <typename T, precision P>
+       struct outerProduct_trait<T, P, tvec4, tvec4>
+       {
+               typedef tmat4x4<T, P> type;
+       };
+
+}//namespace detail
+
+       /// @addtogroup core_func_matrix
+       /// @{
+
+       /// Multiply matrix x by matrix y component-wise, i.e., 
+       /// result[i][j] is the scalar product of x[i][j] and y[i][j].
+       /// 
+       /// @tparam matType Floating-point matrix types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/matrixCompMult.xml">GLSL matrixCompMult man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL matType<T, P> matrixCompMult(matType<T, P> const & x, matType<T, P> const & y);
+
+       /// Treats the first parameter c as a column vector
+       /// and the second parameter r as a row vector
+       /// and does a linear algebraic matrix multiply c * r.
+       /// 
+       /// @tparam matType Floating-point matrix types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/outerProduct.xml">GLSL outerProduct man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecTypeA, template <typename, precision> class vecTypeB>
+       GLM_FUNC_DECL typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type outerProduct(vecTypeA<T, P> const & c, vecTypeB<T, P> const & r);
+
+       /// Returns the transposed matrix of x
+       /// 
+       /// @tparam matType Floating-point matrix types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/transpose.xml">GLSL transpose man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>
+#      if((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC11))
+               template <typename T, precision P, template <typename, precision> class matType>
+               GLM_FUNC_DECL typename matType<T, P>::transpose_type transpose(matType<T, P> const & x);
+#      endif
+       
+       /// Return the determinant of a squared matrix.
+       /// 
+       /// @tparam valType Floating-point scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/determinant.xml">GLSL determinant man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>        
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL T determinant(matType<T, P> const & m);
+
+       /// Return the inverse of a squared matrix.
+       /// 
+       /// @tparam valType Floating-point scalar types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/inverse.xml">GLSL inverse man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.6 Matrix Functions</a>         
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL matType<T, P> inverse(matType<T, P> const & m);
+
+       /// @}
+}//namespace glm
+
+#include "func_matrix.inl"
diff --git a/core/deps/glm/glm/detail/func_matrix.inl b/core/deps/glm/glm/detail/func_matrix.inl
new file mode 100755 (executable)
index 0000000..6d1746b
--- /dev/null
@@ -0,0 +1,401 @@
+/// @ref core
+/// @file glm/detail/func_matrix.inl
+
+#include "../geometric.hpp"
+#include <limits>
+
+namespace glm{
+namespace detail
+{
+       template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
+       struct compute_matrixCompMult
+       {
+               GLM_FUNC_QUALIFIER static matType<T, P> call(matType<T, P> const& x, matType<T, P> const& y)
+               {
+                       matType<T, P> result(uninitialize);
+                       for(length_t i = 0; i < result.length(); ++i)
+                               result[i] = x[i] * y[i];
+                       return result;
+               }
+       };
+
+       template <template <class, precision> class matType, typename T, precision P, bool Aligned>
+       struct compute_transpose{};
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat2x2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat2x2<T, P> call(tmat2x2<T, P> const & m)
+               {
+                       tmat2x2<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat2x3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat3x2<T, P> call(tmat2x3<T, P> const & m)
+               {
+                       tmat3x2<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat2x4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x2<T, P> call(tmat2x4<T, P> const & m)
+               {
+                       tmat4x2<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       result[3][0] = m[0][3];
+                       result[3][1] = m[1][3];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat3x2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat2x3<T, P> call(tmat3x2<T, P> const & m)
+               {
+                       tmat2x3<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat3x3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat3x3<T, P> call(tmat3x3<T, P> const & m)
+               {
+                       tmat3x3<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       result[2][2] = m[2][2];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat3x4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x3<T, P> call(tmat3x4<T, P> const & m)
+               {
+                       tmat4x3<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       result[2][2] = m[2][2];
+                       result[3][0] = m[0][3];
+                       result[3][1] = m[1][3];
+                       result[3][2] = m[2][3];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat4x2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat2x4<T, P> call(tmat4x2<T, P> const & m)
+               {
+                       tmat2x4<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+                       result[0][3] = m[3][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+                       result[1][3] = m[3][1];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat4x3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat3x4<T, P> call(tmat4x3<T, P> const & m)
+               {
+                       tmat3x4<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+                       result[0][3] = m[3][0];
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+                       result[1][3] = m[3][1];
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       result[2][2] = m[2][2];
+                       result[2][3] = m[3][2];
+                       return result;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_transpose<tmat4x4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x4<T, P> call(tmat4x4<T, P> const & m)
+               {
+                       tmat4x4<T, P> result(uninitialize);
+                       result[0][0] = m[0][0];
+                       result[0][1] = m[1][0];
+                       result[0][2] = m[2][0];
+                       result[0][3] = m[3][0];
+
+                       result[1][0] = m[0][1];
+                       result[1][1] = m[1][1];
+                       result[1][2] = m[2][1];
+                       result[1][3] = m[3][1];
+
+                       result[2][0] = m[0][2];
+                       result[2][1] = m[1][2];
+                       result[2][2] = m[2][2];
+                       result[2][3] = m[3][2];
+
+                       result[3][0] = m[0][3];
+                       result[3][1] = m[1][3];
+                       result[3][2] = m[2][3];
+                       result[3][3] = m[3][3];
+                       return result;
+               }
+       };
+
+       template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
+       struct compute_determinant{};
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_determinant<tmat2x2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tmat2x2<T, P> const & m)
+               {
+                       return m[0][0] * m[1][1] - m[1][0] * m[0][1];
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_determinant<tmat3x3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tmat3x3<T, P> const & m)
+               {
+                       return
+                               + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
+                               - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
+                               + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_determinant<tmat4x4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static T call(tmat4x4<T, P> const & m)
+               {
+                       T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+                       T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+                       T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+                       T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+                       T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+                       T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+
+                       tvec4<T, P> DetCof(
+                               + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),
+                               - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),
+                               + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),
+                               - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));
+
+                       return
+                               m[0][0] * DetCof[0] + m[0][1] * DetCof[1] +
+                               m[0][2] * DetCof[2] + m[0][3] * DetCof[3];
+               }
+       };
+
+       template <template <typename, precision> class matType, typename T, precision P, bool Aligned>
+       struct compute_inverse{};
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_inverse<tmat2x2, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat2x2<T, P> call(tmat2x2<T, P> const& m)
+               {
+                       T OneOverDeterminant = static_cast<T>(1) / (
+                               + m[0][0] * m[1][1]
+                               - m[1][0] * m[0][1]);
+
+                       tmat2x2<T, P> Inverse(
+                               + m[1][1] * OneOverDeterminant,
+                               - m[0][1] * OneOverDeterminant,
+                               - m[1][0] * OneOverDeterminant,
+                               + m[0][0] * OneOverDeterminant);
+
+                       return Inverse;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_inverse<tmat3x3, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat3x3<T, P> call(tmat3x3<T, P> const& m)
+               {
+                       T OneOverDeterminant = static_cast<T>(1) / (
+                               + m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2])
+                               - m[1][0] * (m[0][1] * m[2][2] - m[2][1] * m[0][2])
+                               + m[2][0] * (m[0][1] * m[1][2] - m[1][1] * m[0][2]));
+
+                       tmat3x3<T, P> Inverse(uninitialize);
+                       Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]) * OneOverDeterminant;
+                       Inverse[1][0] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]) * OneOverDeterminant;
+                       Inverse[2][0] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]) * OneOverDeterminant;
+                       Inverse[0][1] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]) * OneOverDeterminant;
+                       Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]) * OneOverDeterminant;
+                       Inverse[2][1] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]) * OneOverDeterminant;
+                       Inverse[0][2] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]) * OneOverDeterminant;
+                       Inverse[1][2] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]) * OneOverDeterminant;
+                       Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]) * OneOverDeterminant;
+
+                       return Inverse;
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_inverse<tmat4x4, T, P, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x4<T, P> call(tmat4x4<T, P> const& m)
+               {
+                       T Coef00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+                       T Coef02 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+                       T Coef03 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+
+                       T Coef04 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+                       T Coef06 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+                       T Coef07 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+
+                       T Coef08 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+                       T Coef10 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+                       T Coef11 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+
+                       T Coef12 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+                       T Coef14 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+                       T Coef15 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+
+                       T Coef16 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+                       T Coef18 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+                       T Coef19 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+
+                       T Coef20 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+                       T Coef22 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+                       T Coef23 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+                       tvec4<T, P> Fac0(Coef00, Coef00, Coef02, Coef03);
+                       tvec4<T, P> Fac1(Coef04, Coef04, Coef06, Coef07);
+                       tvec4<T, P> Fac2(Coef08, Coef08, Coef10, Coef11);
+                       tvec4<T, P> Fac3(Coef12, Coef12, Coef14, Coef15);
+                       tvec4<T, P> Fac4(Coef16, Coef16, Coef18, Coef19);
+                       tvec4<T, P> Fac5(Coef20, Coef20, Coef22, Coef23);
+
+                       tvec4<T, P> Vec0(m[1][0], m[0][0], m[0][0], m[0][0]);
+                       tvec4<T, P> Vec1(m[1][1], m[0][1], m[0][1], m[0][1]);
+                       tvec4<T, P> Vec2(m[1][2], m[0][2], m[0][2], m[0][2]);
+                       tvec4<T, P> Vec3(m[1][3], m[0][3], m[0][3], m[0][3]);
+
+                       tvec4<T, P> Inv0(Vec1 * Fac0 - Vec2 * Fac1 + Vec3 * Fac2);
+                       tvec4<T, P> Inv1(Vec0 * Fac0 - Vec2 * Fac3 + Vec3 * Fac4);
+                       tvec4<T, P> Inv2(Vec0 * Fac1 - Vec1 * Fac3 + Vec3 * Fac5);
+                       tvec4<T, P> Inv3(Vec0 * Fac2 - Vec1 * Fac4 + Vec2 * Fac5);
+
+                       tvec4<T, P> SignA(+1, -1, +1, -1);
+                       tvec4<T, P> SignB(-1, +1, -1, +1);
+                       tmat4x4<T, P> Inverse(Inv0 * SignA, Inv1 * SignB, Inv2 * SignA, Inv3 * SignB);
+
+                       tvec4<T, P> Row0(Inverse[0][0], Inverse[1][0], Inverse[2][0], Inverse[3][0]);
+
+                       tvec4<T, P> Dot0(m[0] * Row0);
+                       T Dot1 = (Dot0.x + Dot0.y) + (Dot0.z + Dot0.w);
+
+                       T OneOverDeterminant = static_cast<T>(1) / Dot1;
+
+                       return Inverse * OneOverDeterminant;
+               }
+       };
+}//namespace detail
+
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER matType<T, P> matrixCompMult(matType<T, P> const & x, matType<T, P> const & y)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'matrixCompMult' only accept floating-point inputs");
+               return detail::compute_matrixCompMult<matType, T, P, detail::is_aligned<P>::value>::call(x, y);
+       }
+
+       template<typename T, precision P, template <typename, precision> class vecTypeA, template <typename, precision> class vecTypeB>
+       GLM_FUNC_QUALIFIER typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type outerProduct(vecTypeA<T, P> const & c, vecTypeB<T, P> const & r)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'outerProduct' only accept floating-point inputs");
+
+               typename detail::outerProduct_trait<T, P, vecTypeA, vecTypeB>::type m(uninitialize);
+               for(length_t i = 0; i < m.length(); ++i)
+                       m[i] = c * r[i];
+               return m;
+       }
+
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER typename matType<T, P>::transpose_type transpose(matType<T, P> const & m)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'transpose' only accept floating-point inputs");
+               return detail::compute_transpose<matType, T, P, detail::is_aligned<P>::value>::call(m);
+       }
+
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER T determinant(matType<T, P> const & m)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'determinant' only accept floating-point inputs");
+               return detail::compute_determinant<matType, T, P, detail::is_aligned<P>::value>::call(m);
+       }
+
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER matType<T, P> inverse(matType<T, P> const & m)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559 || GLM_UNRESTRICTED_GENTYPE, "'inverse' only accept floating-point inputs");
+               return detail::compute_inverse<matType, T, P, detail::is_aligned<P>::value>::call(m);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_matrix_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/detail/func_matrix_simd.inl b/core/deps/glm/glm/detail/func_matrix_simd.inl
new file mode 100755 (executable)
index 0000000..61b0a5b
--- /dev/null
@@ -0,0 +1,88 @@
+/// @ref core
+/// @file glm/detail/func_matrix_simd.inl
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+#include "type_mat4x4.hpp"
+#include "func_geometric.hpp"
+#include "../simd/matrix.h"
+
+namespace glm{
+namespace detail
+{
+       template <precision P>
+       struct compute_matrixCompMult<tmat4x4, float, P, true>
+       {
+               GLM_STATIC_ASSERT(detail::is_aligned<P>::value, "Specialization requires aligned");
+
+               GLM_FUNC_QUALIFIER static tmat4x4<float, P> call(tmat4x4<float, P> const & x, tmat4x4<float, P> const & y)
+               {
+                       tmat4x4<float, P> result(uninitialize);
+                       glm_mat4_matrixCompMult(
+                               *(glm_vec4 const (*)[4])&x[0].data,
+                               *(glm_vec4 const (*)[4])&y[0].data,
+                               *(glm_vec4(*)[4])&result[0].data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_transpose<tmat4x4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x4<float, P> call(tmat4x4<float, P> const & m)
+               {
+                       tmat4x4<float, P> result(uninitialize);
+                       glm_mat4_transpose(
+                               *(glm_vec4 const (*)[4])&m[0].data,
+                               *(glm_vec4(*)[4])&result[0].data);
+                       return result;
+               }
+       };
+
+       template <precision P>
+       struct compute_determinant<tmat4x4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static float call(tmat4x4<float, P> const& m)
+               {
+                       return _mm_cvtss_f32(glm_mat4_determinant(*reinterpret_cast<__m128 const(*)[4]>(&m[0].data)));
+               }
+       };
+
+       template <precision P>
+       struct compute_inverse<tmat4x4, float, P, true>
+       {
+               GLM_FUNC_QUALIFIER static tmat4x4<float, P> call(tmat4x4<float, P> const& m)
+               {
+                       tmat4x4<float, P> Result(uninitialize);
+                       glm_mat4_inverse(*reinterpret_cast<__m128 const(*)[4]>(&m[0].data), *reinterpret_cast<__m128(*)[4]>(&Result[0].data));
+                       return Result;
+               }
+       };
+}//namespace detail
+
+       template<>
+       GLM_FUNC_QUALIFIER tmat4x4<float, aligned_lowp> outerProduct<float, aligned_lowp, tvec4, tvec4>(tvec4<float, aligned_lowp> const & c, tvec4<float, aligned_lowp> const & r)
+       {
+               tmat4x4<float, aligned_lowp> m(uninitialize);
+               glm_mat4_outerProduct(c.data, r.data, *reinterpret_cast<__m128(*)[4]>(&m[0].data));
+               return m;
+       }
+
+       template<>
+       GLM_FUNC_QUALIFIER tmat4x4<float, aligned_mediump> outerProduct<float, aligned_mediump, tvec4, tvec4>(tvec4<float, aligned_mediump> const & c, tvec4<float, aligned_mediump> const & r)
+       {
+               tmat4x4<float, aligned_mediump> m(uninitialize);
+               glm_mat4_outerProduct(c.data, r.data, *reinterpret_cast<__m128(*)[4]>(&m[0].data));
+               return m;
+       }
+
+       template<>
+       GLM_FUNC_QUALIFIER tmat4x4<float, aligned_highp> outerProduct<float, aligned_highp, tvec4, tvec4>(tvec4<float, aligned_highp> const & c, tvec4<float, aligned_highp> const & r)
+       {
+               tmat4x4<float, aligned_highp> m(uninitialize);
+               glm_mat4_outerProduct(c.data, r.data, *reinterpret_cast<__m128(*)[4]>(&m[0].data));
+               return m;
+       }
+}//namespace glm
+
+#endif
diff --git a/core/deps/glm/glm/detail/func_packing.hpp b/core/deps/glm/glm/detail/func_packing.hpp
new file mode 100755 (executable)
index 0000000..47e074b
--- /dev/null
@@ -0,0 +1,168 @@
+/// @ref core
+/// @file glm/detail/func_packing.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+/// @see gtc_packing
+///
+/// @defgroup core_func_packing Floating-Point Pack and Unpack Functions
+/// @ingroup core
+///
+/// These functions do not operate component-wise, rather as described in each case.
+
+#pragma once
+
+#include "type_vec2.hpp"
+#include "type_vec4.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_packing
+       /// @{
+
+       /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. 
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       /// 
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm2x16: round(clamp(c, 0, +1) * 65535.0) 
+       /// 
+       /// The first component of the vector will be written to the least significant bits of the output; 
+       /// the last component will be written to the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm2x16.xml">GLSL packUnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint packUnorm2x16(vec2 const & v);
+
+       /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. 
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       /// 
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packSnorm2x16: round(clamp(v, -1, +1) * 32767.0)
+       /// 
+       /// The first component of the vector will be written to the least significant bits of the output; 
+       /// the last component will be written to the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm2x16.xml">GLSL packSnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint packSnorm2x16(vec2 const & v);
+
+       /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. 
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       /// 
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm4x8:       round(clamp(c, 0, +1) * 255.0)
+       /// 
+       /// The first component of the vector will be written to the least significant bits of the output; 
+       /// the last component will be written to the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml">GLSL packUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint packUnorm4x8(vec4 const & v);
+
+       /// First, converts each component of the normalized floating-point value v into 8- or 16-bit integer values. 
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       /// 
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packSnorm4x8:       round(clamp(c, -1, +1) * 127.0) 
+       /// 
+       /// The first component of the vector will be written to the least significant bits of the output; 
+       /// the last component will be written to the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml">GLSL packSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint packSnorm4x8(vec4 const & v);
+
+       /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnorm2x16: f / 65535.0 
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml">GLSL unpackUnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec2 unpackUnorm2x16(uint p);
+
+       /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm2x16: clamp(f / 32767.0, -1, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm2x16.xml">GLSL unpackSnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec2 unpackSnorm2x16(uint p);
+
+       /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnorm4x8: f / 255.0
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml">GLSL unpackUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec4 unpackUnorm4x8(uint p);
+
+       /// First, unpacks a single 32-bit unsigned integer p into a pair of 16-bit unsigned integers, four 8-bit unsigned integers, or four 8-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two- or four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm4x8: clamp(f / 127.0, -1, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml">GLSL unpackSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec4 unpackSnorm4x8(uint p);
+
+       /// Returns a double-precision value obtained by packing the components of v into a 64-bit value. 
+       /// If an IEEE 754 Inf or NaN is created, it will not signal, and the resulting floating point value is unspecified. 
+       /// Otherwise, the bit- level representation of v is preserved. 
+       /// The first vector component specifies the 32 least significant bits; 
+       /// the second component specifies the 32 most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packDouble2x32.xml">GLSL packDouble2x32 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL double packDouble2x32(uvec2 const & v);
+
+       /// Returns a two-component unsigned integer vector representation of v. 
+       /// The bit-level representation of v is preserved. 
+       /// The first component of the vector contains the 32 least significant bits of the double; 
+       /// the second component consists the 32 most significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackDouble2x32.xml">GLSL unpackDouble2x32 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uvec2 unpackDouble2x32(double v);
+
+       /// Returns an unsigned integer obtained by converting the components of a two-component floating-point vector 
+       /// to the 16-bit floating-point representation found in the OpenGL Specification, 
+       /// and then packing these two 16- bit integers into a 32-bit unsigned integer.
+       /// The first vector component specifies the 16 least-significant bits of the result; 
+       /// the second component specifies the 16 most-significant bits.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml">GLSL packHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint packHalf2x16(vec2 const & v);
+       
+       /// Returns a two-component floating-point vector with components obtained by unpacking a 32-bit unsigned integer into a pair of 16-bit values, 
+       /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, 
+       /// and converting them to 32-bit floating-point values.
+       /// The first component of the vector is obtained from the 16 least-significant bits of v; 
+       /// the second component is obtained from the 16 most-significant bits of v.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml">GLSL unpackHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec2 unpackHalf2x16(uint v);
+       
+       /// @}
+}//namespace glm
+
+#include "func_packing.inl"
diff --git a/core/deps/glm/glm/detail/func_packing.inl b/core/deps/glm/glm/detail/func_packing.inl
new file mode 100755 (executable)
index 0000000..505c80a
--- /dev/null
@@ -0,0 +1,190 @@
+/// @ref core
+/// @file glm/detail/func_packing.inl
+
+#include "func_common.hpp"
+#include "type_half.hpp"
+#include "../fwd.hpp"
+
+namespace glm
+{
+       GLM_FUNC_QUALIFIER uint packUnorm2x16(vec2 const & v)
+       {
+               union
+               {
+                       u16  in[2];
+                       uint out;
+               } u;
+
+               u16vec2 result(round(clamp(v, 0.0f, 1.0f) * 65535.0f));
+
+               u.in[0] = result[0];
+               u.in[1] = result[1];
+
+               return u.out;
+       }
+
+       GLM_FUNC_QUALIFIER vec2 unpackUnorm2x16(uint p)
+       {
+               union
+               {
+                       uint in;
+                       u16  out[2];
+               } u;
+
+               u.in = p;
+
+               return vec2(u.out[0], u.out[1]) * 1.5259021896696421759365224689097e-5f;
+       }
+
+       GLM_FUNC_QUALIFIER uint packSnorm2x16(vec2 const & v)
+       {
+               union
+               {
+                       i16  in[2];
+                       uint out;
+               } u;
+
+               i16vec2 result(round(clamp(v, -1.0f, 1.0f) * 32767.0f));
+
+               u.in[0] = result[0];
+               u.in[1] = result[1];
+
+               return u.out;
+       }
+
+       GLM_FUNC_QUALIFIER vec2 unpackSnorm2x16(uint p)
+       {
+               union
+               {
+                       uint in;
+                       i16  out[2];
+               } u;
+
+               u.in = p;
+
+               return clamp(vec2(u.out[0], u.out[1]) * 3.0518509475997192297128208258309e-5f, -1.0f, 1.0f);
+       }
+
+       GLM_FUNC_QUALIFIER uint packUnorm4x8(vec4 const & v)
+       {
+               union
+               {
+                       u8   in[4];
+                       uint out;
+               } u;
+
+               u8vec4 result(round(clamp(v, 0.0f, 1.0f) * 255.0f));
+
+               u.in[0] = result[0];
+               u.in[1] = result[1];
+               u.in[2] = result[2];
+               u.in[3] = result[3];
+
+               return u.out;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackUnorm4x8(uint p)
+       {
+               union
+               {
+                       uint in;
+                       u8   out[4];
+               } u;
+
+               u.in = p;
+
+               return vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0039215686274509803921568627451f;
+       }
+       
+       GLM_FUNC_QUALIFIER uint packSnorm4x8(vec4 const & v)
+       {
+               union
+               {
+                       i8   in[4];
+                       uint out;
+               } u;
+
+               i8vec4 result(round(clamp(v, -1.0f, 1.0f) * 127.0f));
+
+               u.in[0] = result[0];
+               u.in[1] = result[1];
+               u.in[2] = result[2];
+               u.in[3] = result[3];
+
+               return u.out;
+       }
+       
+       GLM_FUNC_QUALIFIER glm::vec4 unpackSnorm4x8(uint p)
+       {
+               union
+               {
+                       uint in;
+                       i8   out[4];
+               } u;
+
+               u.in = p;
+
+               return clamp(vec4(u.out[0], u.out[1], u.out[2], u.out[3]) * 0.0078740157480315f, -1.0f, 1.0f);
+       }
+
+       GLM_FUNC_QUALIFIER double packDouble2x32(uvec2 const & v)
+       {
+               union
+               {
+                       uint   in[2];
+                       double out;
+               } u;
+
+               u.in[0] = v[0];
+               u.in[1] = v[1];
+
+               return u.out;
+       }
+
+       GLM_FUNC_QUALIFIER uvec2 unpackDouble2x32(double v)
+       {
+               union
+               {
+                       double in;
+                       uint   out[2];
+               } u;
+
+               u.in = v;
+
+               return uvec2(u.out[0], u.out[1]);
+       }
+
+       GLM_FUNC_QUALIFIER uint packHalf2x16(vec2 const & v)
+       {
+               union
+               {
+                       i16  in[2];
+                       uint out;
+               } u;
+
+               u.in[0] = detail::toFloat16(v.x);
+               u.in[1] = detail::toFloat16(v.y);
+
+               return u.out;
+       }
+
+       GLM_FUNC_QUALIFIER vec2 unpackHalf2x16(uint v)
+       {
+               union
+               {
+                       uint in;
+                       i16  out[2];
+               } u;
+
+               u.in = v;
+
+               return vec2(
+                       detail::toFloat32(u.out[0]),
+                       detail::toFloat32(u.out[1]));
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_packing_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/detail/func_packing_simd.inl b/core/deps/glm/glm/detail/func_packing_simd.inl
new file mode 100755 (executable)
index 0000000..1d4a522
--- /dev/null
@@ -0,0 +1,9 @@
+/// @ref core
+/// @file glm/detail/func_packing_simd.inl
+
+namespace glm{
+namespace detail
+{
+
+}//namespace detail
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/func_trigonometric.hpp b/core/deps/glm/glm/detail/func_trigonometric.hpp
new file mode 100755 (executable)
index 0000000..719cff0
--- /dev/null
@@ -0,0 +1,176 @@
+/// @ref core
+/// @file glm/detail/func_trigonometric.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+/// 
+/// @defgroup core_func_trigonometric Angle and Trigonometry Functions
+/// @ingroup core
+/// 
+/// Function parameters specified as angle are assumed to be in units of radians. 
+/// In no case will any of these functions result in a divide by zero error. If 
+/// the divisor of a ratio is 0, then results will be undefined.
+/// 
+/// These all operate component-wise. The description is per component.
+
+#pragma once
+
+#include "setup.hpp"
+#include "precision.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_trigonometric
+       /// @{
+
+       /// Converts degrees to radians and returns the result.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/radians.xml">GLSL radians man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL GLM_CONSTEXPR vecType<T, P> radians(vecType<T, P> const & degrees);
+
+       /// Converts radians to degrees and returns the result.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/degrees.xml">GLSL degrees man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL GLM_CONSTEXPR vecType<T, P> degrees(vecType<T, P> const & radians);
+
+       /// The standard trigonometric sine function. 
+       /// The values returned by this function will range from [-1, 1].
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/sin.xml">GLSL sin man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> sin(vecType<T, P> const & angle);
+
+       /// The standard trigonometric cosine function. 
+       /// The values returned by this function will range from [-1, 1].
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/cos.xml">GLSL cos man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> cos(vecType<T, P> const & angle);
+
+       /// The standard trigonometric tangent function.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/tan.xml">GLSL tan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> tan(vecType<T, P> const & angle); 
+
+       /// Arc sine. Returns an angle whose sine is x. 
+       /// The range of values returned by this function is [-PI/2, PI/2]. 
+       /// Results are undefined if |x| > 1.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/asin.xml">GLSL asin man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> asin(vecType<T, P> const & x);
+
+       /// Arc cosine. Returns an angle whose sine is x. 
+       /// The range of values returned by this function is [0, PI]. 
+       /// Results are undefined if |x| > 1.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/acos.xml">GLSL acos man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> acos(vecType<T, P> const & x);
+
+       /// Arc tangent. Returns an angle whose tangent is y/x. 
+       /// The signs of x and y are used to determine what 
+       /// quadrant the angle is in. The range of values returned 
+       /// by this function is [-PI, PI]. Results are undefined 
+       /// if x and y are both 0. 
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/atan.xml">GLSL atan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> atan(vecType<T, P> const & y, vecType<T, P> const & x);
+
+       /// Arc tangent. Returns an angle whose tangent is y_over_x. 
+       /// The range of values returned by this function is [-PI/2, PI/2].
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/atan.xml">GLSL atan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> atan(vecType<T, P> const & y_over_x);
+
+       /// Returns the hyperbolic sine function, (exp(x) - exp(-x)) / 2
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/sinh.xml">GLSL sinh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> sinh(vecType<T, P> const & angle);
+
+       /// Returns the hyperbolic cosine function, (exp(x) + exp(-x)) / 2
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/cosh.xml">GLSL cosh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> cosh(vecType<T, P> const & angle);
+
+       /// Returns the hyperbolic tangent function, sinh(angle) / cosh(angle)
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/tanh.xml">GLSL tanh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> tanh(vecType<T, P> const & angle);
+
+       /// Arc hyperbolic sine; returns the inverse of sinh.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/asinh.xml">GLSL asinh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> asinh(vecType<T, P> const & x);
+       
+       /// Arc hyperbolic cosine; returns the non-negative inverse
+       /// of cosh. Results are undefined if x < 1.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/acosh.xml">GLSL acosh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> acosh(vecType<T, P> const & x);
+
+       /// Arc hyperbolic tangent; returns the inverse of tanh.
+       /// Results are undefined if abs(x) >= 1.
+       ///
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/atanh.xml">GLSL atanh man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.1 Angle and Trigonometry Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> atanh(vecType<T, P> const & x);
+
+       /// @}
+}//namespace glm
+
+#include "func_trigonometric.inl"
diff --git a/core/deps/glm/glm/detail/func_trigonometric.inl b/core/deps/glm/glm/detail/func_trigonometric.inl
new file mode 100755 (executable)
index 0000000..2986673
--- /dev/null
@@ -0,0 +1,200 @@
+/// @ref core
+/// @file glm/detail/func_trigonometric.inl
+
+#include "_vectorize.hpp"
+#include <cmath>
+#include <limits>
+
+namespace glm
+{
+       // radians
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType radians(genType degrees)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'radians' only accept floating-point input");
+
+               return degrees * static_cast<genType>(0.01745329251994329576923690768489);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR vecType<T, P> radians(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(radians, v);
+       }
+       
+       // degrees
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType degrees(genType radians)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'degrees' only accept floating-point input");
+
+               return radians * static_cast<genType>(57.295779513082320876798154814105);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR vecType<T, P> degrees(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(degrees, v);
+       }
+
+       // sin
+       using ::std::sin;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sin(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(sin, v);
+       }
+
+       // cos
+       using std::cos;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> cos(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(cos, v);
+       }
+
+       // tan
+       using std::tan;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> tan(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(tan, v);
+       }
+
+       // asin
+       using std::asin;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> asin(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(asin, v);
+       }
+
+       // acos
+       using std::acos;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acos(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(acos, v);
+       }
+
+       // atan
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType atan(genType y, genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'atan' only accept floating-point input");
+
+               return ::std::atan2(y, x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> atan(vecType<T, P> const & a, vecType<T, P> const & b)
+       {
+               return detail::functor2<T, P, vecType>::call(::std::atan2, a, b);
+       }
+
+       using std::atan;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> atan(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(atan, v);
+       }
+
+       // sinh
+       using std::sinh;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sinh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(sinh, v);
+       }
+
+       // cosh
+       using std::cosh;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> cosh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(cosh, v);
+       }
+
+       // tanh
+       using std::tanh;
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> tanh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(tanh, v);
+       }
+
+       // asinh
+#      if GLM_HAS_CXX11_STL
+               using std::asinh;
+#      else
+               template <typename genType>
+               GLM_FUNC_QUALIFIER genType asinh(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'asinh' only accept floating-point input");
+
+                       return (x < static_cast<genType>(0) ? static_cast<genType>(-1) : (x > static_cast<genType>(0) ? static_cast<genType>(1) : static_cast<genType>(0))) * log(std::abs(x) + sqrt(static_cast<genType>(1) + x * x));
+               }
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> asinh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(asinh, v);
+       }
+
+       // acosh
+#      if GLM_HAS_CXX11_STL
+               using std::acosh;
+#      else
+               template <typename genType> 
+               GLM_FUNC_QUALIFIER genType acosh(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'acosh' only accept floating-point input");
+
+                       if(x < static_cast<genType>(1))
+                               return static_cast<genType>(0);
+                       return log(x + sqrt(x * x - static_cast<genType>(1)));
+               }
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acosh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(acosh, v);
+       }
+
+       // atanh
+#      if GLM_HAS_CXX11_STL
+               using std::atanh;
+#      else
+               template <typename genType>
+               GLM_FUNC_QUALIFIER genType atanh(genType x)
+               {
+                       GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'atanh' only accept floating-point input");
+               
+                       if(std::abs(x) >= static_cast<genType>(1))
+                               return 0;
+                       return static_cast<genType>(0.5) * log((static_cast<genType>(1) + x) / (static_cast<genType>(1) - x));
+               }
+#      endif
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> atanh(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(atanh, v);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_trigonometric_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/detail/func_trigonometric_simd.inl b/core/deps/glm/glm/detail/func_trigonometric_simd.inl
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/core/deps/glm/glm/detail/func_vector_relational.hpp b/core/deps/glm/glm/detail/func_vector_relational.hpp
new file mode 100755 (executable)
index 0000000..ec0f68a
--- /dev/null
@@ -0,0 +1,111 @@
+/// @ref core
+/// @file glm/detail/func_vector_relational.hpp
+///
+/// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+/// 
+/// @defgroup core_func_vector_relational Vector Relational Functions
+/// @ingroup core
+/// 
+/// Relational and equality operators (<, <=, >, >=, ==, !=) are defined to 
+/// operate on scalars and produce scalar Boolean results. For vector results, 
+/// use the following built-in functions. 
+/// 
+/// In all cases, the sizes of all the input and return vectors for any particular 
+/// call must match.
+
+#pragma once
+
+#include "precision.hpp"
+#include "setup.hpp"
+
+namespace glm
+{
+       /// @addtogroup core_func_vector_relational
+       /// @{
+
+       /// Returns the component-wise comparison result of x < y.
+       /// 
+       /// @tparam vecType Floating-point or integer vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/lessThan.xml">GLSL lessThan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> lessThan(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x <= y.
+       ///
+       /// @tparam vecType Floating-point or integer vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/lessThanEqual.xml">GLSL lessThanEqual man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> lessThanEqual(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x > y.
+       ///
+       /// @tparam vecType Floating-point or integer vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/greaterThan.xml">GLSL greaterThan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> greaterThan(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x >= y.
+       ///
+       /// @tparam vecType Floating-point or integer vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/greaterThanEqual.xml">GLSL greaterThanEqual man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> greaterThanEqual(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x == y.
+       ///
+       /// @tparam vecType Floating-point, integer or boolean vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/equal.xml">GLSL equal man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> equal(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x != y.
+       /// 
+       /// @tparam vecType Floating-point, integer or boolean vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/notEqual.xml">GLSL notEqual man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> notEqual(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns true if any component of x is true.
+       ///
+       /// @tparam vecType Boolean vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/any.xml">GLSL any man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool any(vecType<bool, P> const & v);
+
+       /// Returns true if all components of x are true.
+       ///
+       /// @tparam vecType Boolean vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/all.xml">GLSL all man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool all(vecType<bool, P> const & v);
+
+       /// Returns the component-wise logical complement of x.
+       /// /!\ Because of language incompatibilities between C++ and GLSL, GLM defines the function not but not_ instead.
+       ///
+       /// @tparam vecType Boolean vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/not.xml">GLSL not man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.7 Vector Relational Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> not_(vecType<bool, P> const & v);
+
+       /// @}
+}//namespace glm
+
+#include "func_vector_relational.inl"
diff --git a/core/deps/glm/glm/detail/func_vector_relational.inl b/core/deps/glm/glm/detail/func_vector_relational.inl
new file mode 100755 (executable)
index 0000000..3d8d2b7
--- /dev/null
@@ -0,0 +1,105 @@
+/// @ref core
+/// @file glm/detail/func_vector_relational.inl
+
+#include <limits>
+
+namespace glm
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> lessThan(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] < y[i];
+
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> lessThanEqual(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] <= y[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> greaterThan(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] > y[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> greaterThanEqual(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] >= y[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> equal(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] == y[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> notEqual(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               assert(x.length() == y.length());
+
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] != y[i];
+               return Result;
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool any(vecType<bool, P> const & v)
+       {
+               bool Result = false;
+               for(length_t i = 0; i < v.length(); ++i)
+                       Result = Result || v[i];
+               return Result;
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool all(vecType<bool, P> const & v)
+       {
+               bool Result = true;
+               for(length_t i = 0; i < v.length(); ++i)
+                       Result = Result && v[i];
+               return Result;
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> not_(vecType<bool, P> const & v)
+       {
+               vecType<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < v.length(); ++i)
+                       Result[i] = !v[i];
+               return Result;
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_UNRESTRICTED_UNIONS
+#      include "func_vector_relational_simd.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/func_vector_relational_simd.inl b/core/deps/glm/glm/detail/func_vector_relational_simd.inl
new file mode 100755 (executable)
index 0000000..faab59b
--- /dev/null
@@ -0,0 +1,9 @@
+/// @ref core
+/// @file glm/detail/func_vector_relational_simd.inl
+
+namespace glm{
+namespace detail
+{
+
+}//namespace detail
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/glm.cpp b/core/deps/glm/glm/detail/glm.cpp
new file mode 100755 (executable)
index 0000000..da3be4e
--- /dev/null
@@ -0,0 +1,257 @@
+/// @ref core
+/// @file glm/glm.cpp
+
+#include <glm/glm.hpp>
+#include <glm/gtc/quaternion.hpp>
+#include <glm/gtx/dual_quaternion.hpp>
+
+namespace glm
+{
+// tvec1 type explicit instantiation
+template struct tvec1<uint8, lowp>;
+template struct tvec1<uint16, lowp>;
+template struct tvec1<uint32, lowp>;
+template struct tvec1<uint64, lowp>;
+template struct tvec1<int8, lowp>;
+template struct tvec1<int16, lowp>;
+template struct tvec1<int32, lowp>;
+template struct tvec1<int64, lowp>;
+template struct tvec1<float32, lowp>;
+template struct tvec1<float64, lowp>;
+
+template struct tvec1<uint8, mediump>;
+template struct tvec1<uint16, mediump>;
+template struct tvec1<uint32, mediump>;
+template struct tvec1<uint64, mediump>;
+template struct tvec1<int8, mediump>;
+template struct tvec1<int16, mediump>;
+template struct tvec1<int32, mediump>;
+template struct tvec1<int64, mediump>;
+template struct tvec1<float32, mediump>;
+template struct tvec1<float64, mediump>;
+
+template struct tvec1<uint8, highp>;
+template struct tvec1<uint16, highp>;
+template struct tvec1<uint32, highp>;
+template struct tvec1<uint64, highp>;
+template struct tvec1<int8, highp>;
+template struct tvec1<int16, highp>;
+template struct tvec1<int32, highp>;
+template struct tvec1<int64, highp>;
+template struct tvec1<float32, highp>;
+template struct tvec1<float64, highp>;
+
+// tvec2 type explicit instantiation
+template struct tvec2<uint8, lowp>;
+template struct tvec2<uint16, lowp>;
+template struct tvec2<uint32, lowp>;
+template struct tvec2<uint64, lowp>;
+template struct tvec2<int8, lowp>;
+template struct tvec2<int16, lowp>;
+template struct tvec2<int32, lowp>;
+template struct tvec2<int64, lowp>;
+template struct tvec2<float32, lowp>;
+template struct tvec2<float64, lowp>;
+
+template struct tvec2<uint8, mediump>;
+template struct tvec2<uint16, mediump>;
+template struct tvec2<uint32, mediump>;
+template struct tvec2<uint64, mediump>;
+template struct tvec2<int8, mediump>;
+template struct tvec2<int16, mediump>;
+template struct tvec2<int32, mediump>;
+template struct tvec2<int64, mediump>;
+template struct tvec2<float32, mediump>;
+template struct tvec2<float64, mediump>;
+
+template struct tvec2<uint8, highp>;
+template struct tvec2<uint16, highp>;
+template struct tvec2<uint32, highp>;
+template struct tvec2<uint64, highp>;
+template struct tvec2<int8, highp>;
+template struct tvec2<int16, highp>;
+template struct tvec2<int32, highp>;
+template struct tvec2<int64, highp>;
+template struct tvec2<float32, highp>;
+template struct tvec2<float64, highp>;
+
+// tvec3 type explicit instantiation
+template struct tvec3<uint8, lowp>;
+template struct tvec3<uint16, lowp>;
+template struct tvec3<uint32, lowp>;
+template struct tvec3<uint64, lowp>;
+template struct tvec3<int8, lowp>;
+template struct tvec3<int16, lowp>;
+template struct tvec3<int32, lowp>;
+template struct tvec3<int64, lowp>;
+template struct tvec3<float32, lowp>;
+template struct tvec3<float64, lowp>;
+
+template struct tvec3<uint8, mediump>;
+template struct tvec3<uint16, mediump>;
+template struct tvec3<uint32, mediump>;
+template struct tvec3<uint64, mediump>;
+template struct tvec3<int8, mediump>;
+template struct tvec3<int16, mediump>;
+template struct tvec3<int32, mediump>;
+template struct tvec3<int64, mediump>;
+template struct tvec3<float32, mediump>;
+template struct tvec3<float64, mediump>;
+
+template struct tvec3<uint8, highp>;
+template struct tvec3<uint16, highp>;
+template struct tvec3<uint32, highp>;
+template struct tvec3<uint64, highp>;
+template struct tvec3<int8, highp>;
+template struct tvec3<int16, highp>;
+template struct tvec3<int32, highp>;
+template struct tvec3<int64, highp>;
+template struct tvec3<float32, highp>;
+template struct tvec3<float64, highp>;
+
+// tvec4 type explicit instantiation
+template struct tvec4<uint8, lowp>;
+template struct tvec4<uint16, lowp>;
+template struct tvec4<uint32, lowp>;
+template struct tvec4<uint64, lowp>;
+template struct tvec4<int8, lowp>;
+template struct tvec4<int16, lowp>;
+template struct tvec4<int32, lowp>;
+template struct tvec4<int64, lowp>;
+template struct tvec4<float32, lowp>;
+template struct tvec4<float64, lowp>;
+
+template struct tvec4<uint8, mediump>;
+template struct tvec4<uint16, mediump>;
+template struct tvec4<uint32, mediump>;
+template struct tvec4<uint64, mediump>;
+template struct tvec4<int8, mediump>;
+template struct tvec4<int16, mediump>;
+template struct tvec4<int32, mediump>;
+template struct tvec4<int64, mediump>;
+template struct tvec4<float32, mediump>;
+template struct tvec4<float64, mediump>;
+
+template struct tvec4<uint8, highp>;
+template struct tvec4<uint16, highp>;
+template struct tvec4<uint32, highp>;
+template struct tvec4<uint64, highp>;
+template struct tvec4<int8, highp>;
+template struct tvec4<int16, highp>;
+template struct tvec4<int32, highp>;
+template struct tvec4<int64, highp>;
+template struct tvec4<float32, highp>;
+template struct tvec4<float64, highp>;
+
+// tmat2x2 type explicit instantiation
+template struct tmat2x2<float32, lowp>;
+template struct tmat2x2<float64, lowp>;
+
+template struct tmat2x2<float32, mediump>;
+template struct tmat2x2<float64, mediump>;
+
+template struct tmat2x2<float32, highp>;
+template struct tmat2x2<float64, highp>;
+
+// tmat2x3 type explicit instantiation
+template struct tmat2x3<float32, lowp>;
+template struct tmat2x3<float64, lowp>;
+
+template struct tmat2x3<float32, mediump>;
+template struct tmat2x3<float64, mediump>;
+
+template struct tmat2x3<float32, highp>;
+template struct tmat2x3<float64, highp>;
+
+// tmat2x4 type explicit instantiation
+template struct tmat2x4<float32, lowp>;
+template struct tmat2x4<float64, lowp>;
+
+template struct tmat2x4<float32, mediump>;
+template struct tmat2x4<float64, mediump>;
+
+template struct tmat2x4<float32, highp>;
+template struct tmat2x4<float64, highp>;
+
+// tmat3x2 type explicit instantiation
+template struct tmat3x2<float32, lowp>;
+template struct tmat3x2<float64, lowp>;
+
+template struct tmat3x2<float32, mediump>;
+template struct tmat3x2<float64, mediump>;
+
+template struct tmat3x2<float32, highp>;
+template struct tmat3x2<float64, highp>;
+
+// tmat3x3 type explicit instantiation
+template struct tmat3x3<float32, lowp>;
+template struct tmat3x3<float64, lowp>;
+
+template struct tmat3x3<float32, mediump>;
+template struct tmat3x3<float64, mediump>;
+
+template struct tmat3x3<float32, highp>;
+template struct tmat3x3<float64, highp>;
+
+// tmat3x4 type explicit instantiation
+template struct tmat3x4<float32, lowp>;
+template struct tmat3x4<float64, lowp>;
+
+template struct tmat3x4<float32, mediump>;
+template struct tmat3x4<float64, mediump>;
+
+template struct tmat3x4<float32, highp>;
+template struct tmat3x4<float64, highp>;
+
+// tmat4x2 type explicit instantiation
+template struct tmat4x2<float32, lowp>;
+template struct tmat4x2<float64, lowp>;
+
+template struct tmat4x2<float32, mediump>;
+template struct tmat4x2<float64, mediump>;
+
+template struct tmat4x2<float32, highp>;
+template struct tmat4x2<float64, highp>;
+
+// tmat4x3 type explicit instantiation
+template struct tmat4x3<float32, lowp>;
+template struct tmat4x3<float64, lowp>;
+
+template struct tmat4x3<float32, mediump>;
+template struct tmat4x3<float64, mediump>;
+
+template struct tmat4x3<float32, highp>;
+template struct tmat4x3<float64, highp>;
+
+// tmat4x4 type explicit instantiation
+template struct tmat4x4<float32, lowp>;
+template struct tmat4x4<float64, lowp>;
+
+template struct tmat4x4<float32, mediump>;
+template struct tmat4x4<float64, mediump>;
+
+template struct tmat4x4<float32, highp>;
+template struct tmat4x4<float64, highp>;
+
+// tquat type explicit instantiation
+template struct tquat<float32, lowp>;
+template struct tquat<float64, lowp>;
+
+template struct tquat<float32, mediump>;
+template struct tquat<float64, mediump>;
+
+template struct tquat<float32, highp>;
+template struct tquat<float64, highp>;
+
+//tdualquat type explicit instantiation
+template struct tdualquat<float32, lowp>;
+template struct tdualquat<float64, lowp>;
+
+template struct tdualquat<float32, mediump>;
+template struct tdualquat<float64, mediump>;
+
+template struct tdualquat<float32, highp>;
+template struct tdualquat<float64, highp>;
+
+}//namespace glm
+
diff --git a/core/deps/glm/glm/detail/precision.hpp b/core/deps/glm/glm/detail/precision.hpp
new file mode 100755 (executable)
index 0000000..7c54437
--- /dev/null
@@ -0,0 +1,63 @@
+/// @ref core
+/// @file glm/detail/precision.hpp
+
+#pragma once
+
+#include "setup.hpp"
+
+namespace glm
+{
+       enum precision
+       {
+               packed_highp,
+               packed_mediump,
+               packed_lowp,
+
+#              if GLM_HAS_ALIGNED_TYPE
+                       aligned_highp,
+                       aligned_mediump,
+                       aligned_lowp,
+                       aligned = aligned_highp,
+#              endif
+
+               highp = packed_highp,
+               mediump = packed_mediump,
+               lowp = packed_lowp,
+               packed = packed_highp,
+
+#              if GLM_HAS_ALIGNED_TYPE && defined(GLM_FORCE_ALIGNED)
+                       defaultp = aligned_highp
+#              else
+                       defaultp = highp
+#              endif
+       };
+       
+namespace detail
+{
+       template <glm::precision P>
+       struct is_aligned
+       {
+               static const bool value = false;
+       };
+
+#      if GLM_HAS_ALIGNED_TYPE
+               template<>
+               struct is_aligned<glm::aligned_lowp>
+               {
+                       static const bool value = true;
+               };
+
+               template<>
+               struct is_aligned<glm::aligned_mediump>
+               {
+                       static const bool value = true;
+               };
+
+               template<>
+               struct is_aligned<glm::aligned_highp>
+               {
+                       static const bool value = true;
+               };
+#      endif
+}//namespace detail
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/setup.hpp b/core/deps/glm/glm/detail/setup.hpp
new file mode 100755 (executable)
index 0000000..68c8cb4
--- /dev/null
@@ -0,0 +1,828 @@
+/// @ref core
+/// @file glm/detail/setup.hpp
+
+#pragma once
+
+#if (defined(GLM_FORCE_SWIZZLE) || defined(GLM_SWIZZLE)) && defined(GLM_FORCE_UNRESTRICTED_GENTYPE)
+#      error "Both GLM_FORCE_SWIZZLE and GLM_FORCE_UNRESTRICTED_GENTYPE can't be defined at the same time"
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+// Messages
+
+#ifdef GLM_MESSAGES
+#      pragma message("GLM: GLM_MESSAGES is deprecated, use GLM_FORCE_MESSAGES instead")
+#endif
+
+#define GLM_MESSAGES_ENABLED 1
+#define GLM_MESSAGES_DISABLE 0
+
+#if defined(GLM_FORCE_MESSAGES) || defined(GLM_MESSAGES)
+#      undef GLM_MESSAGES
+#      define GLM_MESSAGES GLM_MESSAGES_ENABLED
+#else
+#      undef GLM_MESSAGES
+#      define GLM_MESSAGES GLM_MESSAGES_DISABLE
+#endif
+
+#include <cassert>
+#include <cstddef>
+#include "../simd/platform.h"
+
+///////////////////////////////////////////////////////////////////////////////////
+// Version
+
+#define GLM_VERSION                                    98
+#define GLM_VERSION_MAJOR                      0
+#define GLM_VERSION_MINOR                      9
+#define GLM_VERSION_PATCH                      8
+#define GLM_VERSION_REVISION           4
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_VERSION_DISPLAYED)
+#      define GLM_MESSAGE_VERSION_DISPLAYED
+#      pragma message ("GLM: version 0.9.8.4")
+#endif//GLM_MESSAGES
+
+// Report compiler detection
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_COMPILER_DISPLAYED)
+#      define GLM_MESSAGE_COMPILER_DISPLAYED
+#      if GLM_COMPILER & GLM_COMPILER_CUDA
+#              pragma message("GLM: CUDA compiler detected")
+#      elif GLM_COMPILER & GLM_COMPILER_VC
+#              pragma message("GLM: Visual C++ compiler detected")
+#      elif GLM_COMPILER & GLM_COMPILER_CLANG
+#              pragma message("GLM: Clang compiler detected")
+#      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#              pragma message("GLM: Intel Compiler detected")
+#      elif GLM_COMPILER & GLM_COMPILER_GCC
+#              pragma message("GLM: GCC compiler detected")
+#      else
+#              pragma message("GLM: Compiler not detected")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Build model
+
+#if defined(__arch64__) || defined(__LP64__) || defined(_M_X64) || defined(__ppc64__) || defined(__x86_64__)
+#      define GLM_MODEL        GLM_MODEL_64
+#elif defined(__i386__) || defined(__ppc__)
+#      define GLM_MODEL        GLM_MODEL_32
+#else
+#      define GLM_MODEL        GLM_MODEL_32
+#endif//
+
+#if !defined(GLM_MODEL) && GLM_COMPILER != 0
+#      error "GLM_MODEL undefined, your compiler may not be supported by GLM. Add #define GLM_MODEL 0 to ignore this message."
+#endif//GLM_MODEL
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_MODEL_DISPLAYED)
+#      define GLM_MESSAGE_MODEL_DISPLAYED
+#      if(GLM_MODEL == GLM_MODEL_64)
+#              pragma message("GLM: 64 bits model")
+#      elif(GLM_MODEL == GLM_MODEL_32)
+#              pragma message("GLM: 32 bits model")
+#      endif//GLM_MODEL
+#endif//GLM_MESSAGES
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_ARCH_DISPLAYED)
+#      define GLM_MESSAGE_ARCH_DISPLAYED
+#      if(GLM_ARCH == GLM_ARCH_PURE)
+#              pragma message("GLM: Platform independent code")
+#      elif(GLM_ARCH == GLM_ARCH_AVX2)
+#              pragma message("GLM: AVX2 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_AVX)
+#              pragma message("GLM: AVX instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_SSE42)
+#              pragma message("GLM: SSE4.2 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_SSE41)
+#              pragma message("GLM: SSE4.1 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_SSSE3)
+#              pragma message("GLM: SSSE3 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_SSE3)
+#              pragma message("GLM: SSE3 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_SSE2)
+#              pragma message("GLM: SSE2 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_X86)
+#              pragma message("GLM: x86 instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_NEON)
+#              pragma message("GLM: NEON instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_ARM)
+#              pragma message("GLM: ARM instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_MIPS)
+#              pragma message("GLM: MIPS instruction set")
+#      elif(GLM_ARCH == GLM_ARCH_PPC)
+#              pragma message("GLM: PowerPC architechture")
+#      endif//GLM_ARCH
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// C++ Version
+
+// User defines: GLM_FORCE_CXX98, GLM_FORCE_CXX03, GLM_FORCE_CXX11, GLM_FORCE_CXX14
+
+#define GLM_LANG_CXX98_FLAG                    (1 << 1)
+#define GLM_LANG_CXX03_FLAG                    (1 << 2)
+#define GLM_LANG_CXX0X_FLAG                    (1 << 3)
+#define GLM_LANG_CXX11_FLAG                    (1 << 4)
+#define GLM_LANG_CXX1Y_FLAG                    (1 << 5)
+#define GLM_LANG_CXX14_FLAG                    (1 << 6)
+#define GLM_LANG_CXX1Z_FLAG                    (1 << 7)
+#define GLM_LANG_CXXMS_FLAG                    (1 << 8)
+#define GLM_LANG_CXXGNU_FLAG           (1 << 9)
+
+#define GLM_LANG_CXX98                 GLM_LANG_CXX98_FLAG
+#define GLM_LANG_CXX03                 (GLM_LANG_CXX98 | GLM_LANG_CXX03_FLAG)
+#define GLM_LANG_CXX0X                 (GLM_LANG_CXX03 | GLM_LANG_CXX0X_FLAG)
+#define GLM_LANG_CXX11                 (GLM_LANG_CXX0X | GLM_LANG_CXX11_FLAG)
+#define GLM_LANG_CXX1Y                 (GLM_LANG_CXX11 | GLM_LANG_CXX1Y_FLAG)
+#define GLM_LANG_CXX14                 (GLM_LANG_CXX1Y | GLM_LANG_CXX14_FLAG)
+#define GLM_LANG_CXX1Z                 (GLM_LANG_CXX14 | GLM_LANG_CXX1Z_FLAG)
+#define GLM_LANG_CXXMS                 GLM_LANG_CXXMS_FLAG
+#define GLM_LANG_CXXGNU                        GLM_LANG_CXXGNU_FLAG
+
+#if defined(GLM_FORCE_CXX14)
+#      if((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER <= GLM_COMPILER_GCC50)) || ((GLM_COMPILER & GLM_COMPILER_CLANG) && (GLM_COMPILER <= GLM_COMPILER_CLANG34))
+#                      pragma message("GLM: Using GLM_FORCE_CXX14 with a compiler that doesn't fully support C++14")
+#      elif GLM_COMPILER & GLM_COMPILER_VC
+#                      pragma message("GLM: Using GLM_FORCE_CXX14 but there is no known version of Visual C++ compiler that fully supports C++14")
+#      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#                      pragma message("GLM: Using GLM_FORCE_CXX14 but there is no known version of ICC compiler that fully supports C++14")
+#      endif
+#      define GLM_LANG GLM_LANG_CXX14
+#      define GLM_LANG_STL11_FORCED
+#elif defined(GLM_FORCE_CXX11)
+#      if((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER <= GLM_COMPILER_GCC48)) || ((GLM_COMPILER & GLM_COMPILER_CLANG) && (GLM_COMPILER <= GLM_COMPILER_CLANG33))
+#                      pragma message("GLM: Using GLM_FORCE_CXX11 with a compiler that doesn't fully support C++11")
+#      elif GLM_COMPILER & GLM_COMPILER_VC
+#                      pragma message("GLM: Using GLM_FORCE_CXX11 but there is no known version of Visual C++ compiler that fully supports C++11")
+#      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#                      pragma message("GLM: Using GLM_FORCE_CXX11 but there is no known version of ICC compiler that fully supports C++11")
+#      endif
+#      define GLM_LANG GLM_LANG_CXX11
+#      define GLM_LANG_STL11_FORCED
+#elif defined(GLM_FORCE_CXX03)
+#      define GLM_LANG GLM_LANG_CXX03
+#elif defined(GLM_FORCE_CXX98)
+#      define GLM_LANG GLM_LANG_CXX98
+#else
+#      if GLM_COMPILER & GLM_COMPILER_CLANG
+#              if __cplusplus >= 201402L // GLM_COMPILER_CLANG34 + -std=c++14
+#                      define GLM_LANG GLM_LANG_CXX14
+#              elif __has_feature(cxx_decltype_auto) && __has_feature(cxx_aggregate_nsdmi) // GLM_COMPILER_CLANG33 + -std=c++1y
+#                      define GLM_LANG GLM_LANG_CXX1Y
+#              elif __cplusplus >= 201103L // GLM_COMPILER_CLANG33 + -std=c++11
+#                      define GLM_LANG GLM_LANG_CXX11
+#              elif __has_feature(cxx_static_assert) // GLM_COMPILER_CLANG29 + -std=c++11
+#                      define GLM_LANG GLM_LANG_CXX0X
+#              elif __cplusplus >= 199711L
+#                      define GLM_LANG GLM_LANG_CXX98
+#              else
+#                      define GLM_LANG GLM_LANG_CXX
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_GCC
+#              if __cplusplus >= 201402L
+#                      define GLM_LANG GLM_LANG_CXX14
+#              elif __cplusplus >= 201103L
+#                      define GLM_LANG GLM_LANG_CXX11
+#              elif defined(__GXX_EXPERIMENTAL_CXX0X__)
+#                      define GLM_LANG GLM_LANG_CXX0X
+#              else
+#                      define GLM_LANG GLM_LANG_CXX98
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_VC
+#              ifdef _MSC_EXTENSIONS
+#                      if __cplusplus >= 201402L
+#                              define GLM_LANG (GLM_LANG_CXX14 | GLM_LANG_CXXMS_FLAG)
+//#                    elif GLM_COMPILER >= GLM_COMPILER_VC14
+//#                            define GLM_LANG (GLM_LANG_CXX1Y | GLM_LANG_CXXMS_FLAG)
+#                      elif __cplusplus >= 201103L
+#                              define GLM_LANG (GLM_LANG_CXX11 | GLM_LANG_CXXMS_FLAG)
+#                      elif GLM_COMPILER >= GLM_COMPILER_VC10
+#                              define GLM_LANG (GLM_LANG_CXX0X | GLM_LANG_CXXMS_FLAG)
+#                      elif __cplusplus >= 199711L
+#                              define GLM_LANG (GLM_LANG_CXX98 | GLM_LANG_CXXMS_FLAG)
+#                      else
+#                              define GLM_LANG (GLM_LANG_CXX | GLM_LANG_CXXMS_FLAG)
+#                      endif
+#              else
+#                      if __cplusplus >= 201402L
+#                              define GLM_LANG GLM_LANG_CXX14
+#                      elif __cplusplus >= 201103L
+#                              define GLM_LANG GLM_LANG_CXX11
+#                      elif GLM_COMPILER >= GLM_COMPILER_VC10
+#                              define GLM_LANG GLM_LANG_CXX0X
+#                      elif __cplusplus >= 199711L
+#                              define GLM_LANG GLM_LANG_CXX98
+#                      else
+#                              define GLM_LANG GLM_LANG_CXX
+#                      endif
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#              ifdef _MSC_EXTENSIONS
+#                      define GLM_MSC_EXT GLM_LANG_CXXMS_FLAG
+#              else
+#                      define GLM_MSC_EXT 0
+#              endif
+#              if __cplusplus >= 201402L
+#                      define GLM_LANG (GLM_LANG_CXX14 | GLM_MSC_EXT)
+#              elif __cplusplus >= 201103L
+#                      define GLM_LANG (GLM_LANG_CXX11 | GLM_MSC_EXT)
+#              elif __INTEL_CXX11_MODE__
+#                      define GLM_LANG (GLM_LANG_CXX0X | GLM_MSC_EXT)
+#              elif __cplusplus >= 199711L
+#                      define GLM_LANG (GLM_LANG_CXX98 | GLM_MSC_EXT)
+#              else
+#                      define GLM_LANG (GLM_LANG_CXX | GLM_MSC_EXT)
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_CUDA
+#              ifdef _MSC_EXTENSIONS
+#                      define GLM_MSC_EXT GLM_LANG_CXXMS_FLAG
+#              else
+#                      define GLM_MSC_EXT 0
+#              endif
+#              if GLM_COMPILER >= GLM_COMPILER_CUDA75
+#                      define GLM_LANG (GLM_LANG_CXX0X | GLM_MSC_EXT)
+#              else
+#                      define GLM_LANG (GLM_LANG_CXX98 | GLM_MSC_EXT)
+#              endif
+#      else // Unknown compiler
+#              if __cplusplus >= 201402L
+#                      define GLM_LANG GLM_LANG_CXX14
+#              elif __cplusplus >= 201103L
+#                      define GLM_LANG GLM_LANG_CXX11
+#              elif __cplusplus >= 199711L
+#                      define GLM_LANG GLM_LANG_CXX98
+#              else
+#                      define GLM_LANG GLM_LANG_CXX // Good luck with that!
+#              endif
+#              ifndef GLM_FORCE_PURE
+#                      define GLM_FORCE_PURE
+#              endif
+#      endif
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_LANG_DISPLAYED)
+#      define GLM_MESSAGE_LANG_DISPLAYED
+
+#      if GLM_LANG & GLM_LANG_CXX1Z_FLAG
+#              pragma message("GLM: C++1z")
+#      elif GLM_LANG & GLM_LANG_CXX14_FLAG
+#              pragma message("GLM: C++14")
+#      elif GLM_LANG & GLM_LANG_CXX1Y_FLAG
+#              pragma message("GLM: C++1y")
+#      elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#              pragma message("GLM: C++11")
+#      elif GLM_LANG & GLM_LANG_CXX0X_FLAG
+#              pragma message("GLM: C++0x")
+#      elif GLM_LANG & GLM_LANG_CXX03_FLAG
+#              pragma message("GLM: C++03")
+#      elif GLM_LANG & GLM_LANG_CXX98_FLAG
+#              pragma message("GLM: C++98")
+#      else
+#              pragma message("GLM: C++ language undetected")
+#      endif//GLM_LANG
+
+#      if GLM_LANG & (GLM_LANG_CXXGNU_FLAG | GLM_LANG_CXXMS_FLAG)
+#              pragma message("GLM: Language extensions enabled")
+#      endif//GLM_LANG
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Has of C++ features
+
+// http://clang.llvm.org/cxx_status.html
+// http://gcc.gnu.org/projects/cxx0x.html
+// http://msdn.microsoft.com/en-us/library/vstudio/hh567368(v=vs.120).aspx
+
+// Android has multiple STLs but C++11 STL detection doesn't always work #284 #564
+#if GLM_PLATFORM == GLM_PLATFORM_ANDROID && !defined(GLM_LANG_STL11_FORCED)
+#      define GLM_HAS_CXX11_STL 0
+#elif GLM_COMPILER & GLM_COMPILER_CLANG
+#      if (defined(_LIBCPP_VERSION) && GLM_LANG & GLM_LANG_CXX11_FLAG) || defined(GLM_LANG_STL11_FORCED)
+#              define GLM_HAS_CXX11_STL 1
+#      else
+#              define GLM_HAS_CXX11_STL 0
+#      endif
+#else
+#      define GLM_HAS_CXX11_STL ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_PLATFORM != GLM_PLATFORM_WINDOWS) && (GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15))))
+#endif
+
+// N1720
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_STATIC_ASSERT __has_feature(cxx_static_assert)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_STATIC_ASSERT 1
+#else
+#      define GLM_HAS_STATIC_ASSERT ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC))))
+#endif
+
+// N1988
+#if GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_EXTENDED_INTEGER_TYPE 1
+#else
+#      define GLM_HAS_EXTENDED_INTEGER_TYPE (\
+               ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC11)) || \
+               ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CUDA)) || \
+               ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_GCC)) || \
+               ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (GLM_COMPILER & GLM_COMPILER_CLANG)))
+#endif
+
+// N2235
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_CONSTEXPR __has_feature(cxx_constexpr)
+#      define GLM_HAS_CONSTEXPR_PARTIAL GLM_HAS_CONSTEXPR
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_CONSTEXPR 1
+#      define GLM_HAS_CONSTEXPR_PARTIAL GLM_HAS_CONSTEXPR
+#else
+#      define GLM_HAS_CONSTEXPR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)))) // GCC 4.6 support constexpr but there is a compiler bug causing a crash
+#      define GLM_HAS_CONSTEXPR_PARTIAL (GLM_HAS_CONSTEXPR || ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)))
+#endif
+
+// N2672
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_INITIALIZER_LISTS __has_feature(cxx_generalized_initializers)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_INITIALIZER_LISTS 1
+#else
+#      define GLM_HAS_INITIALIZER_LISTS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA75))))
+#endif
+
+// N2544 Unrestricted unions http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2008/n2544.pdf
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_UNRESTRICTED_UNIONS __has_feature(cxx_unrestricted_unions)
+#elif GLM_LANG & (GLM_LANG_CXX11_FLAG | GLM_LANG_CXXMS_FLAG)
+#      define GLM_HAS_UNRESTRICTED_UNIONS 1
+#else
+#      define GLM_HAS_UNRESTRICTED_UNIONS (GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_LANG & GLM_LANG_CXXMS_FLAG)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA75)) || \
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC46)))
+#endif
+
+// N2346
+#if defined(GLM_FORCE_UNRESTRICTED_GENTYPE)
+#      define GLM_HAS_DEFAULTED_FUNCTIONS 0
+#elif GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_DEFAULTED_FUNCTIONS __has_feature(cxx_defaulted_functions)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_DEFAULTED_FUNCTIONS 1
+#else
+#      define GLM_HAS_DEFAULTED_FUNCTIONS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL12)) || \
+               (GLM_COMPILER & GLM_COMPILER_CUDA)))
+#endif
+
+// N2118
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_RVALUE_REFERENCES __has_feature(cxx_rvalue_references)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_RVALUE_REFERENCES 1
+#else
+#      define GLM_HAS_RVALUE_REFERENCES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC11)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA50))))
+#endif
+
+// N2437 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2437.pdf
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS __has_feature(cxx_explicit_conversions)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS 1
+#else
+#      define GLM_HAS_EXPLICIT_CONVERSION_OPERATORS ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC45)) || \
+               ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL14)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA50))))
+#endif
+
+// N2258 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2258.pdf
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_TEMPLATE_ALIASES __has_feature(cxx_alias_templates)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_TEMPLATE_ALIASES 1
+#else
+#      define GLM_HAS_TEMPLATE_ALIASES ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL12_1)) || \
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC47)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA50))))
+#endif
+
+// N2930 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2009/n2930.html
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_RANGE_FOR __has_feature(cxx_range_for)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_RANGE_FOR 1
+#else
+#      define GLM_HAS_RANGE_FOR ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC46)) || \
+               ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL13)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC11)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA50))))
+#endif
+
+// N2341 http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2341.pdf
+#if GLM_COMPILER & GLM_COMPILER_CLANG
+#      define GLM_HAS_ALIGNOF __has_feature(c_alignof)
+#elif GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_ALIGNOF 1
+#else
+#      define GLM_HAS_ALIGNOF ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC48)) || \
+               ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_COMPILER >= GLM_COMPILER_INTEL15)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA70))))
+#endif
+
+#define GLM_HAS_ONLY_XYZW ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER < GLM_COMPILER_GCC46))
+#if GLM_HAS_ONLY_XYZW
+#      pragma message("GLM: GCC older than 4.6 has a bug presenting the use of rgba and stpq components")
+#endif
+
+//
+#if GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_ASSIGNABLE 1
+#else
+#      define GLM_HAS_ASSIGNABLE ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC15)) || \
+               ((GLM_COMPILER & GLM_COMPILER_GCC) && (GLM_COMPILER >= GLM_COMPILER_GCC49))))
+#endif
+
+//
+#define GLM_HAS_TRIVIAL_QUERIES 0
+
+//
+#if GLM_LANG & GLM_LANG_CXX11_FLAG
+#      define GLM_HAS_MAKE_SIGNED 1
+#else
+#      define GLM_HAS_MAKE_SIGNED ((GLM_LANG & GLM_LANG_CXX0X_FLAG) && (\
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC12)) || \
+               ((GLM_COMPILER & GLM_COMPILER_CUDA) && (GLM_COMPILER >= GLM_COMPILER_CUDA50))))
+#endif
+
+#if GLM_ARCH == GLM_ARCH_PURE
+#      define GLM_HAS_BITSCAN_WINDOWS 0
+#else
+#      define GLM_HAS_BITSCAN_WINDOWS ((GLM_PLATFORM & GLM_PLATFORM_WINDOWS) && (\
+               ((GLM_COMPILER & GLM_COMPILER_INTEL)) || \
+               ((GLM_COMPILER & GLM_COMPILER_VC) && (GLM_COMPILER >= GLM_COMPILER_VC14) && (GLM_ARCH & GLM_ARCH_X86_BIT))))
+#endif
+
+// OpenMP
+#ifdef _OPENMP
+#      if GLM_COMPILER & GLM_COMPILER_GCC
+#              if GLM_COMPILER >= GLM_COMPILER_GCC61
+#                      define GLM_HAS_OPENMP 45
+#              elif GLM_COMPILER >= GLM_COMPILER_GCC49
+#                      define GLM_HAS_OPENMP 40
+#              elif GLM_COMPILER >= GLM_COMPILER_GCC47
+#                      define GLM_HAS_OPENMP 31
+#              elif GLM_COMPILER >= GLM_COMPILER_GCC44
+#                      define GLM_HAS_OPENMP 30
+#              elif GLM_COMPILER >= GLM_COMPILER_GCC42
+#                      define GLM_HAS_OPENMP 25
+#              else
+#                      define GLM_HAS_OPENMP 0
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_CLANG
+#              if GLM_COMPILER >= GLM_COMPILER_CLANG38
+#                      define GLM_HAS_OPENMP 31
+#              else
+#                      define GLM_HAS_OPENMP 0
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_VC
+#              if GLM_COMPILER >= GLM_COMPILER_VC10
+#                      define GLM_HAS_OPENMP 20
+#              else
+#                      define GLM_HAS_OPENMP 0
+#              endif
+#      elif GLM_COMPILER & GLM_COMPILER_INTEL
+#              if GLM_COMPILER >= GLM_COMPILER_INTEL16
+#                      define GLM_HAS_OPENMP 40
+#              elif GLM_COMPILER >= GLM_COMPILER_INTEL12
+#                      define GLM_HAS_OPENMP 31
+#              else
+#                      define GLM_HAS_OPENMP 0
+#              endif
+#      else
+#              define GLM_HAS_OPENMP 0
+#      endif// GLM_COMPILER & GLM_COMPILER_VC
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+// Static assert
+
+#if GLM_HAS_STATIC_ASSERT
+#      define GLM_STATIC_ASSERT(x, message) static_assert(x, message)
+#elif defined(BOOST_STATIC_ASSERT)
+#      define GLM_STATIC_ASSERT(x, message) BOOST_STATIC_ASSERT(x)
+#elif GLM_COMPILER & GLM_COMPILER_VC
+#      define GLM_STATIC_ASSERT(x, message) typedef char __CASSERT__##__LINE__[(x) ? 1 : -1]
+#else
+#      define GLM_STATIC_ASSERT(x, message)
+#      define GLM_STATIC_ASSERT_NULL
+#endif//GLM_LANG
+
+///////////////////////////////////////////////////////////////////////////////////
+// Qualifiers
+
+#if GLM_COMPILER & GLM_COMPILER_CUDA
+#      define GLM_CUDA_FUNC_DEF __device__ __host__
+#      define GLM_CUDA_FUNC_DECL __device__ __host__
+#else
+#      define GLM_CUDA_FUNC_DEF
+#      define GLM_CUDA_FUNC_DECL
+#endif
+
+#if GLM_COMPILER & GLM_COMPILER_GCC
+#      define GLM_VAR_USED __attribute__ ((unused))
+#else
+#      define GLM_VAR_USED
+#endif
+
+#if defined(GLM_FORCE_INLINE)
+#      if GLM_COMPILER & GLM_COMPILER_VC
+#              define GLM_INLINE __forceinline
+#              define GLM_NEVER_INLINE __declspec((noinline))
+#      elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG)
+#              define GLM_INLINE inline __attribute__((__always_inline__))
+#              define GLM_NEVER_INLINE __attribute__((__noinline__))
+#      elif GLM_COMPILER & GLM_COMPILER_CUDA
+#              define GLM_INLINE __forceinline__
+#              define GLM_NEVER_INLINE __noinline__
+#      else
+#              define GLM_INLINE inline
+#              define GLM_NEVER_INLINE
+#      endif//GLM_COMPILER
+#else
+#      define GLM_INLINE inline
+#      define GLM_NEVER_INLINE
+#endif//defined(GLM_FORCE_INLINE)
+
+#define GLM_FUNC_DECL GLM_CUDA_FUNC_DECL
+#define GLM_FUNC_QUALIFIER GLM_CUDA_FUNC_DEF GLM_INLINE
+
+///////////////////////////////////////////////////////////////////////////////////
+// Swizzle operators
+
+// User defines: GLM_FORCE_SWIZZLE
+
+#ifdef GLM_SWIZZLE
+#      pragma message("GLM: GLM_SWIZZLE is deprecated, use GLM_FORCE_SWIZZLE instead")
+#endif
+
+#define GLM_SWIZZLE_ENABLED 1
+#define GLM_SWIZZLE_DISABLE 0
+
+#if defined(GLM_FORCE_SWIZZLE) || defined(GLM_SWIZZLE)
+#      undef GLM_SWIZZLE
+#      define GLM_SWIZZLE GLM_SWIZZLE_ENABLED
+#else
+#      undef GLM_SWIZZLE
+#      define GLM_SWIZZLE GLM_SWIZZLE_DISABLE
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_SWIZZLE_DISPLAYED)
+#      define GLM_MESSAGE_SWIZZLE_DISPLAYED
+#      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#              pragma message("GLM: Swizzling operators enabled")
+#      else
+#              pragma message("GLM: Swizzling operators disabled, #define GLM_SWIZZLE to enable swizzle operators")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Allows using not basic types as genType
+
+// #define GLM_FORCE_UNRESTRICTED_GENTYPE
+
+#ifdef GLM_FORCE_UNRESTRICTED_GENTYPE
+#      define GLM_UNRESTRICTED_GENTYPE 1
+#else
+#      define GLM_UNRESTRICTED_GENTYPE 0
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_UNRESTRICTED_GENTYPE_DISPLAYED)
+#      define GLM_MESSAGE_UNRESTRICTED_GENTYPE_DISPLAYED
+#      ifdef GLM_FORCE_UNRESTRICTED_GENTYPE
+#              pragma message("GLM: Use unrestricted genType")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Clip control
+
+#ifdef GLM_DEPTH_ZERO_TO_ONE // Legacy 0.9.8 development
+#      error Define GLM_FORCE_DEPTH_ZERO_TO_ONE instead of GLM_DEPTH_ZERO_TO_ONE to use 0 to 1 clip space.
+#endif
+
+#define GLM_DEPTH_ZERO_TO_ONE                          0x00000001
+#define GLM_DEPTH_NEGATIVE_ONE_TO_ONE          0x00000002
+
+#ifdef GLM_FORCE_DEPTH_ZERO_TO_ONE
+#      define GLM_DEPTH_CLIP_SPACE GLM_DEPTH_ZERO_TO_ONE
+#else
+#      define GLM_DEPTH_CLIP_SPACE GLM_DEPTH_NEGATIVE_ONE_TO_ONE
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_DEPTH_DISPLAYED)
+#      define GLM_MESSAGE_DEPTH_DISPLAYED
+#      if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+#              pragma message("GLM: Depth clip space: Zero to one")
+#      else
+#              pragma message("GLM: Depth clip space: negative one to one")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Coordinate system, define GLM_FORCE_LEFT_HANDED before including GLM
+// to use left handed coordinate system by default.
+
+#ifdef GLM_LEFT_HANDED // Legacy 0.9.8 development
+#      error Define GLM_FORCE_LEFT_HANDED instead of GLM_LEFT_HANDED left handed coordinate system by default.
+#endif
+
+#define GLM_LEFT_HANDED                                0x00000001      // For DirectX, Metal, Vulkan
+#define GLM_RIGHT_HANDED                       0x00000002      // For OpenGL, default in GLM
+
+#ifdef GLM_FORCE_LEFT_HANDED
+#      define GLM_COORDINATE_SYSTEM GLM_LEFT_HANDED
+#else
+#      define GLM_COORDINATE_SYSTEM GLM_RIGHT_HANDED
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_HANDED_DISPLAYED)
+#      define GLM_MESSAGE_HANDED_DISPLAYED
+#      if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+#              pragma message("GLM: Coordinate system: left handed")
+#      else
+#              pragma message("GLM: Coordinate system: right handed")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Qualifiers
+
+#if (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))
+#      define GLM_DEPRECATED __declspec(deprecated)
+#      define GLM_ALIGN(x) __declspec(align(x))
+#      define GLM_ALIGNED_STRUCT(x) struct __declspec(align(x))
+#      define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef __declspec(align(alignment)) type name
+#      define GLM_RESTRICT_FUNC __declspec(restrict)
+#      define GLM_RESTRICT __restrict
+#      if GLM_COMPILER >= GLM_COMPILER_VC12
+#              define GLM_VECTOR_CALL __vectorcall
+#      else
+#              define GLM_VECTOR_CALL
+#      endif
+#elif GLM_COMPILER & (GLM_COMPILER_GCC | GLM_COMPILER_CLANG | GLM_COMPILER_INTEL)
+#      define GLM_DEPRECATED __attribute__((__deprecated__))
+#      define GLM_ALIGN(x) __attribute__((aligned(x)))
+#      define GLM_ALIGNED_STRUCT(x) struct __attribute__((aligned(x)))
+#      define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __attribute__((aligned(alignment)))
+#      define GLM_RESTRICT_FUNC __restrict__
+#      define GLM_RESTRICT __restrict__
+#      if GLM_COMPILER & GLM_COMPILER_CLANG
+#              if GLM_COMPILER >= GLM_COMPILER_CLANG37
+#                      define GLM_VECTOR_CALL __vectorcall
+#              else
+#                      define GLM_VECTOR_CALL
+#              endif
+#      else
+#              define GLM_VECTOR_CALL
+#      endif
+#elif GLM_COMPILER & GLM_COMPILER_CUDA
+#      define GLM_DEPRECATED
+#      define GLM_ALIGN(x) __align__(x)
+#      define GLM_ALIGNED_STRUCT(x) struct __align__(x)
+#      define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name __align__(x)
+#      define GLM_RESTRICT_FUNC __restrict__
+#      define GLM_RESTRICT __restrict__
+#      define GLM_VECTOR_CALL
+#else
+#      define GLM_DEPRECATED
+#      define GLM_ALIGN
+#      define GLM_ALIGNED_STRUCT(x) struct
+#      define GLM_ALIGNED_TYPEDEF(type, name, alignment) typedef type name
+#      define GLM_RESTRICT_FUNC
+#      define GLM_RESTRICT
+#      define GLM_VECTOR_CALL
+#endif//GLM_COMPILER
+
+#if GLM_HAS_DEFAULTED_FUNCTIONS
+#      define GLM_DEFAULT = default
+#      ifdef GLM_FORCE_NO_CTOR_INIT
+#              define GLM_DEFAULT_CTOR = default
+#      else
+#              define GLM_DEFAULT_CTOR
+#      endif
+#else
+#      define GLM_DEFAULT
+#      define GLM_DEFAULT_CTOR
+#endif
+
+#if GLM_HAS_CONSTEXPR || GLM_HAS_CONSTEXPR_PARTIAL
+#      define GLM_CONSTEXPR constexpr
+#      if GLM_COMPILER & GLM_COMPILER_VC // Visual C++ has a bug #594 https://github.com/g-truc/glm/issues/594
+#              define GLM_CONSTEXPR_CTOR
+#      else
+#              define GLM_CONSTEXPR_CTOR constexpr
+#      endif
+#else
+#      define GLM_CONSTEXPR
+#      define GLM_CONSTEXPR_CTOR
+#endif
+
+#if GLM_HAS_CONSTEXPR
+#      define GLM_RELAXED_CONSTEXPR constexpr
+#else
+#      define GLM_RELAXED_CONSTEXPR const
+#endif
+
+#if GLM_ARCH == GLM_ARCH_PURE
+#      define GLM_CONSTEXPR_SIMD GLM_CONSTEXPR_CTOR
+#else
+#      define GLM_CONSTEXPR_SIMD
+#endif
+
+#ifdef GLM_FORCE_EXPLICIT_CTOR
+#      define GLM_EXPLICIT explicit
+#else
+#      define GLM_EXPLICIT
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+
+#define GLM_HAS_ALIGNED_TYPE GLM_HAS_UNRESTRICTED_UNIONS
+
+///////////////////////////////////////////////////////////////////////////////////
+// Length type
+
+// User defines: GLM_FORCE_SIZE_T_LENGTH GLM_FORCE_SIZE_FUNC
+
+namespace glm
+{
+       using std::size_t;
+#      if defined(GLM_FORCE_SIZE_T_LENGTH)
+               typedef size_t length_t;
+#      else
+               typedef int length_t;
+#      endif
+}//namespace glm
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_FORCE_SIZE_T_LENGTH)
+#      define GLM_MESSAGE_FORCE_SIZE_T_LENGTH
+#      if defined GLM_FORCE_SIZE_T_LENGTH
+#              pragma message("GLM: .length() returns glm::length_t, a typedef of std::size_t")
+#      else
+#              pragma message("GLM: .length() returns glm::length_t, a typedef of int following the GLSL specification")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// countof
+
+#ifndef __has_feature
+#      define __has_feature(x) 0 // Compatibility with non-clang compilers.
+#endif
+
+#if GLM_HAS_CONSTEXPR_PARTIAL
+       namespace glm
+       {
+               template <typename T, std::size_t N>
+               constexpr std::size_t countof(T const (&)[N])
+               {
+                       return N;
+               }
+       }//namespace glm
+#      define GLM_COUNTOF(arr) glm::countof(arr)
+#elif defined(_MSC_VER)
+#      define GLM_COUNTOF(arr) _countof(arr)
+#else
+#      define GLM_COUNTOF(arr) sizeof(arr) / sizeof(arr[0])
+#endif
+
+///////////////////////////////////////////////////////////////////////////////////
+// Uninitialize constructors
+
+namespace glm
+{
+       enum ctor{uninitialize};
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_float.hpp b/core/deps/glm/glm/detail/type_float.hpp
new file mode 100755 (executable)
index 0000000..900a3fb
--- /dev/null
@@ -0,0 +1,67 @@
+/// @ref core
+/// @file glm/detail/type_float.hpp
+
+#pragma once
+
+#include "setup.hpp"
+
+namespace glm{
+namespace detail
+{
+       typedef float                           float32;
+       typedef double                          float64;
+}//namespace detail
+       
+       typedef float                           lowp_float_t;
+       typedef float                           mediump_float_t;
+       typedef double                          highp_float_t;
+
+       /// @addtogroup core_precision
+       /// @{
+
+       /// Low precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.4 Floats</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef lowp_float_t            lowp_float;
+
+       /// Medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.4 Floats</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef mediump_float_t         mediump_float;
+
+       /// High precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.4 Floats</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef highp_float_t           highp_float;
+
+#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef mediump_float           float_t;
+#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef highp_float                     float_t;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef mediump_float           float_t;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_float                      float_t;
+#else
+#      error "GLM error: multiple default precision requested for floating-point types"
+#endif
+
+       typedef float                           float32;
+       typedef double                          float64;
+
+////////////////////
+// check type sizes
+#ifndef GLM_STATIC_ASSERT_NULL
+       GLM_STATIC_ASSERT(sizeof(glm::float32) == 4, "float32 size isn't 4 bytes on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::float64) == 8, "float64 size isn't 8 bytes on this platform");
+#endif//GLM_STATIC_ASSERT_NULL
+
+       /// @}
+
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_gentype.hpp b/core/deps/glm/glm/detail/type_gentype.hpp
new file mode 100755 (executable)
index 0000000..8fd202e
--- /dev/null
@@ -0,0 +1,195 @@
+/// @ref core
+/// @file glm/detail/type_gentype.hpp
+
+#pragma once
+
+namespace glm
+{
+       enum profile
+       {
+               nice,
+               fast,
+               simd
+       };
+
+       typedef std::size_t sizeType;
+       
+namespace detail
+{
+       template
+       <
+               typename VALTYPE, 
+               template <typename> class TYPE
+       >
+       struct genType
+       {
+       public:
+               enum ctor{null};
+
+               typedef VALTYPE value_type;
+               typedef VALTYPE & value_reference;
+               typedef VALTYPE * value_pointer;
+               typedef VALTYPE const * value_const_pointer;
+               typedef TYPE<bool> bool_type;
+
+               typedef sizeType size_type;
+               static bool is_vector();
+               static bool is_matrix();
+               
+               typedef TYPE<VALTYPE> type;
+               typedef TYPE<VALTYPE> * pointer;
+               typedef TYPE<VALTYPE> const * const_pointer;
+               typedef TYPE<VALTYPE> const * const const_pointer_const;
+               typedef TYPE<VALTYPE> * const pointer_const;
+               typedef TYPE<VALTYPE> & reference;
+               typedef TYPE<VALTYPE> const & const_reference;
+               typedef TYPE<VALTYPE> const & param_type;
+
+               //////////////////////////////////////
+               // Address (Implementation details)
+
+               value_const_pointer value_address() const{return value_pointer(this);}
+               value_pointer value_address(){return value_pointer(this);}
+
+       //protected:
+       //      enum kind
+       //      {
+       //              GEN_TYPE,
+       //              VEC_TYPE,
+       //              MAT_TYPE
+       //      };
+
+       //      typedef typename TYPE::kind kind;
+       };
+
+       template
+       <
+               typename VALTYPE, 
+               template <typename> class TYPE
+       >
+       bool genType<VALTYPE, TYPE>::is_vector()
+       {
+               return true;
+       }
+/*
+       template <typename valTypeT, unsigned int colT, unsigned int rowT, profile proT = nice>
+       class base
+       {
+       public:
+               //////////////////////////////////////
+               // Traits
+
+               typedef sizeType                                                        size_type;
+               typedef valTypeT                                                        value_type;
+
+               typedef base<value_type, colT, rowT>            class_type;
+
+               typedef base<bool, colT, rowT>                          bool_type;
+               typedef base<value_type, rowT, 1>                       col_type;
+               typedef base<value_type, colT, 1>                       row_type;
+               typedef base<value_type, rowT, colT>            transpose_type;
+
+               static size_type                                                        col_size();
+               static size_type                                                        row_size();
+               static size_type                                                        value_size();
+               static bool                                                                     is_scalar();
+               static bool                                                                     is_vector();
+               static bool                                                                     is_matrix();
+
+       private:
+               // Data 
+               col_type value[colT];           
+
+       public:
+               //////////////////////////////////////
+               // Constructors
+               base();
+               base(class_type const & m);
+
+               explicit base(T const & x);
+               explicit base(value_type const * const x);
+               explicit base(col_type const * const x);
+
+               //////////////////////////////////////
+               // Conversions
+               template <typename vU, uint cU, uint rU, profile pU>
+               explicit base(base<vU, cU, rU, pU> const & m);
+
+               //////////////////////////////////////
+               // Accesses
+               col_type& operator[](size_type i);
+               col_type const & operator[](size_type i) const;
+
+               //////////////////////////////////////
+               // Unary updatable operators
+               class_type& operator=  (class_type const & x);
+               class_type& operator+= (T const & x);
+               class_type& operator+= (class_type const & x);
+               class_type& operator-= (T const & x);
+               class_type& operator-= (class_type const & x);
+               class_type& operator*= (T const & x);
+               class_type& operator*= (class_type const & x);
+               class_type& operator/= (T const & x);
+               class_type& operator/= (class_type const & x);
+               class_type& operator++ ();
+               class_type& operator-- ();
+       };
+*/
+       
+       //template <typename T>
+       //struct traits
+       //{
+       //      static const bool is_signed = false;
+       //      static const bool is_float = false;
+       //      static const bool is_vector = false;
+       //      static const bool is_matrix = false;
+       //      static const bool is_genType = false;
+       //      static const bool is_genIType = false;
+       //      static const bool is_genUType = false;
+       //};
+       
+       //template <>
+       //struct traits<half>
+       //{
+       //      static const bool is_float = true;
+       //      static const bool is_genType = true;
+       //};
+       
+       //template <>
+       //struct traits<float>
+       //{
+       //      static const bool is_float = true;
+       //      static const bool is_genType = true;
+       //};
+       
+       //template <>
+       //struct traits<double>
+       //{
+       //      static const bool is_float = true;
+       //      static const bool is_genType = true;
+       //};
+       
+       //template <typename genType>
+       //struct desc
+       //{
+       //      typedef genType                                                 type;
+       //      typedef genType *                                               pointer;
+       //      typedef genType const*                                  const_pointer;
+       //      typedef genType const *const                    const_pointer_const;
+       //      typedef genType *const                                  pointer_const;
+       //      typedef genType &                                               reference;
+       //      typedef genType const&                                  const_reference;
+       //      typedef genType const&                                  param_type;
+       
+       //      typedef typename genType::value_type    value_type;
+       //      typedef typename genType::size_type             size_type;
+       //      static const typename size_type                 value_size;
+       //};
+       
+       //template <typename genType>
+       //const typename desc<genType>::size_type desc<genType>::value_size = genType::value_size();
+       
+}//namespace detail
+}//namespace glm
+
+//#include "type_gentype.inl"
diff --git a/core/deps/glm/glm/detail/type_gentype.inl b/core/deps/glm/glm/detail/type_gentype.inl
new file mode 100755 (executable)
index 0000000..6a90288
--- /dev/null
@@ -0,0 +1,341 @@
+/// @ref core
+/// @file glm/detail/type_gentype.inl
+
+namespace glm{
+namespace detail{
+
+/////////////////////////////////
+// Static functions
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::size_type base<vT, cT, rT, pT>::col_size()
+{
+       return cT;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::size_type base<vT, cT, rT, pT>::row_size()
+{
+       return rT;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::size_type base<vT, cT, rT, pT>::value_size()
+{
+       return rT * cT;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+bool base<vT, cT, rT, pT>::is_scalar()
+{
+       return rT == 1 && cT == 1;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+bool base<vT, cT, rT, pT>::is_vector()
+{
+       return rT == 1;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+bool base<vT, cT, rT, pT>::is_matrix()
+{
+       return rT != 1;
+}
+
+/////////////////////////////////
+// Constructor
+
+template <typename vT, uint cT, uint rT, profile pT>
+base<vT, cT, rT, pT>::base()
+{
+       memset(&this->value, 0, cT * rT * sizeof(vT));
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+base<vT, cT, rT, pT>::base
+(
+       typename base<vT, cT, rT, pT>::class_type const & m
+)
+{
+       for
+       (
+               typename genType<vT, cT, rT, pT>::size_type i = typename base<vT, cT, rT, pT>::size_type(0);
+               i < base<vT, cT, rT, pT>::col_size();
+               ++i
+       )
+       {
+               this->value[i] = m[i];
+       }
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+base<vT, cT, rT, pT>::base
+(
+       typename base<vT, cT, rT, pT>::T const & x
+)
+{
+       if(rT == 1) // vector
+       {
+               for
+               (
+                       typename base<vT, cT, rT, pT>::size_type i = typename base<vT, cT, rT, pT>::size_type(0);
+                       i < base<vT, cT, rT, pT>::col_size();
+                       ++i
+               )
+               {
+                       this->value[i][rT] = x;
+               }
+       }
+       else // matrix
+       {
+               memset(&this->value, 0, cT * rT * sizeof(vT));
+
+               typename base<vT, cT, rT, pT>::size_type stop = cT < rT ? cT : rT;
+
+               for
+               (
+                       typename base<vT, cT, rT, pT>::size_type i = typename base<vT, cT, rT, pT>::size_type(0);
+                       i < stop;
+                       ++i
+               )
+               {
+                       this->value[i][i] = x;
+               }
+       }
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+base<vT, cT, rT, pT>::base
+(
+       typename base<vT, cT, rT, pT>::value_type const * const x
+)
+{
+       memcpy(&this->value, &x.value, cT * rT * sizeof(vT));
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+base<vT, cT, rT, pT>::base
+(
+       typename base<vT, cT, rT, pT>::col_type const * const x
+)
+{
+       for
+       (
+               typename base<vT, cT, rT, pT>::size_type i = typename base<vT, cT, rT, pT>::size_type(0);
+               i < base<vT, cT, rT, pT>::col_size();
+               ++i
+       )
+       {
+               this->value[i] = x[i];
+       }
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+template <typename vU, uint cU, uint rU, profile pU>
+base<vT, cT, rT, pT>::base
+(
+       base<vU, cU, rU, pU> const & m
+)
+{
+       for
+       (
+               typename base<vT, cT, rT, pT>::size_type i = typename base<vT, cT, rT, pT>::size_type(0);
+               i < base<vT, cT, rT, pT>::col_size();
+               ++i
+       )
+       {
+               this->value[i] = base<vT, cT, rT, pT>(m[i]);
+       }
+}
+
+//////////////////////////////////////
+// Accesses
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::col_type& base<vT, cT, rT, pT>::operator[]
+(
+       typename base<vT, cT, rT, pT>::size_type i
+)
+{
+       return this->value[i];
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::col_type const & base<vT, cT, rT, pT>::operator[]
+(
+       typename base<vT, cT, rT, pT>::size_type i
+) const
+{
+       return this->value[i];
+}
+
+//////////////////////////////////////
+// Unary updatable operators
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator= 
+(
+       typename base<vT, cT, rT, pT>::class_type const & x
+)
+{
+       memcpy(&this->value, &x.value, cT * rT * sizeof(vT));
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator+= 
+(
+       typename base<vT, cT, rT, pT>::T const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] += x;
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator+= 
+(
+       typename base<vT, cT, rT, pT>::class_type const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] += x[j][i];
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator-= 
+(
+       typename base<vT, cT, rT, pT>::T const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] -= x;
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator-= 
+(
+       typename base<vT, cT, rT, pT>::class_type const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] -= x[j][i];
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator*= 
+(
+       typename base<vT, cT, rT, pT>::T const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] *= x;
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator*= 
+(
+       typename base<vT, cT, rT, pT>::class_type const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] *= x[j][i];
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator/= 
+(
+       typename base<vT, cT, rT, pT>::T const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] /= x;
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator/= 
+(
+       typename base<vT, cT, rT, pT>::class_type const & x
+)
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = x.col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = x.row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               this->value[j][i] /= x[j][i];
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator++ ()
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               ++this->value[j][i];
+
+       return *this;
+}
+
+template <typename vT, uint cT, uint rT, profile pT>
+typename base<vT, cT, rT, pT>::class_type& base<vT, cT, rT, pT>::operator-- ()
+{
+       typename base<vT, cT, rT, pT>::size_type stop_col = col_size();
+       typename base<vT, cT, rT, pT>::size_type stop_row = row_size();
+
+       for(typename base<vT, cT, rT, pT>::size_type j = 0; j < stop_col; ++j)
+       for(typename base<vT, cT, rT, pT>::size_type i = 0; i < stop_row; ++i)
+               --this->value[j][i];
+
+       return *this;
+}
+
+} //namespace detail
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_half.hpp b/core/deps/glm/glm/detail/type_half.hpp
new file mode 100755 (executable)
index 0000000..c3ef617
--- /dev/null
@@ -0,0 +1,19 @@
+/// @ref core
+/// @file glm/detail/type_half.hpp
+
+#pragma once
+
+#include "setup.hpp"
+
+namespace glm{
+namespace detail
+{
+       typedef short hdata;
+
+       GLM_FUNC_DECL float toFloat32(hdata value);
+       GLM_FUNC_DECL hdata toFloat16(float const & value);
+
+}//namespace detail
+}//namespace glm
+
+#include "type_half.inl"
diff --git a/core/deps/glm/glm/detail/type_half.inl b/core/deps/glm/glm/detail/type_half.inl
new file mode 100755 (executable)
index 0000000..78d3e26
--- /dev/null
@@ -0,0 +1,244 @@
+/// @ref core
+/// @file glm/detail/type_half.inl
+
+namespace glm{
+namespace detail
+{
+       GLM_FUNC_QUALIFIER float overflow()
+       {
+               volatile float f = 1e10;
+
+               for(int i = 0; i < 10; ++i)     
+                       f *= f; // this will overflow before the for loop terminates
+               return f;
+       }
+
+       union uif32
+       {
+               GLM_FUNC_QUALIFIER uif32() :
+                       i(0)
+               {}
+
+               GLM_FUNC_QUALIFIER uif32(float f_) :
+                       f(f_)
+               {}
+
+               GLM_FUNC_QUALIFIER uif32(uint32 i_) :
+                       i(i_)
+               {}
+
+               float f;
+               uint32 i;
+       };
+
+       GLM_FUNC_QUALIFIER float toFloat32(hdata value)
+       {
+               int s = (value >> 15) & 0x00000001;
+               int e = (value >> 10) & 0x0000001f;
+               int m =  value        & 0x000003ff;
+
+               if(e == 0)
+               {
+                       if(m == 0)
+                       {
+                               //
+                               // Plus or minus zero
+                               //
+
+                               detail::uif32 result;
+                               result.i = (unsigned int)(s << 31);
+                               return result.f;
+                       }
+                       else
+                       {
+                               //
+                               // Denormalized number -- renormalize it
+                               //
+
+                               while(!(m & 0x00000400))
+                               {
+                                       m <<= 1;
+                                       e -=  1;
+                               }
+
+                               e += 1;
+                               m &= ~0x00000400;
+                       }
+               }
+               else if(e == 31)
+               {
+                       if(m == 0)
+                       {
+                               //
+                               // Positive or negative infinity
+                               //
+
+                               uif32 result;
+                               result.i = (unsigned int)((s << 31) | 0x7f800000);
+                               return result.f;
+                       }
+                       else
+                       {
+                               //
+                               // Nan -- preserve sign and significand bits
+                               //
+
+                               uif32 result;
+                               result.i = (unsigned int)((s << 31) | 0x7f800000 | (m << 13));
+                               return result.f;
+                       }
+               }
+
+               //
+               // Normalized number
+               //
+
+               e = e + (127 - 15);
+               m = m << 13;
+
+               //
+               // Assemble s, e and m.
+               //
+
+               uif32 Result;
+               Result.i = (unsigned int)((s << 31) | (e << 23) | m);
+               return Result.f;
+       }
+
+       GLM_FUNC_QUALIFIER hdata toFloat16(float const & f)
+       {
+               uif32 Entry;
+               Entry.f = f;
+               int i = (int)Entry.i;
+
+               //
+               // Our floating point number, f, is represented by the bit
+               // pattern in integer i.  Disassemble that bit pattern into
+               // the sign, s, the exponent, e, and the significand, m.
+               // Shift s into the position where it will go in in the
+               // resulting half number.
+               // Adjust e, accounting for the different exponent bias
+               // of float and half (127 versus 15).
+               //
+
+               int s =  (i >> 16) & 0x00008000;
+               int e = ((i >> 23) & 0x000000ff) - (127 - 15);
+               int m =   i        & 0x007fffff;
+
+               //
+               // Now reassemble s, e and m into a half:
+               //
+
+               if(e <= 0)
+               {
+                       if(e < -10)
+                       {
+                               //
+                               // E is less than -10.  The absolute value of f is
+                               // less than half_MIN (f may be a small normalized
+                               // float, a denormalized float or a zero).
+                               //
+                               // We convert f to a half zero.
+                               //
+
+                               return hdata(s);
+                       }
+
+                       //
+                       // E is between -10 and 0.  F is a normalized float,
+                       // whose magnitude is less than __half_NRM_MIN.
+                       //
+                       // We convert f to a denormalized half.
+                       // 
+
+                       m = (m | 0x00800000) >> (1 - e);
+
+                       //
+                       // Round to nearest, round "0.5" up.
+                       //
+                       // Rounding may cause the significand to overflow and make
+                       // our number normalized.  Because of the way a half's bits
+                       // are laid out, we don't have to treat this case separately;
+                       // the code below will handle it correctly.
+                       // 
+
+                       if(m & 0x00001000) 
+                               m += 0x00002000;
+
+                       //
+                       // Assemble the half from s, e (zero) and m.
+                       //
+
+                       return hdata(s | (m >> 13));
+               }
+               else if(e == 0xff - (127 - 15))
+               {
+                       if(m == 0)
+                       {
+                               //
+                               // F is an infinity; convert f to a half
+                               // infinity with the same sign as f.
+                               //
+
+                               return hdata(s | 0x7c00);
+                       }
+                       else
+                       {
+                               //
+                               // F is a NAN; we produce a half NAN that preserves
+                               // the sign bit and the 10 leftmost bits of the
+                               // significand of f, with one exception: If the 10
+                               // leftmost bits are all zero, the NAN would turn 
+                               // into an infinity, so we have to set at least one
+                               // bit in the significand.
+                               //
+
+                               m >>= 13;
+
+                               return hdata(s | 0x7c00 | m | (m == 0));
+                       }
+               }
+               else
+               {
+                       //
+                       // E is greater than zero.  F is a normalized float.
+                       // We try to convert f to a normalized half.
+                       //
+
+                       //
+                       // Round to nearest, round "0.5" up
+                       //
+
+                       if(m &  0x00001000)
+                       {
+                               m += 0x00002000;
+
+                               if(m & 0x00800000)
+                               {
+                                       m =  0;     // overflow in significand,
+                                       e += 1;     // adjust exponent
+                               }
+                       }
+
+                       //
+                       // Handle exponent overflow
+                       //
+
+                       if (e > 30)
+                       {
+                               overflow();        // Cause a hardware floating point overflow;
+
+                               return hdata(s | 0x7c00);
+                               // if this returns, the half becomes an
+                       }   // infinity with the same sign as f.
+
+                       //
+                       // Assemble the half from s, e and m.
+                       //
+
+                       return hdata(s | (e << 10) | (m >> 13));
+               }
+       }
+
+}//namespace detail
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_int.hpp b/core/deps/glm/glm/detail/type_int.hpp
new file mode 100755 (executable)
index 0000000..764a32c
--- /dev/null
@@ -0,0 +1,306 @@
+/// @ref core
+/// @file glm/detail/type_int.hpp
+
+#pragma once
+
+#include "setup.hpp"
+#if GLM_HAS_MAKE_SIGNED
+#      include <type_traits>
+#endif
+
+#if GLM_HAS_EXTENDED_INTEGER_TYPE
+#      include <cstdint>
+#endif
+
+namespace glm{
+namespace detail
+{
+#      if GLM_HAS_EXTENDED_INTEGER_TYPE
+               typedef std::int8_t                                     int8;
+               typedef std::int16_t                            int16;
+               typedef std::int32_t                            int32;
+               typedef std::int64_t                            int64;
+       
+               typedef std::uint8_t                            uint8;
+               typedef std::uint16_t                           uint16;
+               typedef std::uint32_t                           uint32;
+               typedef std::uint64_t                           uint64;
+#      else
+#              if(defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L)) // C99 detected, 64 bit types available
+                       typedef int64_t                                 sint64;
+                       typedef uint64_t                                uint64;
+       
+#              elif GLM_COMPILER & GLM_COMPILER_VC
+                       typedef signed __int64                  sint64;
+                       typedef unsigned __int64                uint64;
+       
+#              elif GLM_COMPILER & GLM_COMPILER_GCC
+#                      pragma GCC diagnostic ignored "-Wlong-long"
+                       __extension__ typedef signed long long          sint64;
+                       __extension__ typedef unsigned long long        uint64;
+       
+#              elif (GLM_COMPILER & GLM_COMPILER_CLANG)
+#                      pragma clang diagnostic ignored "-Wc++11-long-long"
+                       typedef signed long     long            sint64;
+                       typedef unsigned long long              uint64;
+       
+#              else//unknown compiler
+                       typedef signed long     long            sint64;
+                       typedef unsigned long long              uint64;
+#              endif//GLM_COMPILER
+               
+               typedef signed char                                     int8;
+               typedef signed short                            int16;
+               typedef signed int                                      int32;
+               typedef sint64                                          int64;
+       
+               typedef unsigned char                           uint8;
+               typedef unsigned short                          uint16;
+               typedef unsigned int                            uint32;
+               typedef uint64                                          uint64;
+#endif//
+       
+       typedef signed int                                              lowp_int_t;
+       typedef signed int                                              mediump_int_t;
+       typedef signed int                                              highp_int_t;
+       
+       typedef unsigned int                                    lowp_uint_t;
+       typedef unsigned int                                    mediump_uint_t;
+       typedef unsigned int                                    highp_uint_t;
+
+#      if GLM_HAS_MAKE_SIGNED
+               using std::make_signed;
+               using std::make_unsigned;
+
+#      else//GLM_HAS_MAKE_SIGNED
+               template <typename genType>
+               struct make_signed
+               {};
+
+               template <>
+               struct make_signed<char>
+               {
+                       typedef char type;
+               };
+
+               template <>
+               struct make_signed<short>
+               {
+                       typedef short type;
+               };
+
+               template <>
+               struct make_signed<int>
+               {
+                       typedef int type;
+               };
+
+               template <>
+               struct make_signed<long>
+               {
+                       typedef long type;
+               };
+       
+               template <>
+               struct make_signed<unsigned char>
+               {
+                       typedef char type;
+               };
+
+               template <>
+               struct make_signed<unsigned short>
+               {
+                       typedef short type;
+               };
+
+               template <>
+               struct make_signed<unsigned int>
+               {
+                       typedef int type;
+               };
+
+               template <>
+               struct make_signed<unsigned long>
+               {
+                       typedef long type;
+               };
+
+               template <typename genType>
+               struct make_unsigned
+               {};
+
+               template <>
+               struct make_unsigned<char>
+               {
+                       typedef unsigned char type;
+               };
+
+               template <>
+               struct make_unsigned<short>
+               {
+                       typedef unsigned short type;
+               };
+
+               template <>
+               struct make_unsigned<int>
+               {
+                       typedef unsigned int type;
+               };
+
+               template <>
+               struct make_unsigned<long>
+               {
+                       typedef unsigned long type;
+               };
+
+               template <>
+               struct make_unsigned<unsigned char>
+               {
+                       typedef unsigned char type;
+               };
+
+               template <>
+               struct make_unsigned<unsigned short>
+               {
+                       typedef unsigned short type;
+               };
+
+               template <>
+               struct make_unsigned<unsigned int>
+               {
+                       typedef unsigned int type;
+               };
+
+               template <>
+               struct make_unsigned<unsigned long>
+               {
+                       typedef unsigned long type;
+               };
+
+               template <>
+               struct make_signed<long long>
+               {
+                       typedef long long type;
+               };
+       
+               template <>
+               struct make_signed<unsigned long long>
+               {
+                       typedef long long type;
+               };
+       
+               template <>
+               struct make_unsigned<long long>
+               {
+                       typedef unsigned long long type;
+               };
+       
+               template <>
+               struct make_unsigned<unsigned long long>
+               {
+                       typedef unsigned long long type;
+               };
+#      endif//GLM_HAS_MAKE_SIGNED
+}//namespace detail
+
+       typedef detail::int8                                    int8;
+       typedef detail::int16                                   int16;
+       typedef detail::int32                                   int32;
+       typedef detail::int64                                   int64;
+       
+       typedef detail::uint8                                   uint8;
+       typedef detail::uint16                                  uint16;
+       typedef detail::uint32                                  uint32;
+       typedef detail::uint64                                  uint64;
+
+       /// @addtogroup core_precision
+       /// @{
+
+       /// Low precision signed integer. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::lowp_int_t                              lowp_int;
+
+       /// Medium precision signed integer. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::mediump_int_t                   mediump_int;
+
+       /// High precision signed integer.
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::highp_int_t                             highp_int;
+
+       /// Low precision unsigned integer. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::lowp_uint_t                             lowp_uint;
+
+       /// Medium precision unsigned integer. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::mediump_uint_t                  mediump_uint;
+
+       /// High precision unsigned integer. 
+       /// There is no guarantee on the actual precision.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef detail::highp_uint_t                    highp_uint;
+
+#if(!defined(GLM_PRECISION_HIGHP_INT) && !defined(GLM_PRECISION_MEDIUMP_INT) && !defined(GLM_PRECISION_LOWP_INT))
+       typedef mediump_int                                     int_t;
+#elif(defined(GLM_PRECISION_HIGHP_INT) && !defined(GLM_PRECISION_MEDIUMP_INT) && !defined(GLM_PRECISION_LOWP_INT))
+       typedef highp_int                                       int_t;
+#elif(!defined(GLM_PRECISION_HIGHP_INT) && defined(GLM_PRECISION_MEDIUMP_INT) && !defined(GLM_PRECISION_LOWP_INT))
+       typedef mediump_int                                     int_t;
+#elif(!defined(GLM_PRECISION_HIGHP_INT) && !defined(GLM_PRECISION_MEDIUMP_INT) && defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_int                                        int_t;
+#else
+#      error "GLM error: multiple default precision requested for signed integer types"
+#endif
+
+#if(!defined(GLM_PRECISION_HIGHP_UINT) && !defined(GLM_PRECISION_MEDIUMP_UINT) && !defined(GLM_PRECISION_LOWP_UINT))
+       typedef mediump_uint                            uint_t;
+#elif(defined(GLM_PRECISION_HIGHP_UINT) && !defined(GLM_PRECISION_MEDIUMP_UINT) && !defined(GLM_PRECISION_LOWP_UINT))
+       typedef highp_uint                                      uint_t;
+#elif(!defined(GLM_PRECISION_HIGHP_UINT) && defined(GLM_PRECISION_MEDIUMP_UINT) && !defined(GLM_PRECISION_LOWP_UINT))
+       typedef mediump_uint                            uint_t;
+#elif(!defined(GLM_PRECISION_HIGHP_UINT) && !defined(GLM_PRECISION_MEDIUMP_UINT) && defined(GLM_PRECISION_LOWP_UINT))
+       typedef lowp_uint                                       uint_t;
+#else
+#      error "GLM error: multiple default precision requested for unsigned integer types"
+#endif
+
+       /// Unsigned integer type.
+       /// 
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.3 Integers</a>
+       typedef unsigned int                            uint;
+
+       /// @}
+
+////////////////////
+// check type sizes
+#ifndef GLM_STATIC_ASSERT_NULL
+       GLM_STATIC_ASSERT(sizeof(glm::int8) == 1, "int8 size isn't 1 byte on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::int16) == 2, "int16 size isn't 2 bytes on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::int32) == 4, "int32 size isn't 4 bytes on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::int64) == 8, "int64 size isn't 8 bytes on this platform");
+
+       GLM_STATIC_ASSERT(sizeof(glm::uint8) == 1, "uint8 size isn't 1 byte on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::uint16) == 2, "uint16 size isn't 2 bytes on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::uint32) == 4, "uint32 size isn't 4 bytes on this platform");
+       GLM_STATIC_ASSERT(sizeof(glm::uint64) == 8, "uint64 size isn't 8 bytes on this platform");
+#endif//GLM_STATIC_ASSERT_NULL
+
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat.hpp b/core/deps/glm/glm/detail/type_mat.hpp
new file mode 100755 (executable)
index 0000000..aad74e5
--- /dev/null
@@ -0,0 +1,767 @@
+/// @ref core
+/// @file glm/detail/type_mat.hpp
+
+#pragma once
+
+#include "precision.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <class, precision> class colType, template <class, precision> class rowType>
+       struct outerProduct_trait{};
+}//namespace detail
+
+       template <typename T, precision P> struct tvec2;
+       template <typename T, precision P> struct tvec3;
+       template <typename T, precision P> struct tvec4;
+       template <typename T, precision P> struct tmat2x2;
+       template <typename T, precision P> struct tmat2x3;
+       template <typename T, precision P> struct tmat2x4;
+       template <typename T, precision P> struct tmat3x2;
+       template <typename T, precision P> struct tmat3x3;
+       template <typename T, precision P> struct tmat3x4;
+       template <typename T, precision P> struct tmat4x2;
+       template <typename T, precision P> struct tmat4x3;
+       template <typename T, precision P> struct tmat4x4;
+
+       template <typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL matType<T, P> inverse(matType<T, P> const & m);
+
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, lowp>            lowp_mat2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, mediump>         mediump_mat2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, highp>           highp_mat2;
+       
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, lowp>            lowp_mat2x2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, mediump>         mediump_mat2x2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, highp>           highp_mat2x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, lowp>            lowp_mat2x3;
+       
+       /// 2 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, mediump>         mediump_mat2x3;
+       
+       /// 2 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, highp>           highp_mat2x3;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, lowp>            lowp_mat2x4;
+       
+       /// 2 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, mediump>         mediump_mat2x4;
+       
+       /// 2 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, highp>           highp_mat2x4;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, lowp>            lowp_mat3x2;
+       
+       /// 3 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, mediump>         mediump_mat3x2;
+       
+       /// 3 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, highp>           highp_mat3x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, lowp>            lowp_mat3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, mediump>         mediump_mat3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, highp>           highp_mat3;
+       
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, lowp>            lowp_mat3x3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, mediump>         mediump_mat3x3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, highp>           highp_mat3x3;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, lowp>            lowp_mat3x4;
+       
+       /// 3 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, mediump>         mediump_mat3x4;
+       
+       /// 3 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, highp>           highp_mat3x4;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, lowp>            lowp_mat4x2;
+       
+       /// 4 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, mediump>         mediump_mat4x2;
+       
+       /// 4 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, highp>           highp_mat4x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, lowp>            lowp_mat4x3;
+       
+       /// 4 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, mediump>         mediump_mat4x3;
+       
+       /// 4 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, highp>           highp_mat4x3;
+       
+       /// @}
+       
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, lowp>            lowp_mat4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, mediump>         mediump_mat4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, highp>           highp_mat4;
+       
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, lowp>            lowp_mat4x4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, mediump>         mediump_mat4x4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, highp>           highp_mat4x4;
+       
+       /// @}
+       
+       /// @addtogroup core_types
+       /// @{
+       
+       //////////////////////////
+       // Float definition
+       
+#if(defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_mat2x2                     mat2x2;
+       typedef lowp_mat2x3                     mat2x3;
+       typedef lowp_mat2x4                     mat2x4;
+       typedef lowp_mat3x2                     mat3x2;
+       typedef lowp_mat3x3                     mat3x3;
+       typedef lowp_mat3x4                     mat3x4;
+       typedef lowp_mat4x2                     mat4x2;
+       typedef lowp_mat4x3                     mat4x3;
+       typedef lowp_mat4x4                     mat4x4;
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+       typedef mediump_mat2x2          mat2x2;
+       typedef mediump_mat2x3          mat2x3;
+       typedef mediump_mat2x4          mat2x4;
+       typedef mediump_mat3x2          mat3x2;
+       typedef mediump_mat3x3          mat3x3;
+       typedef mediump_mat3x4          mat3x4;
+       typedef mediump_mat4x2          mat4x2;
+       typedef mediump_mat4x3          mat4x3;
+       typedef mediump_mat4x4          mat4x4;
+#else  
+       //! 2 columns of 2 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat2x2                    mat2x2;
+       
+       //! 2 columns of 3 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat2x3                    mat2x3;
+       
+       //! 2 columns of 4 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat2x4                    mat2x4;
+       
+       //! 3 columns of 2 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat3x2                    mat3x2;
+       
+       //! 3 columns of 3 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat3x3                    mat3x3;
+       
+       //! 3 columns of 4 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat3x4                    mat3x4;
+       
+       //! 4 columns of 2 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat4x2                    mat4x2;
+       
+       //! 4 columns of 3 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat4x3                    mat4x3;
+       
+       //! 4 columns of 4 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_mat4x4                    mat4x4;
+       
+#endif//GLM_PRECISION
+       
+       //! 2 columns of 2 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef mat2x2                                  mat2;
+       
+       //! 3 columns of 3 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef mat3x3                                  mat3;
+       
+       //! 4 columns of 4 components matrix of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef mat4x4                                  mat4;
+               
+       //////////////////////////
+       // Double definition
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, lowp>           lowp_dmat2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, mediump>        mediump_dmat2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, highp>          highp_dmat2;
+       
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, lowp>           lowp_dmat2x2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, mediump>        mediump_dmat2x2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<double, highp>          highp_dmat2x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 3 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<double, lowp>           lowp_dmat2x3;
+       
+       /// 2 columns of 3 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<double, mediump>        mediump_dmat2x3;
+       
+       /// 2 columns of 3 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<double, highp>          highp_dmat2x3;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 2 columns of 4 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<double, lowp>           lowp_dmat2x4;
+       
+       /// 2 columns of 4 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<double, mediump>        mediump_dmat2x4;
+       
+       /// 2 columns of 4 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<double, highp>          highp_dmat2x4;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 2 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<double, lowp>           lowp_dmat3x2;
+       
+       /// 3 columns of 2 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<double, mediump>        mediump_dmat3x2;
+       
+       /// 3 columns of 2 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<double, highp>          highp_dmat3x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, lowp>            lowp_dmat3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<double, mediump>        mediump_dmat3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<double, highp>          highp_dmat3;
+       
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<double, lowp>           lowp_dmat3x3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<double, mediump>        mediump_dmat3x3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<double, highp>          highp_dmat3x3;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 3 columns of 4 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<double, lowp>           lowp_dmat3x4;
+       
+       /// 3 columns of 4 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<double, mediump>        mediump_dmat3x4;
+       
+       /// 3 columns of 4 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<double, highp>          highp_dmat3x4;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 2 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<double, lowp>           lowp_dmat4x2;
+       
+       /// 4 columns of 2 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<double, mediump>        mediump_dmat4x2;
+       
+       /// 4 columns of 2 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<double, highp>          highp_dmat4x2;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 3 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<double, lowp>           lowp_dmat4x3;
+       
+       /// 4 columns of 3 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<double, mediump>        mediump_dmat4x3;
+       
+       /// 4 columns of 3 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<double, highp>          highp_dmat4x3;
+       
+       /// @}
+       
+       /// @addtogroup core_precision
+       /// @{
+       
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, lowp>           lowp_dmat4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, mediump>        mediump_dmat4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, highp>          highp_dmat4;
+       
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, lowp>           lowp_dmat4x4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, mediump>        mediump_dmat4x4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<double, highp>          highp_dmat4x4;
+       
+       /// @}
+       
+#if(defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_dmat2x2            dmat2x2;
+       typedef lowp_dmat2x3            dmat2x3;
+       typedef lowp_dmat2x4            dmat2x4;
+       typedef lowp_dmat3x2            dmat3x2;
+       typedef lowp_dmat3x3            dmat3x3;
+       typedef lowp_dmat3x4            dmat3x4;
+       typedef lowp_dmat4x2            dmat4x2;
+       typedef lowp_dmat4x3            dmat4x3;
+       typedef lowp_dmat4x4            dmat4x4;
+#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))
+       typedef mediump_dmat2x2         dmat2x2;
+       typedef mediump_dmat2x3         dmat2x3;
+       typedef mediump_dmat2x4         dmat2x4;
+       typedef mediump_dmat3x2         dmat3x2;
+       typedef mediump_dmat3x3         dmat3x3;
+       typedef mediump_dmat3x4         dmat3x4;
+       typedef mediump_dmat4x2         dmat4x2;
+       typedef mediump_dmat4x3         dmat4x3;
+       typedef mediump_dmat4x4         dmat4x4;
+#else //defined(GLM_PRECISION_HIGHP_DOUBLE)
+       
+       //! 2 * 2 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat2x2           dmat2;
+       
+       //! 3 * 3 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat3x3           dmat3;
+       
+       //! 4 * 4 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat4x4           dmat4;
+       
+       //! 2 * 2 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat2x2           dmat2x2;
+       
+       //! 2 * 3 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat2x3           dmat2x3;
+       
+       //! 2 * 4 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat2x4           dmat2x4;
+       
+       //! 3 * 2 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat3x2           dmat3x2;
+       
+       /// 3 * 3 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat3x3           dmat3x3;
+       
+       /// 3 * 4 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat3x4           dmat3x4;
+       
+       /// 4 * 2 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat4x2           dmat4x2;
+       
+       /// 4 * 3 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat4x3           dmat4x3;
+       
+       /// 4 * 4 matrix of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       typedef highp_dmat4x4           dmat4x4;
+
+#endif//GLM_PRECISION
+       
+       /// @}
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat.inl b/core/deps/glm/glm/detail/type_mat.inl
new file mode 100755 (executable)
index 0000000..5714995
--- /dev/null
@@ -0,0 +1,3 @@
+/// @ref core
+/// @file glm/detail/type_mat.inl
+
diff --git a/core/deps/glm/glm/detail/type_mat2x2.hpp b/core/deps/glm/glm/detail/type_mat2x2.hpp
new file mode 100755 (executable)
index 0000000..e7fde26
--- /dev/null
@@ -0,0 +1,183 @@
+/// @ref core
+/// @file glm/detail/type_mat2x2.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec2.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat2x2
+       {
+               typedef tvec2<T, P> col_type;
+               typedef tvec2<T, P> row_type;
+               typedef tmat2x2<T, P> type;
+               typedef tmat2x2<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[2];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat2x2() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat2x2(tmat2x2<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat2x2(tmat2x2<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat2x2(ctor);
+               GLM_FUNC_DECL explicit tmat2x2(T scalar);
+               GLM_FUNC_DECL tmat2x2(
+                       T const & x1, T const & y1,
+                       T const & x2, T const & y2);
+               GLM_FUNC_DECL tmat2x2(
+                       col_type const & v1,
+                       col_type const & v2);
+
+               // -- Conversions --
+
+               template <typename U, typename V, typename M, typename N>
+               GLM_FUNC_DECL tmat2x2(
+                       U const & x1, V const & y1,
+                       M const & x2, N const & y2);
+
+               template <typename U, typename V>
+               GLM_FUNC_DECL tmat2x2(
+                       tvec2<U, P> const & v1,
+                       tvec2<V, P> const & v2);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat2x2<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x2(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 2;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat2x2<T, P> & operator=(tmat2x2<T, P> const & v) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator=(tmat2x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator+=(tmat2x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator-=(tmat2x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator*=(tmat2x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator/=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x2<T, P> & operator/=(tmat2x2<U, P> const & m);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat2x2<T, P> & operator++ ();
+               GLM_FUNC_DECL tmat2x2<T, P> & operator-- ();
+               GLM_FUNC_DECL tmat2x2<T, P> operator++(int);
+               GLM_FUNC_DECL tmat2x2<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator+(tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator-(tmat2x2<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator+(tmat2x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator+(T scalar, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator+(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator-(tmat2x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator-(T scalar, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator-(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator*(tmat2x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator*(T scalar, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x2<T, P>::col_type operator*(tmat2x2<T, P> const & m, typename tmat2x2<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x2<T, P>::row_type operator*(typename tmat2x2<T, P>::col_type const & v, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator/(tmat2x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator/(T scalar, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x2<T, P>::col_type operator/(tmat2x2<T, P> const & m, typename tmat2x2<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x2<T, P>::row_type operator/(typename tmat2x2<T, P>::col_type const & v, tmat2x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator/(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2);
+} //namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat2x2.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat2x2.inl b/core/deps/glm/glm/detail/type_mat2x2.inl
new file mode 100755 (executable)
index 0000000..02c5ee8
--- /dev/null
@@ -0,0 +1,484 @@
+/// @ref core
+/// @file glm/detail/type_mat2x2.inl
+
+#include "func_matrix.hpp"
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0);
+                               this->value[1] = col_type(0, 1);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat2x2<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat2x2<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat2x2<T, P>::tmat2x2(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0);
+               this->value[1] = col_type(0, scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2
+       (
+               T const & x0, T const & y0,
+               T const & x1, T const & y1
+       )
+       {
+               this->value[0] = col_type(x0, y0);
+               this->value[1] = col_type(x1, y1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(col_type const & v0, col_type const & v1)
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <typename X1, typename Y1, typename X2, typename Y2>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2
+       (
+               X1 const & x1, Y1 const & y1,
+               X2 const & x2, Y2 const & y2
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tvec2<V1, P> const & v1, tvec2<V2, P> const & v2)
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+       }
+
+       // -- mat2x2 matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat2x2<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>::tmat2x2(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::col_type & tmat2x2<T, P>::operator[](typename tmat2x2<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::col_type const & tmat2x2<T, P>::operator[](typename tmat2x2<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator=(tmat2x2<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator=(tmat2x2<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator+=(U scalar)
+       {
+               this->value[0] += scalar;
+               this->value[1] += scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator+=(tmat2x2<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator-=(U scalar)
+       {
+               this->value[0] -= scalar;
+               this->value[1] -= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator-=(tmat2x2<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator*=(U scalar)
+       {
+               this->value[0] *= scalar;
+               this->value[1] *= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator*=(tmat2x2<U, P> const & m)
+       {
+               return (*this = *this * m);
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator/=(U scalar)
+       {
+               this->value[0] /= scalar;
+               this->value[1] /= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator/=(tmat2x2<U, P> const & m)
+       {
+               return *this *= inverse(m);
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P>& tmat2x2<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> tmat2x2<T, P>::operator++(int)
+       {
+               tmat2x2<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> tmat2x2<T, P>::operator--(int)
+       {
+               tmat2x2<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator+(tmat2x2<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator-(tmat2x2<T, P> const & m)
+       {
+               return tmat2x2<T, P>(
+                       -m[0], 
+                       -m[1]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator+(tmat2x2<T, P> const & m, T scalar)
+       {
+               return tmat2x2<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator+(T scalar, tmat2x2<T, P> const & m)
+       {
+               return tmat2x2<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator+(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return tmat2x2<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator-(tmat2x2<T, P> const & m, T scalar)
+       {
+               return tmat2x2<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator-(T scalar, tmat2x2<T, P> const & m)
+       {
+               return tmat2x2<T, P>(
+                       scalar - m[0],
+                       scalar - m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator-(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return tmat2x2<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator*(tmat2x2<T, P> const & m, T scalar)
+       {
+               return tmat2x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator*(T scalar, tmat2x2<T, P> const & m)
+       {
+               return tmat2x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::col_type operator*
+       (
+               tmat2x2<T, P> const & m,
+               typename tmat2x2<T, P>::row_type const & v
+       )
+       {
+               return tvec2<T, P>(
+                       m[0][0] * v.x + m[1][0] * v.y,
+                       m[0][1] * v.x + m[1][1] * v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::row_type operator*
+       (
+               typename tmat2x2<T, P>::col_type const & v,
+               tmat2x2<T, P> const & m
+       )
+       {
+               return tvec2<T, P>(
+                       v.x * m[0][0] + v.y * m[0][1],
+                       v.x * m[1][0] + v.y * m[1][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return tmat2x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return tmat3x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator*(tmat2x2<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return tmat4x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator/(tmat2x2<T, P> const & m, T scalar)
+       {
+               return tmat2x2<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator/(T scalar, tmat2x2<T, P> const & m)
+       {
+               return tmat2x2<T, P>(
+                       scalar / m[0],
+                       scalar / m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::col_type operator/(tmat2x2<T, P> const & m, typename tmat2x2<T, P>::row_type const & v)
+       {
+               return inverse(m) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x2<T, P>::row_type operator/(typename tmat2x2<T, P>::col_type const & v, tmat2x2<T, P> const & m)
+       {
+               return v *  inverse(m);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator/(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {       
+               tmat2x2<T, P> m1_copy(m1);
+               return m1_copy /= m2;
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat2x2<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat2x3.hpp b/core/deps/glm/glm/detail/type_mat2x3.hpp
new file mode 100755 (executable)
index 0000000..db55886
--- /dev/null
@@ -0,0 +1,165 @@
+/// @ref core
+/// @file glm/detail/type_mat2x3.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat2x3
+       {
+               typedef tvec3<T, P> col_type;
+               typedef tvec2<T, P> row_type;
+               typedef tmat2x3<T, P> type;
+               typedef tmat3x2<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[2];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat2x3() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat2x3(tmat2x3<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat2x3(tmat2x3<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat2x3(ctor);
+               GLM_FUNC_DECL explicit tmat2x3(T scalar);
+               GLM_FUNC_DECL tmat2x3(
+                       T x0, T y0, T z0,
+                       T x1, T y1, T z1);
+               GLM_FUNC_DECL tmat2x3(
+                       col_type const & v0,
+                       col_type const & v1);
+
+               // -- Conversions --
+
+               template <typename X1, typename Y1, typename Z1, typename X2, typename Y2, typename Z2>
+               GLM_FUNC_DECL tmat2x3(
+                       X1 x1, Y1 y1, Z1 z1,
+                       X2 x2, Y2 y2, Z2 z2);
+
+               template <typename U, typename V>
+               GLM_FUNC_DECL tmat2x3(
+                       tvec3<U, P> const & v1,
+                       tvec3<V, P> const & v2);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat2x3<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x3(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 2;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat2x3<T, P> & operator=(tmat2x3<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator=(tmat2x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator+=(tmat2x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator-=(tmat2x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x3<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat2x3<T, P> & operator++ ();
+               GLM_FUNC_DECL tmat2x3<T, P> & operator-- ();
+               GLM_FUNC_DECL tmat2x3<T, P> operator++(int);
+               GLM_FUNC_DECL tmat2x3<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator+(tmat2x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator-(tmat2x3<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator+(tmat2x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator+(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator-(tmat2x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator-(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator*(tmat2x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator*(T scalar, tmat2x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x3<T, P>::col_type operator*(tmat2x3<T, P> const & m, typename tmat2x3<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x3<T, P>::row_type operator*(typename tmat2x3<T, P>::col_type const & v, tmat2x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator/(tmat2x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator/(T scalar, tmat2x3<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat2x3.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat2x3.inl b/core/deps/glm/glm/detail/type_mat2x3.inl
new file mode 100755 (executable)
index 0000000..b0f8337
--- /dev/null
@@ -0,0 +1,458 @@
+/// @ref core
+/// @file glm/detail/type_mat2x3.inl
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P> 
+               GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0);
+                               this->value[1] = col_type(0, 1, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat2x3<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat2x3<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat2x3<T, P>::tmat2x3(ctor)
+       {}
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0, 0);
+               this->value[1] = col_type(0, scalar, 0);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3
+       (
+               T x0, T y0, T z0,
+               T x1, T y1, T z1
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0);
+               this->value[1] = col_type(x1, y1, z1);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(col_type const & v0, col_type const & v1)
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1, typename Z1,
+               typename X2, typename Y2, typename Z2>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3
+       (
+               X1 x1, Y1 y1, Z1 z1,
+               X2 x2, Y2 y2, Z2 z2
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tvec3<V1, P> const & v1, tvec3<V2, P> const & v2)
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat2x3<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER  tmat2x3<T, P>::tmat2x3(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>::tmat2x3(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x3<T, P>::col_type & tmat2x3<T, P>::operator[](typename tmat2x3<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x3<T, P>::col_type const & tmat2x3<T, P>::operator[](typename tmat2x3<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator=(tmat2x3<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator=(tmat2x3<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> & tmat2x3<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator+=(tmat2x3<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator-=(tmat2x3<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P>& tmat2x3<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> & tmat2x3<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> & tmat2x3<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> & tmat2x3<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> tmat2x3<T, P>::operator++(int)
+       {
+               tmat2x3<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> tmat2x3<T, P>::operator--(int)
+       {
+               tmat2x3<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator+(tmat2x3<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator-(tmat2x3<T, P> const & m)
+       {
+               return tmat2x3<T, P>(
+                       -m[0],
+                       -m[1]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator+(tmat2x3<T, P> const & m, T scalar)
+       {
+               return tmat2x3<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator+(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return tmat2x3<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator-(tmat2x3<T, P> const & m, T scalar)
+       {
+               return tmat2x3<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator-(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return tmat2x3<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*(tmat2x3<T, P> const & m, T scalar)
+       {
+               return tmat2x3<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*(T scalar, tmat2x3<T, P> const & m)
+       {
+               return tmat2x3<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x3<T, P>::col_type operator*
+       (
+               tmat2x3<T, P> const & m,
+               typename tmat2x3<T, P>::row_type const & v)
+       {
+               return typename tmat2x3<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y,
+                       m[0][1] * v.x + m[1][1] * v.y,
+                       m[0][2] * v.x + m[1][2] * v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x3<T, P>::row_type operator*
+       (
+               typename tmat2x3<T, P>::col_type const & v,
+               tmat2x3<T, P> const & m)
+       {
+               return typename tmat2x3<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2],
+                       v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return tmat2x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               T SrcA00 = m1[0][0];
+               T SrcA01 = m1[0][1];
+               T SrcA02 = m1[0][2];
+               T SrcA10 = m1[1][0];
+               T SrcA11 = m1[1][1];
+               T SrcA12 = m1[1][2];
+
+               T SrcB00 = m2[0][0];
+               T SrcB01 = m2[0][1];
+               T SrcB10 = m2[1][0];
+               T SrcB11 = m2[1][1];
+               T SrcB20 = m2[2][0];
+               T SrcB21 = m2[2][1];
+
+               tmat3x3<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01;
+               Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11;
+               Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11;
+               Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21;
+               Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21;
+               Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*(tmat2x3<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return tmat4x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1],
+                       m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator/(tmat2x3<T, P> const & m, T scalar)
+       {
+               return tmat2x3<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator/(T scalar, tmat2x3<T, P> const & m)
+       {
+               return tmat2x3<T, P>(
+                       scalar / m[0],
+                       scalar / m[1]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat2x3<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat2x4.hpp b/core/deps/glm/glm/detail/type_mat2x4.hpp
new file mode 100755 (executable)
index 0000000..c9d195f
--- /dev/null
@@ -0,0 +1,167 @@
+/// @ref core
+/// @file glm/detail/type_mat2x4.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec2.hpp"
+#include "type_vec4.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat2x4
+       {
+               typedef tvec4<T, P> col_type;
+               typedef tvec2<T, P> row_type;
+               typedef tmat2x4<T, P> type;
+               typedef tmat4x2<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[2];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat2x4() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat2x4(tmat2x4<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat2x4(tmat2x4<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat2x4(ctor);
+               GLM_FUNC_DECL explicit tmat2x4(T scalar);
+               GLM_FUNC_DECL tmat2x4(
+                       T x0, T y0, T z0, T w0,
+                       T x1, T y1, T z1, T w1);
+               GLM_FUNC_DECL tmat2x4(
+                       col_type const & v0,
+                       col_type const & v1);
+
+               // -- Conversions --
+
+               template <
+                       typename X1, typename Y1, typename Z1, typename W1,
+                       typename X2, typename Y2, typename Z2, typename W2>
+               GLM_FUNC_DECL tmat2x4(
+                       X1 x1, Y1 y1, Z1 z1, W1 w1,
+                       X2 x2, Y2 y2, Z2 z2, W2 w2);
+
+               template <typename U, typename V>
+               GLM_FUNC_DECL tmat2x4(
+                       tvec4<U, P> const & v1,
+                       tvec4<V, P> const & v2);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat2x4<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat2x4(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 2;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat2x4<T, P> & operator=(tmat2x4<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator=(tmat2x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator+=(tmat2x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator-=(tmat2x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat2x4<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat2x4<T, P> & operator++ ();
+               GLM_FUNC_DECL tmat2x4<T, P> & operator-- ();
+               GLM_FUNC_DECL tmat2x4<T, P> operator++(int);
+               GLM_FUNC_DECL tmat2x4<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator+(tmat2x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator-(tmat2x4<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator+(tmat2x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator+(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator-(tmat2x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator-(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator*(tmat2x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator*(T scalar, tmat2x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x4<T, P>::col_type operator*(tmat2x4<T, P> const & m, typename tmat2x4<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat2x4<T, P>::row_type operator*(typename tmat2x4<T, P>::col_type const & v, tmat2x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat2x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator/(tmat2x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator/(T scalar, tmat2x4<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat2x4.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat2x4.inl b/core/deps/glm/glm/detail/type_mat2x4.inl
new file mode 100755 (executable)
index 0000000..74af34c
--- /dev/null
@@ -0,0 +1,467 @@
+/// @ref core
+/// @file glm/detail/type_mat2x4.inl
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0, 0);
+                               this->value[1] = col_type(0, 1, 0, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat2x4<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat2x4<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat2x4<T, P>::tmat2x4(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(T scalar)
+       {
+               value_type const Zero(0);
+               this->value[0] = col_type(scalar, Zero, Zero, Zero);
+               this->value[1] = col_type(Zero, scalar, Zero, Zero);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4
+       (
+               T x0, T y0, T z0, T w0,
+               T x1, T y1, T z1, T w1
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0, w0);
+               this->value[1] = col_type(x1, y1, z1, w1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(col_type const & v0, col_type const & v1)
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1, typename Z1, typename W1,
+               typename X2, typename Y2, typename Z2, typename W2>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4
+       (
+               X1 x1, Y1 y1, Z1 z1, W1 w1,
+               X2 x2, Y2 y2, Z2 z2, W2 w2
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1), value_type(w1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2), value_type(w2));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tvec4<V1, P> const & v1, tvec4<V2, P> const & v2)
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat2x4<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>::tmat2x4(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x4<T, P>::col_type & tmat2x4<T, P>::operator[](typename tmat2x4<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x4<T, P>::col_type const & tmat2x4<T, P>::operator[](typename tmat2x4<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator=(tmat2x4<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator=(tmat2x4<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator+=(tmat2x4<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator-=(tmat2x4<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> & tmat2x4<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P>& tmat2x4<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> tmat2x4<T, P>::operator++(int)
+       {
+               tmat2x4<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> tmat2x4<T, P>::operator--(int)
+       {
+               tmat2x4<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator+(tmat2x4<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator-(tmat2x4<T, P> const & m)
+       {
+               return tmat2x4<T, P>(
+                       -m[0], 
+                       -m[1]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator+(tmat2x4<T, P> const & m, T scalar)
+       {
+               return tmat2x4<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator+(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return tmat2x4<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator-(tmat2x4<T, P> const & m, T scalar)
+       {
+               return tmat2x4<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator-(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return tmat2x4<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator*(tmat2x4<T, P> const & m, T scalar)
+       {
+               return tmat2x4<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator*(T scalar, tmat2x4<T, P> const & m)
+       {
+               return tmat2x4<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x4<T, P>::col_type operator*(tmat2x4<T, P> const & m, typename tmat2x4<T, P>::row_type const & v)
+       {
+               return typename tmat2x4<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y,
+                       m[0][1] * v.x + m[1][1] * v.y,
+                       m[0][2] * v.x + m[1][2] * v.y,
+                       m[0][3] * v.x + m[1][3] * v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat2x4<T, P>::row_type operator*(typename tmat2x4<T, P>::col_type const & v, tmat2x4<T, P> const & m)
+       {
+               return typename tmat2x4<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],
+                       v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               T SrcA00 = m1[0][0];
+               T SrcA01 = m1[0][1];
+               T SrcA02 = m1[0][2];
+               T SrcA03 = m1[0][3];
+               T SrcA10 = m1[1][0];
+               T SrcA11 = m1[1][1];
+               T SrcA12 = m1[1][2];
+               T SrcA13 = m1[1][3];
+
+               T SrcB00 = m2[0][0];
+               T SrcB01 = m2[0][1];
+               T SrcB10 = m2[1][0];
+               T SrcB11 = m2[1][1];
+               T SrcB20 = m2[2][0];
+               T SrcB21 = m2[2][1];
+               T SrcB30 = m2[3][0];
+               T SrcB31 = m2[3][1];
+
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01;
+               Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01;
+               Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11;
+               Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11;
+               Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11;
+               Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21;
+               Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21;
+               Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21;
+               Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21;
+               Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31;
+               Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31;
+               Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31;
+               Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat2x2<T, P> const & m2)
+       {
+               return tmat2x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator*(tmat2x4<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return tmat3x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1],
+                       m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator/(tmat2x4<T, P> const & m, T scalar)
+       {
+               return tmat2x4<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator/(T scalar, tmat2x4<T, P> const & m)
+       {
+               return tmat2x4<T, P>(
+                       scalar / m[0],
+                       scalar / m[1]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat2x4<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat3x2.hpp b/core/deps/glm/glm/detail/type_mat3x2.hpp
new file mode 100755 (executable)
index 0000000..8549745
--- /dev/null
@@ -0,0 +1,173 @@
+/// @ref core
+/// @file glm/detail/type_mat3x2.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec2.hpp"
+#include "type_vec3.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat3x2
+       {
+               typedef tvec2<T, P> col_type;
+               typedef tvec3<T, P> row_type;
+               typedef tmat3x2<T, P> type;
+               typedef tmat2x3<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[3];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat3x2() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat3x2(tmat3x2<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat3x2(tmat3x2<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat3x2(ctor);
+               GLM_FUNC_DECL explicit tmat3x2(T scalar);
+               GLM_FUNC_DECL tmat3x2(
+                       T x0, T y0,
+                       T x1, T y1,
+                       T x2, T y2);
+               GLM_FUNC_DECL tmat3x2(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2);
+
+               // -- Conversions --
+
+               template<
+                       typename X1, typename Y1,
+                       typename X2, typename Y2,
+                       typename X3, typename Y3>
+               GLM_FUNC_DECL tmat3x2(
+                       X1 x1, Y1 y1,
+                       X2 x2, Y2 y2,
+                       X3 x3, Y3 y3);
+
+               template <typename V1, typename V2, typename V3>
+               GLM_FUNC_DECL tmat3x2(
+                       tvec2<V1, P> const & v1,
+                       tvec2<V2, P> const & v2,
+                       tvec2<V3, P> const & v3);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat3x2<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x2(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 3;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat3x2<T, P> & operator=(tmat3x2<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator=(tmat3x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator+=(tmat3x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator-=(tmat3x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x2<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat3x2<T, P> & operator++ ();
+               GLM_FUNC_DECL tmat3x2<T, P> & operator-- ();
+               GLM_FUNC_DECL tmat3x2<T, P> operator++(int);
+               GLM_FUNC_DECL tmat3x2<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator+(tmat3x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator-(tmat3x2<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator+(tmat3x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator+(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator-(tmat3x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator-(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator*(tmat3x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator*(T scalar, tmat3x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x2<T, P>::col_type operator*(tmat3x2<T, P> const & m, typename tmat3x2<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x2<T, P>::row_type operator*(typename tmat3x2<T, P>::col_type const & v, tmat3x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator/(tmat3x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator/(T scalar, tmat3x2<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2);
+
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat3x2.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat3x2.inl b/core/deps/glm/glm/detail/type_mat3x2.inl
new file mode 100755 (executable)
index 0000000..2a1b8bd
--- /dev/null
@@ -0,0 +1,492 @@
+/// @ref core
+/// @file glm/detail/type_mat3x2.inl
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P> 
+               GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0);
+                               this->value[1] = col_type(0, 1);
+                               this->value[2] = col_type(0, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat3x2<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+                       this->value[2] = m.value[2];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat3x2<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+               this->value[2] = m.value[2];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat3x2<T, P>::tmat3x2(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0);
+               this->value[1] = col_type(0, scalar);
+               this->value[2] = col_type(0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2
+       (
+               T x0, T y0,
+               T x1, T y1,
+               T x2, T y2
+       )
+       {
+               this->value[0] = col_type(x0, y0);
+               this->value[1] = col_type(x1, y1);
+               this->value[2] = col_type(x2, y2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1,
+               typename X2, typename Y2,
+               typename X3, typename Y3>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2
+       (
+               X1 x1, Y1 y1,
+               X2 x2, Y2 y2,
+               X3 x3, Y3 y3
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3));
+       }
+
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2
+       (
+               tvec2<V1, P> const & v1,
+               tvec2<V2, P> const & v2,
+               tvec2<V3, P> const & v3
+       )
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat3x2<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(T(0));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(T(0));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>::tmat3x2(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x2<T, P>::col_type & tmat3x2<T, P>::operator[](typename tmat3x2<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x2<T, P>::col_type const & tmat3x2<T, P>::operator[](typename tmat3x2<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator=(tmat3x2<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator=(tmat3x2<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator+=(tmat3x2<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator-=(tmat3x2<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> & tmat3x2<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P>& tmat3x2<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> tmat3x2<T, P>::operator++(int)
+       {
+               tmat3x2<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> tmat3x2<T, P>::operator--(int)
+       {
+               tmat3x2<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator+(tmat3x2<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator-(tmat3x2<T, P> const & m)
+       {
+               return tmat3x2<T, P>(
+                       -m[0],
+                       -m[1],
+                       -m[2]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator+(tmat3x2<T, P> const & m, T scalar)
+       {
+               return tmat3x2<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar,
+                       m[2] + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator+(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return tmat3x2<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator-(tmat3x2<T, P> const & m, T scalar)
+       {
+               return tmat3x2<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar,
+                       m[2] - scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator-(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return tmat3x2<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator*(tmat3x2<T, P> const & m, T scalar)
+       {
+               return tmat3x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator*(T scalar, tmat3x2<T, P> const & m)
+       {
+               return tmat3x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+   
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x2<T, P>::col_type operator*(tmat3x2<T, P> const & m, typename tmat3x2<T, P>::row_type const & v)
+       {
+               return typename tmat3x2<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,
+                       m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x2<T, P>::row_type operator*(typename tmat3x2<T, P>::col_type const & v, tmat3x2<T, P> const & m)
+       {
+               return typename tmat3x2<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1],
+                       v.x * m[1][0] + v.y * m[1][1],
+                       v.x * m[2][0] + v.y * m[2][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               const T SrcA00 = m1[0][0];
+               const T SrcA01 = m1[0][1];
+               const T SrcA10 = m1[1][0];
+               const T SrcA11 = m1[1][1];
+               const T SrcA20 = m1[2][0];
+               const T SrcA21 = m1[2][1];
+
+               const T SrcB00 = m2[0][0];
+               const T SrcB01 = m2[0][1];
+               const T SrcB02 = m2[0][2];
+               const T SrcB10 = m2[1][0];
+               const T SrcB11 = m2[1][1];
+               const T SrcB12 = m2[1][2];
+
+               tmat2x2<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return tmat3x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator*(tmat3x2<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return tmat4x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator/(tmat3x2<T, P> const & m, T scalar)
+       {
+               return tmat3x2<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar,
+                       m[2] / scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator/(T scalar, tmat3x2<T, P> const & m)
+       {
+               return tmat3x2<T, P>(
+                       scalar / m[0],
+                       scalar / m[1],
+                       scalar / m[2]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER bool operator!=(tmat3x2<T, P> const & m1, tmat3x2<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat3x3.hpp b/core/deps/glm/glm/detail/type_mat3x3.hpp
new file mode 100755 (executable)
index 0000000..d5ebe62
--- /dev/null
@@ -0,0 +1,190 @@
+/// @ref core
+/// @file glm/detail/type_mat3x3.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec3.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat3x3
+       {
+               typedef tvec3<T, P> col_type;
+               typedef tvec3<T, P> row_type;
+               typedef tmat3x3<T, P> type;
+               typedef tmat3x3<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[3];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat3x3() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat3x3(tmat3x3<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat3x3(tmat3x3<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat3x3(ctor);
+               GLM_FUNC_DECL explicit tmat3x3(T scalar);
+               GLM_FUNC_DECL tmat3x3(
+                       T x0, T y0, T z0,
+                       T x1, T y1, T z1,
+                       T x2, T y2, T z2);
+               GLM_FUNC_DECL tmat3x3(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2);
+
+               // -- Conversions --
+
+               template<
+                       typename X1, typename Y1, typename Z1,
+                       typename X2, typename Y2, typename Z2,
+                       typename X3, typename Y3, typename Z3>
+               GLM_FUNC_DECL tmat3x3(
+                       X1 x1, Y1 y1, Z1 z1,
+                       X2 x2, Y2 y2, Z2 z2,
+                       X3 x3, Y3 y3, Z3 z3);
+
+               template <typename V1, typename V2, typename V3>
+               GLM_FUNC_DECL tmat3x3(
+                       tvec3<V1, P> const & v1,
+                       tvec3<V2, P> const & v2,
+                       tvec3<V3, P> const & v3);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat3x3<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x3(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 3;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat3x3<T, P> & operator=(tmat3x3<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator=(tmat3x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator+=(tmat3x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator-=(tmat3x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator*=(tmat3x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator/=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x3<T, P> & operator/=(tmat3x3<U, P> const & m);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat3x3<T, P> & operator++();
+               GLM_FUNC_DECL tmat3x3<T, P> & operator--();
+               GLM_FUNC_DECL tmat3x3<T, P> operator++(int);
+               GLM_FUNC_DECL tmat3x3<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator+(tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator-(tmat3x3<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator+(tmat3x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator+(T scalar, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator+(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator-(tmat3x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator-(T scalar, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator-(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator*(tmat3x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator*(T scalar, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x3<T, P>::col_type operator*(tmat3x3<T, P> const & m, typename tmat3x3<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x3<T, P>::row_type operator*(typename tmat3x3<T, P>::col_type const & v, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator/(tmat3x3<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator/(T scalar, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x3<T, P>::col_type operator/(tmat3x3<T, P> const & m, typename tmat3x3<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x3<T, P>::row_type operator/(typename tmat3x3<T, P>::col_type const & v, tmat3x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator/(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat3x3.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat3x3.inl b/core/deps/glm/glm/detail/type_mat3x3.inl
new file mode 100755 (executable)
index 0000000..324cca3
--- /dev/null
@@ -0,0 +1,561 @@
+/// @ref core
+/// @file glm/detail/type_mat3x3.inl
+
+#include "func_matrix.hpp"
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0);
+                               this->value[1] = col_type(0, 1, 0);
+                               this->value[2] = col_type(0, 0, 1);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat3x3<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+                       this->value[2] = m.value[2];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat3x3<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+               this->value[2] = m.value[2];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat3x3<T, P>::tmat3x3(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0, 0);
+               this->value[1] = col_type(0, scalar, 0);
+               this->value[2] = col_type(0, 0, scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
+       (
+               T x0, T y0, T z0,
+               T x1, T y1, T z1,
+               T x2, T y2, T z2
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0);
+               this->value[1] = col_type(x1, y1, z1);
+               this->value[2] = col_type(x2, y2, z2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1, typename Z1,
+               typename X2, typename Y2, typename Z2,
+               typename X3, typename Y3, typename Z3>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
+       (
+               X1 x1, Y1 y1, Z1 z1,
+               X2 x2, Y2 y2, Z2 z2,
+               X3 x3, Y3 y3, Z3 z3
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3), value_type(z3));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3
+       (
+               tvec3<V1, P> const & v1,
+               tvec3<V2, P> const & v2,
+               tvec3<V3, P> const & v3
+       )
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat3x3<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = col_type(0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P>::tmat3x3(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type & tmat3x3<T, P>::operator[](typename tmat3x3<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type const & tmat3x3<T, P>::operator[](typename tmat3x3<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator=(tmat3x3<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator=(tmat3x3<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator+=(tmat3x3<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator-=(tmat3x3<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator*=(tmat3x3<U, P> const & m)
+       {
+               return (*this = *this * m);
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator/=(tmat3x3<U, P> const & m)
+       {
+               return *this *= inverse(m);
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> & tmat3x3<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> tmat3x3<T, P>::operator++(int)
+       {
+               tmat3x3<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> tmat3x3<T, P>::operator--(int)
+       {
+               tmat3x3<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+(tmat3x3<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-(tmat3x3<T, P> const & m)
+       {
+               return tmat3x3<T, P>(
+                       -m[0], 
+                       -m[1],
+                       -m[2]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+(tmat3x3<T, P> const & m, T scalar)
+       {
+               return tmat3x3<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar,
+                       m[2] + scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+(T scalar, tmat3x3<T, P> const & m)
+       {
+               return tmat3x3<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar,
+                       m[2] + scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator+(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return tmat3x3<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-(tmat3x3<T, P> const & m, T scalar)
+       {
+               return tmat3x3<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar,
+                       m[2] - scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-(T scalar, tmat3x3<T, P> const & m)
+       {
+               return tmat3x3<T, P>(
+                       scalar - m[0],
+                       scalar - m[1],
+                       scalar - m[2]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator-(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return tmat3x3<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2]);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*(tmat3x3<T, P> const & m, T scalar)
+       {
+               return tmat3x3<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*(T scalar, tmat3x3<T, P> const & m)
+       {
+               return tmat3x3<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type operator*(tmat3x3<T, P> const & m, typename tmat3x3<T, P>::row_type const & v)
+       {
+               return typename tmat3x3<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,
+                       m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z,
+                       m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::row_type operator*(typename tmat3x3<T, P>::col_type const & v, tmat3x3<T, P> const & m)
+       {
+               return typename tmat3x3<T, P>::row_type(
+                       m[0][0] * v.x + m[0][1] * v.y + m[0][2] * v.z,
+                       m[1][0] * v.x + m[1][1] * v.y + m[1][2] * v.z,
+                       m[2][0] * v.x + m[2][1] * v.y + m[2][2] * v.z);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               T const SrcA00 = m1[0][0];
+               T const SrcA01 = m1[0][1];
+               T const SrcA02 = m1[0][2];
+               T const SrcA10 = m1[1][0];
+               T const SrcA11 = m1[1][1];
+               T const SrcA12 = m1[1][2];
+               T const SrcA20 = m1[2][0];
+               T const SrcA21 = m1[2][1];
+               T const SrcA22 = m1[2][2];
+
+               T const SrcB00 = m2[0][0];
+               T const SrcB01 = m2[0][1];
+               T const SrcB02 = m2[0][2];
+               T const SrcB10 = m2[1][0];
+               T const SrcB11 = m2[1][1];
+               T const SrcB12 = m2[1][2];
+               T const SrcB20 = m2[2][0];
+               T const SrcB21 = m2[2][1];
+               T const SrcB22 = m2[2][2];
+
+               tmat3x3<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;
+               Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;
+               Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12;
+               Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22;
+               Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22;
+               Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return tmat2x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*(tmat3x3<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return tmat4x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2],
+                       m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/(tmat3x3<T, P> const & m,     T scalar)
+       {
+               return tmat3x3<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar,
+                       m[2] / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/(T scalar, tmat3x3<T, P> const & m)
+       {
+               return tmat3x3<T, P>(
+                       scalar / m[0],
+                       scalar / m[1],
+                       scalar / m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::col_type operator/(tmat3x3<T, P> const & m, typename tmat3x3<T, P>::row_type const & v)
+       {
+               return  inverse(m) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x3<T, P>::row_type operator/(typename tmat3x3<T, P>::col_type const & v, tmat3x3<T, P> const & m)
+       {
+               return v * inverse(m);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator/(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               tmat3x3<T, P> m1_copy(m1);
+               return m1_copy /= m2;
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat3x3<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat3x4.hpp b/core/deps/glm/glm/detail/type_mat3x4.hpp
new file mode 100755 (executable)
index 0000000..c5bb9a9
--- /dev/null
@@ -0,0 +1,172 @@
+/// @ref core
+/// @file glm/detail/type_mat3x4.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat3x4
+       {
+               typedef tvec4<T, P> col_type;
+               typedef tvec3<T, P> row_type;
+               typedef tmat3x4<T, P> type;
+               typedef tmat4x3<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[3];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat3x4() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat3x4(tmat3x4<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat3x4(tmat3x4<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat3x4(ctor);
+               GLM_FUNC_DECL explicit tmat3x4(T scalar);
+               GLM_FUNC_DECL tmat3x4(
+                       T x0, T y0, T z0, T w0,
+                       T x1, T y1, T z1, T w1,
+                       T x2, T y2, T z2, T w2);
+               GLM_FUNC_DECL tmat3x4(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2);
+
+               // -- Conversions --
+
+               template<
+                       typename X1, typename Y1, typename Z1, typename W1,
+                       typename X2, typename Y2, typename Z2, typename W2,
+                       typename X3, typename Y3, typename Z3, typename W3>
+               GLM_FUNC_DECL tmat3x4(
+                       X1 x1, Y1 y1, Z1 z1, W1 w1,
+                       X2 x2, Y2 y2, Z2 z2, W2 w2,
+                       X3 x3, Y3 y3, Z3 z3, W3 w3);
+
+               template <typename V1, typename V2, typename V3>
+               GLM_FUNC_DECL tmat3x4(
+                       tvec4<V1, P> const & v1,
+                       tvec4<V2, P> const & v2,
+                       tvec4<V3, P> const & v3);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat3x4<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat3x4(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 3;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat3x4<T, P> & operator=(tmat3x4<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator=(tmat3x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator+=(tmat3x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator-=(tmat3x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat3x4<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat3x4<T, P> & operator++();
+               GLM_FUNC_DECL tmat3x4<T, P> & operator--();
+               GLM_FUNC_DECL tmat3x4<T, P> operator++(int);
+               GLM_FUNC_DECL tmat3x4<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator+(tmat3x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator-(tmat3x4<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator+(tmat3x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator+(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator-(tmat3x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator-(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator*(tmat3x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator*(T scalar, tmat3x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x4<T, P>::col_type operator*(tmat3x4<T, P> const & m, typename tmat3x4<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat3x4<T, P>::row_type operator*(typename tmat3x4<T, P>::col_type const & v, tmat3x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat2x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat3x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator/(tmat3x4<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator/(T scalar, tmat3x4<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat3x4.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat3x4.inl b/core/deps/glm/glm/detail/type_mat3x4.inl
new file mode 100755 (executable)
index 0000000..3596f26
--- /dev/null
@@ -0,0 +1,532 @@
+/// @ref core
+/// @file glm/detail/type_mat3x4.inl
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0, 0);
+                               this->value[1] = col_type(0, 1, 0, 0);
+                               this->value[2] = col_type(0, 0, 1, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat3x4<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+                       this->value[2] = m.value[2];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat3x4<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+               this->value[2] = m.value[2];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat3x4<T, P>::tmat3x4(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0, 0, 0);
+               this->value[1] = col_type(0, scalar, 0, 0);
+               this->value[2] = col_type(0, 0, scalar, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4
+       (
+               T x0, T y0, T z0, T w0,
+               T x1, T y1, T z1, T w1,
+               T x2, T y2, T z2, T w2
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0, w0);
+               this->value[1] = col_type(x1, y1, z1, w1);
+               this->value[2] = col_type(x2, y2, z2, w2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1, typename Z1, typename W1,
+               typename X2, typename Y2, typename Z2, typename W2,
+               typename X3, typename Y3, typename Z3, typename W3>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4
+       (
+               X1 x1, Y1 y1, Z1 z1, W1 w1,
+               X2 x2, Y2 y2, Z2 z2, W2 w2,
+               X3 x3, Y3 y3, Z3 z3, W3 w3
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1), value_type(w1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2), value_type(w2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3), value_type(z3), value_type(w3));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4
+       (
+               tvec4<V1, P> const & v1,
+               tvec4<V2, P> const & v2,
+               tvec4<V3, P> const & v3
+       )
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+       }
+       
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat3x4<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(0, 0, 1, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(0, 0, 1, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(m[2], 1, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0, 0, 1, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(m[2], 1, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>::tmat3x4(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 0);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x4<T, P>::col_type & tmat3x4<T, P>::operator[](typename tmat3x4<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x4<T, P>::col_type const & tmat3x4<T, P>::operator[](typename tmat3x4<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator=(tmat3x4<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P> 
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator=(tmat3x4<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator+=(tmat3x4<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator-=(tmat3x4<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> & tmat3x4<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P>& tmat3x4<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> tmat3x4<T, P>::operator++(int)
+       {
+               tmat3x4<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> tmat3x4<T, P>::operator--(int)
+       {
+               tmat3x4<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator+(tmat3x4<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator-(tmat3x4<T, P> const & m)
+       {
+               return tmat3x4<T, P>(
+                       -m[0],
+                       -m[1],
+                       -m[2]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator+(tmat3x4<T, P> const & m, T scalar)
+       {
+               return tmat3x4<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar,
+                       m[2] + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator+(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return tmat3x4<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator-(tmat3x4<T, P> const & m,     T scalar)
+       {
+               return tmat3x4<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar,
+                       m[2] - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator-(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return tmat3x4<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator*(tmat3x4<T, P> const & m, T scalar)
+       {
+               return tmat3x4<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator*(T scalar, tmat3x4<T, P> const & m)
+       {
+               return tmat3x4<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x4<T, P>::col_type operator*
+       (
+               tmat3x4<T, P> const & m,
+               typename tmat3x4<T, P>::row_type const & v
+       )
+       {
+               return typename tmat3x4<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z,
+                       m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z,
+                       m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z,
+                       m[0][3] * v.x + m[1][3] * v.y + m[2][3] * v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat3x4<T, P>::row_type operator*
+       (
+               typename tmat3x4<T, P>::col_type const & v,
+               tmat3x4<T, P> const & m
+       )
+       {
+               return typename tmat3x4<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2] + v.w * m[0][3],
+                       v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2] + v.w * m[1][3],
+                       v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2] + v.w * m[2][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               const T SrcA00 = m1[0][0];
+               const T SrcA01 = m1[0][1];
+               const T SrcA02 = m1[0][2];
+               const T SrcA03 = m1[0][3];
+               const T SrcA10 = m1[1][0];
+               const T SrcA11 = m1[1][1];
+               const T SrcA12 = m1[1][2];
+               const T SrcA13 = m1[1][3];
+               const T SrcA20 = m1[2][0];
+               const T SrcA21 = m1[2][1];
+               const T SrcA22 = m1[2][2];
+               const T SrcA23 = m1[2][3];
+
+               const T SrcB00 = m2[0][0];
+               const T SrcB01 = m2[0][1];
+               const T SrcB02 = m2[0][2];
+               const T SrcB10 = m2[1][0];
+               const T SrcB11 = m2[1][1];
+               const T SrcB12 = m2[1][2];
+               const T SrcB20 = m2[2][0];
+               const T SrcB21 = m2[2][1];
+               const T SrcB22 = m2[2][2];
+               const T SrcB30 = m2[3][0];
+               const T SrcB31 = m2[3][1];
+               const T SrcB32 = m2[3][2];
+
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02;
+               Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02;
+               Result[0][3] = SrcA03 * SrcB00 + SrcA13 * SrcB01 + SrcA23 * SrcB02;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12;
+               Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12;
+               Result[1][3] = SrcA03 * SrcB10 + SrcA13 * SrcB11 + SrcA23 * SrcB12;
+               Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22;
+               Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22;
+               Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22;
+               Result[2][3] = SrcA03 * SrcB20 + SrcA13 * SrcB21 + SrcA23 * SrcB22;
+               Result[3][0] = SrcA00 * SrcB30 + SrcA10 * SrcB31 + SrcA20 * SrcB32;
+               Result[3][1] = SrcA01 * SrcB30 + SrcA11 * SrcB31 + SrcA21 * SrcB32;
+               Result[3][2] = SrcA02 * SrcB30 + SrcA12 * SrcB31 + SrcA22 * SrcB32;
+               Result[3][3] = SrcA03 * SrcB30 + SrcA13 * SrcB31 + SrcA23 * SrcB32;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat2x3<T, P> const & m2)
+       {
+               return tmat2x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator*(tmat3x4<T, P> const & m1, tmat3x3<T, P> const & m2)
+       {
+               return tmat3x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2],
+                       m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator/(tmat3x4<T, P> const & m,     T scalar)
+       {
+               return tmat3x4<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar,
+                       m[2] / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator/(T scalar, tmat3x4<T, P> const & m)
+       {
+               return tmat3x4<T, P>(
+                       scalar / m[0],
+                       scalar / m[1],
+                       scalar / m[2]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat3x4<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat4x2.hpp b/core/deps/glm/glm/detail/type_mat4x2.hpp
new file mode 100755 (executable)
index 0000000..a899d94
--- /dev/null
@@ -0,0 +1,177 @@
+/// @ref core
+/// @file glm/detail/type_mat4x2.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec2.hpp"
+#include "type_vec4.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat4x2
+       {
+               typedef tvec2<T, P> col_type;
+               typedef tvec4<T, P> row_type;
+               typedef tmat4x2<T, P> type;
+               typedef tmat2x4<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[4];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat4x2() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat4x2(tmat4x2<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat4x2(tmat4x2<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat4x2(ctor);
+               GLM_FUNC_DECL explicit tmat4x2(T scalar);
+               GLM_FUNC_DECL tmat4x2(
+                       T x0, T y0,
+                       T x1, T y1,
+                       T x2, T y2,
+                       T x3, T y3);
+               GLM_FUNC_DECL tmat4x2(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2,
+                       col_type const & v3);
+
+               // -- Conversions --
+
+               template <
+                       typename X1, typename Y1,
+                       typename X2, typename Y2,
+                       typename X3, typename Y3,
+                       typename X4, typename Y4>
+               GLM_FUNC_DECL tmat4x2(
+                       X1 x1, Y1 y1,
+                       X2 x2, Y2 y2,
+                       X3 x3, Y3 y3,
+                       X4 x4, Y4 y4);
+
+               template <typename V1, typename V2, typename V3, typename V4>
+               GLM_FUNC_DECL tmat4x2(
+                       tvec2<V1, P> const & v1,
+                       tvec2<V2, P> const & v2,
+                       tvec2<V3, P> const & v3,
+                       tvec2<V4, P> const & v4);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat4x2<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat4x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x2(tmat3x4<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 4;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat4x2<T, P> & operator=(tmat4x2<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator=(tmat4x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator+=(tmat4x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator-=(tmat4x2<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x2<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat4x2<T, P> & operator++ ();
+               GLM_FUNC_DECL tmat4x2<T, P> & operator-- ();
+               GLM_FUNC_DECL tmat4x2<T, P> operator++(int);
+               GLM_FUNC_DECL tmat4x2<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator+(tmat4x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator-(tmat4x2<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator+(tmat4x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator+(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator-(tmat4x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator-(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator*(tmat4x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator*(T scalar, tmat4x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x2<T, P>::col_type operator*(tmat4x2<T, P> const & m, typename tmat4x2<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x2<T, P>::row_type operator*(typename tmat4x2<T, P>::col_type const & v, tmat4x2<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator/(tmat4x2<T, P> const & m, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> operator/(T scalar, tmat4x2<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat4x2.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat4x2.inl b/core/deps/glm/glm/detail/type_mat4x2.inl
new file mode 100755 (executable)
index 0000000..6d83229
--- /dev/null
@@ -0,0 +1,545 @@
+/// @ref core
+/// @file glm/detail/type_mat4x2.inl
+
+namespace glm
+{
+#      ifdef GLM_STATIC_CONST_MEMBERS
+               template<typename T, precision P>
+               const tmat4x2<T, P> tmat4x2<T, P>::ZERO(static_cast<T>(0));
+
+               template<typename T, precision P>
+               const tmat4x2<T, P> tmat4x2<T, P>::IDENTITY(static_cast<T>(1));
+#      endif
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P> 
+               GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0);
+                               this->value[1] = col_type(0, 1);
+                               this->value[2] = col_type(0, 0);
+                               this->value[3] = col_type(0, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat4x2<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+                       this->value[2] = m.value[2];
+                       this->value[3] = m.value[3];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat4x2<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+               this->value[2] = m.value[2];
+               this->value[3] = m.value[3];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat4x2<T, P>::tmat4x2(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(T scalar)
+       {
+               this->value[0] = col_type(scalar, 0);
+               this->value[1] = col_type(0, scalar);
+               this->value[2] = col_type(0, 0);
+               this->value[3] = col_type(0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2
+       (
+               T x0, T y0,
+               T x1, T y1,
+               T x2, T y2,
+               T x3, T y3
+       )
+       {
+               this->value[0] = col_type(x0, y0);
+               this->value[1] = col_type(x1, y1);
+               this->value[2] = col_type(x2, y2);
+               this->value[3] = col_type(x3, y3);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2,
+               col_type const & v3
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+               this->value[3] = v3;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1,
+               typename X2, typename Y2,
+               typename X3, typename Y3,
+               typename X4, typename Y4>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2
+       (
+               X1 x1, Y1 y1,
+               X2 x2, Y2 y2,
+               X3 x3, Y3 y3,
+               X4 x4, Y4 y4
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3));
+               this->value[3] = col_type(static_cast<T>(x4), value_type(y4));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3, typename V4>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2
+       (
+               tvec2<V1, P> const & v1,
+               tvec2<V2, P> const & v2,
+               tvec2<V3, P> const & v3,
+               tvec2<V4, P> const & v4
+       )
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+               this->value[3] = col_type(v4);
+       }
+
+       // -- Conversion --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat4x2<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>::tmat4x2(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(0);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x2<T, P>::col_type & tmat4x2<T, P>::operator[](typename tmat4x2<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x2<T, P>::col_type const & tmat4x2<T, P>::operator[](typename tmat4x2<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x2<T, P>& tmat4x2<T, P>::operator=(tmat4x2<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       this->value[3] = m[3];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P>& tmat4x2<T, P>::operator=(tmat4x2<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               this->value[3] = m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               this->value[3] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator+=(tmat4x2<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               this->value[3] += m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               this->value[3] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator-=(tmat4x2<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               this->value[3] -= m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               this->value[3] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               this->value[3] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               ++this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> & tmat4x2<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               --this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> tmat4x2<T, P>::operator++(int)
+       {
+               tmat4x2<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> tmat4x2<T, P>::operator--(int)
+       {
+               tmat4x2<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator+(tmat4x2<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator-(tmat4x2<T, P> const & m)
+       {
+               return tmat4x2<T, P>(
+                       -m[0],
+                       -m[1],
+                       -m[2],
+                       -m[3]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator+(tmat4x2<T, P> const & m, T scalar)
+       {
+               return tmat4x2<T, P>(
+                       m[0] + scalar,
+                       m[1] + scalar,
+                       m[2] + scalar,
+                       m[3] + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator+(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return tmat4x2<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2],
+                       m1[3] + m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator-(tmat4x2<T, P> const & m, T scalar)
+       {
+               return tmat4x2<T, P>(
+                       m[0] - scalar,
+                       m[1] - scalar,
+                       m[2] - scalar,
+                       m[3] - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator-(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return tmat4x2<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2],
+                       m1[3] - m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator*(tmat4x2<T, P> const & m, T scalar)
+       {
+               return tmat4x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar,
+                       m[3] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator*(T scalar, tmat4x2<T, P> const & m)
+       {
+               return tmat4x2<T, P>(
+                       m[0] * scalar,
+                       m[1] * scalar,
+                       m[2] * scalar,
+                       m[3] * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x2<T, P>::col_type operator*(tmat4x2<T, P> const & m, typename tmat4x2<T, P>::row_type const & v)
+       {
+               return typename tmat4x2<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w,
+                       m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x2<T, P>::row_type operator*(typename tmat4x2<T, P>::col_type const & v, tmat4x2<T, P> const & m)
+       {
+               return typename tmat4x2<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1],
+                       v.x * m[1][0] + v.y * m[1][1],
+                       v.x * m[2][0] + v.y * m[2][1],
+                       v.x * m[3][0] + v.y * m[3][1]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               T const SrcA00 = m1[0][0];
+               T const SrcA01 = m1[0][1];
+               T const SrcA10 = m1[1][0];
+               T const SrcA11 = m1[1][1];
+               T const SrcA20 = m1[2][0];
+               T const SrcA21 = m1[2][1];
+               T const SrcA30 = m1[3][0];
+               T const SrcA31 = m1[3][1];
+
+               T const SrcB00 = m2[0][0];
+               T const SrcB01 = m2[0][1];
+               T const SrcB02 = m2[0][2];
+               T const SrcB03 = m2[0][3];
+               T const SrcB10 = m2[1][0];
+               T const SrcB11 = m2[1][1];
+               T const SrcB12 = m2[1][2];
+               T const SrcB13 = m2[1][3];
+
+               tmat2x2<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return tmat3x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator*(tmat4x2<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return tmat4x2<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator/(tmat4x2<T, P> const & m, T scalar)
+       {
+               return tmat4x2<T, P>(
+                       m[0] / scalar,
+                       m[1] / scalar,
+                       m[2] / scalar,
+                       m[3] / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> operator/(T scalar, tmat4x2<T, P> const & m)
+       {
+               return tmat4x2<T, P>(
+                       scalar / m[0],
+                       scalar / m[1],
+                       scalar / m[2],
+                       scalar / m[3]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat4x2<T, P> const & m1, tmat4x2<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat4x3.hpp b/core/deps/glm/glm/detail/type_mat4x3.hpp
new file mode 100755 (executable)
index 0000000..c696735
--- /dev/null
@@ -0,0 +1,177 @@
+/// @ref core
+/// @file glm/detail/type_mat4x3.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec3.hpp"
+#include "type_vec4.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat4x3
+       {
+               typedef tvec3<T, P> col_type;
+               typedef tvec4<T, P> row_type;
+               typedef tmat4x3<T, P> type;
+               typedef tmat3x4<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[4];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat4x3() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat4x3(tmat4x3<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat4x3(tmat4x3<T, Q> const & m);
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tmat4x3(ctor);
+               GLM_FUNC_DECL explicit tmat4x3(T const & x);
+               GLM_FUNC_DECL tmat4x3(
+                       T const & x0, T const & y0, T const & z0,
+                       T const & x1, T const & y1, T const & z1,
+                       T const & x2, T const & y2, T const & z2,
+                       T const & x3, T const & y3, T const & z3);
+               GLM_FUNC_DECL tmat4x3(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2,
+                       col_type const & v3);
+
+               // -- Conversions --
+
+               template <
+                       typename X1, typename Y1, typename Z1,
+                       typename X2, typename Y2, typename Z2,
+                       typename X3, typename Y3, typename Z3,
+                       typename X4, typename Y4, typename Z4>
+               GLM_FUNC_DECL tmat4x3(
+                       X1 const & x1, Y1 const & y1, Z1 const & z1,
+                       X2 const & x2, Y2 const & y2, Z2 const & z2,
+                       X3 const & x3, Y3 const & y3, Z3 const & z3,
+                       X4 const & x4, Y4 const & y4, Z4 const & z4);
+
+               template <typename V1, typename V2, typename V3, typename V4>
+               GLM_FUNC_DECL tmat4x3(
+                       tvec3<V1, P> const & v1,
+                       tvec3<V2, P> const & v2,
+                       tvec3<V3, P> const & v3,
+                       tvec3<V4, P> const & v4);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat4x3<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat4x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x3(tmat3x4<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 4;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat4x3<T, P> & operator=(tmat4x3<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator=(tmat4x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator+=(tmat4x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator-=(tmat4x3<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x3<T, P> & operator/=(U s);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat4x3<T, P> & operator++();
+               GLM_FUNC_DECL tmat4x3<T, P> & operator--();
+               GLM_FUNC_DECL tmat4x3<T, P> operator++(int);
+               GLM_FUNC_DECL tmat4x3<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator+(tmat4x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator-(tmat4x3<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator+(tmat4x3<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator+(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator-(tmat4x3<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator-(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator*(tmat4x3<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator*(T const & s, tmat4x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x3<T, P>::col_type operator*(tmat4x3<T, P> const & m, typename tmat4x3<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x3<T, P>::row_type operator*(typename tmat4x3<T, P>::col_type const & v, tmat4x3<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator/(tmat4x3<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> operator/(T const & s, tmat4x3<T, P> const & m);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat4x3.inl"
+#endif //GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_mat4x3.inl b/core/deps/glm/glm/detail/type_mat4x3.inl
new file mode 100755 (executable)
index 0000000..cfb408b
--- /dev/null
@@ -0,0 +1,562 @@
+/// @ref core
+/// @file glm/detail/type_mat4x3.inl
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0);
+                               this->value[1] = col_type(0, 1, 0);
+                               this->value[2] = col_type(0, 0, 1);
+                               this->value[3] = col_type(0, 0, 0);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat4x3<T, P> const & m)
+               {
+                       this->value[0] = m.value[0];
+                       this->value[1] = m.value[1];
+                       this->value[2] = m.value[2];
+                       this->value[3] = m.value[3];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat4x3<T, Q> const & m)
+       {
+               this->value[0] = m.value[0];
+               this->value[1] = m.value[1];
+               this->value[2] = m.value[2];
+               this->value[3] = m.value[3];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tmat4x3<T, P>::tmat4x3(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(T const & s)
+       {
+               this->value[0] = col_type(s, 0, 0);
+               this->value[1] = col_type(0, s, 0);
+               this->value[2] = col_type(0, 0, s);
+               this->value[3] = col_type(0, 0, 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3
+       (
+               T const & x0, T const & y0, T const & z0,
+               T const & x1, T const & y1, T const & z1,
+               T const & x2, T const & y2, T const & z2,
+               T const & x3, T const & y3, T const & z3
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0);
+               this->value[1] = col_type(x1, y1, z1);
+               this->value[2] = col_type(x2, y2, z2);
+               this->value[3] = col_type(x3, y3, z3);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2,
+               col_type const & v3
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+               this->value[3] = v3;
+       }
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <
+               typename X1, typename Y1, typename Z1,
+               typename X2, typename Y2, typename Z2,
+               typename X3, typename Y3, typename Z3,
+               typename X4, typename Y4, typename Z4>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3
+       (
+               X1 const & x1, Y1 const & y1, Z1 const & z1,
+               X2 const & x2, Y2 const & y2, Z2 const & z2,
+               X3 const & x3, Y3 const & y3, Z3 const & z3,
+               X4 const & x4, Y4 const & y4, Z4 const & z4
+       )
+       {
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3), value_type(z3));
+               this->value[3] = col_type(static_cast<T>(x4), value_type(y4), value_type(z4));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3, typename V4>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3
+       (
+               tvec3<V1, P> const & v1,
+               tvec3<V2, P> const & v2,
+               tvec3<V3, P> const & v3,
+               tvec3<V4, P> const & v4
+       )
+       {
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+               this->value[3] = col_type(v4);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat4x3<U, Q> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(0, 0, 1);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat4x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0, 0, 1);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 1);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(0, 0, 1);
+               this->value[3] = col_type(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 1);
+               this->value[3] = col_type(m[3], 0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>::tmat4x3(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(0);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x3<T, P>::col_type & tmat4x3<T, P>::operator[](typename tmat4x3<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x3<T, P>::col_type const & tmat4x3<T, P>::operator[](typename tmat4x3<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary updatable operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x3<T, P>& tmat4x3<T, P>::operator=(tmat4x3<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       this->value[3] = m[3];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P>& tmat4x3<T, P>::operator=(tmat4x3<U, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               this->value[3] = m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               this->value[3] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator+=(tmat4x3<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               this->value[3] += m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               this->value[3] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator-=(tmat4x3<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               this->value[3] -= m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               this->value[3] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               this->value[3] /= s;
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               ++this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> & tmat4x3<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               --this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> tmat4x3<T, P>::operator++(int)
+       {
+               tmat4x3<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> tmat4x3<T, P>::operator--(int)
+       {
+               tmat4x3<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator+(tmat4x3<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator-(tmat4x3<T, P> const & m)
+       {
+               return tmat4x3<T, P>(
+                       -m[0],
+                       -m[1],
+                       -m[2],
+                       -m[3]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator+(tmat4x3<T, P> const & m, T const & s)
+       {
+               return tmat4x3<T, P>(
+                       m[0] + s,
+                       m[1] + s,
+                       m[2] + s,
+                       m[3] + s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator+(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return tmat4x3<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2],
+                       m1[3] + m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator-(tmat4x3<T, P> const & m, T const & s)
+       {
+               return tmat4x3<T, P>(
+                       m[0] - s,
+                       m[1] - s,
+                       m[2] - s,
+                       m[3] - s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator-(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return tmat4x3<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2],
+                       m1[3] - m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*(tmat4x3<T, P> const & m, T const & s)
+       {
+               return tmat4x3<T, P>(
+                       m[0] * s,
+                       m[1] * s,
+                       m[2] * s,
+                       m[3] * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*(T const & s, tmat4x3<T, P> const & m)
+       {
+               return tmat4x3<T, P>(
+                       m[0] * s,
+                       m[1] * s,
+                       m[2] * s,
+                       m[3] * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x3<T, P>::col_type operator*
+       (
+               tmat4x3<T, P> const & m,
+               typename tmat4x3<T, P>::row_type const & v)
+       {
+               return typename tmat4x3<T, P>::col_type(
+                       m[0][0] * v.x + m[1][0] * v.y + m[2][0] * v.z + m[3][0] * v.w,
+                       m[0][1] * v.x + m[1][1] * v.y + m[2][1] * v.z + m[3][1] * v.w,
+                       m[0][2] * v.x + m[1][2] * v.y + m[2][2] * v.z + m[3][2] * v.w);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x3<T, P>::row_type operator*
+       (
+               typename tmat4x3<T, P>::col_type const & v,
+               tmat4x3<T, P> const & m)
+       {
+               return typename tmat4x3<T, P>::row_type(
+                       v.x * m[0][0] + v.y * m[0][1] + v.z * m[0][2],
+                       v.x * m[1][0] + v.y * m[1][1] + v.z * m[1][2],
+                       v.x * m[2][0] + v.y * m[2][1] + v.z * m[2][2],
+                       v.x * m[3][0] + v.y * m[3][1] + v.z * m[3][2]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return tmat2x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               T const SrcA00 = m1[0][0];
+               T const SrcA01 = m1[0][1];
+               T const SrcA02 = m1[0][2];
+               T const SrcA10 = m1[1][0];
+               T const SrcA11 = m1[1][1];
+               T const SrcA12 = m1[1][2];
+               T const SrcA20 = m1[2][0];
+               T const SrcA21 = m1[2][1];
+               T const SrcA22 = m1[2][2];
+               T const SrcA30 = m1[3][0];
+               T const SrcA31 = m1[3][1];
+               T const SrcA32 = m1[3][2];
+
+               T const SrcB00 = m2[0][0];
+               T const SrcB01 = m2[0][1];
+               T const SrcB02 = m2[0][2];
+               T const SrcB03 = m2[0][3];
+               T const SrcB10 = m2[1][0];
+               T const SrcB11 = m2[1][1];
+               T const SrcB12 = m2[1][2];
+               T const SrcB13 = m2[1][3];
+               T const SrcB20 = m2[2][0];
+               T const SrcB21 = m2[2][1];
+               T const SrcB22 = m2[2][2];
+               T const SrcB23 = m2[2][3];
+
+               tmat3x3<T, P> Result(uninitialize);
+               Result[0][0] = SrcA00 * SrcB00 + SrcA10 * SrcB01 + SrcA20 * SrcB02 + SrcA30 * SrcB03;
+               Result[0][1] = SrcA01 * SrcB00 + SrcA11 * SrcB01 + SrcA21 * SrcB02 + SrcA31 * SrcB03;
+               Result[0][2] = SrcA02 * SrcB00 + SrcA12 * SrcB01 + SrcA22 * SrcB02 + SrcA32 * SrcB03;
+               Result[1][0] = SrcA00 * SrcB10 + SrcA10 * SrcB11 + SrcA20 * SrcB12 + SrcA30 * SrcB13;
+               Result[1][1] = SrcA01 * SrcB10 + SrcA11 * SrcB11 + SrcA21 * SrcB12 + SrcA31 * SrcB13;
+               Result[1][2] = SrcA02 * SrcB10 + SrcA12 * SrcB11 + SrcA22 * SrcB12 + SrcA32 * SrcB13;
+               Result[2][0] = SrcA00 * SrcB20 + SrcA10 * SrcB21 + SrcA20 * SrcB22 + SrcA30 * SrcB23;
+               Result[2][1] = SrcA01 * SrcB20 + SrcA11 * SrcB21 + SrcA21 * SrcB22 + SrcA31 * SrcB23;
+               Result[2][2] = SrcA02 * SrcB20 + SrcA12 * SrcB21 + SrcA22 * SrcB22 + SrcA32 * SrcB23;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator*(tmat4x3<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return tmat4x3<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3],
+                       m1[0][0] * m2[3][0] + m1[1][0] * m2[3][1] + m1[2][0] * m2[3][2] + m1[3][0] * m2[3][3],
+                       m1[0][1] * m2[3][0] + m1[1][1] * m2[3][1] + m1[2][1] * m2[3][2] + m1[3][1] * m2[3][3],
+                       m1[0][2] * m2[3][0] + m1[1][2] * m2[3][1] + m1[2][2] * m2[3][2] + m1[3][2] * m2[3][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator/(tmat4x3<T, P> const & m, T const & s)
+       {
+               return tmat4x3<T, P>(
+                       m[0] / s,
+                       m[1] / s,
+                       m[2] / s,
+                       m[3] / s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> operator/(T const & s, tmat4x3<T, P> const & m)
+       {
+               return tmat4x3<T, P>(
+                       s / m[0],
+                       s / m[1],
+                       s / m[2],
+                       s / m[3]);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat4x3<T, P> const & m1, tmat4x3<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/detail/type_mat4x4.hpp b/core/deps/glm/glm/detail/type_mat4x4.hpp
new file mode 100755 (executable)
index 0000000..2222d10
--- /dev/null
@@ -0,0 +1,195 @@
+/// @ref core
+/// @file glm/detail/type_mat4x4.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec4.hpp"
+#include "type_mat.hpp"
+#include <limits>
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tmat4x4
+       {
+               typedef tvec4<T, P> col_type;
+               typedef tvec4<T, P> row_type;
+               typedef tmat4x4<T, P> type;
+               typedef tmat4x4<T, P> transpose_type;
+               typedef T value_type;
+
+       private:
+               col_type value[4];
+
+       public:
+               // -- Constructors --
+
+               GLM_FUNC_DECL tmat4x4() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL tmat4x4(tmat4x4<T, P> const & m) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL tmat4x4(tmat4x4<T, Q> const & m);
+
+               GLM_FUNC_DECL explicit tmat4x4(ctor);
+               GLM_FUNC_DECL explicit tmat4x4(T const & x);
+               GLM_FUNC_DECL tmat4x4(
+                       T const & x0, T const & y0, T const & z0, T const & w0,
+                       T const & x1, T const & y1, T const & z1, T const & w1,
+                       T const & x2, T const & y2, T const & z2, T const & w2,
+                       T const & x3, T const & y3, T const & z3, T const & w3);
+               GLM_FUNC_DECL tmat4x4(
+                       col_type const & v0,
+                       col_type const & v1,
+                       col_type const & v2,
+                       col_type const & v3);
+
+               // -- Conversions --
+
+               template <
+                       typename X1, typename Y1, typename Z1, typename W1,
+                       typename X2, typename Y2, typename Z2, typename W2,
+                       typename X3, typename Y3, typename Z3, typename W3,
+                       typename X4, typename Y4, typename Z4, typename W4>
+               GLM_FUNC_DECL tmat4x4(
+                       X1 const & x1, Y1 const & y1, Z1 const & z1, W1 const & w1,
+                       X2 const & x2, Y2 const & y2, Z2 const & z2, W2 const & w2,
+                       X3 const & x3, Y3 const & y3, Z3 const & z3, W3 const & w3,
+                       X4 const & x4, Y4 const & y4, Z4 const & z4, W4 const & w4);
+
+               template <typename V1, typename V2, typename V3, typename V4>
+               GLM_FUNC_DECL tmat4x4(
+                       tvec4<V1, P> const & v1,
+                       tvec4<V2, P> const & v2,
+                       tvec4<V3, P> const & v3,
+                       tvec4<V4, P> const & v4);
+
+               // -- Matrix conversions --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat4x4<U, Q> const & m);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat2x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat3x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat2x3<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat3x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat2x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat4x2<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat3x4<T, P> const & x);
+               GLM_FUNC_DECL GLM_EXPLICIT tmat4x4(tmat4x3<T, P> const & x);
+
+               // -- Accesses --
+
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 4;}
+
+               GLM_FUNC_DECL col_type & operator[](length_type i);
+               GLM_FUNC_DECL col_type const & operator[](length_type i) const;
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tmat4x4<T, P> & operator=(tmat4x4<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator=(tmat4x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator+=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator+=(tmat4x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator-=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator-=(tmat4x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator*=(tmat4x4<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator/=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tmat4x4<T, P> & operator/=(tmat4x4<U, P> const & m);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tmat4x4<T, P> & operator++();
+               GLM_FUNC_DECL tmat4x4<T, P> & operator--();
+               GLM_FUNC_DECL tmat4x4<T, P> operator++(int);
+               GLM_FUNC_DECL tmat4x4<T, P> operator--(int);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator+(tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator-(tmat4x4<T, P> const & m);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator+(tmat4x4<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator+(T const & s, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator+(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator-(tmat4x4<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator-(T const & s, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator-(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator*(tmat4x4<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator*(T const & s, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x4<T, P>::col_type operator*(tmat4x4<T, P> const & m, typename tmat4x4<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x4<T, P>::row_type operator*(typename tmat4x4<T, P>::col_type const & v, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat2x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat3x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator/(tmat4x4<T, P> const & m, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator/(T const & s, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x4<T, P>::col_type operator/(tmat4x4<T, P> const & m, typename tmat4x4<T, P>::row_type const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL typename tmat4x4<T, P>::row_type operator/(typename tmat4x4<T, P>::col_type const & v, tmat4x4<T, P> const & m);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> operator/(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_mat4x4.inl"
+#endif//GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_mat4x4.inl b/core/deps/glm/glm/detail/type_mat4x4.inl
new file mode 100755 (executable)
index 0000000..4b75d94
--- /dev/null
@@ -0,0 +1,671 @@
+/// @ref core
+/// @file glm/detail/type_mat4x4.inl
+
+#include "func_matrix.hpp"
+
+namespace glm
+{
+       // -- Constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4()
+               {
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               this->value[0] = col_type(1, 0, 0, 0);
+                               this->value[1] = col_type(0, 1, 0, 0);
+                               this->value[2] = col_type(0, 0, 1, 0);
+                               this->value[3] = col_type(0, 0, 0, 1);
+#                      endif
+               }
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat4x4<T, P> const & m)
+               {
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       this->value[3] = m[3];
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat4x4<T, Q> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               this->value[3] = m[3];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(T const & s)
+       {
+               this->value[0] = col_type(s, 0, 0, 0);
+               this->value[1] = col_type(0, s, 0, 0);
+               this->value[2] = col_type(0, 0, s, 0);
+               this->value[3] = col_type(0, 0, 0, s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4
+       (
+               T const & x0, T const & y0, T const & z0, T const & w0,
+               T const & x1, T const & y1, T const & z1, T const & w1,
+               T const & x2, T const & y2, T const & z2, T const & w2,
+               T const & x3, T const & y3, T const & z3, T const & w3
+       )
+       {
+               this->value[0] = col_type(x0, y0, z0, w0);
+               this->value[1] = col_type(x1, y1, z1, w1);
+               this->value[2] = col_type(x2, y2, z2, w2);
+               this->value[3] = col_type(x3, y3, z3, w3);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4
+       (
+               col_type const & v0,
+               col_type const & v1,
+               col_type const & v2,
+               col_type const & v3
+       )
+       {
+               this->value[0] = v0;
+               this->value[1] = v1;
+               this->value[2] = v2;
+               this->value[3] = v3;
+       }
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4
+       (
+               tmat4x4<U, Q> const & m
+       )
+       {
+               this->value[0] = col_type(m[0]);
+               this->value[1] = col_type(m[1]);
+               this->value[2] = col_type(m[2]);
+               this->value[3] = col_type(m[3]);
+       }
+
+       // -- Conversions --
+
+       template <typename T, precision P> 
+       template <
+               typename X1, typename Y1, typename Z1, typename W1,
+               typename X2, typename Y2, typename Z2, typename W2,
+               typename X3, typename Y3, typename Z3, typename W3,
+               typename X4, typename Y4, typename Z4, typename W4>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4
+       (
+               X1 const & x1, Y1 const & y1, Z1 const & z1, W1 const & w1,
+               X2 const & x2, Y2 const & y2, Z2 const & z2, W2 const & w2,
+               X3 const & x3, Y3 const & y3, Z3 const & z3, W3 const & w3,
+               X4 const & x4, Y4 const & y4, Z4 const & z4, W4 const & w4
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<X1>::is_iec559 || std::numeric_limits<X1>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Y1>::is_iec559 || std::numeric_limits<Y1>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Z1>::is_iec559 || std::numeric_limits<Z1>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<W1>::is_iec559 || std::numeric_limits<W1>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid.");
+
+               GLM_STATIC_ASSERT(std::numeric_limits<X2>::is_iec559 || std::numeric_limits<X2>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 5th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Y2>::is_iec559 || std::numeric_limits<Y2>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 6th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Z2>::is_iec559 || std::numeric_limits<Z2>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 7th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<W2>::is_iec559 || std::numeric_limits<W2>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 8th parameter type invalid.");
+
+               GLM_STATIC_ASSERT(std::numeric_limits<X3>::is_iec559 || std::numeric_limits<X3>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 9th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Y3>::is_iec559 || std::numeric_limits<Y3>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 10th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Z3>::is_iec559 || std::numeric_limits<Z3>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 11th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<W3>::is_iec559 || std::numeric_limits<W3>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 12th parameter type invalid.");
+
+               GLM_STATIC_ASSERT(std::numeric_limits<X4>::is_iec559 || std::numeric_limits<X4>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 13th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Y4>::is_iec559 || std::numeric_limits<Y4>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 14th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<Z4>::is_iec559 || std::numeric_limits<Z4>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 15th parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<W4>::is_iec559 || std::numeric_limits<W4>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 16th parameter type invalid.");
+
+               this->value[0] = col_type(static_cast<T>(x1), value_type(y1), value_type(z1), value_type(w1));
+               this->value[1] = col_type(static_cast<T>(x2), value_type(y2), value_type(z2), value_type(w2));
+               this->value[2] = col_type(static_cast<T>(x3), value_type(y3), value_type(z3), value_type(w3));
+               this->value[3] = col_type(static_cast<T>(x4), value_type(y4), value_type(z4), value_type(w4));
+       }
+       
+       template <typename T, precision P>
+       template <typename V1, typename V2, typename V3, typename V4>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4
+       (
+               tvec4<V1, P> const & v1,
+               tvec4<V2, P> const & v2,
+               tvec4<V3, P> const & v3,
+               tvec4<V4, P> const & v4
+       )               
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<V1>::is_iec559 || std::numeric_limits<V1>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 1st parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<V2>::is_iec559 || std::numeric_limits<V2>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 2nd parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<V3>::is_iec559 || std::numeric_limits<V3>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 3rd parameter type invalid.");
+               GLM_STATIC_ASSERT(std::numeric_limits<V4>::is_iec559 || std::numeric_limits<V4>::is_integer || GLM_UNRESTRICTED_GENTYPE, "*mat4x4 constructor only takes float and integer types, 4th parameter type invalid.");
+
+               this->value[0] = col_type(v1);
+               this->value[1] = col_type(v2);
+               this->value[2] = col_type(v3);
+               this->value[3] = col_type(v4);
+       }
+
+       // -- Matrix conversions --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat2x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(0, 0, 1, 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat3x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat2x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(0, 0, 1, 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat3x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(m[2], 1, 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat2x4<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = col_type(0, 0, 1, 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat4x2<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0, 0);
+               this->value[1] = col_type(m[1], 0, 0);
+               this->value[2] = col_type(0, 0, 1, 0);
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat3x4<T, P> const & m)
+       {
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               this->value[3] = col_type(0, 0, 0, 1);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>::tmat4x4(tmat4x3<T, P> const & m)
+       {
+               this->value[0] = col_type(m[0], 0);
+               this->value[1] = col_type(m[1], 0);
+               this->value[2] = col_type(m[2], 0);
+               this->value[3] = col_type(m[3], 1);
+       }
+
+       // -- Accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::col_type & tmat4x4<T, P>::operator[](typename tmat4x4<T, P>::length_type i)
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::col_type const & tmat4x4<T, P>::operator[](typename tmat4x4<T, P>::length_type i) const
+       {
+               assert(i < this->length());
+               return this->value[i];
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tmat4x4<T, P>& tmat4x4<T, P>::operator=(tmat4x4<T, P> const & m)
+               {
+                       //memcpy could be faster
+                       //memcpy(&this->value, &m.value, 16 * sizeof(valType));
+                       this->value[0] = m[0];
+                       this->value[1] = m[1];
+                       this->value[2] = m[2];
+                       this->value[3] = m[3];
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P> 
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>& tmat4x4<T, P>::operator=(tmat4x4<U, P> const & m)
+       {
+               //memcpy could be faster
+               //memcpy(&this->value, &m.value, 16 * sizeof(valType));
+               this->value[0] = m[0];
+               this->value[1] = m[1];
+               this->value[2] = m[2];
+               this->value[3] = m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>& tmat4x4<T, P>::operator+=(U s)
+       {
+               this->value[0] += s;
+               this->value[1] += s;
+               this->value[2] += s;
+               this->value[3] += s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P>& tmat4x4<T, P>::operator+=(tmat4x4<U, P> const & m)
+       {
+               this->value[0] += m[0];
+               this->value[1] += m[1];
+               this->value[2] += m[2];
+               this->value[3] += m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator-=(U s)
+       {
+               this->value[0] -= s;
+               this->value[1] -= s;
+               this->value[2] -= s;
+               this->value[3] -= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator-=(tmat4x4<U, P> const & m)
+       {
+               this->value[0] -= m[0];
+               this->value[1] -= m[1];
+               this->value[2] -= m[2];
+               this->value[3] -= m[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator*=(U s)
+       {
+               this->value[0] *= s;
+               this->value[1] *= s;
+               this->value[2] *= s;
+               this->value[3] *= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator*=(tmat4x4<U, P> const & m)
+       {
+               return (*this = *this * m);
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator/=(U s)
+       {
+               this->value[0] /= s;
+               this->value[1] /= s;
+               this->value[2] /= s;
+               this->value[3] /= s;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator/=(tmat4x4<U, P> const & m)
+       {
+               return *this *= inverse(m);
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator++()
+       {
+               ++this->value[0];
+               ++this->value[1];
+               ++this->value[2];
+               ++this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> & tmat4x4<T, P>::operator--()
+       {
+               --this->value[0];
+               --this->value[1];
+               --this->value[2];
+               --this->value[3];
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> tmat4x4<T, P>::operator++(int)
+       {
+               tmat4x4<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> tmat4x4<T, P>::operator--(int)
+       {
+               tmat4x4<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary constant operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator+(tmat4x4<T, P> const & m)
+       {
+               return m;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator-(tmat4x4<T, P> const & m)
+       {
+               return tmat4x4<T, P>(
+                       -m[0],
+                       -m[1],
+                       -m[2],
+                       -m[3]);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator+(tmat4x4<T, P> const & m, T const & s)
+       {
+               return tmat4x4<T, P>(
+                       m[0] + s,
+                       m[1] + s,
+                       m[2] + s,
+                       m[3] + s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator+(T const & s, tmat4x4<T, P> const & m)
+       {
+               return tmat4x4<T, P>(
+                       m[0] + s,
+                       m[1] + s,
+                       m[2] + s,
+                       m[3] + s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator+(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return tmat4x4<T, P>(
+                       m1[0] + m2[0],
+                       m1[1] + m2[1],
+                       m1[2] + m2[2],
+                       m1[3] + m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator-(tmat4x4<T, P> const & m, T const & s)
+       {
+               return tmat4x4<T, P>(
+                       m[0] - s,
+                       m[1] - s,
+                       m[2] - s,
+                       m[3] - s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator-(T const & s, tmat4x4<T, P> const & m)
+       {
+               return tmat4x4<T, P>(
+                       s - m[0],
+                       s - m[1],
+                       s - m[2],
+                       s - m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator-(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return tmat4x4<T, P>(
+                       m1[0] - m2[0],
+                       m1[1] - m2[1],
+                       m1[2] - m2[2],
+                       m1[3] - m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator*(tmat4x4<T, P> const & m, T const  & s)
+       {
+               return tmat4x4<T, P>(
+                       m[0] * s,
+                       m[1] * s,
+                       m[2] * s,
+                       m[3] * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator*(T const & s, tmat4x4<T, P> const & m)
+       {
+               return tmat4x4<T, P>(
+                       m[0] * s,
+                       m[1] * s,
+                       m[2] * s,
+                       m[3] * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::col_type operator*
+       (
+               tmat4x4<T, P> const & m,
+               typename tmat4x4<T, P>::row_type const & v
+       )
+       {
+/*
+               __m128 v0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 v1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 v2 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 v3 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 m0 = _mm_mul_ps(m[0].data, v0);
+               __m128 m1 = _mm_mul_ps(m[1].data, v1);
+               __m128 a0 = _mm_add_ps(m0, m1);
+
+               __m128 m2 = _mm_mul_ps(m[2].data, v2);
+               __m128 m3 = _mm_mul_ps(m[3].data, v3);
+               __m128 a1 = _mm_add_ps(m2, m3);
+
+               __m128 a2 = _mm_add_ps(a0, a1);
+
+               return typename tmat4x4<T, P>::col_type(a2);
+*/
+
+               typename tmat4x4<T, P>::col_type const Mov0(v[0]);
+               typename tmat4x4<T, P>::col_type const Mov1(v[1]);
+               typename tmat4x4<T, P>::col_type const Mul0 = m[0] * Mov0;
+               typename tmat4x4<T, P>::col_type const Mul1 = m[1] * Mov1;
+               typename tmat4x4<T, P>::col_type const Add0 = Mul0 + Mul1;
+               typename tmat4x4<T, P>::col_type const Mov2(v[2]);
+               typename tmat4x4<T, P>::col_type const Mov3(v[3]);
+               typename tmat4x4<T, P>::col_type const Mul2 = m[2] * Mov2;
+               typename tmat4x4<T, P>::col_type const Mul3 = m[3] * Mov3;
+               typename tmat4x4<T, P>::col_type const Add1 = Mul2 + Mul3;
+               typename tmat4x4<T, P>::col_type const Add2 = Add0 + Add1;
+               return Add2;
+
+/*
+               return typename tmat4x4<T, P>::col_type(
+                       m[0][0] * v[0] + m[1][0] * v[1] + m[2][0] * v[2] + m[3][0] * v[3],
+                       m[0][1] * v[0] + m[1][1] * v[1] + m[2][1] * v[2] + m[3][1] * v[3],
+                       m[0][2] * v[0] + m[1][2] * v[1] + m[2][2] * v[2] + m[3][2] * v[3],
+                       m[0][3] * v[0] + m[1][3] * v[1] + m[2][3] * v[2] + m[3][3] * v[3]);
+*/
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::row_type operator*
+       (
+               typename tmat4x4<T, P>::col_type const & v,
+               tmat4x4<T, P> const & m
+       )
+       {
+               return typename tmat4x4<T, P>::row_type(
+                       m[0][0] * v[0] + m[0][1] * v[1] + m[0][2] * v[2] + m[0][3] * v[3],
+                       m[1][0] * v[0] + m[1][1] * v[1] + m[1][2] * v[2] + m[1][3] * v[3],
+                       m[2][0] * v[0] + m[2][1] * v[1] + m[2][2] * v[2] + m[2][3] * v[3],
+                       m[3][0] * v[0] + m[3][1] * v[1] + m[3][2] * v[2] + m[3][3] * v[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat2x4<T, P> const & m2)
+       {
+               return tmat2x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat3x4<T, P> const & m2)
+       {
+               return tmat3x4<T, P>(
+                       m1[0][0] * m2[0][0] + m1[1][0] * m2[0][1] + m1[2][0] * m2[0][2] + m1[3][0] * m2[0][3],
+                       m1[0][1] * m2[0][0] + m1[1][1] * m2[0][1] + m1[2][1] * m2[0][2] + m1[3][1] * m2[0][3],
+                       m1[0][2] * m2[0][0] + m1[1][2] * m2[0][1] + m1[2][2] * m2[0][2] + m1[3][2] * m2[0][3],
+                       m1[0][3] * m2[0][0] + m1[1][3] * m2[0][1] + m1[2][3] * m2[0][2] + m1[3][3] * m2[0][3],
+                       m1[0][0] * m2[1][0] + m1[1][0] * m2[1][1] + m1[2][0] * m2[1][2] + m1[3][0] * m2[1][3],
+                       m1[0][1] * m2[1][0] + m1[1][1] * m2[1][1] + m1[2][1] * m2[1][2] + m1[3][1] * m2[1][3],
+                       m1[0][2] * m2[1][0] + m1[1][2] * m2[1][1] + m1[2][2] * m2[1][2] + m1[3][2] * m2[1][3],
+                       m1[0][3] * m2[1][0] + m1[1][3] * m2[1][1] + m1[2][3] * m2[1][2] + m1[3][3] * m2[1][3],
+                       m1[0][0] * m2[2][0] + m1[1][0] * m2[2][1] + m1[2][0] * m2[2][2] + m1[3][0] * m2[2][3],
+                       m1[0][1] * m2[2][0] + m1[1][1] * m2[2][1] + m1[2][1] * m2[2][2] + m1[3][1] * m2[2][3],
+                       m1[0][2] * m2[2][0] + m1[1][2] * m2[2][1] + m1[2][2] * m2[2][2] + m1[3][2] * m2[2][3],
+                       m1[0][3] * m2[2][0] + m1[1][3] * m2[2][1] + m1[2][3] * m2[2][2] + m1[3][3] * m2[2][3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator*(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               typename tmat4x4<T, P>::col_type const SrcA0 = m1[0];
+               typename tmat4x4<T, P>::col_type const SrcA1 = m1[1];
+               typename tmat4x4<T, P>::col_type const SrcA2 = m1[2];
+               typename tmat4x4<T, P>::col_type const SrcA3 = m1[3];
+
+               typename tmat4x4<T, P>::col_type const SrcB0 = m2[0];
+               typename tmat4x4<T, P>::col_type const SrcB1 = m2[1];
+               typename tmat4x4<T, P>::col_type const SrcB2 = m2[2];
+               typename tmat4x4<T, P>::col_type const SrcB3 = m2[3];
+
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0] = SrcA0 * SrcB0[0] + SrcA1 * SrcB0[1] + SrcA2 * SrcB0[2] + SrcA3 * SrcB0[3];
+               Result[1] = SrcA0 * SrcB1[0] + SrcA1 * SrcB1[1] + SrcA2 * SrcB1[2] + SrcA3 * SrcB1[3];
+               Result[2] = SrcA0 * SrcB2[0] + SrcA1 * SrcB2[1] + SrcA2 * SrcB2[2] + SrcA3 * SrcB2[3];
+               Result[3] = SrcA0 * SrcB3[0] + SrcA1 * SrcB3[1] + SrcA2 * SrcB3[2] + SrcA3 * SrcB3[3];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator/(tmat4x4<T, P> const & m, T const & s)
+       {
+               return tmat4x4<T, P>(
+                       m[0] / s,
+                       m[1] / s,
+                       m[2] / s,
+                       m[3] / s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator/(T const & s, tmat4x4<T, P> const & m)
+       {
+               return tmat4x4<T, P>(
+                       s / m[0],
+                       s / m[1],
+                       s / m[2],
+                       s / m[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::col_type operator/(tmat4x4<T, P> const & m, typename tmat4x4<T, P>::row_type const & v)
+       {
+               return inverse(m) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tmat4x4<T, P>::row_type operator/(typename tmat4x4<T, P>::col_type const & v, tmat4x4<T, P> const & m)
+       {
+               return v * inverse(m);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> operator/(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               tmat4x4<T, P> m1_copy(m1);
+               return m1_copy /= m2;
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return (m1[0] == m2[0]) && (m1[1] == m2[1]) && (m1[2] == m2[2]) && (m1[3] == m2[3]);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tmat4x4<T, P> const & m1, tmat4x4<T, P> const & m2)
+       {
+               return (m1[0] != m2[0]) || (m1[1] != m2[1]) || (m1[2] != m2[2]) || (m1[3] != m2[3]);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE
+#      include "type_mat4x4_simd.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_mat4x4_simd.inl b/core/deps/glm/glm/detail/type_mat4x4_simd.inl
new file mode 100755 (executable)
index 0000000..09d0b1f
--- /dev/null
@@ -0,0 +1,7 @@
+/// @ref core
+/// @file glm/detail/type_mat4x4_sse2.inl
+
+namespace glm
+{
+
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_vec.hpp b/core/deps/glm/glm/detail/type_vec.hpp
new file mode 100755 (executable)
index 0000000..7849db6
--- /dev/null
@@ -0,0 +1,576 @@
+/// @ref core
+/// @file glm/detail/type_vec.hpp
+
+#pragma once
+
+#include "precision.hpp"
+#include "type_int.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename T, std::size_t size, bool aligned>
+       struct storage
+       {
+               typedef struct type {
+                       uint8 data[size];
+               } type;
+       };
+
+       #define GLM_ALIGNED_STORAGE_TYPE_STRUCT(x) \
+               template <typename T> \
+               struct storage<T, x, true> { \
+                       GLM_ALIGNED_STRUCT(x) type { \
+                               uint8 data[x]; \
+                       }; \
+               };
+
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(1)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(2)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(4)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(8)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(16)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(32)
+       GLM_ALIGNED_STORAGE_TYPE_STRUCT(64)
+               
+#      if GLM_ARCH & GLM_ARCH_SSE2_BIT
+               template <>
+               struct storage<float, 16, true>
+               {
+                       typedef glm_vec4 type;
+               };
+
+               template <>
+               struct storage<int, 16, true>
+               {
+                       typedef glm_ivec4 type;
+               };
+
+               template <>
+               struct storage<unsigned int, 16, true>
+               {
+                       typedef glm_uvec4 type;
+               };
+/*
+#      else
+               typedef union __declspec(align(16)) glm_128
+               {
+                       unsigned __int8 data[16];
+               } glm_128;
+
+               template <>
+               struct storage<float, 16, true>
+               {
+                       typedef glm_128 type;
+               };
+
+               template <>
+               struct storage<int, 16, true>
+               {
+                       typedef glm_128 type;
+               };
+
+               template <>
+               struct storage<unsigned int, 16, true>
+               {
+                       typedef glm_128 type;
+               };
+*/
+#      endif
+
+#      if (GLM_ARCH & GLM_ARCH_AVX_BIT)
+               template <>
+               struct storage<double, 32, true>
+               {
+                       typedef glm_dvec4 type;
+               };
+#      endif
+
+#      if (GLM_ARCH & GLM_ARCH_AVX2_BIT)
+               template <>
+               struct storage<int64, 32, true>
+               {
+                       typedef glm_i64vec4 type;
+               };
+
+               template <>
+               struct storage<uint64, 32, true>
+               {
+                       typedef glm_u64vec4 type;
+               };
+#      endif
+}//namespace detail
+
+       template <typename T, precision P> struct tvec1;
+       template <typename T, precision P> struct tvec2;
+       template <typename T, precision P> struct tvec3;
+       template <typename T, precision P> struct tvec4;
+
+       typedef tvec1<float, highp>             highp_vec1_t;
+       typedef tvec1<float, mediump>   mediump_vec1_t;
+       typedef tvec1<float, lowp>              lowp_vec1_t;
+       typedef tvec1<double, highp>    highp_dvec1_t;
+       typedef tvec1<double, mediump>  mediump_dvec1_t;
+       typedef tvec1<double, lowp>             lowp_dvec1_t;
+       typedef tvec1<int, highp>               highp_ivec1_t;
+       typedef tvec1<int, mediump>             mediump_ivec1_t;
+       typedef tvec1<int, lowp>                lowp_ivec1_t;
+       typedef tvec1<uint, highp>              highp_uvec1_t;
+       typedef tvec1<uint, mediump>    mediump_uvec1_t;
+       typedef tvec1<uint, lowp>               lowp_uvec1_t;
+       typedef tvec1<bool, highp>              highp_bvec1_t;
+       typedef tvec1<bool, mediump>    mediump_bvec1_t;
+       typedef tvec1<bool, lowp>               lowp_bvec1_t;
+
+       /// @addtogroup core_precision
+       /// @{
+
+       /// 2 components vector of high single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<float, highp>             highp_vec2;
+
+       /// 2 components vector of medium single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<float, mediump>   mediump_vec2;
+
+       /// 2 components vector of low single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<float, lowp>              lowp_vec2;
+
+       /// 2 components vector of high double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<double, highp>    highp_dvec2;
+
+       /// 2 components vector of medium double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<double, mediump>  mediump_dvec2;
+
+       /// 2 components vector of low double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<double, lowp>             lowp_dvec2;
+
+       /// 2 components vector of high precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<int, highp>               highp_ivec2;
+
+       /// 2 components vector of medium precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<int, mediump>             mediump_ivec2;
+
+       /// 2 components vector of low precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<int, lowp>                lowp_ivec2;
+
+       /// 2 components vector of high precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<uint, highp>              highp_uvec2;
+
+       /// 2 components vector of medium precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<uint, mediump>    mediump_uvec2;
+
+       /// 2 components vector of low precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<uint, lowp>               lowp_uvec2;
+
+       /// 2 components vector of high precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<bool, highp>              highp_bvec2;
+
+       /// 2 components vector of medium precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<bool, mediump>    mediump_bvec2;
+
+       /// 2 components vector of low precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec2<bool, lowp>               lowp_bvec2;
+
+       /// @}
+
+       /// @addtogroup core_precision
+       /// @{
+
+       /// 3 components vector of high single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<float, highp>             highp_vec3;
+
+       /// 3 components vector of medium single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<float, mediump>   mediump_vec3;
+
+       /// 3 components vector of low single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<float, lowp>              lowp_vec3;
+
+       /// 3 components vector of high double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<double, highp>    highp_dvec3;
+
+       /// 3 components vector of medium double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<double, mediump>  mediump_dvec3;
+
+       /// 3 components vector of low double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<double, lowp>             lowp_dvec3;
+
+       /// 3 components vector of high precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<int, highp>               highp_ivec3;
+
+       /// 3 components vector of medium precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<int, mediump>             mediump_ivec3;
+
+       /// 3 components vector of low precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<int, lowp>                lowp_ivec3;
+
+       /// 3 components vector of high precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<uint, highp>              highp_uvec3;
+
+       /// 3 components vector of medium precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<uint, mediump>    mediump_uvec3;
+
+       /// 3 components vector of low precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<uint, lowp>               lowp_uvec3;
+
+       /// 3 components vector of high precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<bool, highp>              highp_bvec3;
+
+       /// 3 components vector of medium precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<bool, mediump>    mediump_bvec3;
+
+       /// 3 components vector of low precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec3<bool, lowp>               lowp_bvec3;
+
+       /// @}
+
+       /// @addtogroup core_precision
+       /// @{
+
+       /// 4 components vector of high single-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<float, highp>             highp_vec4;
+
+       /// 4 components vector of medium single-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<float, mediump>   mediump_vec4;
+
+       /// 4 components vector of low single-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<float, lowp>              lowp_vec4;
+
+       /// 4 components vector of high double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<double, highp>    highp_dvec4;
+
+       /// 4 components vector of medium double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<double, mediump>  mediump_dvec4;
+
+       /// 4 components vector of low double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<double, lowp>             lowp_dvec4;
+
+       /// 4 components vector of high precision signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<int, highp>               highp_ivec4;
+
+       /// 4 components vector of medium precision signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<int, mediump>             mediump_ivec4;
+
+       /// 4 components vector of low precision signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<int, lowp>                lowp_ivec4;
+
+       /// 4 components vector of high precision unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<uint, highp>              highp_uvec4;
+
+       /// 4 components vector of medium precision unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<uint, mediump>    mediump_uvec4;
+
+       /// 4 components vector of low precision unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<uint, lowp>               lowp_uvec4;
+
+       /// 4 components vector of high precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<bool, highp>              highp_bvec4;
+
+       /// 4 components vector of medium precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<bool, mediump>    mediump_bvec4;
+
+       /// 4 components vector of low precision bool numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tvec4<bool, lowp>               lowp_bvec4;
+
+       /// @}
+
+       /// @addtogroup core_types
+       /// @{
+
+       // -- Default float definition --
+
+#if(defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_vec2                       vec2;
+       typedef lowp_vec3                       vec3;
+       typedef lowp_vec4                       vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+       typedef mediump_vec2            vec2;
+       typedef mediump_vec3            vec3;
+       typedef mediump_vec4            vec4;
+#else //defined(GLM_PRECISION_HIGHP_FLOAT)
+       /// 2 components vector of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_vec2                      vec2;
+
+       //! 3 components vector of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_vec3                      vec3;
+
+       //! 4 components vector of floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_vec4                      vec4;
+#endif//GLM_PRECISION
+
+       // -- Default double definition --
+
+#if(defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_dvec2                      dvec2;
+       typedef lowp_dvec3                      dvec3;
+       typedef lowp_dvec4                      dvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))
+       typedef mediump_dvec2           dvec2;
+       typedef mediump_dvec3           dvec3;
+       typedef mediump_dvec4           dvec4;
+#else //defined(GLM_PRECISION_HIGHP_DOUBLE)
+       /// 2 components vector of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_dvec2                     dvec2;
+
+       //! 3 components vector of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_dvec3                     dvec3;
+
+       //! 4 components vector of double-precision floating-point numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_dvec4                     dvec4;
+#endif//GLM_PRECISION
+
+       // -- Signed integer definition --
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_ivec2                      ivec2;
+       typedef lowp_ivec3                      ivec3;
+       typedef lowp_ivec4                      ivec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_ivec2           ivec2;
+       typedef mediump_ivec3           ivec3;
+       typedef mediump_ivec4           ivec4;
+#else //defined(GLM_PRECISION_HIGHP_INT)
+       /// 2 components vector of signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_ivec2                     ivec2;
+
+       /// 3 components vector of signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_ivec3                     ivec3;
+
+       /// 4 components vector of signed integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_ivec4                     ivec4;
+#endif//GLM_PRECISION
+
+       // -- Unsigned integer definition --
+
+#if(defined(GLM_PRECISION_LOWP_UINT))
+       typedef lowp_uvec2                      uvec2;
+       typedef lowp_uvec3                      uvec3;
+       typedef lowp_uvec4                      uvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_UINT))
+       typedef mediump_uvec2           uvec2;
+       typedef mediump_uvec3           uvec3;
+       typedef mediump_uvec4           uvec4;
+#else //defined(GLM_PRECISION_HIGHP_UINT)
+       /// 2 components vector of unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_uvec2                     uvec2;
+
+       /// 3 components vector of unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_uvec3                     uvec3;
+
+       /// 4 components vector of unsigned integer numbers.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_uvec4                     uvec4;
+#endif//GLM_PRECISION
+
+       // -- Boolean definition --
+
+#if(defined(GLM_PRECISION_LOWP_BOOL))
+       typedef lowp_bvec2                      bvec2;
+       typedef lowp_bvec3                      bvec3;
+       typedef lowp_bvec4                      bvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_BOOL))
+       typedef mediump_bvec2           bvec2;
+       typedef mediump_bvec3           bvec3;
+       typedef mediump_bvec4           bvec4;
+#else //defined(GLM_PRECISION_HIGHP_BOOL)
+       /// 2 components vector of boolean.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_bvec2                     bvec2;
+
+       /// 3 components vector of boolean.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_bvec3                     bvec3;
+
+       /// 4 components vector of boolean.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.5 Vectors</a>
+       typedef highp_bvec4                     bvec4;
+#endif//GLM_PRECISION
+
+       /// @}
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_vec.inl b/core/deps/glm/glm/detail/type_vec.inl
new file mode 100755 (executable)
index 0000000..2238a1b
--- /dev/null
@@ -0,0 +1,2 @@
+/// @ref core
+/// @file glm/detail/type_vec.inl
diff --git a/core/deps/glm/glm/detail/type_vec1.hpp b/core/deps/glm/glm/detail/type_vec1.hpp
new file mode 100755 (executable)
index 0000000..f5c7f01
--- /dev/null
@@ -0,0 +1,302 @@
+/// @ref core
+/// @file glm/detail/type_vec1.hpp
+
+#pragma once
+
+#include "../fwd.hpp"
+#include "type_vec.hpp"
+#if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#      if GLM_HAS_UNRESTRICTED_UNIONS
+#              include "_swizzle.hpp"
+#      else
+#              include "_swizzle_func.hpp"
+#      endif
+#endif //GLM_SWIZZLE
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tvec1
+       {
+               // -- Implementation detail --
+
+               typedef T value_type;
+               typedef tvec1<T, P> type;
+               typedef tvec1<bool, P> bool_type;
+
+               // -- Data --
+
+#              if GLM_HAS_ONLY_XYZW
+                       T x;
+
+#              elif GLM_HAS_ALIGNED_TYPE
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic push
+#                              pragma GCC diagnostic ignored "-Wpedantic"
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic push
+#                              pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#                              pragma clang diagnostic ignored "-Wnested-anon-types"
+#                      endif
+               
+                       union
+                       {
+                               T x;
+                               T r;
+                               T s;
+/*
+#                              if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                                       _GLM_SWIZZLE1_2_MEMBERS(T, P, tvec2, x)
+                                       _GLM_SWIZZLE1_2_MEMBERS(T, P, tvec2, r)
+                                       _GLM_SWIZZLE1_2_MEMBERS(T, P, tvec2, s)
+                                       _GLM_SWIZZLE1_3_MEMBERS(T, P, tvec3, x)
+                                       _GLM_SWIZZLE1_3_MEMBERS(T, P, tvec3, r)
+                                       _GLM_SWIZZLE1_3_MEMBERS(T, P, tvec3, s)
+                                       _GLM_SWIZZLE1_4_MEMBERS(T, P, tvec4, x)
+                                       _GLM_SWIZZLE1_4_MEMBERS(T, P, tvec4, r)
+                                       _GLM_SWIZZLE1_4_MEMBERS(T, P, tvec4, s)
+#                              endif//GLM_SWIZZLE*/
+                       };
+               
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic pop
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic pop
+#                      endif
+#              else
+                       union {T x, r, s;};
+/*
+#                      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                               GLM_SWIZZLE_GEN_VEC_FROM_VEC1(T, P, tvec2, tvec2, tvec3, tvec4)
+#                      endif//GLM_SWIZZLE*/
+#              endif
+
+               // -- Component accesses --
+
+               /// Return the count of components of the vector
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 1;}
+
+               GLM_FUNC_DECL T & operator[](length_type i);
+               GLM_FUNC_DECL T const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec1() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec1(tvec1<T, P> const & v) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec1(tvec1<T, Q> const & v);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec1(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec1(T scalar);
+
+               // -- Conversion vector constructors --
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec1(tvec2<U, Q> const & v);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec1(tvec3<U, Q> const & v);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec1(tvec4<U, Q> const & v);
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec1(tvec1<U, Q> const & v);
+
+               // -- Swizzle constructors --
+/*
+#              if(GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED))
+                       template <int E0>
+                       GLM_FUNC_DECL tvec1(detail::_swizzle<1, T, P, tvec1, E0, -1,-2,-3> const & that)
+                       {
+                               *this = that();
+                       }
+#              endif//(GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED))
+*/
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tvec1<T, P> & operator=(tvec1<T, P> const & v) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator+=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator+=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator-=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator-=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator*=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator*=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator/=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator/=(tvec1<U, P> const & v);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tvec1<T, P> & operator++();
+               GLM_FUNC_DECL tvec1<T, P> & operator--();
+               GLM_FUNC_DECL tvec1<T, P> operator++(int);
+               GLM_FUNC_DECL tvec1<T, P> operator--(int);
+
+               // -- Unary bit operators --
+
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator%=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator%=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator&=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator&=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator|=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator|=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator^=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator^=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator<<=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator<<=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator>>=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec1<T, P> & operator>>=(tvec1<U, P> const & v);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator+(tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator-(tvec1<T, P> const & v);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator+(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator+(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator+(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator-(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator-(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator-     (tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator*(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator*(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator*(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator/(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator/(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator/(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator%(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator%(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator%(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator&(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator&(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator&(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator|(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator|(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator|(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator^(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator^(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator^(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator<<(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator<<(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator<<(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator>>(tvec1<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator>>(T scalar, tvec1<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator>>(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec1<T, P> operator~(tvec1<T, P> const & v);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tvec1<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec1<bool, P> operator&&(tvec1<bool, P> const & v1, tvec1<bool, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec1<bool, P> operator||(tvec1<bool, P> const & v1, tvec1<bool, P> const & v2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_vec1.inl"
+#endif//GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_vec1.inl b/core/deps/glm/glm/detail/type_vec1.inl
new file mode 100755 (executable)
index 0000000..72f9437
--- /dev/null
@@ -0,0 +1,558 @@
+/// @ref core
+/// @file glm/detail/type_vec1.inl
+
+namespace glm
+{
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                               : x(0)
+#                      endif
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec1<T, P> const & v)
+                       : x(v.x)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec1<T, Q> const & v)
+               : x(v.x)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(T scalar)
+               : x(scalar)
+       {}
+
+       // -- Conversion vector constructors --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec1<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec2<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec3<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec1<T, P>::tvec1(tvec4<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+       {}
+
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T & tvec1<T, P>::operator[](typename tvec1<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T const & tvec1<T, P>::operator[](typename tvec1<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator=(tvec1<T, P> const & v)
+               {
+                       this->x = v.x;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator=(tvec1<U, P> const & v)
+       {
+               this->x = static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator+=(U scalar)
+       {
+               this->x += static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator+=(tvec1<U, P> const & v)
+       {
+               this->x += static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator-=(U scalar)
+       {
+               this->x -= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator-=(tvec1<U, P> const & v)
+       {
+               this->x -= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator*=(U scalar)
+       {
+               this->x *= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator*=(tvec1<U, P> const & v)
+       {
+               this->x *= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator/=(U scalar)
+       {
+               this->x /= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator/=(tvec1<U, P> const & v)
+       {
+               this->x /= static_cast<T>(v.x);
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator++()
+       {
+               ++this->x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator--()
+       {
+               --this->x;
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> tvec1<T, P>::operator++(int)
+       {
+               tvec1<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> tvec1<T, P>::operator--(int)
+       {
+               tvec1<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator%=(U scalar)
+       {
+               this->x %= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator%=(tvec1<U, P> const & v)
+       {
+               this->x %= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator&=(U scalar)
+       {
+               this->x &= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator&=(tvec1<U, P> const & v)
+       {
+               this->x &= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator|=(U scalar)
+       {
+               this->x |= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator|=(tvec1<U, P> const & v)
+       {
+               this->x |= U(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator^=(U scalar)
+       {
+               this->x ^= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator^=(tvec1<U, P> const & v)
+       {
+               this->x ^= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator<<=(U scalar)
+       {
+               this->x <<= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator<<=(tvec1<U, P> const & v)
+       {
+               this->x <<= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator>>=(U scalar)
+       {
+               this->x >>= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> & tvec1<T, P>::operator>>=(tvec1<U, P> const & v)
+       {
+               this->x >>= static_cast<T>(v.x);
+               return *this;
+       }
+
+       // -- Unary constant operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator+(tvec1<T, P> const & v)
+       {
+               return v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator-(tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       -v.x);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator+(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x + scalar);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator+(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar + v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator+(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x + v2.x);
+       }
+
+       //operator-
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator-(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator-(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar - v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator-(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x - v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator*(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator*(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar * v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator*(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x * v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator/(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator/(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar / v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator/(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x / v2.x);
+       }
+
+       // -- Binary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator%(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x % scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator%(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar % v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator%(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x % v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator&(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x & scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator&(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar & v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator&(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x & v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator|(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x | scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator|(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar | v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator|(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x | v2.x);
+       }
+               
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator^(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x ^ scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator^(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar ^ v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator^(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x ^ v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator<<(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x << scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator<<(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar << v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator<<(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x << v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator>>(tvec1<T, P> const & v, T scalar)
+       {
+               return tvec1<T, P>(
+                       v.x >> scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator>>(T scalar, tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       scalar >> v.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator>>(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec1<T, P>(
+                       v1.x >> v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<T, P> operator~(tvec1<T, P> const & v)
+       {
+               return tvec1<T, P>(
+                       ~v.x);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER bool operator==(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return (v1.x == v2.x);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER bool operator!=(tvec1<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return (v1.x != v2.x);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec1<bool, P> operator&&(tvec1<bool, P> const & v1, tvec1<bool, P> const & v2)
+       {
+               return tvec1<bool, P>(v1.x && v2.x);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec1<bool, P> operator||(tvec1<bool, P> const & v1, tvec1<bool, P> const & v2)
+       {
+               return tvec1<bool, P>(v1.x || v2.x);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_vec2.hpp b/core/deps/glm/glm/detail/type_vec2.hpp
new file mode 100755 (executable)
index 0000000..a9af32e
--- /dev/null
@@ -0,0 +1,388 @@
+/// @ref core
+/// @file glm/detail/type_vec2.hpp
+
+#pragma once
+
+#include "type_vec.hpp"
+#if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#      if GLM_HAS_UNRESTRICTED_UNIONS
+#              include "_swizzle.hpp"
+#      else
+#              include "_swizzle_func.hpp"
+#      endif
+#endif //GLM_SWIZZLE
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tvec2
+       {
+               // -- Implementation detail --
+
+               typedef T value_type;
+               typedef tvec2<T, P> type;
+               typedef tvec2<bool, P> bool_type;
+
+               // -- Data --
+
+#              if GLM_HAS_ONLY_XYZW
+                       T x, y;
+
+#              elif GLM_HAS_ALIGNED_TYPE
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic push
+#                              pragma GCC diagnostic ignored "-Wpedantic"
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic push
+#                              pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#                              pragma clang diagnostic ignored "-Wnested-anon-types"
+#                      endif
+               
+                       union
+                       {
+                               struct{ T x, y; };
+                               struct{ T r, g; };
+                               struct{ T s, t; };
+
+#                              if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                                       _GLM_SWIZZLE2_2_MEMBERS(T, P, glm::tvec2, x, y)
+                                       _GLM_SWIZZLE2_2_MEMBERS(T, P, glm::tvec2, r, g)
+                                       _GLM_SWIZZLE2_2_MEMBERS(T, P, glm::tvec2, s, t)
+                                       _GLM_SWIZZLE2_3_MEMBERS(T, P, glm::tvec3, x, y)
+                                       _GLM_SWIZZLE2_3_MEMBERS(T, P, glm::tvec3, r, g)
+                                       _GLM_SWIZZLE2_3_MEMBERS(T, P, glm::tvec3, s, t)
+                                       _GLM_SWIZZLE2_4_MEMBERS(T, P, glm::tvec4, x, y)
+                                       _GLM_SWIZZLE2_4_MEMBERS(T, P, glm::tvec4, r, g)
+                                       _GLM_SWIZZLE2_4_MEMBERS(T, P, glm::tvec4, s, t)
+#                              endif//GLM_SWIZZLE
+
+                       };
+               
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic pop
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic pop
+#                      endif
+#              else
+                       union {T x, r, s;};
+                       union {T y, g, t;};
+
+#                      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                               GLM_SWIZZLE_GEN_VEC_FROM_VEC2(T, P, tvec2, tvec2, tvec3, tvec4)
+#                      endif//GLM_SWIZZLE
+#              endif
+
+               // -- Component accesses --
+
+               /// Return the count of components of the vector
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 2;}
+
+               GLM_FUNC_DECL T & operator[](length_type i);
+               GLM_FUNC_DECL T const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2(tvec2<T, P> const& v) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2(tvec2<T, Q> const& v);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec2(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec2(T scalar);
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2(T s1, T s2);
+
+               // -- Conversion constructors --
+
+               /// Explicit converions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2(A x, B y);
+               template <typename A, typename B>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec2(tvec1<A, P> const & v1, tvec1<B, P> const & v2);
+
+               // -- Conversion vector constructors --
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec2(tvec3<U, Q> const & v);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec2(tvec4<U, Q> const & v);
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec2(tvec2<U, Q> const & v);
+
+               // -- Swizzle constructors --
+#              if GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec2(detail::_swizzle<2, T, P, glm::tvec2, E0, E1,-1,-2> const& that)
+                       {
+                               *this = that();
+                       }
+#              endif// GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tvec2<T, P>& operator=(tvec2<T, P> const & v) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator=(tvec2<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator+=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator+=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator+=(tvec2<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator-=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator-=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator-=(tvec2<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator*=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator*=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator*=(tvec2<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator/=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator/=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec2<T, P>& operator/=(tvec2<U, P> const & v);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tvec2<T, P> & operator++();
+               GLM_FUNC_DECL tvec2<T, P> & operator--();
+               GLM_FUNC_DECL tvec2<T, P> operator++(int);
+               GLM_FUNC_DECL tvec2<T, P> operator--(int);
+
+               // -- Unary bit operators --
+
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator%=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator%=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator%=(tvec2<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator&=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator&=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator&=(tvec2<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator|=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator|=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator|=(tvec2<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator^=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator^=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator^=(tvec2<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator<<=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator<<=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator<<=(tvec2<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator>>=(U scalar);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator>>=(tvec1<U, P> const & v);
+               template <typename U> 
+               GLM_FUNC_DECL tvec2<T, P> & operator>>=(tvec2<U, P> const & v);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(tvec2<T, P> const & v);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator+(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator-(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator*(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator*(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator*(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator*(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator*(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator/(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator/(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator/(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator/(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator/(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator%(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator%(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator%(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator%(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator%(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator&(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator&(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator&(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator&(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator&(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator|(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator|(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator|(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator|(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator|(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator^(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator^(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator^(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator^(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator^(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator<<(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator<<(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator<<(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator<<(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator<<(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator>>(tvec2<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator>>(tvec2<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator>>(T scalar, tvec2<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator>>(tvec1<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator>>(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> operator~(tvec2<T, P> const & v);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tvec2<T, P> const & v1, tvec2<T, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec2<bool, P> operator&&(tvec2<bool, P> const & v1, tvec2<bool, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec2<bool, P> operator||(tvec2<bool, P> const & v1, tvec2<bool, P> const & v2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_vec2.inl"
+#endif//GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_vec2.inl b/core/deps/glm/glm/detail/type_vec2.inl
new file mode 100755 (executable)
index 0000000..cf79da2
--- /dev/null
@@ -0,0 +1,894 @@
+/// @ref core
+/// @file glm/core/type_tvec2.inl
+
+namespace glm
+{
+#      ifdef GLM_STATIC_CONST_MEMBERS
+       template <typename T, precision P>
+       const tvec2<T, P> tvec2<T, P>::ZERO(static_cast<T>(0), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec2<T, P> tvec2<T, P>::X(static_cast<T>(1), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec2<T, P> tvec2<T, P>::Y(static_cast<T>(0), static_cast<T>(1));
+
+       template <typename T, precision P>
+       const tvec2<T, P> tvec2<T, P>::XY(static_cast<T>(1), static_cast<T>(1));
+#      endif
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                               : x(0), y(0)
+#                      endif
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec2<T, P> const & v)
+                       : x(v.x), y(v.y)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec2<T, Q> const & v)
+               : x(v.x), y(v.y)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(T scalar)
+               : x(scalar), y(scalar)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(T s1, T s2)
+               : x(s1), y(s2)
+       {}
+
+       // -- Conversion scalar constructors --
+
+       template <typename T, precision P>
+       template <typename A, typename B>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(A a, B b)
+               : x(static_cast<T>(a))
+               , y(static_cast<T>(b))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec1<A, P> const & a, tvec1<B, P> const & b)
+               : x(static_cast<T>(a.x))
+               , y(static_cast<T>(b.x))
+       {}
+
+       // -- Conversion vector constructors --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec2<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+               , y(static_cast<T>(v.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec3<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+               , y(static_cast<T>(v.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec2<T, P>::tvec2(tvec4<U, Q> const & v)
+               : x(static_cast<T>(v.x))
+               , y(static_cast<T>(v.y))
+       {}
+
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T & tvec2<T, P>::operator[](typename tvec2<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T const & tvec2<T, P>::operator[](typename tvec2<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator=(tvec2<T, P> const & v)
+               {
+                       this->x = v.x;
+                       this->y = v.y;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator=(tvec2<U, P> const & v)
+       {
+               this->x = static_cast<T>(v.x);
+               this->y = static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator+=(U scalar)
+       {
+               this->x += static_cast<T>(scalar);
+               this->y += static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator+=(tvec1<U, P> const & v)
+       {
+               this->x += static_cast<T>(v.x);
+               this->y += static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator+=(tvec2<U, P> const & v)
+       {
+               this->x += static_cast<T>(v.x);
+               this->y += static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator-=(U scalar)
+       {
+               this->x -= static_cast<T>(scalar);
+               this->y -= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator-=(tvec1<U, P> const & v)
+       {
+               this->x -= static_cast<T>(v.x);
+               this->y -= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator-=(tvec2<U, P> const & v)
+       {
+               this->x -= static_cast<T>(v.x);
+               this->y -= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator*=(U scalar)
+       {
+               this->x *= static_cast<T>(scalar);
+               this->y *= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator*=(tvec1<U, P> const & v)
+       {
+               this->x *= static_cast<T>(v.x);
+               this->y *= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator*=(tvec2<U, P> const & v)
+       {
+               this->x *= static_cast<T>(v.x);
+               this->y *= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator/=(U scalar)
+       {
+               this->x /= static_cast<T>(scalar);
+               this->y /= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator/=(tvec1<U, P> const & v)
+       {
+               this->x /= static_cast<T>(v.x);
+               this->y /= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator/=(tvec2<U, P> const & v)
+       {
+               this->x /= static_cast<T>(v.x);
+               this->y /= static_cast<T>(v.y);
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator++()
+       {
+               ++this->x;
+               ++this->y;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator--()
+       {
+               --this->x;
+               --this->y;
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec2<T, P> tvec2<T, P>::operator++(int)
+       {
+               tvec2<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec2<T, P> tvec2<T, P>::operator--(int)
+       {
+               tvec2<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator%=(U scalar)
+       {
+               this->x %= static_cast<T>(scalar);
+               this->y %= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator%=(tvec1<U, P> const & v)
+       {
+               this->x %= static_cast<T>(v.x);
+               this->y %= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator%=(tvec2<U, P> const & v)
+       {
+               this->x %= static_cast<T>(v.x);
+               this->y %= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator&=(U scalar)
+       {
+               this->x &= static_cast<T>(scalar);
+               this->y &= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator&=(tvec1<U, P> const & v)
+       {
+               this->x &= static_cast<T>(v.x);
+               this->y &= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator&=(tvec2<U, P> const & v)
+       {
+               this->x &= static_cast<T>(v.x);
+               this->y &= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator|=(U scalar)
+       {
+               this->x |= static_cast<T>(scalar);
+               this->y |= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator|=(tvec1<U, P> const & v)
+       {
+               this->x |= static_cast<T>(v.x);
+               this->y |= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator|=(tvec2<U, P> const & v)
+       {
+               this->x |= static_cast<T>(v.x);
+               this->y |= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator^=(U scalar)
+       {
+               this->x ^= static_cast<T>(scalar);
+               this->y ^= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator^=(tvec1<U, P> const & v)
+       {
+               this->x ^= static_cast<T>(v.x);
+               this->y ^= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator^=(tvec2<U, P> const & v)
+       {
+               this->x ^= static_cast<T>(v.x);
+               this->y ^= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator<<=(U scalar)
+       {
+               this->x <<= static_cast<T>(scalar);
+               this->y <<= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator<<=(tvec1<U, P> const & v)
+       {
+               this->x <<= static_cast<T>(v.x);
+               this->y <<= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator<<=(tvec2<U, P> const & v)
+       {
+               this->x <<= static_cast<T>(v.x);
+               this->y <<= static_cast<T>(v.y);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator>>=(U scalar)
+       {
+               this->x >>= static_cast<T>(scalar);
+               this->y >>= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator>>=(tvec1<U, P> const & v)
+       {
+               this->x >>= static_cast<T>(v.x);
+               this->y >>= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec2<T, P> & tvec2<T, P>::operator>>=(tvec2<U, P> const & v)
+       {
+               this->x >>= static_cast<T>(v.x);
+               this->y >>= static_cast<T>(v.y);
+               return *this;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(tvec2<T, P> const & v)
+       {
+               return v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       -v.x, 
+                       -v.y);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x + scalar,
+                       v.y + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x + v2.x,
+                       v1.y + v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar + v.x,
+                       scalar + v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x + v2.x,
+                       v1.x + v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator+(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x + v2.x,
+                       v1.y + v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x - scalar,
+                       v.y - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x - v2.x,
+                       v1.y - v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar - v.x,
+                       scalar - v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x - v2.x,
+                       v1.x - v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator-(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x - v2.x,
+                       v1.y - v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator*(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x * scalar,
+                       v.y * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator*(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x * v2.x,
+                       v1.y * v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator*(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar * v.x,
+                       scalar * v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator*(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x * v2.x,
+                       v1.x * v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator*(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x * v2.x,
+                       v1.y * v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator/(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x / scalar,
+                       v.y / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator/(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x / v2.x,
+                       v1.y / v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator/(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar / v.x,
+                       scalar / v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator/(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x / v2.x,
+                       v1.x / v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator/(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x / v2.x,
+                       v1.y / v2.y);
+       }
+
+       // -- Binary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator%(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x % scalar,
+                       v.y % scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator%(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x % v2.x,
+                       v1.y % v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator%(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar % v.x,
+                       scalar % v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator%(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x % v2.x,
+                       v1.x % v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator%(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x % v2.x,
+                       v1.y % v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator&(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x & scalar,
+                       v.y & scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator&(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x & v2.x,
+                       v1.y & v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator&(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar & v.x,
+                       scalar & v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator&(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x & v2.x,
+                       v1.x & v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator&(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x & v2.x,
+                       v1.y & v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator|(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x | scalar,
+                       v.y | scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator|(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x | v2.x,
+                       v1.y | v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator|(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar | v.x,
+                       scalar | v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator|(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x | v2.x,
+                       v1.x | v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator|(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x | v2.x,
+                       v1.y | v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator^(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x ^ scalar,
+                       v.y ^ scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator^(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x ^ v2.x,
+                       v1.y ^ v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator^(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar ^ v.x,
+                       scalar ^ v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator^(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x ^ v2.x,
+                       v1.x ^ v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator^(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x ^ v2.x,
+                       v1.y ^ v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator<<(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x << scalar,
+                       v.y << scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator<<(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x << v2.x,
+                       v1.y << v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator<<(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar << v.x,
+                       scalar << v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator<<(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x << v2.x,
+                       v1.x << v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator<<(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x << v2.x,
+                       v1.y << v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator>>(tvec2<T, P> const & v, T scalar)
+       {
+               return tvec2<T, P>(
+                       v.x >> scalar,
+                       v.y >> scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator>>(tvec2<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x >> v2.x,
+                       v1.y >> v2.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator>>(T scalar, tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       scalar >> v.x,
+                       scalar >> v.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator>>(tvec1<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x >> v2.x,
+                       v1.x >> v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator>>(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return tvec2<T, P>(
+                       v1.x >> v2.x,
+                       v1.y >> v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> operator~(tvec2<T, P> const & v)
+       {
+               return tvec2<T, P>(
+                       ~v.x,
+                       ~v.y);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return (v1.x == v2.x) && (v1.y == v2.y);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tvec2<T, P> const & v1, tvec2<T, P> const & v2)
+       {
+               return (v1.x != v2.x) || (v1.y != v2.y);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec2<bool, P> operator&&(tvec2<bool, P> const & v1, tvec2<bool, P> const & v2)
+       {
+               return tvec2<bool, P>(v1.x && v2.x, v1.y && v2.y);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec2<bool, P> operator||(tvec2<bool, P> const & v1, tvec2<bool, P> const & v2)
+       {
+               return tvec2<bool, P>(v1.x || v2.x, v1.y || v2.y);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_vec3.hpp b/core/deps/glm/glm/detail/type_vec3.hpp
new file mode 100755 (executable)
index 0000000..f85f0a5
--- /dev/null
@@ -0,0 +1,409 @@
+/// @ref core
+/// @file glm/detail/type_vec3.hpp
+
+#pragma once
+
+#include "type_vec.hpp"
+#if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#      if GLM_HAS_UNRESTRICTED_UNIONS
+#              include "_swizzle.hpp"
+#      else
+#              include "_swizzle_func.hpp"
+#      endif
+#endif //GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tvec3
+       {
+               // -- Implementation detail --
+
+               typedef T value_type;
+               typedef tvec3<T, P> type;
+               typedef tvec3<bool, P> bool_type;
+
+               // -- Data --
+
+#              if GLM_HAS_ONLY_XYZW
+                       T x, y, z;
+
+#              elif GLM_HAS_ALIGNED_TYPE
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic push
+#                              pragma GCC diagnostic ignored "-Wpedantic"
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic push
+#                              pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#                              pragma clang diagnostic ignored "-Wnested-anon-types"
+#                      endif
+
+                       union
+                       {
+                               struct{ T x, y, z; };
+                               struct{ T r, g, b; };
+                               struct{ T s, t, p; };
+
+#                              if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                                       _GLM_SWIZZLE3_2_MEMBERS(T, P, glm::tvec2, x, y, z)
+                                       _GLM_SWIZZLE3_2_MEMBERS(T, P, glm::tvec2, r, g, b)
+                                       _GLM_SWIZZLE3_2_MEMBERS(T, P, glm::tvec2, s, t, p)
+                                       _GLM_SWIZZLE3_3_MEMBERS(T, P, glm::tvec3, x, y, z)
+                                       _GLM_SWIZZLE3_3_MEMBERS(T, P, glm::tvec3, r, g, b)
+                                       _GLM_SWIZZLE3_3_MEMBERS(T, P, glm::tvec3, s, t, p)
+                                       _GLM_SWIZZLE3_4_MEMBERS(T, P, glm::tvec4, x, y, z)
+                                       _GLM_SWIZZLE3_4_MEMBERS(T, P, glm::tvec4, r, g, b)
+                                       _GLM_SWIZZLE3_4_MEMBERS(T, P, glm::tvec4, s, t, p)
+#                              endif//GLM_SWIZZLE
+                       };
+               
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic pop
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic pop
+#                      endif
+#              else
+                       union { T x, r, s; };
+                       union { T y, g, t; };
+                       union { T z, b, p; };
+
+#                      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                               GLM_SWIZZLE_GEN_VEC_FROM_VEC3(T, P, tvec3, tvec2, tvec3, tvec4)
+#                      endif//GLM_SWIZZLE
+#              endif//GLM_LANG
+
+               // -- Component accesses --
+
+               /// Return the count of components of the vector
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 3;}
+
+               GLM_FUNC_DECL T & operator[](length_type i);
+               GLM_FUNC_DECL T const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec3<T, P> const & v) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec3<T, Q> const & v);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec3(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tvec3(T scalar);
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(T a, T b, T c);
+
+               // -- Conversion scalar constructors --
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(A a, B b, C c);
+               template <typename A, typename B, typename C>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec1<A, P> const & a, tvec1<B, P> const & b, tvec1<C, P> const & c);
+
+               // -- Conversion vector constructors --
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec2<A, Q> const & a, B b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec2<A, Q> const & a, tvec1<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(A a, tvec2<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec3(tvec1<A, Q> const & a, tvec2<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec3(tvec4<U, Q> const & v);
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec3(tvec3<U, Q> const & v);
+
+               // -- Swizzle constructors --
+#              if GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+                       template <int E0, int E1, int E2>
+                       GLM_FUNC_DECL tvec3(detail::_swizzle<3, T, P, glm::tvec3, E0, E1, E2, -1> const & that)
+                       {
+                               *this = that();
+                       }
+
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec3(detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v, T const & scalar)
+                       {
+                               *this = tvec3<T, P>(v(), scalar);
+                       }
+
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec3(T const & scalar, detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v)
+                       {
+                               *this = tvec3<T, P>(scalar, v());
+                       }
+#              endif// GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tvec3<T, P> & operator=(tvec3<T, P> const & v) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator+=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator+=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator+=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator-=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator-=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator-=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator*=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator*=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator*=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator/=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator/=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator/=(tvec3<U, P> const & v);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tvec3<T, P> & operator++();
+               GLM_FUNC_DECL tvec3<T, P> & operator--();
+               GLM_FUNC_DECL tvec3<T, P> operator++(int);
+               GLM_FUNC_DECL tvec3<T, P> operator--(int);
+
+               // -- Unary bit operators --
+
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator%=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator%=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator%=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator&=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator&=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator&=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator|=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator|=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator|=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator^=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator^=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator^=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator<<=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator<<=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator<<=(tvec3<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator>>=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator>>=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec3<T, P> & operator>>=(tvec3<U, P> const & v);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(tvec3<T, P> const & v);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(tvec3<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator+(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator-(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator/(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator/(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator/(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator/(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator/(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator%(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator%(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator%(T const & scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator%(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator%(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator&(tvec3<T, P> const & v1, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator&(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator&(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator&(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator&(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator|(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator|(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator|(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator|(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator|(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator^(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator^(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator^(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator^(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator^(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator<<(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator<<(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator<<(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator<<(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator<<(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator>>(tvec3<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator>>(tvec3<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator>>(T scalar, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator>>(tvec1<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator>>(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tvec3<T, P> operator~(tvec3<T, P> const & v);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tvec3<T, P> const & v1, tvec3<T, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec3<bool, P> operator&&(tvec3<bool, P> const & v1, tvec3<bool, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec3<bool, P> operator||(tvec3<bool, P> const & v1, tvec3<bool, P> const & v2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_vec3.inl"
+#endif//GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_vec3.inl b/core/deps/glm/glm/detail/type_vec3.inl
new file mode 100755 (executable)
index 0000000..d84299d
--- /dev/null
@@ -0,0 +1,1022 @@
+/// @ref core
+/// @file glm/detail/type_tvec3.inl
+
+namespace glm
+{
+
+#      ifdef GLM_STATIC_CONST_MEMBERS
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::ZERO(static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::X(static_cast<T>(1), static_cast<T>(0), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::Y(static_cast<T>(0), static_cast<T>(1), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::Z(static_cast<T>(0), static_cast<T>(0), static_cast<T>(1));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::XY(static_cast<T>(1), static_cast<T>(1), static_cast<T>(0));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::XZ(static_cast<T>(1), static_cast<T>(0), static_cast<T>(1));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::YZ(static_cast<T>(0), static_cast<T>(1), static_cast<T>(1));
+
+       template <typename T, precision P>
+       const tvec3<T, P> tvec3<T, P>::XYZ(static_cast<T>(1), static_cast<T>(1), static_cast<T>(1));
+#      endif
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               : x(0), y(0), z(0)
+#                      endif
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec3<T, P> const & v)
+                       : x(v.x), y(v.y), z(v.z)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec3<T, Q> const & v)
+               : x(v.x), y(v.y), z(v.z)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(T scalar)
+               : x(scalar), y(scalar), z(scalar)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(T a, T b, T c)
+               : x(a), y(b), z(c)
+       {}
+
+       // -- Conversion scalar constructors --
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(A a, B b, C c) :
+               x(static_cast<T>(a)),
+               y(static_cast<T>(b)),
+               z(static_cast<T>(c))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec1<A, P> const & a, tvec1<B, P> const & b, tvec1<C, P> const & c) :
+               x(static_cast<T>(a)),
+               y(static_cast<T>(b)),
+               z(static_cast<T>(c))
+       {}
+
+       // -- Conversion vector constructors --
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec2<A, Q> const & a, B b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(b))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec2<A, Q> const & a, tvec1<B, Q> const & b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(b.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(A a, tvec2<B, Q> const & b) :
+               x(static_cast<T>(a)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(b.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec1<A, Q> const & a, tvec2<B, Q> const & b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(b.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec3<U, Q> const & v) :
+               x(static_cast<T>(v.x)),
+               y(static_cast<T>(v.y)),
+               z(static_cast<T>(v.z))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec3<T, P>::tvec3(tvec4<U, Q> const & v) :
+               x(static_cast<T>(v.x)),
+               y(static_cast<T>(v.y)),
+               z(static_cast<T>(v.z))
+       {}
+
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T & tvec3<T, P>::operator[](typename tvec3<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T const & tvec3<T, P>::operator[](typename tvec3<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tvec3<T, P>& tvec3<T, P>::operator=(tvec3<T, P> const & v)
+               {
+                       this->x = v.x;
+                       this->y = v.y;
+                       this->z = v.z;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P>& tvec3<T, P>::operator=(tvec3<U, P> const & v)
+       {
+               this->x = static_cast<T>(v.x);
+               this->y = static_cast<T>(v.y);
+               this->z = static_cast<T>(v.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator+=(U scalar)
+       {
+               this->x += static_cast<T>(scalar);
+               this->y += static_cast<T>(scalar);
+               this->z += static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator+=(tvec1<U, P> const & v)
+       {
+               this->x += static_cast<T>(v.x);
+               this->y += static_cast<T>(v.x);
+               this->z += static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator+=(tvec3<U, P> const & v)
+       {
+               this->x += static_cast<T>(v.x);
+               this->y += static_cast<T>(v.y);
+               this->z += static_cast<T>(v.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator-=(U scalar)
+       {
+               this->x -= static_cast<T>(scalar);
+               this->y -= static_cast<T>(scalar);
+               this->z -= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator-=(tvec1<U, P> const & v)
+       {
+               this->x -= static_cast<T>(v.x);
+               this->y -= static_cast<T>(v.x);
+               this->z -= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator-=(tvec3<U, P> const & v)
+       {
+               this->x -= static_cast<T>(v.x);
+               this->y -= static_cast<T>(v.y);
+               this->z -= static_cast<T>(v.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator*=(U scalar)
+       {
+               this->x *= static_cast<T>(scalar);
+               this->y *= static_cast<T>(scalar);
+               this->z *= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator*=(tvec1<U, P> const & v)
+       {
+               this->x *= static_cast<T>(v.x);
+               this->y *= static_cast<T>(v.x);
+               this->z *= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator*=(tvec3<U, P> const & v)
+       {
+               this->x *= static_cast<T>(v.x);
+               this->y *= static_cast<T>(v.y);
+               this->z *= static_cast<T>(v.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator/=(U v)
+       {
+               this->x /= static_cast<T>(v);
+               this->y /= static_cast<T>(v);
+               this->z /= static_cast<T>(v);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator/=(tvec1<U, P> const & v)
+       {
+               this->x /= static_cast<T>(v.x);
+               this->y /= static_cast<T>(v.x);
+               this->z /= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator/=(tvec3<U, P> const & v)
+       {
+               this->x /= static_cast<T>(v.x);
+               this->y /= static_cast<T>(v.y);
+               this->z /= static_cast<T>(v.z);
+               return *this;
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator++()
+       {
+               ++this->x;
+               ++this->y;
+               ++this->z;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator--()
+       {
+               --this->x;
+               --this->y;
+               --this->z;
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> tvec3<T, P>::operator++(int)
+       {
+               tvec3<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> tvec3<T, P>::operator--(int)
+       {
+               tvec3<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator%=(U scalar)
+       {
+               this->x %= scalar;
+               this->y %= scalar;
+               this->z %= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator%=(tvec1<U, P> const & v)
+       {
+               this->x %= v.x;
+               this->y %= v.x;
+               this->z %= v.x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator%=(tvec3<U, P> const & v)
+       {
+               this->x %= v.x;
+               this->y %= v.y;
+               this->z %= v.z;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator&=(U scalar)
+       {
+               this->x &= scalar;
+               this->y &= scalar;
+               this->z &= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator&=(tvec1<U, P> const & v)
+       {
+               this->x &= v.x;
+               this->y &= v.x;
+               this->z &= v.x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator&=(tvec3<U, P> const & v)
+       {
+               this->x &= v.x;
+               this->y &= v.y;
+               this->z &= v.z;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator|=(U scalar)
+       {
+               this->x |= scalar;
+               this->y |= scalar;
+               this->z |= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator|=(tvec1<U, P> const & v)
+       {
+               this->x |= v.x;
+               this->y |= v.x;
+               this->z |= v.x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator|=(tvec3<U, P> const & v)
+       {
+               this->x |= v.x;
+               this->y |= v.y;
+               this->z |= v.z;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator^=(U scalar)
+       {
+               this->x ^= scalar;
+               this->y ^= scalar;
+               this->z ^= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator^=(tvec1<U, P> const & v)
+       {
+               this->x ^= v.x;
+               this->y ^= v.x;
+               this->z ^= v.x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator^=(tvec3<U, P> const & v)
+       {
+               this->x ^= v.x;
+               this->y ^= v.y;
+               this->z ^= v.z;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator<<=(U scalar)
+       {
+               this->x <<= scalar;
+               this->y <<= scalar;
+               this->z <<= scalar;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator<<=(tvec1<U, P> const & v)
+       {
+               this->x <<= static_cast<T>(v.x);
+               this->y <<= static_cast<T>(v.x);
+               this->z <<= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator<<=(tvec3<U, P> const & v)
+       {
+               this->x <<= static_cast<T>(v.x);
+               this->y <<= static_cast<T>(v.y);
+               this->z <<= static_cast<T>(v.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator>>=(U scalar)
+       {
+               this->x >>= static_cast<T>(scalar);
+               this->y >>= static_cast<T>(scalar);
+               this->z >>= static_cast<T>(scalar);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator>>=(tvec1<U, P> const & v)
+       {
+               this->x >>= static_cast<T>(v.x);
+               this->y >>= static_cast<T>(v.x);
+               this->z >>= static_cast<T>(v.x);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> & tvec3<T, P>::operator>>=(tvec3<U, P> const & v)
+       {
+               this->x >>= static_cast<T>(v.x);
+               this->y >>= static_cast<T>(v.y);
+               this->z >>= static_cast<T>(v.z);
+               return *this;
+       }
+
+       // -- Unary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(tvec3<T, P> const & v)
+       {
+               return v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       -v.x, 
+                       -v.y, 
+                       -v.z);
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x + scalar,
+                       v.y + scalar,
+                       v.z + scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x + scalar.x,
+                       v.y + scalar.x,
+                       v.z + scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar + v.x,
+                       scalar + v.y,
+                       scalar + v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x + v.x,
+                       scalar.x + v.y,
+                       scalar.x + v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator+(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x + v2.x,
+                       v1.y + v2.y,
+                       v1.z + v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x - scalar,
+                       v.y - scalar,
+                       v.z - scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x - scalar.x,
+                       v.y - scalar.x,
+                       v.z - scalar.x);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar - v.x,
+                       scalar - v.y,
+                       scalar - v.z);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x - v.x,
+                       scalar.x - v.y,
+                       scalar.x - v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator-(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x - v2.x,
+                       v1.y - v2.y,
+                       v1.z - v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x * scalar,
+                       v.y * scalar,
+                       v.z * scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x * scalar.x,
+                       v.y * scalar.x,
+                       v.z * scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar * v.x,
+                       scalar * v.y,
+                       scalar * v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x * v.x,
+                       scalar.x * v.y,
+                       scalar.x * v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x * v2.x,
+                       v1.y * v2.y,
+                       v1.z * v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator/(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x / scalar,
+                       v.y / scalar,
+                       v.z / scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator/(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x / scalar.x,
+                       v.y / scalar.x,
+                       v.z / scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator/(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar / v.x,
+                       scalar / v.y,
+                       scalar / v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator/(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x / v.x,
+                       scalar.x / v.y,
+                       scalar.x / v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator/(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x / v2.x,
+                       v1.y / v2.y,
+                       v1.z / v2.z);
+       }
+
+       // -- Binary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator%(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x % scalar,
+                       v.y % scalar,
+                       v.z % scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator%(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x % scalar.x,
+                       v.y % scalar.x,
+                       v.z % scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator%(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar % v.x,
+                       scalar % v.y,
+                       scalar % v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator%(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x % v.x,
+                       scalar.x % v.y,
+                       scalar.x % v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator%(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x % v2.x,
+                       v1.y % v2.y,
+                       v1.z % v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator&(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x & scalar,
+                       v.y & scalar,
+                       v.z & scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator&(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x & scalar.x,
+                       v.y & scalar.x,
+                       v.z & scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator&(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar & v.x,
+                       scalar & v.y,
+                       scalar & v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator&(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x & v.x,
+                       scalar.x & v.y,
+                       scalar.x & v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator&(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x & v2.x,
+                       v1.y & v2.y,
+                       v1.z & v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator|(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x | scalar,
+                       v.y | scalar,
+                       v.z | scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator|(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x | scalar.x,
+                       v.y | scalar.x,
+                       v.z | scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator|(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar | v.x,
+                       scalar | v.y,
+                       scalar | v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator|(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x | v.x,
+                       scalar.x | v.y,
+                       scalar.x | v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator|(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x | v2.x,
+                       v1.y | v2.y,
+                       v1.z | v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator^(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x ^ scalar,
+                       v.y ^ scalar,
+                       v.z ^ scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator^(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x ^ scalar.x,
+                       v.y ^ scalar.x,
+                       v.z ^ scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator^(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar ^ v.x,
+                       scalar ^ v.y,
+                       scalar ^ v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator^(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x ^ v.x,
+                       scalar.x ^ v.y,
+                       scalar.x ^ v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator^(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x ^ v2.x,
+                       v1.y ^ v2.y,
+                       v1.z ^ v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator<<(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x << scalar,
+                       v.y << scalar,
+                       v.z << scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator<<(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x << scalar.x,
+                       v.y << scalar.x,
+                       v.z << scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator<<(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar << v.x,
+                       scalar << v.y,
+                       scalar << v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator<<(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x << v.x,
+                       scalar.x << v.y,
+                       scalar.x << v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator<<(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x << v2.x,
+                       v1.y << v2.y,
+                       v1.z << v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator>>(tvec3<T, P> const & v, T scalar)
+       {
+               return tvec3<T, P>(
+                       v.x >> scalar,
+                       v.y >> scalar,
+                       v.z >> scalar);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator>>(tvec3<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec3<T, P>(
+                       v.x >> scalar.x,
+                       v.y >> scalar.x,
+                       v.z >> scalar.x);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator>>(T scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar >> v.x,
+                       scalar >> v.y,
+                       scalar >> v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator>>(tvec1<T, P> const & scalar, tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       scalar.x >> v.x,
+                       scalar.x >> v.y,
+                       scalar.x >> v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator>>(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return tvec3<T, P>(
+                       v1.x >> v2.x,
+                       v1.y >> v2.y,
+                       v1.z >> v2.z);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator~(tvec3<T, P> const & v)
+       {
+               return tvec3<T, P>(
+                       ~v.x,
+                       ~v.y,
+                       ~v.z);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tvec3<T, P> const & v1, tvec3<T, P> const & v2)
+       {
+               return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec3<bool, P> operator&&(tvec3<bool, P> const & v1, tvec3<bool, P> const & v2)
+       {
+               return tvec3<bool, P>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec3<bool, P> operator||(tvec3<bool, P> const & v1, tvec3<bool, P> const & v2)
+       {
+               return tvec3<bool, P>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/detail/type_vec4.hpp b/core/deps/glm/glm/detail/type_vec4.hpp
new file mode 100755 (executable)
index 0000000..5e89b74
--- /dev/null
@@ -0,0 +1,454 @@
+/// @ref core
+/// @file glm/detail/type_vec4.hpp
+
+#pragma once
+
+#include "type_vec.hpp"
+#if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+#      if GLM_HAS_UNRESTRICTED_UNIONS
+#              include "_swizzle.hpp"
+#      else
+#              include "_swizzle_func.hpp"
+#      endif
+#endif //GLM_SWIZZLE
+#include <cstddef>
+
+namespace glm
+{
+       template <typename T, precision P = defaultp>
+       struct tvec4
+       {
+               // -- Implementation detail --
+
+               typedef T value_type;
+               typedef tvec4<T, P> type;
+               typedef tvec4<bool, P> bool_type;
+
+               // -- Data --
+
+#              if GLM_HAS_ONLY_XYZW
+                       T x, y, z, w;
+
+#              elif GLM_HAS_ALIGNED_TYPE
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic push
+#                              pragma GCC diagnostic ignored "-Wpedantic"
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic push
+#                              pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#                              pragma clang diagnostic ignored "-Wnested-anon-types"
+#                      endif
+
+                       union
+                       {
+                               struct { T x, y, z, w;};
+                               struct { T r, g, b, a; };
+                               struct { T s, t, p, q; };
+
+                               typename detail::storage<T, sizeof(T) * 4, detail::is_aligned<P>::value>::type data;
+
+#                              if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                                       _GLM_SWIZZLE4_2_MEMBERS(T, P, glm::tvec2, x, y, z, w)
+                                       _GLM_SWIZZLE4_2_MEMBERS(T, P, glm::tvec2, r, g, b, a)
+                                       _GLM_SWIZZLE4_2_MEMBERS(T, P, glm::tvec2, s, t, p, q)
+                                       _GLM_SWIZZLE4_3_MEMBERS(T, P, glm::tvec3, x, y, z, w)
+                                       _GLM_SWIZZLE4_3_MEMBERS(T, P, glm::tvec3, r, g, b, a)
+                                       _GLM_SWIZZLE4_3_MEMBERS(T, P, glm::tvec3, s, t, p, q)
+                                       _GLM_SWIZZLE4_4_MEMBERS(T, P, glm::tvec4, x, y, z, w)
+                                       _GLM_SWIZZLE4_4_MEMBERS(T, P, glm::tvec4, r, g, b, a)
+                                       _GLM_SWIZZLE4_4_MEMBERS(T, P, glm::tvec4, s, t, p, q)
+#                              endif//GLM_SWIZZLE
+                       };
+
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic pop
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic pop
+#                      endif
+#              else
+                       union { T x, r, s; };
+                       union { T y, g, t; };
+                       union { T z, b, p; };
+                       union { T w, a, q; };
+
+#                      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+                               GLM_SWIZZLE_GEN_VEC_FROM_VEC4(T, P, tvec4, tvec2, tvec3, tvec4)
+#                      endif//GLM_SWIZZLE
+#              endif
+
+               // -- Component accesses --
+
+               /// Return the count of components of the vector
+               typedef length_t length_type;
+               GLM_FUNC_DECL static length_type length(){return 4;}
+
+               GLM_FUNC_DECL T & operator[](length_type i);
+               GLM_FUNC_DECL T const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD tvec4() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD tvec4(tvec4<T, P> const& v) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD tvec4(tvec4<T, Q> const& v);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD explicit tvec4(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD explicit tvec4(T scalar);
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD tvec4(T a, T b, T c, T d);
+
+               // -- Conversion scalar constructors --
+
+               /// Explicit converions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, typename D>
+               GLM_FUNC_DECL GLM_CONSTEXPR_SIMD tvec4(A a, B b, C c, D d);
+               template <typename A, typename B, typename C, typename D>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec1<A, P> const& a, tvec1<B, P> const& b, tvec1<C, P> const& c, tvec1<D, P> const& d);
+
+               // -- Conversion vector constructors --
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec2<A, Q> const & a, B b, C c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec2<A, Q> const & a, tvec1<B, Q> const & b, tvec1<C, Q> const & c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(A a, tvec2<B, Q> const & b, C c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec1<A, Q> const & a, tvec2<B, Q> const & b, tvec1<C, Q> const & c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(A a, B b, tvec2<C, Q> const & c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, typename C, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec1<A, Q> const & a, tvec1<B, Q> const & b, tvec2<C, Q> const & c);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec3<A, Q> const & a, B b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec3<A, Q> const & a, tvec1<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(A a, tvec3<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec1<A, Q> const & a, tvec3<B, Q> const & b);
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename A, typename B, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR tvec4(tvec2<A, Q> const & a, tvec2<B, Q> const & b);
+
+               /// Explicit conversions (From section 5.4.1 Conversion and scalar constructors of GLSL 1.30.08 specification)
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR GLM_EXPLICIT tvec4(tvec4<U, Q> const& v);
+
+               // -- Swizzle constructors --
+#              if GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+                       template <int E0, int E1, int E2, int E3>
+                       GLM_FUNC_DECL tvec4(detail::_swizzle<4, T, P, glm::tvec4, E0, E1, E2, E3> const & that)
+                       {
+                               *this = that();
+                       }
+
+                       template <int E0, int E1, int F0, int F1>
+                       GLM_FUNC_DECL tvec4(detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v, detail::_swizzle<2, T, P, glm::tvec2, F0, F1, -1, -2> const & u)
+                       {
+                               *this = tvec4<T, P>(v(), u());
+                       }
+
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec4(T const & x, T const & y, detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v)
+                       {
+                               *this = tvec4<T, P>(x, y, v());
+                       }
+
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec4(T const & x, detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v, T const & w)
+                       {
+                               *this = tvec4<T, P>(x, v(), w);
+                       }
+
+                       template <int E0, int E1>
+                       GLM_FUNC_DECL tvec4(detail::_swizzle<2, T, P, glm::tvec2, E0, E1, -1, -2> const & v, T const & z, T const & w)
+                       {
+                               *this = tvec4<T, P>(v(), z, w);
+                       }
+
+                       template <int E0, int E1, int E2>
+                       GLM_FUNC_DECL tvec4(detail::_swizzle<3, T, P, glm::tvec3, E0, E1, E2, -1> const & v, T const & w)
+                       {
+                               *this = tvec4<T, P>(v(), w);
+                       }
+
+                       template <int E0, int E1, int E2>
+                       GLM_FUNC_DECL tvec4(T const & x, detail::_swizzle<3, T, P, glm::tvec3, E0, E1, E2, -1> const & v)
+                       {
+                               *this = tvec4<T, P>(x, v());
+                       }
+#              endif// GLM_HAS_UNRESTRICTED_UNIONS && (GLM_SWIZZLE == GLM_SWIZZLE_ENABLED)
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tvec4<T, P> & operator=(tvec4<T, P> const & v) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator+=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator+=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator+=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator-=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator-=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator-=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator*=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator*=(tvec1<U, P> const& v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator*=(tvec4<U, P> const& v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator/=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator/=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator/=(tvec4<U, P> const & v);
+
+               // -- Increment and decrement operators --
+
+               GLM_FUNC_DECL tvec4<T, P> & operator++();
+               GLM_FUNC_DECL tvec4<T, P> & operator--();
+               GLM_FUNC_DECL tvec4<T, P> operator++(int);
+               GLM_FUNC_DECL tvec4<T, P> operator--(int);
+
+               // -- Unary bit operators --
+
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator%=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator%=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator%=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator&=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator&=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator&=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator|=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator|=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator|=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator^=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator^=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator^=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator<<=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator<<=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator<<=(tvec4<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator>>=(U scalar);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator>>=(tvec1<U, P> const & v);
+               template <typename U>
+               GLM_FUNC_DECL tvec4<T, P> & operator>>=(tvec4<U, P> const & v);
+       };
+
+       // -- Unary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(tvec4<T, P> const & v);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(tvec4<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(tvec1<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator+(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(tvec4<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(tvec1<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator-(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec4<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec1<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator/(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator/(tvec4<T, P> const & v1, tvec1<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator/(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator/(tvec1<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator/(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator%(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator%(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator%(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator%(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator%(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator&(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator&(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator&(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator&(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator&(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator|(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator|(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator|(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator|(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator|(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator^(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator^(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator^(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator^(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator^(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator<<(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator<<(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator<<(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator<<(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator<<(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator>>(tvec4<T, P> const & v, T scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator>>(tvec4<T, P> const & v, tvec1<T, P> const & scalar);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator>>(T scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator>>(tvec1<T, P> const & scalar, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator>>(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tvec4<T, P> operator~(tvec4<T, P> const & v);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tvec4<T, P> const & v1, tvec4<T, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec4<bool, P> operator&&(tvec4<bool, P> const & v1, tvec4<bool, P> const & v2);
+
+       template <precision P>
+       GLM_FUNC_DECL tvec4<bool, P> operator||(tvec4<bool, P> const & v1, tvec4<bool, P> const & v2);
+}//namespace glm
+
+#ifndef GLM_EXTERNAL_TEMPLATE
+#include "type_vec4.inl"
+#endif//GLM_EXTERNAL_TEMPLATE
diff --git a/core/deps/glm/glm/detail/type_vec4.inl b/core/deps/glm/glm/detail/type_vec4.inl
new file mode 100755 (executable)
index 0000000..b10a662
--- /dev/null
@@ -0,0 +1,969 @@
+/// @ref core
+/// @file glm/detail/type_tvec4.inl
+
+namespace glm{
+namespace detail
+{
+       template <typename T>
+       struct is_int
+       {
+               enum test {value = 0};
+       };
+
+       template <>
+       struct is_int<uint32>
+       {
+               enum test {value = ~0};
+       };
+
+       template <>
+       struct is_int<int32>
+       {
+               enum test {value = ~0};
+       };
+
+       template <>
+       struct is_int<uint64>
+       {
+               enum test {value = ~0};
+       };
+
+       template <>
+       struct is_int<int64>
+       {
+               enum test {value = ~0};
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_vec4_add
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_vec4_sub
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_vec4_mul
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x * b.x, a.y * b.y, a.z * b.z, a.w * b.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_vec4_div
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x / b.x, a.y / b.y, a.z / b.z, a.w / b.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_vec4_mod
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x % b.x, a.y % b.y, a.z % b.z, a.w % b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_and
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x & b.x, a.y & b.y, a.z & b.z, a.w & b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_or
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x | b.x, a.y | b.y, a.z | b.z, a.w | b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_xor
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x ^ b.x, a.y ^ b.y, a.z ^ b.z, a.w ^ b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_shift_left
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x << b.x, a.y << b.y, a.z << b.z, a.w << b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_shift_right
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & a, tvec4<T, P> const & b)
+               {
+                       return tvec4<T, P>(a.x >> b.x, a.y >> b.y, a.z >> b.z, a.w >> b.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_equal
+       {
+               GLM_FUNC_QUALIFIER static bool call(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+               {
+                       return (v1.x == v2.x) && (v1.y == v2.y) && (v1.z == v2.z) && (v1.w == v2.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_nequal
+       {
+               GLM_FUNC_QUALIFIER static bool call(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+               {
+                       return (v1.x != v2.x) || (v1.y != v2.y) || (v1.z != v2.z) || (v1.w != v2.w);
+               }
+       };
+
+       template <typename T, precision P, int IsInt, std::size_t Size, bool Aligned>
+       struct compute_vec4_bitwise_not
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const & v)
+               {
+                       return tvec4<T, P>(~v.x, ~v.y, ~v.z, ~v.w);
+               }
+       };
+}//namespace detail
+
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                               : x(0), y(0), z(0), w(0)
+#                      endif
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(tvec4<T, P> const & v)
+                       : x(v.x), y(v.y), z(v.z), w(v.w)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(tvec4<T, Q> const & v)
+               : x(v.x), y(v.y), z(v.z), w(v.w)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(T scalar)
+               : x(scalar), y(scalar), z(scalar), w(scalar)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(T a, T b, T c, T d)
+               : x(a), y(b), z(c), w(d)
+       {}
+
+       // -- Conversion scalar constructors --
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, typename D>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<T, P>::tvec4(A a, B b, C c, D d) :
+               x(static_cast<T>(a)),
+               y(static_cast<T>(b)),
+               z(static_cast<T>(c)),
+               w(static_cast<T>(d))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, typename D>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec1<A, P> const & a, tvec1<B, P> const & b, tvec1<C, P> const & c, tvec1<D, P> const & d) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(c.x)),
+               w(static_cast<T>(d.x))
+       {}
+
+       // -- Conversion vector constructors --
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec2<A, Q> const & a, B b, C c) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(b)),
+               w(static_cast<T>(c))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec2<A, Q> const & a, tvec1<B, Q> const & b, tvec1<C, Q> const & c) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(b.x)),
+               w(static_cast<T>(c.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(A s1, tvec2<B, Q> const & v, C s2) :
+               x(static_cast<T>(s1)),
+               y(static_cast<T>(v.x)),
+               z(static_cast<T>(v.y)),
+               w(static_cast<T>(s2))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec1<A, Q> const & a, tvec2<B, Q> const & b, tvec1<C, Q> const & c) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(b.y)),
+               w(static_cast<T>(c.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(A s1, B s2, tvec2<C, Q> const & v) :
+               x(static_cast<T>(s1)),
+               y(static_cast<T>(s2)),
+               z(static_cast<T>(v.x)),
+               w(static_cast<T>(v.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, typename C, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec1<A, Q> const & a, tvec1<B, Q> const & b, tvec2<C, Q> const & c) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(c.x)),
+               w(static_cast<T>(c.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec3<A, Q> const & a, B b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(a.z)),
+               w(static_cast<T>(b))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec3<A, Q> const & a, tvec1<B, Q> const & b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(a.z)),
+               w(static_cast<T>(b.x))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(A a, tvec3<B, Q> const & b) :
+               x(static_cast<T>(a)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(b.y)),
+               w(static_cast<T>(b.z))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec1<A, Q> const & a, tvec3<B, Q> const & b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(b.x)),
+               z(static_cast<T>(b.y)),
+               w(static_cast<T>(b.z))
+       {}
+
+       template <typename T, precision P>
+       template <typename A, typename B, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec2<A, Q> const & a, tvec2<B, Q> const & b) :
+               x(static_cast<T>(a.x)),
+               y(static_cast<T>(a.y)),
+               z(static_cast<T>(b.x)),
+               w(static_cast<T>(b.y))
+       {}
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tvec4<T, P>::tvec4(tvec4<U, Q> const & v) :
+               x(static_cast<T>(v.x)),
+               y(static_cast<T>(v.y)),
+               z(static_cast<T>(v.z)),
+               w(static_cast<T>(v.w))
+       {}
+
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T & tvec4<T, P>::operator[](typename tvec4<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T const & tvec4<T, P>::operator[](typename tvec4<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tvec4<T, P>& tvec4<T, P>::operator=(tvec4<T, P> const & v)
+               {
+                       this->x = v.x;
+                       this->y = v.y;
+                       this->z = v.z;
+                       this->w = v.w;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P>& tvec4<T, P>::operator=(tvec4<U, P> const & v)
+       {
+               this->x = static_cast<T>(v.x);
+               this->y = static_cast<T>(v.y);
+               this->z = static_cast<T>(v.z);
+               this->w = static_cast<T>(v.w);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator+=(U scalar)
+       {
+               return (*this = detail::compute_vec4_add<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator+=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_add<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v.x)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator+=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_add<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator-=(U scalar)
+       {
+               return (*this = detail::compute_vec4_sub<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator-=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_sub<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v.x)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator-=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_sub<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator*=(U scalar)
+       {
+               return (*this = detail::compute_vec4_mul<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator*=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_mul<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v.x)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator*=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_mul<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator/=(U scalar)
+       {
+               return (*this = detail::compute_vec4_div<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator/=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_div<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v.x)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator/=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_div<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       // -- Increment and decrement operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator++()
+       {
+               ++this->x;
+               ++this->y;
+               ++this->z;
+               ++this->w;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator--()
+       {
+               --this->x;
+               --this->y;
+               --this->z;
+               --this->w;
+               return *this;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> tvec4<T, P>::operator++(int)
+       {
+               tvec4<T, P> Result(*this);
+               ++*this;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> tvec4<T, P>::operator--(int)
+       {
+               tvec4<T, P> Result(*this);
+               --*this;
+               return Result;
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator%=(U scalar)
+       {
+               return (*this = detail::compute_vec4_mod<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator%=(tvec1<U, P> const& v)
+       {
+               return (*this = detail::compute_vec4_mod<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator%=(tvec4<U, P> const& v)
+       {
+               return (*this = detail::compute_vec4_mod<T, P, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator&=(U scalar)
+       {
+               return (*this = detail::compute_vec4_and<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator&=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_and<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator&=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_and<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator|=(U scalar)
+       {
+               return (*this = detail::compute_vec4_or<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator|=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_or<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator|=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_or<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator^=(U scalar)
+       {
+               return (*this = detail::compute_vec4_xor<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator^=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_xor<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator^=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_xor<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator<<=(U scalar)
+       {
+               return (*this = detail::compute_vec4_shift_left<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator<<=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_shift_left<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator<<=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_shift_left<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator>>=(U scalar)
+       {
+               return (*this = detail::compute_vec4_shift_right<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(scalar)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator>>=(tvec1<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_shift_right<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       template <typename T, precision P>
+       template <typename U> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> & tvec4<T, P>::operator>>=(tvec4<U, P> const & v)
+       {
+               return (*this = detail::compute_vec4_shift_right<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(*this, tvec4<T, P>(v)));
+       }
+
+       // -- Unary constant operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(tvec4<T, P> const & v)
+       {
+               return v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(0) -= v;
+       }
+
+       // -- Binary arithmetic operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) += scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) += v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(v) += scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v2) += v1;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator+(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) += v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) -= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) -= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) -= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) -= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator-(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) -= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) *= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) *= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(v) *= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v2) *= v1;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) *= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator/(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) /= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator/(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) /= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator/(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) /= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator/(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) /= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator/(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) /= v2;
+       }
+
+       // -- Binary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator%(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) %= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator%(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) %= v2.x;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator%(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) %= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator%(tvec1<T, P> const & scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar.x) %= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator%(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) %= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator&(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) &= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator&(tvec4<T, P> const & v, tvec1<T, P> const & scalar)
+       {
+               return tvec4<T, P>(v) &= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator&(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) &= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator&(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) &= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator&(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) &= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator|(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) |= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator|(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) |= v2.x;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator|(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) |= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator|(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) |= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator|(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) |= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator^(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) ^= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator^(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) ^= v2.x;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator^(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) ^= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator^(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) ^= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator^(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) ^= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator<<(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) <<= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator<<(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) <<= v2.x;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator<<(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) <<= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator<<(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) <<= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator<<(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) <<= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator>>(tvec4<T, P> const & v, T scalar)
+       {
+               return tvec4<T, P>(v) >>= scalar;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator>>(tvec4<T, P> const & v1, tvec1<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) >>= v2.x;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator>>(T scalar, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(scalar) >>= v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator>>(tvec1<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1.x) >>= v2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator>>(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return tvec4<T, P>(v1) >>= v2;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator~(tvec4<T, P> const & v)
+       {
+               return detail::compute_vec4_bitwise_not<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(v);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return detail::compute_vec4_equal<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(v1, v2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tvec4<T, P> const & v1, tvec4<T, P> const & v2)
+       {
+               return detail::compute_vec4_nequal<T, P, detail::is_int<T>::value, sizeof(T) * 8, detail::is_aligned<P>::value>::call(v1, v2);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> operator&&(tvec4<bool, P> const & v1, tvec4<bool, P> const & v2)
+       {
+               return tvec4<bool, P>(v1.x && v2.x, v1.y && v2.y, v1.z && v2.z, v1.w && v2.w);
+       }
+
+       template <precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> operator||(tvec4<bool, P> const & v1, tvec4<bool, P> const & v2)
+       {
+               return tvec4<bool, P>(v1.x || v2.x, v1.y || v2.y, v1.z || v2.z, v1.w || v2.w);
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_ALIGNED_TYPE
+#      include "type_vec4_simd.inl"
+#endif
diff --git a/core/deps/glm/glm/detail/type_vec4_simd.inl b/core/deps/glm/glm/detail/type_vec4_simd.inl
new file mode 100755 (executable)
index 0000000..90652fd
--- /dev/null
@@ -0,0 +1,481 @@
+/// @ref core
+/// @file glm/detail/type_tvec4_simd.inl
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+namespace glm{
+namespace detail
+{
+#      if GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+       template <precision P, int E0, int E1, int E2, int E3>
+       struct _swizzle_base1<4, float, P, glm::tvec4, E0,E1,E2,E3, true> : public _swizzle_base0<float, 4>
+       { 
+               GLM_FUNC_QUALIFIER tvec4<float, P> operator ()()  const
+               {
+                       __m128 data = *reinterpret_cast<__m128 const*>(&this->_buffer);
+
+                       tvec4<float, P> Result(uninitialize);
+#                      if GLM_ARCH & GLM_ARCH_AVX_BIT
+                               Result.data = _mm_permute_ps(data, _MM_SHUFFLE(E3, E2, E1, E0));
+#                      else
+                               Result.data = _mm_shuffle_ps(data, data, _MM_SHUFFLE(E3, E2, E1, E0));
+#                      endif
+                       return Result;
+               }
+       };
+
+       template <precision P, int E0, int E1, int E2, int E3>
+       struct _swizzle_base1<4, int32, P, glm::tvec4, E0,E1,E2,E3, true> : public _swizzle_base0<int32, 4>
+       { 
+               GLM_FUNC_QUALIFIER tvec4<int32, P> operator ()()  const
+               {
+                       __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer);
+
+                       tvec4<int32, P> Result(uninitialize);
+                       Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0));
+                       return Result;
+               }
+       };
+
+       template <precision P, int E0, int E1, int E2, int E3>
+       struct _swizzle_base1<4, uint32, P, glm::tvec4, E0,E1,E2,E3, true> : public _swizzle_base0<uint32, 4>
+       { 
+               GLM_FUNC_QUALIFIER tvec4<uint32, P> operator ()()  const
+               {
+                       __m128i data = *reinterpret_cast<__m128i const*>(&this->_buffer);
+
+                       tvec4<uint32, P> Result(uninitialize);
+                       Result.data = _mm_shuffle_epi32(data, _MM_SHUFFLE(E3, E2, E1, E0));
+                       return Result;
+               }
+       };
+#      endif// GLM_SWIZZLE == GLM_SWIZZLE_ENABLED
+
+       template <precision P>
+       struct compute_vec4_add<float, P, true>
+       {
+               static tvec4<float, P> call(tvec4<float, P> const & a, tvec4<float, P> const & b)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_add_ps(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_vec4_add<double, P, true>
+       {
+               static tvec4<double, P> call(tvec4<double, P> const & a, tvec4<double, P> const & b)
+               {
+                       tvec4<double, P> Result(uninitialize);
+                       Result.data = _mm256_add_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_vec4_sub<float, P, true>
+       {
+               static tvec4<float, P> call(tvec4<float, P> const & a, tvec4<float, P> const & b)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_sub_ps(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_vec4_sub<double, P, true>
+       {
+               static tvec4<double, P> call(tvec4<double, P> const & a, tvec4<double, P> const & b)
+               {
+                       tvec4<double, P> Result(uninitialize);
+                       Result.data = _mm256_sub_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_vec4_mul<float, P, true>
+       {
+               static tvec4<float, P> call(tvec4<float, P> const & a, tvec4<float, P> const & b)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_mul_ps(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_vec4_mul<double, P, true>
+       {
+               static tvec4<double, P> call(tvec4<double, P> const & a, tvec4<double, P> const & b)
+               {
+                       tvec4<double, P> Result(uninitialize);
+                       Result.data = _mm256_mul_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_vec4_div<float, P, true>
+       {
+               static tvec4<float, P> call(tvec4<float, P> const & a, tvec4<float, P> const & b)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_div_ps(a.data, b.data);
+                       return Result;
+               }
+       };
+
+       #       if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_vec4_div<double, P, true>
+       {
+               static tvec4<double, P> call(tvec4<double, P> const & a, tvec4<double, P> const & b)
+               {
+                       tvec4<double, P> Result(uninitialize);
+                       Result.data = _mm256_div_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <>
+       struct compute_vec4_div<float, aligned_lowp, true>
+       {
+               static tvec4<float, aligned_lowp> call(tvec4<float, aligned_lowp> const & a, tvec4<float, aligned_lowp> const & b)
+               {
+                       tvec4<float, aligned_lowp> Result(uninitialize);
+                       Result.data = _mm_mul_ps(a.data, _mm_rcp_ps(b.data));
+                       return Result;
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_vec4_and<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_and_si128(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_and<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_and_si256(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <typename T, precision P>
+       struct compute_vec4_or<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_or_si128(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_or<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_or_si256(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <typename T, precision P>
+       struct compute_vec4_xor<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_xor_si128(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_xor<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_xor_si256(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <typename T, precision P>
+       struct compute_vec4_shift_left<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_sll_epi32(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_shift_left<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_sll_epi64(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <typename T, precision P>
+       struct compute_vec4_shift_right<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_srl_epi32(a.data, b.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_shift_right<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const& a, tvec4<T, P> const& b)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_srl_epi64(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <typename T, precision P>
+       struct compute_vec4_bitwise_not<T, P, true, 32, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const & v)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm_xor_si128(v.data, _mm_set1_epi32(-1));
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <typename T, precision P>
+       struct compute_vec4_bitwise_not<T, P, true, 64, true>
+       {
+               static tvec4<T, P> call(tvec4<T, P> const & v)
+               {
+                       tvec4<T, P> Result(uninitialize);
+                       Result.data = _mm256_xor_si256(v.data, _mm_set1_epi32(-1));
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_vec4_equal<float, P, false, 32, true>
+       {
+               static bool call(tvec4<float, P> const & v1, tvec4<float, P> const & v2)
+               {
+                       return _mm_movemask_ps(_mm_cmpeq_ps(v1.data, v2.data)) != 0;
+               }
+       };
+
+       template <precision P>
+       struct compute_vec4_equal<int32, P, true, 32, true>
+       {
+               static bool call(tvec4<int32, P> const & v1, tvec4<int32, P> const & v2)
+               {
+                       return _mm_movemask_epi8(_mm_cmpeq_epi32(v1.data, v2.data)) != 0;
+               }
+       };
+
+       template <precision P>
+       struct compute_vec4_nequal<float, P, false, 32, true>
+       {
+               static bool call(tvec4<float, P> const & v1, tvec4<float, P> const & v2)
+               {
+                       return _mm_movemask_ps(_mm_cmpneq_ps(v1.data, v2.data)) != 0;
+               }
+       };
+
+       template <precision P>
+       struct compute_vec4_nequal<int32, P, true, 32, true>
+       {
+               static bool call(tvec4<int32, P> const & v1, tvec4<int32, P> const & v2)
+               {
+                       return _mm_movemask_epi8(_mm_cmpneq_epi32(v1.data, v2.data)) != 0;
+               }
+       };
+}//namespace detail
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_lowp>::tvec4()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                               : data(_mm_setzero_ps())
+#                      endif
+               {}
+
+               template <>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_mediump>::tvec4()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                       : data(_mm_setzero_ps())
+#                      endif
+               {}
+
+               template <>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_highp>::tvec4()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                       : data(_mm_setzero_ps())
+#                      endif
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_lowp>::tvec4(float s) :
+               data(_mm_set1_ps(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_mediump>::tvec4(float s) :
+               data(_mm_set1_ps(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_highp>::tvec4(float s) :
+               data(_mm_set1_ps(s))
+       {}
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<double, aligned_lowp>::tvec4(double s) :
+               data(_mm256_set1_pd(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<double, aligned_mediump>::tvec4(double s) :
+               data(_mm256_set1_pd(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<double, aligned_highp>::tvec4(double s) :
+               data(_mm256_set1_pd(s))
+       {}
+#      endif
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_lowp>::tvec4(int32 s) :
+               data(_mm_set1_epi32(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_mediump>::tvec4(int32 s) :
+               data(_mm_set1_epi32(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_highp>::tvec4(int32 s) :
+               data(_mm_set1_epi32(s))
+       {}
+
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int64, aligned_lowp>::tvec4(int64 s) :
+               data(_mm256_set1_epi64x(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int64, aligned_mediump>::tvec4(int64 s) :
+               data(_mm256_set1_epi64x(s))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int64, aligned_highp>::tvec4(int64 s) :
+               data(_mm256_set1_epi64x(s))
+       {}
+#      endif
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_lowp>::tvec4(float a, float b, float c, float d) :
+               data(_mm_set_ps(d, c, b, a))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_mediump>::tvec4(float a, float b, float c, float d) :
+               data(_mm_set_ps(d, c, b, a))
+       {}
+
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_highp>::tvec4(float a, float b, float c, float d) :
+               data(_mm_set_ps(d, c, b, a))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_lowp>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_set_epi32(d, c, b, a))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_mediump>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_set_epi32(d, c, b, a))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<int32, aligned_highp>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_set_epi32(d, c, b, a))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_lowp>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_castsi128_ps(_mm_set_epi32(d, c, b, a)))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_mediump>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_castsi128_ps(_mm_set_epi32(d, c, b, a)))
+       {}
+
+       template <>
+       template <>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_SIMD tvec4<float, aligned_highp>::tvec4(int32 a, int32 b, int32 c, int32 d) :
+               data(_mm_castsi128_ps(_mm_set_epi32(d, c, b, a)))
+       {}
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/exponential.hpp b/core/deps/glm/glm/exponential.hpp
new file mode 100755 (executable)
index 0000000..f3a7842
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/exponential.hpp
+
+#pragma once
+
+#include "detail/func_exponential.hpp"
diff --git a/core/deps/glm/glm/ext.hpp b/core/deps/glm/glm/ext.hpp
new file mode 100755 (executable)
index 0000000..0c9f9f9
--- /dev/null
@@ -0,0 +1,116 @@
+/// @file glm/ext.hpp
+///
+/// @ref core (Dependence)
+/// 
+/// @defgroup gtc GTC Extensions (Stable)
+///
+/// @brief Functions and types that the GLSL specification doesn't define, but useful to have for a C++ program.
+/// 
+/// GTC extensions aim to be stable. 
+/// 
+/// Even if it's highly unrecommended, it's possible to include all the extensions at once by
+/// including <glm/ext.hpp>. Otherwise, each extension needs to be included  a specific file.
+/// 
+/// @defgroup gtx GTX Extensions (Experimental)
+/// 
+/// @brief Functions and types that the GLSL specification doesn't define, but 
+/// useful to have for a C++ program.
+/// 
+/// Experimental extensions are useful functions and types, but the development of
+/// their API and functionality is not necessarily stable. They can change 
+/// substantially between versions. Backwards compatibility is not much of an issue
+/// for them.
+/// 
+/// Even if it's highly unrecommended, it's possible to include all the extensions 
+/// at once by including <glm/ext.hpp>. Otherwise, each extension needs to be 
+/// included  a specific file.
+
+#pragma once
+
+#include "glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_EXT_INCLUDED_DISPLAYED)
+#      define GLM_MESSAGE_EXT_INCLUDED_DISPLAYED
+#      pragma message("GLM: All extensions included (not recommanded)")
+#endif//GLM_MESSAGES
+
+#include "./gtc/bitfield.hpp"
+#include "./gtc/color_space.hpp"
+#include "./gtc/constants.hpp"
+#include "./gtc/epsilon.hpp"
+#include "./gtc/functions.hpp"
+#include "./gtc/integer.hpp"
+#include "./gtc/matrix_access.hpp"
+#include "./gtc/matrix_integer.hpp"
+#include "./gtc/matrix_inverse.hpp"
+#include "./gtc/matrix_transform.hpp"
+#include "./gtc/noise.hpp"
+#include "./gtc/packing.hpp"
+#include "./gtc/quaternion.hpp"
+#include "./gtc/random.hpp"
+#include "./gtc/reciprocal.hpp"
+#include "./gtc/round.hpp"
+//#include "./gtc/type_aligned.hpp"
+#include "./gtc/type_precision.hpp"
+#include "./gtc/type_ptr.hpp"
+#include "./gtc/ulp.hpp"
+#include "./gtc/vec1.hpp"
+#if GLM_HAS_ALIGNED_TYPE
+#      include "./gtc/type_aligned.hpp"
+#endif
+
+#include "./gtx/associated_min_max.hpp"
+#include "./gtx/bit.hpp"
+#include "./gtx/closest_point.hpp"
+#include "./gtx/color_space.hpp"
+#include "./gtx/color_space_YCoCg.hpp"
+#include "./gtx/compatibility.hpp"
+#include "./gtx/component_wise.hpp"
+#include "./gtx/dual_quaternion.hpp"
+#include "./gtx/euler_angles.hpp"
+#include "./gtx/extend.hpp"
+#include "./gtx/extended_min_max.hpp"
+#include "./gtx/fast_exponential.hpp"
+#include "./gtx/fast_square_root.hpp"
+#include "./gtx/fast_trigonometry.hpp"
+#include "./gtx/gradient_paint.hpp"
+#include "./gtx/handed_coordinate_space.hpp"
+#include "./gtx/integer.hpp"
+#include "./gtx/intersect.hpp"
+#include "./gtx/log_base.hpp"
+#include "./gtx/matrix_cross_product.hpp"
+#include "./gtx/matrix_interpolation.hpp"
+#include "./gtx/matrix_major_storage.hpp"
+#include "./gtx/matrix_operation.hpp"
+#include "./gtx/matrix_query.hpp"
+#include "./gtx/mixed_product.hpp"
+#include "./gtx/norm.hpp"
+#include "./gtx/normal.hpp"
+#include "./gtx/normalize_dot.hpp"
+#include "./gtx/number_precision.hpp"
+#include "./gtx/optimum_pow.hpp"
+#include "./gtx/orthonormalize.hpp"
+#include "./gtx/perpendicular.hpp"
+#include "./gtx/polar_coordinates.hpp"
+#include "./gtx/projection.hpp"
+#include "./gtx/quaternion.hpp"
+#include "./gtx/raw_data.hpp"
+#include "./gtx/rotate_vector.hpp"
+#include "./gtx/spline.hpp"
+#include "./gtx/std_based_type.hpp"
+#if !(GLM_COMPILER & GLM_COMPILER_CUDA)
+#      include "./gtx/string_cast.hpp"
+#endif
+#include "./gtx/transform.hpp"
+#include "./gtx/transform2.hpp"
+#include "./gtx/vector_angle.hpp"
+#include "./gtx/vector_query.hpp"
+#include "./gtx/wrap.hpp"
+
+#if GLM_HAS_TEMPLATE_ALIASES
+#      include "./gtx/scalar_multiplication.hpp"
+#endif
+
+#if GLM_HAS_RANGE_FOR
+#      include "./gtx/range.hpp"
+#endif
diff --git a/core/deps/glm/glm/fwd.hpp b/core/deps/glm/glm/fwd.hpp
new file mode 100755 (executable)
index 0000000..f90c4d0
--- /dev/null
@@ -0,0 +1,2570 @@
+/// @ref core
+/// @file glm/fwd.hpp
+
+#pragma once
+
+#include "detail/type_int.hpp"
+#include "detail/type_float.hpp"
+#include "detail/type_vec.hpp"
+#include "detail/type_mat.hpp"
+
+//////////////////////
+// GLM_GTC_quaternion
+namespace glm
+{
+       template <typename T, precision P> struct tquat;
+
+       /// Quaternion of low single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<float, lowp>              lowp_quat;
+
+       /// Quaternion of medium single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<float, mediump>   mediump_quat;
+
+       /// Quaternion of high single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<float, highp>             highp_quat;
+
+#if(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef highp_quat                      quat;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef mediump_quat            quat;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_quat                       quat;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       /// Quaternion of default single-precision floating-point numbers.
+       typedef highp_quat                      quat;
+#endif
+
+       /// Quaternion of low single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef lowp_quat                       lowp_fquat;
+
+       /// Quaternion of medium single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef mediump_quat            mediump_fquat;
+
+       /// Quaternion of high single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef highp_quat                      highp_fquat;
+
+       /// Quaternion of default single-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef quat                            fquat;
+
+
+       /// Quaternion of low double-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<double, lowp>             lowp_dquat;
+       
+       /// Quaternion of medium double-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<double, mediump>  mediump_dquat;
+       
+       /// Quaternion of high double-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef tquat<double, highp>    highp_dquat;
+       
+#if(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef highp_dquat                     dquat;
+#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef mediump_dquat           dquat;
+#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_dquat                      dquat;
+#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       /// Quaternion of default double-precision floating-point numbers.
+       ///
+       /// @see gtc_quaternion
+       typedef highp_dquat                     dquat;
+#endif
+
+}//namespace glm
+
+//////////////////////
+// GLM_GTC_precision
+namespace glm
+{
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_int8;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_int16;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_int32;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_int64;
+
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_int8_t;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_int16_t;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_int32_t;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_int64_t;
+
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_i8;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_i16;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_i32;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_i64;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_int8;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_int16;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_int32;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_int64;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_int8_t;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_int16_t;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_int32_t;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_int64_t;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_i8;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_i16;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_i32;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_i64;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_int8;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_int16;
+
+       /// High precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_int32;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_int64;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_int8_t;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_int16_t;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_int32_t;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_int64_t;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_i8;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_i16;
+
+       /// High precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_i32;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_i64;
+       
+
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 int8;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 int16;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 int32;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 int64;
+
+
+#if GLM_HAS_EXTENDED_INTEGER_TYPE
+       using std::int8_t;
+       using std::int16_t;
+       using std::int32_t;
+       using std::int64_t;
+#else
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 int8_t;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 int16_t;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 int32_t;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 int64_t;
+#endif
+
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 i8;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 i16;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 i32;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 i64;
+       
+       
+       
+       /// Low precision 8 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i8, lowp> lowp_i8vec1;
+       
+       /// Low precision 8 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i8, lowp> lowp_i8vec2;
+       
+       /// Low precision 8 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i8, lowp> lowp_i8vec3;
+       
+       /// Low precision 8 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i8, lowp> lowp_i8vec4;
+       
+
+       /// Medium precision 8 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i8, mediump> mediump_i8vec1;
+       
+       /// Medium precision 8 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i8, mediump> mediump_i8vec2;
+       
+       /// Medium precision 8 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i8, mediump> mediump_i8vec3;
+       
+       /// Medium precision 8 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i8, mediump> mediump_i8vec4;
+       
+       
+       /// High precision 8 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i8, highp> highp_i8vec1;
+       
+       /// High precision 8 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i8, highp> highp_i8vec2;
+       
+       /// High precision 8 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i8, highp> highp_i8vec3;
+       
+       /// High precision 8 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i8, highp> highp_i8vec4;
+       
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_i8vec1                             i8vec1;
+       typedef lowp_i8vec2                             i8vec2;
+       typedef lowp_i8vec3                             i8vec3;
+       typedef lowp_i8vec4                             i8vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_i8vec1                  i8vec1;
+       typedef mediump_i8vec2                  i8vec2;
+       typedef mediump_i8vec3                  i8vec3;
+       typedef mediump_i8vec4                  i8vec4; 
+#else
+       /// Default precision 8 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_i8vec1                    i8vec1;
+       
+       /// Default precision 8 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_i8vec2                    i8vec2;
+       
+       /// Default precision 8 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_i8vec3                    i8vec3;
+       
+       /// Default precision 8 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_i8vec4                    i8vec4;
+#endif
+       
+       
+       /// Low precision 16 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i16, lowp>                lowp_i16vec1;
+       
+       /// Low precision 16 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i16, lowp>                lowp_i16vec2;
+       
+       /// Low precision 16 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i16, lowp>                lowp_i16vec3;
+       
+       /// Low precision 16 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i16, lowp>                lowp_i16vec4;
+       
+       
+       /// Medium precision 16 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i16, mediump>             mediump_i16vec1;
+       
+       /// Medium precision 16 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i16, mediump>             mediump_i16vec2;
+       
+       /// Medium precision 16 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i16, mediump>             mediump_i16vec3;
+       
+       /// Medium precision 16 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i16, mediump>             mediump_i16vec4;
+       
+       
+       /// High precision 16 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i16, highp>               highp_i16vec1;
+       
+       /// High precision 16 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i16, highp>               highp_i16vec2;
+       
+       /// High precision 16 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i16, highp>               highp_i16vec3;
+       
+       /// High precision 16 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i16, highp>               highp_i16vec4;
+       
+       
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_i16vec1                    i16vec1;
+       typedef lowp_i16vec2                    i16vec2;
+       typedef lowp_i16vec3                    i16vec3;
+       typedef lowp_i16vec4                    i16vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_i16vec1                 i16vec1;
+       typedef mediump_i16vec2                 i16vec2;
+       typedef mediump_i16vec3                 i16vec3;
+       typedef mediump_i16vec4                 i16vec4;
+#else
+       /// Default precision 16 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_i16vec1                   i16vec1;
+       
+       /// Default precision 16 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_i16vec2                   i16vec2;
+       
+       /// Default precision 16 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_i16vec3                   i16vec3;
+       
+       /// Default precision 16 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_i16vec4                   i16vec4;
+#endif
+
+
+       /// Low precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, lowp>                lowp_i32vec1;
+       
+       /// Low precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, lowp>                lowp_i32vec2;
+       
+       /// Low precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, lowp>                lowp_i32vec3;
+       
+       /// Low precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, lowp>                lowp_i32vec4;
+       
+       
+       /// Medium precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, mediump>             mediump_i32vec1;
+       
+       /// Medium precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, mediump>             mediump_i32vec2;
+       
+       /// Medium precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, mediump>             mediump_i32vec3;
+       
+       /// Medium precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, mediump>             mediump_i32vec4;
+       
+       
+       /// High precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, highp>               highp_i32vec1;
+       
+       /// High precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, highp>               highp_i32vec2;
+       
+       /// High precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, highp>               highp_i32vec3;
+       
+       /// High precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, highp>               highp_i32vec4;
+       
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_i32vec1                    i32vec1;
+       typedef lowp_i32vec2                    i32vec2;
+       typedef lowp_i32vec3                    i32vec3;
+       typedef lowp_i32vec4                    i32vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_i32vec1                 i32vec1;
+       typedef mediump_i32vec2                 i32vec2;
+       typedef mediump_i32vec3                 i32vec3;
+       typedef mediump_i32vec4                 i32vec4;
+#else
+       /// Default precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec1                   i32vec1;
+       
+       /// Default precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec2                   i32vec2;
+       
+       /// Default precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec3                   i32vec3;
+       
+       /// Default precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec4                   i32vec4;
+#endif
+
+
+       /// Low precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, lowp>                lowp_i32vec1;
+       
+       /// Low precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, lowp>                lowp_i32vec2;
+       
+       /// Low precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, lowp>                lowp_i32vec3;
+       
+       /// Low precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, lowp>                lowp_i32vec4;
+       
+       
+       /// Medium precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, mediump>             mediump_i32vec1;
+       
+       /// Medium precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, mediump>             mediump_i32vec2;
+       
+       /// Medium precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, mediump>             mediump_i32vec3;
+       
+       /// Medium precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, mediump>             mediump_i32vec4;
+       
+       
+       /// High precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, highp>               highp_i32vec1;
+       
+       /// High precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, highp>               highp_i32vec2;
+       
+       /// High precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, highp>               highp_i32vec3;
+       
+       /// High precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, highp>               highp_i32vec4;
+       
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_i32vec1                    i32vec1;
+       typedef lowp_i32vec2                    i32vec2;
+       typedef lowp_i32vec3                    i32vec3;
+       typedef lowp_i32vec4                    i32vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_i32vec1                 i32vec1;
+       typedef mediump_i32vec2                 i32vec2;
+       typedef mediump_i32vec3                 i32vec3;
+       typedef mediump_i32vec4                 i32vec4;
+#else
+       /// Default precision 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec1                   i32vec1;
+
+       /// Default precision 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec2                   i32vec2;
+       
+       /// Default precision 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec3                   i32vec3;
+       
+       /// Default precision 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_i32vec4                   i32vec4;
+#endif
+
+
+       
+       /// Low precision 64 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i64, lowp>                lowp_i64vec1;
+       
+       /// Low precision 64 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i64, lowp>                lowp_i64vec2;
+       
+       /// Low precision 64 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i64, lowp>                lowp_i64vec3;
+       
+       /// Low precision 64 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i64, lowp>                lowp_i64vec4;
+       
+       
+       /// Medium precision 64 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i64, mediump>             mediump_i64vec1;
+       
+       /// Medium precision 64 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i64, mediump>             mediump_i64vec2;
+       
+       /// Medium precision 64 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i64, mediump>             mediump_i64vec3;
+       
+       /// Medium precision 64 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i64, mediump>             mediump_i64vec4;
+       
+       
+       /// High precision 64 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i64, highp>               highp_i64vec1;
+       
+       /// High precision 64 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i64, highp>               highp_i64vec2;
+       
+       /// High precision 64 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i64, highp>               highp_i64vec3;
+       
+       /// High precision 64 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i64, highp>               highp_i64vec4;
+       
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_i64vec1                    i64vec1;
+       typedef lowp_i64vec2                    i64vec2;
+       typedef lowp_i64vec3                    i64vec3;
+       typedef lowp_i64vec4                    i64vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_i64vec1                 i64vec1;
+       typedef mediump_i64vec2                 i64vec2;
+       typedef mediump_i64vec3                 i64vec3;
+       typedef mediump_i64vec4                 i64vec4;
+#else
+       /// Default precision 64 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_i64vec1                   i64vec1;
+
+       /// Default precision 64 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_i64vec2                   i64vec2;
+       
+       /// Default precision 64 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_i64vec3                   i64vec3;
+       
+       /// Default precision 64 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_i64vec4                   i64vec4;
+#endif
+       
+       
+       /////////////////////////////
+       // Unsigned int vector types
+       
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_uint8;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_uint16;
+       
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_uint32;
+       
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_uint64;
+       
+       
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_uint8_t;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_uint16_t;
+       
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_uint32_t;
+       
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_uint64_t;
+       
+       
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_u8;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_u16;
+       
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_u32;
+       
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_u64;
+       
+       
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_uint8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_uint16;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_uint32;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_uint64;
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_uint8_t;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_uint16_t;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_uint32_t;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_uint64_t;
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_u8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_u16;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_u32;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_u64;
+               
+       
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_uint8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_uint16;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_uint32;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_uint64;
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_uint8_t;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_uint16_t;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_uint32_t;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_uint64_t;
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_u8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_u16;
+       
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_u32;
+       
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_u64;
+       
+       
+       
+       /// 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 uint8;
+       
+       /// 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 uint16;
+       
+       /// 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 uint32;
+       
+       /// 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 uint64;
+       
+#if GLM_HAS_EXTENDED_INTEGER_TYPE
+       using std::uint8_t;
+       using std::uint16_t;
+       using std::uint32_t;
+       using std::uint64_t;
+#else
+       /// 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 uint8_t;
+       
+       /// 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 uint16_t;
+       
+       /// 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 uint32_t;
+       
+       /// 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 uint64_t;
+#endif
+
+       /// 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 u8;
+
+       /// 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 u16;
+
+       /// 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 u32;
+
+       /// 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 u64;
+
+
+
+       /// Low precision 8 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u8, lowp> lowp_u8vec1;
+       
+       /// Low precision 8 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u8, lowp> lowp_u8vec2;
+       
+       /// Low precision 8 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u8, lowp> lowp_u8vec3;
+       
+       /// Low precision 8 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u8, lowp> lowp_u8vec4;
+       
+
+       /// Medium precision 8 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u8, mediump> mediump_u8vec1;
+
+       /// Medium precision 8 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u8, mediump> mediump_u8vec2;
+
+       /// Medium precision 8 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u8, mediump> mediump_u8vec3;
+
+       /// Medium precision 8 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u8, mediump> mediump_u8vec4;
+
+
+       /// High precision 8 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u8, highp> highp_u8vec1;
+
+       /// High precision 8 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u8, highp> highp_u8vec2;
+
+       /// High precision 8 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u8, highp> highp_u8vec3;
+
+       /// High precision 8 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u8, highp> highp_u8vec4;
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_u8vec1                             u8vec1;
+       typedef lowp_u8vec2                             u8vec2;
+       typedef lowp_u8vec3                             u8vec3;
+       typedef lowp_u8vec4                             u8vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_u8vec1                  u8vec1;
+       typedef mediump_u8vec2                  u8vec2;
+       typedef mediump_u8vec3                  u8vec3;
+       typedef mediump_u8vec4                  u8vec4; 
+#else
+       /// Default precision 8 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_u8vec1                    u8vec1;
+
+       /// Default precision 8 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_u8vec2                    u8vec2;
+
+       /// Default precision 8 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_u8vec3                    u8vec3;
+
+       /// Default precision 8 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_u8vec4                    u8vec4;
+#endif
+
+
+       /// Low precision 16 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u16, lowp>                lowp_u16vec1;
+
+       /// Low precision 16 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u16, lowp>                lowp_u16vec2;
+
+       /// Low precision 16 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u16, lowp>                lowp_u16vec3;
+
+       /// Low precision 16 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u16, lowp>                lowp_u16vec4;
+
+
+       /// Medium precision 16 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u16, mediump>             mediump_u16vec1;
+
+       /// Medium precision 16 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u16, mediump>             mediump_u16vec2;
+
+       /// Medium precision 16 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u16, mediump>             mediump_u16vec3;
+
+       /// Medium precision 16 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u16, mediump>             mediump_u16vec4;
+
+
+       /// High precision 16 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u16, highp>               highp_u16vec1;
+
+       /// High precision 16 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u16, highp>               highp_u16vec2;
+
+       /// High precision 16 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u16, highp>               highp_u16vec3;
+
+       /// High precision 16 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u16, highp>               highp_u16vec4;
+
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_u16vec1                    u16vec1;
+       typedef lowp_u16vec2                    u16vec2;
+       typedef lowp_u16vec3                    u16vec3;
+       typedef lowp_u16vec4                    u16vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_u16vec1                 u16vec1;
+       typedef mediump_u16vec2                 u16vec2;
+       typedef mediump_u16vec3                 u16vec3;
+       typedef mediump_u16vec4                 u16vec4;
+#else
+       /// Default precision 16 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_u16vec1                   u16vec1;
+
+       /// Default precision 16 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_u16vec2                   u16vec2;
+
+       /// Default precision 16 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_u16vec3                   u16vec3;
+
+       /// Default precision 16 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_u16vec4                   u16vec4;
+#endif
+
+
+       /// Low precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, lowp>                lowp_u32vec1;
+
+       /// Low precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, lowp>                lowp_u32vec2;
+
+       /// Low precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, lowp>                lowp_u32vec3;
+
+       /// Low precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, lowp>                lowp_u32vec4;
+
+
+       /// Medium precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, mediump>             mediump_u32vec1;
+
+       /// Medium precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, mediump>             mediump_u32vec2;
+
+       /// Medium precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, mediump>             mediump_u32vec3;
+
+       /// Medium precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, mediump>             mediump_u32vec4;
+
+
+       /// High precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, highp>               highp_u32vec1;
+
+       /// High precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, highp>               highp_u32vec2;
+
+       /// High precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, highp>               highp_u32vec3;
+
+       /// High precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, highp>               highp_u32vec4;
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_u32vec1                    u32vec1;
+       typedef lowp_u32vec2                    u32vec2;
+       typedef lowp_u32vec3                    u32vec3;
+       typedef lowp_u32vec4                    u32vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_u32vec1                 u32vec1;
+       typedef mediump_u32vec2                 u32vec2;
+       typedef mediump_u32vec3                 u32vec3;
+       typedef mediump_u32vec4                 u32vec4;
+#else
+       /// Default precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec1                   u32vec1;
+
+       /// Default precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec2                   u32vec2;
+
+       /// Default precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec3                   u32vec3;
+
+       /// Default precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec4                   u32vec4;
+#endif
+
+
+       /// Low precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, lowp>                lowp_u32vec1;
+
+       /// Low precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, lowp>                lowp_u32vec2;
+
+       /// Low precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, lowp>                lowp_u32vec3;
+
+       /// Low precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, lowp>                lowp_u32vec4;
+
+
+       /// Medium precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, mediump>             mediump_u32vec1;
+
+       /// Medium precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, mediump>             mediump_u32vec2;
+
+       /// Medium precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, mediump>             mediump_u32vec3;
+
+       /// Medium precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, mediump>             mediump_u32vec4;
+
+
+       /// High precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, highp>               highp_u32vec1;
+
+       /// High precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, highp>               highp_u32vec2;
+
+       /// High precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, highp>               highp_u32vec3;
+
+       /// High precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, highp>               highp_u32vec4;
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_u32vec1                    u32vec1;
+       typedef lowp_u32vec2                    u32vec2;
+       typedef lowp_u32vec3                    u32vec3;
+       typedef lowp_u32vec4                    u32vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_u32vec1                 u32vec1;
+       typedef mediump_u32vec2                 u32vec2;
+       typedef mediump_u32vec3                 u32vec3;
+       typedef mediump_u32vec4                 u32vec4;
+#else
+       /// Default precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec1                   u32vec1;
+
+       /// Default precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec2                   u32vec2;
+       
+       /// Default precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec3                   u32vec3;
+       
+       /// Default precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_u32vec4                   u32vec4;
+#endif
+
+
+       
+       /// Low precision 64 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u64, lowp>                lowp_u64vec1;
+
+       /// Low precision 64 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u64, lowp>                lowp_u64vec2;
+
+       /// Low precision 64 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u64, lowp>                lowp_u64vec3;
+
+       /// Low precision 64 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u64, lowp>                lowp_u64vec4;
+
+
+       /// Medium precision 64 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u64, mediump>             mediump_u64vec1;
+
+       /// Medium precision 64 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u64, mediump>             mediump_u64vec2;
+
+       /// Medium precision 64 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u64, mediump>             mediump_u64vec3;
+
+       /// Medium precision 64 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u64, mediump>             mediump_u64vec4;
+
+
+       /// High precision 64 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u64, highp>               highp_u64vec1;
+
+       /// High precision 64 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u64, highp>               highp_u64vec2;
+
+       /// High precision 64 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u64, highp>               highp_u64vec3;
+
+       /// High precision 64 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u64, highp>               highp_u64vec4;
+
+#if(defined(GLM_PRECISION_LOWP_UINT))
+       typedef lowp_u64vec1                    u64vec1;
+       typedef lowp_u64vec2                    u64vec2;
+       typedef lowp_u64vec3                    u64vec3;
+       typedef lowp_u64vec4                    u64vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_UINT))
+       typedef mediump_u64vec1                 u64vec1;
+       typedef mediump_u64vec2                 u64vec2;
+       typedef mediump_u64vec3                 u64vec3;
+       typedef mediump_u64vec4                 u64vec4;
+#else
+       /// Default precision 64 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef highp_u64vec1                   u64vec1;
+
+       /// Default precision 64 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef highp_u64vec2                   u64vec2;
+       
+       /// Default precision 64 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef highp_u64vec3                   u64vec3;
+       
+       /// Default precision 64 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef highp_u64vec4                   u64vec4;
+#endif
+       
+       
+       //////////////////////
+       // Float vector types
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32_t;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64_t;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 lowp_f32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 lowp_f64;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32_t;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64_t;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 lowp_f32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 lowp_f64;
+
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 lowp_float32_t;
+       
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 lowp_float64_t;
+
+       /// Low 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 lowp_f32;
+
+       /// Low 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 lowp_f64;
+
+
+       /// Medium 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 mediump_float32;
+
+       /// Medium 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 mediump_float64;
+
+       /// Medium 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 mediump_float32_t;
+
+       /// Medium 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 mediump_float64_t;
+
+       /// Medium 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 mediump_f32;
+
+       /// Medium 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 mediump_f64;
+
+
+       /// High 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 highp_float32;
+
+       /// High 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 highp_float64;
+
+       /// High 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 highp_float32_t;
+
+       /// High 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 highp_float64_t;
+
+       /// High 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 highp_f32;
+
+       /// High 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 highp_f64;
+
+
+#if(defined(GLM_PRECISION_LOWP_FLOAT))
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_float32 float32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_float64 float64;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_float32_t float32_t;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_float64_t float64_t;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_f32 f32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef lowp_f64 f64;
+
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float32 float32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float64 float64;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float32 float32_t;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float64 float64_t;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float32 f32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef mediump_float64 f64;
+
+#else//(defined(GLM_PRECISION_HIGHP_FLOAT))
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float32 float32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float64 float64;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float32_t float32_t;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float64_t float64_t;
+
+       /// Default 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float32_t f32;
+
+       /// Default 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef highp_float64_t f64;
+#endif
+
+
+       /// Low single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, lowp> lowp_vec1;
+
+       /// Low single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<float, lowp> lowp_vec2;
+
+       /// Low single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<float, lowp> lowp_vec3;
+
+       /// Low single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<float, lowp> lowp_vec4;
+
+       /// Low single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, lowp> lowp_fvec1;
+
+       /// Low single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<float, lowp> lowp_fvec2;
+
+       /// Low single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<float, lowp> lowp_fvec3;
+
+       /// Low single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<float, lowp> lowp_fvec4;
+
+
+       /// Medium single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, mediump> mediump_vec1;
+
+       /// Medium Single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<float, mediump> mediump_vec2;
+
+       /// Medium Single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<float, mediump> mediump_vec3;
+
+       /// Medium Single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<float, mediump> mediump_vec4;
+
+       /// Medium single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, mediump> mediump_fvec1;
+
+       /// Medium Single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<float, mediump> mediump_fvec2;
+
+       /// Medium Single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<float, mediump> mediump_fvec3;
+
+       /// Medium Single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<float, mediump> mediump_fvec4;
+
+
+       /// High single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, highp> highp_vec1;
+
+       /// High Single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<float, highp> highp_vec2;
+
+       /// High Single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<float, highp> highp_vec3;
+
+       /// High Single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<float, highp> highp_vec4;
+
+       /// High single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, highp> highp_fvec1;
+
+       /// High Single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<float, highp> highp_fvec2;
+
+       /// High Single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<float, highp> highp_fvec3;
+
+       /// High Single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<float, highp> highp_fvec4;
+
+
+       /// Low single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f32, lowp> lowp_f32vec1;
+
+       /// Low single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<f32, lowp> lowp_f32vec2;
+
+       /// Low single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<f32, lowp> lowp_f32vec3;
+
+       /// Low single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<f32, lowp> lowp_f32vec4;
+
+       /// Medium single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f32, mediump> mediump_f32vec1;
+
+       /// Medium single-precision floating-point vector of 2 components.
+       /// @see core_precision
+       typedef tvec2<f32, mediump> mediump_f32vec2;
+
+       /// Medium single-precision floating-point vector of 3 components.
+       /// @see core_precision
+       typedef tvec3<f32, mediump> mediump_f32vec3;
+
+       /// Medium single-precision floating-point vector of 4 components.
+       /// @see core_precision
+       typedef tvec4<f32, mediump> mediump_f32vec4;
+
+       /// High single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f32, highp> highp_f32vec1;
+
+       /// High single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f32, highp> highp_f32vec2;
+
+       /// High single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f32, highp> highp_f32vec3;
+
+       /// High single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f32, highp> highp_f32vec4;
+
+
+       /// Low double-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f64, lowp> lowp_f64vec1;
+
+       /// Low double-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f64, lowp> lowp_f64vec2;
+
+       /// Low double-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f64, lowp> lowp_f64vec3;
+
+       /// Low double-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f64, lowp> lowp_f64vec4;
+
+       /// Medium double-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f64, mediump> mediump_f64vec1;
+
+       /// Medium double-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f64, mediump> mediump_f64vec2;
+
+       /// Medium double-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f64, mediump> mediump_f64vec3;
+
+       /// Medium double-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f64, mediump> mediump_f64vec4;
+
+       /// High double-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f64, highp> highp_f64vec1;
+
+       /// High double-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f64, highp> highp_f64vec2;
+
+       /// High double-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f64, highp> highp_f64vec3;
+
+       /// High double-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f64, highp> highp_f64vec4;
+
+
+       //////////////////////
+       // Float matrix types
+
+       /// Low single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef lowp_f32 lowp_fmat1x1;
+
+       /// Low single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, lowp> lowp_fmat2x2;
+
+       /// Low single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, lowp> lowp_fmat2x3;
+
+       /// Low single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, lowp> lowp_fmat2x4;
+
+       /// Low single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, lowp> lowp_fmat3x2;
+
+       /// Low single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, lowp> lowp_fmat3x3;
+
+       /// Low single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, lowp> lowp_fmat3x4;
+
+       /// Low single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, lowp> lowp_fmat4x2;
+
+       /// Low single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, lowp> lowp_fmat4x3;
+
+       /// Low single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, lowp> lowp_fmat4x4;
+
+       /// Low single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef lowp_fmat1x1 lowp_fmat1;
+
+       /// Low single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_fmat2x2 lowp_fmat2;
+
+       /// Low single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_fmat3x3 lowp_fmat3;
+
+       /// Low single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_fmat4x4 lowp_fmat4;
+
+
+       /// Medium single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef mediump_f32 mediump_fmat1x1;
+
+       /// Medium single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, mediump> mediump_fmat2x2;
+
+       /// Medium single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, mediump> mediump_fmat2x3;
+
+       /// Medium single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, mediump> mediump_fmat2x4;
+
+       /// Medium single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, mediump> mediump_fmat3x2;
+
+       /// Medium single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, mediump> mediump_fmat3x3;
+
+       /// Medium single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, mediump> mediump_fmat3x4;
+
+       /// Medium single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, mediump> mediump_fmat4x2;
+
+       /// Medium single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, mediump> mediump_fmat4x3;
+
+       /// Medium single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, mediump> mediump_fmat4x4;
+
+       /// Medium single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef mediump_fmat1x1 mediump_fmat1;
+
+       /// Medium single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_fmat2x2 mediump_fmat2;
+
+       /// Medium single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_fmat3x3 mediump_fmat3;
+
+       /// Medium single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_fmat4x4 mediump_fmat4;
+
+
+       /// High single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef highp_f32 highp_fmat1x1;
+
+       /// High single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, highp> highp_fmat2x2;
+
+       /// High single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, highp> highp_fmat2x3;
+
+       /// High single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, highp> highp_fmat2x4;
+
+       /// High single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, highp> highp_fmat3x2;
+
+       /// High single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, highp> highp_fmat3x3;
+
+       /// High single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, highp> highp_fmat3x4;
+
+       /// High single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, highp> highp_fmat4x2;
+
+       /// High single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, highp> highp_fmat4x3;
+
+       /// High single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, highp> highp_fmat4x4;
+
+       /// High single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef highp_fmat1x1 highp_fmat1;
+
+       /// High single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_fmat2x2 highp_fmat2;
+
+       /// High single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_fmat3x3 highp_fmat3;
+       
+       /// High single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_fmat4x4 highp_fmat4;
+
+
+       /// Low single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f32 lowp_f32mat1x1;
+
+       /// Low single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, lowp> lowp_f32mat2x2;
+
+       /// Low single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, lowp> lowp_f32mat2x3;
+
+       /// Low single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, lowp> lowp_f32mat2x4;
+
+       /// Low single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, lowp> lowp_f32mat3x2;
+
+       /// Low single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, lowp> lowp_f32mat3x3;
+
+       /// Low single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, lowp> lowp_f32mat3x4;
+
+       /// Low single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, lowp> lowp_f32mat4x2;
+
+       /// Low single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, lowp> lowp_f32mat4x3;
+
+       /// Low single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, lowp> lowp_f32mat4x4;
+
+       /// Low single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f32, lowp> lowp_f32mat1;
+
+       /// Low single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f32mat2x2 lowp_f32mat2;
+
+       /// Low single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f32mat3x3 lowp_f32mat3;
+
+       /// Low single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f32mat4x4 lowp_f32mat4;
+
+
+       /// High single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f32 mediump_f32mat1x1;
+
+       /// Low single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, mediump> mediump_f32mat2x2;
+
+       /// Medium single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, mediump> mediump_f32mat2x3;
+
+       /// Medium single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, mediump> mediump_f32mat2x4;
+
+       /// Medium single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, mediump> mediump_f32mat3x2;
+
+       /// Medium single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, mediump> mediump_f32mat3x3;
+
+       /// Medium single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, mediump> mediump_f32mat3x4;
+
+       /// Medium single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, mediump> mediump_f32mat4x2;
+
+       /// Medium single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, mediump> mediump_f32mat4x3;
+
+       /// Medium single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, mediump> mediump_f32mat4x4;
+
+       /// Medium single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f32, mediump> f32mat1;
+
+       /// Medium single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f32mat2x2 mediump_f32mat2;
+
+       /// Medium single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f32mat3x3 mediump_f32mat3;
+
+       /// Medium single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f32mat4x4 mediump_f32mat4;
+
+
+       /// High single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f32 highp_f32mat1x1;
+
+       /// High single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, highp> highp_f32mat2x2;
+
+       /// High single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, highp> highp_f32mat2x3;
+
+       /// High single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, highp> highp_f32mat2x4;
+
+       /// High single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, highp> highp_f32mat3x2;
+
+       /// High single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, highp> highp_f32mat3x3;
+
+       /// High single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, highp> highp_f32mat3x4;
+
+       /// High single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, highp> highp_f32mat4x2;
+
+       /// High single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, highp> highp_f32mat4x3;
+
+       /// High single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, highp> highp_f32mat4x4;
+
+       /// High single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f32, highp> f32mat1;
+
+       /// High single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x2 highp_f32mat2;
+
+       /// High single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x3 highp_f32mat3;
+
+       /// High single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x4 highp_f32mat4;
+
+
+       /// Low double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f64 lowp_f64mat1x1;
+
+       /// Low double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f64, lowp> lowp_f64mat2x2;
+
+       /// Low double-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f64, lowp> lowp_f64mat2x3;
+
+       /// Low double-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f64, lowp> lowp_f64mat2x4;
+
+       /// Low double-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f64, lowp> lowp_f64mat3x2;
+
+       /// Low double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f64, lowp> lowp_f64mat3x3;
+
+       /// Low double-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f64, lowp> lowp_f64mat3x4;
+
+       /// Low double-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f64, lowp> lowp_f64mat4x2;
+
+       /// Low double-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f64, lowp> lowp_f64mat4x3;
+       
+       /// Low double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f64, lowp> lowp_f64mat4x4;
+
+       /// Low double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef lowp_f64mat1x1 lowp_f64mat1;
+
+       /// Low double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f64mat2x2 lowp_f64mat2;
+
+       /// Low double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f64mat3x3 lowp_f64mat3;
+
+       /// Low double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef lowp_f64mat4x4 lowp_f64mat4;
+
+
+       /// Medium double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f64 Highp_f64mat1x1;
+
+       /// Medium double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f64, mediump> mediump_f64mat2x2;
+
+       /// Medium double-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f64, mediump> mediump_f64mat2x3;
+
+       /// Medium double-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f64, mediump> mediump_f64mat2x4;
+
+       /// Medium double-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f64, mediump> mediump_f64mat3x2;
+
+       /// Medium double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f64, mediump> mediump_f64mat3x3;
+
+       /// Medium double-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f64, mediump> mediump_f64mat3x4;
+
+       /// Medium double-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f64, mediump> mediump_f64mat4x2;
+
+       /// Medium double-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f64, mediump> mediump_f64mat4x3;
+
+       /// Medium double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f64, mediump> mediump_f64mat4x4;
+
+       /// Medium double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef mediump_f64mat1x1 mediump_f64mat1;
+
+       /// Medium double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f64mat2x2 mediump_f64mat2;
+
+       /// Medium double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f64mat3x3 mediump_f64mat3;
+
+       /// Medium double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef mediump_f64mat4x4 mediump_f64mat4;
+
+       /// High double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f64 highp_f64mat1x1;
+
+       /// High double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f64, highp> highp_f64mat2x2;
+
+       /// High double-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f64, highp> highp_f64mat2x3;
+
+       /// High double-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f64, highp> highp_f64mat2x4;
+
+       /// High double-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f64, highp> highp_f64mat3x2;
+
+       /// High double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f64, highp> highp_f64mat3x3;
+
+       /// High double-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f64, highp> highp_f64mat3x4;
+
+       /// High double-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f64, highp> highp_f64mat4x2;
+
+       /// High double-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f64, highp> highp_f64mat4x3;
+
+       /// High double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f64, highp> highp_f64mat4x4;
+
+       /// High double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef highp_f64mat1x1 highp_f64mat1;
+
+       /// High double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat2x2 highp_f64mat2;
+
+       /// High double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat3x3 highp_f64mat3;
+
+       /// High double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat4x4 highp_f64mat4;
+
+       //////////////////////////
+       // Quaternion types
+
+       /// Low single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f32, lowp> lowp_f32quat;
+
+       /// Low double-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f64, lowp> lowp_f64quat;
+
+       /// Medium single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f32, mediump> mediump_f32quat;
+
+       /// Medium double-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f64, mediump> mediump_f64quat;
+
+       /// High single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f32, highp> highp_f32quat;
+
+       /// High double-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f64, highp> highp_f64quat;
+
+
+#if(defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_f32vec1                    fvec1;
+       typedef lowp_f32vec2                    fvec2;
+       typedef lowp_f32vec3                    fvec3;
+       typedef lowp_f32vec4                    fvec4;
+       typedef lowp_f32mat2                    fmat2;
+       typedef lowp_f32mat3                    fmat3;
+       typedef lowp_f32mat4                    fmat4;
+       typedef lowp_f32mat2x2                  fmat2x2;
+       typedef lowp_f32mat3x2                  fmat3x2;
+       typedef lowp_f32mat4x2                  fmat4x2;
+       typedef lowp_f32mat2x3                  fmat2x3;
+       typedef lowp_f32mat3x3                  fmat3x3;
+       typedef lowp_f32mat4x3                  fmat4x3;
+       typedef lowp_f32mat2x4                  fmat2x4;
+       typedef lowp_f32mat3x4                  fmat3x4;
+       typedef lowp_f32mat4x4                  fmat4x4;
+       typedef lowp_f32quat                    fquat;
+
+       typedef lowp_f32vec1                    f32vec1;
+       typedef lowp_f32vec2                    f32vec2;
+       typedef lowp_f32vec3                    f32vec3;
+       typedef lowp_f32vec4                    f32vec4;
+       typedef lowp_f32mat2                    f32mat2;
+       typedef lowp_f32mat3                    f32mat3;
+       typedef lowp_f32mat4                    f32mat4;
+       typedef lowp_f32mat2x2                  f32mat2x2;
+       typedef lowp_f32mat3x2                  f32mat3x2;
+       typedef lowp_f32mat4x2                  f32mat4x2;
+       typedef lowp_f32mat2x3                  f32mat2x3;
+       typedef lowp_f32mat3x3                  f32mat3x3;
+       typedef lowp_f32mat4x3                  f32mat4x3;
+       typedef lowp_f32mat2x4                  f32mat2x4;
+       typedef lowp_f32mat3x4                  f32mat3x4;
+       typedef lowp_f32mat4x4                  f32mat4x4;
+       typedef lowp_f32quat                    f32quat;
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+       typedef mediump_f32vec1                 fvec1;
+       typedef mediump_f32vec2                 fvec2;
+       typedef mediump_f32vec3                 fvec3;
+       typedef mediump_f32vec4                 fvec4;
+       typedef mediump_f32mat2                 fmat2;
+       typedef mediump_f32mat3                 fmat3;
+       typedef mediump_f32mat4                 fmat4;
+       typedef mediump_f32mat2x2               fmat2x2;
+       typedef mediump_f32mat3x2               fmat3x2;
+       typedef mediump_f32mat4x2               fmat4x2;
+       typedef mediump_f32mat2x3               fmat2x3;
+       typedef mediump_f32mat3x3               fmat3x3;
+       typedef mediump_f32mat4x3               fmat4x3;
+       typedef mediump_f32mat2x4               fmat2x4;
+       typedef mediump_f32mat3x4               fmat3x4;
+       typedef mediump_f32mat4x4               fmat4x4;
+       typedef mediump_f32quat                 fquat;
+
+       typedef mediump_f32vec1                 f32vec1;
+       typedef mediump_f32vec2                 f32vec2;
+       typedef mediump_f32vec3                 f32vec3;
+       typedef mediump_f32vec4                 f32vec4;
+       typedef mediump_f32mat2                 f32mat2;
+       typedef mediump_f32mat3                 f32mat3;
+       typedef mediump_f32mat4                 f32mat4;
+       typedef mediump_f32mat2x2               f32mat2x2;
+       typedef mediump_f32mat3x2               f32mat3x2;
+       typedef mediump_f32mat4x2               f32mat4x2;
+       typedef mediump_f32mat2x3               f32mat2x3;
+       typedef mediump_f32mat3x3               f32mat3x3;
+       typedef mediump_f32mat4x3               f32mat4x3;
+       typedef mediump_f32mat2x4               f32mat2x4;
+       typedef mediump_f32mat3x4               f32mat3x4;
+       typedef mediump_f32mat4x4               f32mat4x4;
+       typedef mediump_f32quat                 f32quat;
+#else//if(defined(GLM_PRECISION_HIGHP_FLOAT))
+       /// Default single-precision floating-point vector of 1 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec1                   fvec1;
+
+       /// Default single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec2                   fvec2;
+
+       /// Default single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec3                   fvec3;
+
+       /// Default single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec4                   fvec4;
+
+       /// Default single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x2                 fmat2x2;
+
+       /// Default single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x3                 fmat2x3;
+
+       /// Default single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x4                 fmat2x4;
+
+       /// Default single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x2                 fmat3x2;
+
+       /// Default single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x3                 fmat3x3;
+
+       /// Default single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x4                 fmat3x4;
+
+       /// Default single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x2                 fmat4x2;
+
+       /// Default single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x3                 fmat4x3;
+
+       /// Default single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x4                 fmat4x4;
+       
+       /// Default single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef fmat2x2                                 fmat2;
+
+       /// Default single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef fmat3x3                                 fmat3;
+
+       /// Default single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef fmat4x4                                 fmat4;
+
+       /// Default single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef highp_fquat                             fquat;
+       
+
+
+       /// Default single-precision floating-point vector of 1 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec1                   f32vec1;
+
+       /// Default single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec2                   f32vec2;
+
+       /// Default single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec3                   f32vec3;
+
+       /// Default single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef highp_f32vec4                   f32vec4;
+
+       /// Default single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x2                 f32mat2x2;
+
+       /// Default single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x3                 f32mat2x3;
+
+       /// Default single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat2x4                 f32mat2x4;
+
+       /// Default single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x2                 f32mat3x2;
+
+       /// Default single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x3                 f32mat3x3;
+
+       /// Default single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat3x4                 f32mat3x4;
+
+       /// Default single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x2                 f32mat4x2;
+
+       /// Default single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x3                 f32mat4x3;
+
+       /// Default single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f32mat4x4                 f32mat4x4;
+
+       /// Default single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef f32mat2x2                               f32mat2;
+
+       /// Default single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef f32mat3x3                               f32mat3;
+
+       /// Default single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef f32mat4x4                               f32mat4;
+
+       /// Default single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef highp_f32quat                   f32quat;
+#endif
+
+#if(defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_f64vec1                    f64vec1;
+       typedef lowp_f64vec2                    f64vec2;
+       typedef lowp_f64vec3                    f64vec3;
+       typedef lowp_f64vec4                    f64vec4;
+       typedef lowp_f64mat2                    f64mat2;
+       typedef lowp_f64mat3                    f64mat3;
+       typedef lowp_f64mat4                    f64mat4;
+       typedef lowp_f64mat2x2                  f64mat2x2;
+       typedef lowp_f64mat3x2                  f64mat3x2;
+       typedef lowp_f64mat4x2                  f64mat4x2;
+       typedef lowp_f64mat2x3                  f64mat2x3;
+       typedef lowp_f64mat3x3                  f64mat3x3;
+       typedef lowp_f64mat4x3                  f64mat4x3;
+       typedef lowp_f64mat2x4                  f64mat2x4;
+       typedef lowp_f64mat3x4                  f64mat3x4;
+       typedef lowp_f64mat4x4                  f64mat4x4;
+       typedef lowp_f64quat                    f64quat;
+#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))
+       typedef mediump_f64vec1                 f64vec1;
+       typedef mediump_f64vec2                 f64vec2;
+       typedef mediump_f64vec3                 f64vec3;
+       typedef mediump_f64vec4                 f64vec4;
+       typedef mediump_f64mat2                 f64mat2;
+       typedef mediump_f64mat3                 f64mat3;
+       typedef mediump_f64mat4                 f64mat4;
+       typedef mediump_f64mat2x2               f64mat2x2;
+       typedef mediump_f64mat3x2               f64mat3x2;
+       typedef mediump_f64mat4x2               f64mat4x2;
+       typedef mediump_f64mat2x3               f64mat2x3;
+       typedef mediump_f64mat3x3               f64mat3x3;
+       typedef mediump_f64mat4x3               f64mat4x3;
+       typedef mediump_f64mat2x4               f64mat2x4;
+       typedef mediump_f64mat3x4               f64mat3x4;
+       typedef mediump_f64mat4x4               f64mat4x4;
+       typedef mediump_f64quat                 f64quat;
+#else
+       /// Default double-precision floating-point vector of 1 components.
+       /// @see gtc_type_precision
+       typedef highp_f64vec1                   f64vec1;
+
+       /// Default double-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef highp_f64vec2                   f64vec2;
+
+       /// Default double-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef highp_f64vec3                   f64vec3;
+
+       /// Default double-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef highp_f64vec4                   f64vec4;
+
+       /// Default double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat2x2                 f64mat2x2;
+
+       /// Default double-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat2x3                 f64mat2x3;
+
+       /// Default double-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat2x4                 f64mat2x4;
+
+       /// Default double-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat3x2                 f64mat3x2;
+
+       /// Default double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat3x3                 f64mat3x3;
+
+       /// Default double-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat3x4                 f64mat3x4;
+
+       /// Default double-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat4x2                 f64mat4x2;
+
+       /// Default double-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat4x3                 f64mat4x3;
+
+       /// Default double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef highp_f64mat4x4                 f64mat4x4;
+
+       /// Default double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef f64mat2x2                               f64mat2;
+
+       /// Default double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef f64mat3x3                               f64mat3;
+
+       /// Default double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef f64mat4x4                               f64mat4;
+
+       /// Default double-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef highp_f64quat                   f64quat;
+#endif
+
+}//namespace glm
diff --git a/core/deps/glm/glm/geometric.hpp b/core/deps/glm/glm/geometric.hpp
new file mode 100755 (executable)
index 0000000..eea45b1
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/geometric.hpp
+
+#pragma once
+
+#include "detail/func_geometric.hpp"
diff --git a/core/deps/glm/glm/glm.hpp b/core/deps/glm/glm/glm.hpp
new file mode 100755 (executable)
index 0000000..021a360
--- /dev/null
@@ -0,0 +1,88 @@
+/// @ref core
+/// @file glm/glm.hpp
+///
+/// @defgroup core GLM Core
+///
+/// @brief The core of GLM, which implements exactly and only the GLSL specification to the degree possible.
+///
+/// The GLM core consists of @ref core_types "C++ types that mirror GLSL types" and
+/// C++ functions that mirror the GLSL functions. It also includes 
+/// @ref core_precision "a set of precision-based types" that can be used in the appropriate
+/// functions. The C++ types are all based on a basic set of @ref core_template "template types".
+///
+/// The best documentation for GLM Core is the current GLSL specification,
+/// <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.clean.pdf">version 4.2
+/// (pdf file)</a>.
+///
+/// GLM core functionnalities require <glm/glm.hpp> to be included to be used.
+///
+/// @defgroup core_types Types
+///
+/// @brief The standard types defined by the specification.
+///
+/// These types are all typedefs of more generalized, template types. To see the definition
+/// of these template types, go to @ref core_template.
+///
+/// @ingroup core
+///
+/// @defgroup core_precision Precision types
+///
+/// @brief Non-GLSL types that are used to define precision-based types.
+///
+/// The GLSL language allows the user to define the precision of a particular variable.
+/// In OpenGL's GLSL, these precision qualifiers have no effect; they are there for compatibility
+/// with OpenGL ES's precision qualifiers, where they @em do have an effect.
+///
+/// C++ has no language equivalent to precision qualifiers. So GLM provides the next-best thing:
+/// a number of typedefs of the @ref core_template that use a particular precision.
+///
+/// None of these types make any guarantees about the actual precision used.
+///
+/// @ingroup core
+///
+/// @defgroup core_template Template types
+///
+/// @brief The generic template types used as the basis for the core types. 
+///
+/// These types are all templates used to define the actual @ref core_types.
+/// These templetes are implementation details of GLM types and should not be used explicitly.
+///
+/// @ingroup core
+
+#include "detail/_fixes.hpp"
+
+#pragma once
+
+#include <cmath>
+#include <climits>
+#include <cfloat>
+#include <limits>
+#include <cassert>
+#include "fwd.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_CORE_INCLUDED_DISPLAYED)
+#      define GLM_MESSAGE_CORE_INCLUDED_DISPLAYED
+#      pragma message("GLM: Core library included")
+#endif//GLM_MESSAGES
+
+#include "vec2.hpp"
+#include "vec3.hpp"
+#include "vec4.hpp"
+#include "mat2x2.hpp"
+#include "mat2x3.hpp"
+#include "mat2x4.hpp"
+#include "mat3x2.hpp"
+#include "mat3x3.hpp"
+#include "mat3x4.hpp"
+#include "mat4x2.hpp"
+#include "mat4x3.hpp"
+#include "mat4x4.hpp"
+
+#include "trigonometric.hpp"
+#include "exponential.hpp"
+#include "common.hpp"
+#include "packing.hpp"
+#include "geometric.hpp"
+#include "matrix.hpp"
+#include "vector_relational.hpp"
+#include "integer.hpp"
diff --git a/core/deps/glm/glm/gtc/bitfield.hpp b/core/deps/glm/glm/gtc/bitfield.hpp
new file mode 100755 (executable)
index 0000000..38a38b6
--- /dev/null
@@ -0,0 +1,207 @@
+/// @ref gtc_bitfield
+/// @file glm/gtc/bitfield.hpp
+///
+/// @see core (dependence)
+/// @see gtc_bitfield (dependence)
+///
+/// @defgroup gtc_bitfield GLM_GTC_bitfield
+/// @ingroup gtc
+/// 
+/// @brief Allow to perform bit operations on integer values
+/// 
+/// <glm/gtc/bitfield.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/type_int.hpp"
+#include "../detail/_vectorize.hpp"
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_bitfield extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_bitfield
+       /// @{
+
+       /// Build a mask of 'count' bits
+       ///
+       /// @see gtc_bitfield
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType mask(genIUType Bits);
+       
+       /// Build a mask of 'count' bits
+       ///
+       /// @see gtc_bitfield
+       template <typename T, precision P, template <typename, precision> class vecIUType>
+       GLM_FUNC_DECL vecIUType<T, P> mask(vecIUType<T, P> const & v);
+
+       /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side.
+       ///
+       /// @see gtc_bitfield
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType bitfieldRotateRight(genIUType In, int Shift);
+
+       /// Rotate all bits to the right. All the bits dropped in the right side are inserted back on the left side.
+       ///
+       /// @see gtc_bitfield
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldRotateRight(vecType<T, P> const & In, int Shift);
+
+       /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side.
+       ///
+       /// @see gtc_bitfield
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType bitfieldRotateLeft(genIUType In, int Shift);
+
+       /// Rotate all bits to the left. All the bits dropped in the left side are inserted back on the right side.
+       ///
+       /// @see gtc_bitfield
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldRotateLeft(vecType<T, P> const & In, int Shift);
+
+       /// Set to 1 a range of bits.
+       ///
+       /// @see gtc_bitfield
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount);
+
+       /// Set to 1 a range of bits.
+       ///
+       /// @see gtc_bitfield
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldFillOne(vecType<T, P> const & Value, int FirstBit, int BitCount);
+
+       /// Set to 0 a range of bits.
+       ///
+       /// @see gtc_bitfield
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount);
+
+       /// Set to 0 a range of bits.
+       ///
+       /// @see gtc_bitfield
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> bitfieldFillZero(vecType<T, P> const & Value, int FirstBit, int BitCount);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int16 bitfieldInterleave(int8 x, int8 y);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint16 bitfieldInterleave(uint8 x, uint8 y);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int32 bitfieldInterleave(int16 x, int16 y);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint32 bitfieldInterleave(uint16 x, uint16 y);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y);
+
+       /// Interleaves the bits of x and y.
+       /// The first bit is the first bit of x followed by the first bit of y.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y);
+
+       /// Interleaves the bits of x, y and z.
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z);
+
+       /// Interleaves the bits of x, y and z.
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z);
+
+       /// Interleaves the bits of x, y and z.
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z);
+
+       /// Interleaves the bits of x, y and z. 
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z);
+
+       /// Interleaves the bits of x, y and z. 
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int64 bitfieldInterleave(int32 x, int32 y, int32 z);
+
+       /// Interleaves the bits of x, y and z. 
+       /// The first bit is the first bit of x followed by the first bit of y and the first bit of z.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z);
+
+       /// Interleaves the bits of x, y, z and w. 
+       /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w);
+
+       /// Interleaves the bits of x, y, z and w. 
+       /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w);
+
+       /// Interleaves the bits of x, y, z and w. 
+       /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w);
+
+       /// Interleaves the bits of x, y, z and w. 
+       /// The first bit is the first bit of x followed by the first bit of y, the first bit of z and finally the first bit of w.
+       /// The other bits are interleaved following the previous sequence.
+       /// 
+       /// @see gtc_bitfield
+       GLM_FUNC_DECL uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w);
+
+       /// @}
+} //namespace glm
+
+#include "bitfield.inl"
diff --git a/core/deps/glm/glm/gtc/bitfield.inl b/core/deps/glm/glm/gtc/bitfield.inl
new file mode 100755 (executable)
index 0000000..490cfb3
--- /dev/null
@@ -0,0 +1,515 @@
+/// @ref gtc_bitfield
+/// @file glm/gtc/bitfield.inl
+
+#include "../simd/integer.h"
+
+namespace glm{
+namespace detail
+{
+       template <typename PARAM, typename RET>
+       GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y);
+
+       template <typename PARAM, typename RET>
+       GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z);
+
+       template <typename PARAM, typename RET>
+       GLM_FUNC_DECL RET bitfieldInterleave(PARAM x, PARAM y, PARAM z, PARAM w);
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint16 bitfieldInterleave(glm::uint8 x, glm::uint8 y)
+       {
+               glm::uint16 REG1(x);
+               glm::uint16 REG2(y);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint16(0x0F0F);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint16(0x0F0F);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint16(0x3333);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint16(0x3333);
+
+               REG1 = ((REG1 <<  1) | REG1) & glm::uint16(0x5555);
+               REG2 = ((REG2 <<  1) | REG2) & glm::uint16(0x5555);
+
+               return REG1 | (REG2 << 1);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint16 x, glm::uint16 y)
+       {
+               glm::uint32 REG1(x);
+               glm::uint32 REG2(y);
+
+               REG1 = ((REG1 <<  8) | REG1) & glm::uint32(0x00FF00FF);
+               REG2 = ((REG2 <<  8) | REG2) & glm::uint32(0x00FF00FF);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint32(0x0F0F0F0F);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint32(0x0F0F0F0F);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint32(0x33333333);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint32(0x33333333);
+
+               REG1 = ((REG1 <<  1) | REG1) & glm::uint32(0x55555555);
+               REG2 = ((REG2 <<  1) | REG2) & glm::uint32(0x55555555);
+
+               return REG1 | (REG2 << 1);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y)
+       {
+               glm::uint64 REG1(x);
+               glm::uint64 REG2(y);
+
+               REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFFull);
+               REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFFull);
+
+               REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0x00FF00FF00FF00FFull);
+               REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0x00FF00FF00FF00FFull);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0Full);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0Full);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x3333333333333333ull);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x3333333333333333ull);
+
+               REG1 = ((REG1 <<  1) | REG1) & glm::uint64(0x5555555555555555ull);
+               REG2 = ((REG2 <<  1) | REG2) & glm::uint64(0x5555555555555555ull);
+
+               return REG1 | (REG2 << 1);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z)
+       {
+               glm::uint32 REG1(x);
+               glm::uint32 REG2(y);
+               glm::uint32 REG3(z);
+
+               REG1 = ((REG1 << 16) | REG1) & glm::uint32(0x00FF0000FF0000FF);
+               REG2 = ((REG2 << 16) | REG2) & glm::uint32(0x00FF0000FF0000FF);
+               REG3 = ((REG3 << 16) | REG3) & glm::uint32(0x00FF0000FF0000FF);
+
+               REG1 = ((REG1 <<  8) | REG1) & glm::uint32(0xF00F00F00F00F00F);
+               REG2 = ((REG2 <<  8) | REG2) & glm::uint32(0xF00F00F00F00F00F);
+               REG3 = ((REG3 <<  8) | REG3) & glm::uint32(0xF00F00F00F00F00F);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint32(0x30C30C30C30C30C3);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint32(0x30C30C30C30C30C3);
+               REG3 = ((REG3 <<  4) | REG3) & glm::uint32(0x30C30C30C30C30C3);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint32(0x9249249249249249);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint32(0x9249249249249249);
+               REG3 = ((REG3 <<  2) | REG3) & glm::uint32(0x9249249249249249);
+
+               return REG1 | (REG2 << 1) | (REG3 << 2);
+       }
+               
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z)
+       {
+               glm::uint64 REG1(x);
+               glm::uint64 REG2(y);
+               glm::uint64 REG3(z);
+
+               REG1 = ((REG1 << 32) | REG1) & glm::uint64(0xFFFF00000000FFFFull);
+               REG2 = ((REG2 << 32) | REG2) & glm::uint64(0xFFFF00000000FFFFull);
+               REG3 = ((REG3 << 32) | REG3) & glm::uint64(0xFFFF00000000FFFFull);
+
+               REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x00FF0000FF0000FFull);
+               REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x00FF0000FF0000FFull);
+               REG3 = ((REG3 << 16) | REG3) & glm::uint64(0x00FF0000FF0000FFull);
+
+               REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0xF00F00F00F00F00Full);
+               REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0xF00F00F00F00F00Full);
+               REG3 = ((REG3 <<  8) | REG3) & glm::uint64(0xF00F00F00F00F00Full);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x30C30C30C30C30C3ull);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x30C30C30C30C30C3ull);
+               REG3 = ((REG3 <<  4) | REG3) & glm::uint64(0x30C30C30C30C30C3ull);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x9249249249249249ull);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x9249249249249249ull);
+               REG3 = ((REG3 <<  2) | REG3) & glm::uint64(0x9249249249249249ull);
+
+               return REG1 | (REG2 << 1) | (REG3 << 2);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint32 x, glm::uint32 y, glm::uint32 z)
+       {
+               glm::uint64 REG1(x);
+               glm::uint64 REG2(y);
+               glm::uint64 REG3(z);
+
+               REG1 = ((REG1 << 32) | REG1) & glm::uint64(0xFFFF00000000FFFFull);
+               REG2 = ((REG2 << 32) | REG2) & glm::uint64(0xFFFF00000000FFFFull);
+               REG3 = ((REG3 << 32) | REG3) & glm::uint64(0xFFFF00000000FFFFull);
+
+               REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x00FF0000FF0000FFull);
+               REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x00FF0000FF0000FFull);
+               REG3 = ((REG3 << 16) | REG3) & glm::uint64(0x00FF0000FF0000FFull);
+
+               REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0xF00F00F00F00F00Full);
+               REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0xF00F00F00F00F00Full);
+               REG3 = ((REG3 <<  8) | REG3) & glm::uint64(0xF00F00F00F00F00Full);
+
+               REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x30C30C30C30C30C3ull);
+               REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x30C30C30C30C30C3ull);
+               REG3 = ((REG3 <<  4) | REG3) & glm::uint64(0x30C30C30C30C30C3ull);
+
+               REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x9249249249249249ull);
+               REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x9249249249249249ull);
+               REG3 = ((REG3 <<  2) | REG3) & glm::uint64(0x9249249249249249ull);
+
+               return REG1 | (REG2 << 1) | (REG3 << 2);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint32 bitfieldInterleave(glm::uint8 x, glm::uint8 y, glm::uint8 z, glm::uint8 w)
+       {
+               glm::uint32 REG1(x);
+               glm::uint32 REG2(y);
+               glm::uint32 REG3(z);
+               glm::uint32 REG4(w);
+
+               REG1 = ((REG1 << 12) | REG1) & glm::uint32(0x000F000F000F000F);
+               REG2 = ((REG2 << 12) | REG2) & glm::uint32(0x000F000F000F000F);
+               REG3 = ((REG3 << 12) | REG3) & glm::uint32(0x000F000F000F000F);
+               REG4 = ((REG4 << 12) | REG4) & glm::uint32(0x000F000F000F000F);
+
+               REG1 = ((REG1 <<  6) | REG1) & glm::uint32(0x0303030303030303);
+               REG2 = ((REG2 <<  6) | REG2) & glm::uint32(0x0303030303030303);
+               REG3 = ((REG3 <<  6) | REG3) & glm::uint32(0x0303030303030303);
+               REG4 = ((REG4 <<  6) | REG4) & glm::uint32(0x0303030303030303);
+
+               REG1 = ((REG1 <<  3) | REG1) & glm::uint32(0x1111111111111111);
+               REG2 = ((REG2 <<  3) | REG2) & glm::uint32(0x1111111111111111);
+               REG3 = ((REG3 <<  3) | REG3) & glm::uint32(0x1111111111111111);
+               REG4 = ((REG4 <<  3) | REG4) & glm::uint32(0x1111111111111111);
+
+               return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3);
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER glm::uint64 bitfieldInterleave(glm::uint16 x, glm::uint16 y, glm::uint16 z, glm::uint16 w)
+       {
+               glm::uint64 REG1(x);
+               glm::uint64 REG2(y);
+               glm::uint64 REG3(z);
+               glm::uint64 REG4(w);
+
+               REG1 = ((REG1 << 24) | REG1) & glm::uint64(0x000000FF000000FFull);
+               REG2 = ((REG2 << 24) | REG2) & glm::uint64(0x000000FF000000FFull);
+               REG3 = ((REG3 << 24) | REG3) & glm::uint64(0x000000FF000000FFull);
+               REG4 = ((REG4 << 24) | REG4) & glm::uint64(0x000000FF000000FFull);
+
+               REG1 = ((REG1 << 12) | REG1) & glm::uint64(0x000F000F000F000Full);
+               REG2 = ((REG2 << 12) | REG2) & glm::uint64(0x000F000F000F000Full);
+               REG3 = ((REG3 << 12) | REG3) & glm::uint64(0x000F000F000F000Full);
+               REG4 = ((REG4 << 12) | REG4) & glm::uint64(0x000F000F000F000Full);
+
+               REG1 = ((REG1 <<  6) | REG1) & glm::uint64(0x0303030303030303ull);
+               REG2 = ((REG2 <<  6) | REG2) & glm::uint64(0x0303030303030303ull);
+               REG3 = ((REG3 <<  6) | REG3) & glm::uint64(0x0303030303030303ull);
+               REG4 = ((REG4 <<  6) | REG4) & glm::uint64(0x0303030303030303ull);
+
+               REG1 = ((REG1 <<  3) | REG1) & glm::uint64(0x1111111111111111ull);
+               REG2 = ((REG2 <<  3) | REG2) & glm::uint64(0x1111111111111111ull);
+               REG3 = ((REG3 <<  3) | REG3) & glm::uint64(0x1111111111111111ull);
+               REG4 = ((REG4 <<  3) | REG4) & glm::uint64(0x1111111111111111ull);
+
+               return REG1 | (REG2 << 1) | (REG3 << 2) | (REG4 << 3);
+       }
+}//namespace detail
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType mask(genIUType Bits)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genIUType>::is_integer, "'mask' accepts only integer values");
+
+               return Bits >= sizeof(genIUType) * 8 ? ~static_cast<genIUType>(0) : (static_cast<genIUType>(1) << Bits) - static_cast<genIUType>(1);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecIUType>
+       GLM_FUNC_QUALIFIER vecIUType<T, P> mask(vecIUType<T, P> const& v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'mask' accepts only integer values");
+
+               return detail::functor1<T, T, P, vecIUType>::call(mask, v);
+       }
+
+       template <typename genIType>
+       GLM_FUNC_QUALIFIER genIType bitfieldRotateRight(genIType In, int Shift)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genIType>::is_integer, "'bitfieldRotateRight' accepts only integer values");
+
+               int const BitSize = static_cast<genIType>(sizeof(genIType) * 8);
+               return (In << static_cast<genIType>(Shift)) | (In >> static_cast<genIType>(BitSize - Shift));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldRotateRight(vecType<T, P> const & In, int Shift)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'bitfieldRotateRight' accepts only integer values");
+
+               int const BitSize = static_cast<int>(sizeof(T) * 8);
+               return (In << static_cast<T>(Shift)) | (In >> static_cast<T>(BitSize - Shift));
+       }
+
+       template <typename genIType>
+       GLM_FUNC_QUALIFIER genIType bitfieldRotateLeft(genIType In, int Shift)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genIType>::is_integer, "'bitfieldRotateLeft' accepts only integer values");
+
+               int const BitSize = static_cast<genIType>(sizeof(genIType) * 8);
+               return (In >> static_cast<genIType>(Shift)) | (In << static_cast<genIType>(BitSize - Shift));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldRotateLeft(vecType<T, P> const& In, int Shift)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_integer, "'bitfieldRotateLeft' accepts only integer values");
+
+               int const BitSize = static_cast<int>(sizeof(T) * 8);
+               return (In >> static_cast<T>(Shift)) | (In << static_cast<T>(BitSize - Shift));
+       }
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType bitfieldFillOne(genIUType Value, int FirstBit, int BitCount)
+       {
+               return Value | static_cast<genIUType>(mask(BitCount) << FirstBit);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldFillOne(vecType<T, P> const& Value, int FirstBit, int BitCount)
+       {
+               return Value | static_cast<T>(mask(BitCount) << FirstBit);
+       }
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType bitfieldFillZero(genIUType Value, int FirstBit, int BitCount)
+       {
+               return Value & static_cast<genIUType>(~(mask(BitCount) << FirstBit));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> bitfieldFillZero(vecType<T, P> const& Value, int FirstBit, int BitCount)
+       {
+               return Value & static_cast<T>(~(mask(BitCount) << FirstBit));
+       }
+
+       GLM_FUNC_QUALIFIER int16 bitfieldInterleave(int8 x, int8 y)
+       {
+               union sign8
+               {
+                       int8 i;
+                       uint8 u;
+               } sign_x, sign_y;
+
+               union sign16
+               {
+                       int16 i;
+                       uint16 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint16 bitfieldInterleave(uint8 x, uint8 y)
+       {
+               return detail::bitfieldInterleave<uint8, uint16>(x, y);
+       }
+
+       GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int16 x, int16 y)
+       {
+               union sign16
+               {
+                       int16 i;
+                       uint16 u;
+               } sign_x, sign_y;
+
+               union sign32
+               {
+                       int32 i;
+                       uint32 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint16 x, uint16 y)
+       {
+               return detail::bitfieldInterleave<uint16, uint32>(x, y);
+       }
+
+       GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y)
+       {
+               union sign32
+               {
+                       int32 i;
+                       uint32 u;
+               } sign_x, sign_y;
+
+               union sign64
+               {
+                       int64 i;
+                       uint64 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y)
+       {
+               return detail::bitfieldInterleave<uint32, uint64>(x, y);
+       }
+
+       GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z)
+       {
+               union sign8
+               {
+                       int8 i;
+                       uint8 u;
+               } sign_x, sign_y, sign_z;
+
+               union sign32
+               {
+                       int32 i;
+                       uint32 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               sign_z.i = z;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z)
+       {
+               return detail::bitfieldInterleave<uint8, uint32>(x, y, z);
+       }
+
+       GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z)
+       {
+               union sign16
+               {
+                       int16 i;
+                       uint16 u;
+               } sign_x, sign_y, sign_z;
+
+               union sign64
+               {
+                       int64 i;
+                       uint64 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               sign_z.i = z;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z)
+       {
+               return detail::bitfieldInterleave<uint32, uint64>(x, y, z);
+       }
+
+       GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int32 x, int32 y, int32 z)
+       {
+               union sign16
+               {
+                       int32 i;
+                       uint32 u;
+               } sign_x, sign_y, sign_z;
+
+               union sign64
+               {
+                       int64 i;
+                       uint64 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               sign_z.i = z;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint32 x, uint32 y, uint32 z)
+       {
+               return detail::bitfieldInterleave<uint32, uint64>(x, y, z);
+       }
+
+       GLM_FUNC_QUALIFIER int32 bitfieldInterleave(int8 x, int8 y, int8 z, int8 w)
+       {
+               union sign8
+               {
+                       int8 i;
+                       uint8 u;
+               } sign_x, sign_y, sign_z, sign_w;
+
+               union sign32
+               {
+                       int32 i;
+                       uint32 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               sign_z.i = z;
+               sign_w.i = w;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint32 bitfieldInterleave(uint8 x, uint8 y, uint8 z, uint8 w)
+       {
+               return detail::bitfieldInterleave<uint8, uint32>(x, y, z, w);
+       }
+
+       GLM_FUNC_QUALIFIER int64 bitfieldInterleave(int16 x, int16 y, int16 z, int16 w)
+       {
+               union sign16
+               {
+                       int16 i;
+                       uint16 u;
+               } sign_x, sign_y, sign_z, sign_w;
+
+               union sign64
+               {
+                       int64 i;
+                       uint64 u;
+               } result;
+
+               sign_x.i = x;
+               sign_y.i = y;
+               sign_z.i = z;
+               sign_w.i = w;
+               result.u = bitfieldInterleave(sign_x.u, sign_y.u, sign_z.u, sign_w.u);
+
+               return result.i;
+       }
+
+       GLM_FUNC_QUALIFIER uint64 bitfieldInterleave(uint16 x, uint16 y, uint16 z, uint16 w)
+       {
+               return detail::bitfieldInterleave<uint16, uint64>(x, y, z, w);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/color_encoding.inl b/core/deps/glm/glm/gtc/color_encoding.inl
new file mode 100755 (executable)
index 0000000..68570cb
--- /dev/null
@@ -0,0 +1,65 @@
+/// @ref gtc_color_encoding
+/// @file glm/gtc/color_encoding.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertLinearSRGBToD65XYZ(tvec3<T, P> const& ColorLinearSRGB)
+       {
+               tvec3<T, P> const M(0.490f, 0.17697f, 0.2f);
+               tvec3<T, P> const N(0.31f,  0.8124f, 0.01063f);
+               tvec3<T, P> const O(0.490f, 0.01f, 0.99f);
+
+               return (M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB) * static_cast<T>(5.650675255693055f);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertD65XYZToLinearSRGB(tvec3<T, P> const& ColorD65XYZ)
+       {
+               tvec3<T, P> const M(0.41847f, -0.091169f, 0.0009209f);
+               tvec3<T, P> const N(-0.15866f, 0.25243f, 0.015708f);
+               tvec3<T, P> const O(0.0009209f, -0.0025498f, 0.1786f);
+
+               return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertLinearSRGBToD50XYZ(tvec3<T, P> const& ColorLinearSRGB)
+       {
+               tvec3<T, P> const M(0.436030342570117f, 0.222438466210245f, 0.013897440074263f);
+               tvec3<T, P> const N(0.385101860087134f, 0.716942745571917f, 0.097076381494207f);
+               tvec3<T, P> const O(0.143067806654203f, 0.060618777416563f, 0.713926257896652f);
+
+               return M * ColorLinearSRGB + N * ColorLinearSRGB + O * ColorLinearSRGB;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertD50XYZToLinearSRGB(tvec3<T, P> const& ColorD50XYZ)
+       {
+               tvec3<T, P> const M();
+               tvec3<T, P> const N();
+               tvec3<T, P> const O();
+
+               return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertD65XYZToD50XYZ(tvec3<T, P> const& ColorD65XYZ)
+       {
+               tvec3<T, P> const M(+1.047844353856414f, +0.029549007606644f, -0.009250984365223f);
+               tvec3<T, P> const N(+0.022898981050086f, +0.990508028941971f, +0.015072338237051f);
+               tvec3<T, P> const O(-0.050206647741605f, -0.017074711360960f, +0.751717835079977f);
+
+               return M * ColorD65XYZ + N * ColorD65XYZ + O * ColorD65XYZ;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> convertD50XYZToD65XYZ(tvec3<T, P> const& ColorD50XYZ)
+       {
+               tvec3<T, P> const M();
+               tvec3<T, P> const N();
+               tvec3<T, P> const O();
+
+               return M * ColorD50XYZ + N * ColorD50XYZ + O * ColorD50XYZ;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/color_space.hpp b/core/deps/glm/glm/gtc/color_space.hpp
new file mode 100755 (executable)
index 0000000..08ece8f
--- /dev/null
@@ -0,0 +1,56 @@
+/// @ref gtc_color_space
+/// @file glm/gtc/color_space.hpp
+///
+/// @see core (dependence)
+/// @see gtc_color_space (dependence)
+///
+/// @defgroup gtc_color_space GLM_GTC_color_space
+/// @ingroup gtc
+///
+/// @brief Allow to perform bit operations on integer values
+///
+/// <glm/gtc/color.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../exponential.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_color_space extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_color_space
+       /// @{
+
+       /// Convert a linear color to sRGB color using a standard gamma correction.
+       /// IEC 61966-2-1:1999 specification https://www.w3.org/Graphics/Color/srgb
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> convertLinearToSRGB(vecType<T, P> const & ColorLinear);
+
+       /// Convert a linear color to sRGB color using a custom gamma correction.
+       /// IEC 61966-2-1:1999 specification https://www.w3.org/Graphics/Color/srgb
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> convertLinearToSRGB(vecType<T, P> const & ColorLinear, T Gamma);
+
+       /// Convert a sRGB color to linear color using a standard gamma correction.
+       /// IEC 61966-2-1:1999 specification https://www.w3.org/Graphics/Color/srgb
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> convertSRGBToLinear(vecType<T, P> const & ColorSRGB);
+
+       /// Convert a sRGB color to linear color using a custom gamma correction.
+       // IEC 61966-2-1:1999 specification https://www.w3.org/Graphics/Color/srgb
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> convertSRGBToLinear(vecType<T, P> const & ColorSRGB, T Gamma);
+
+       /// @}
+} //namespace glm
+
+#include "color_space.inl"
diff --git a/core/deps/glm/glm/gtc/color_space.inl b/core/deps/glm/glm/gtc/color_space.inl
new file mode 100755 (executable)
index 0000000..c9a44ef
--- /dev/null
@@ -0,0 +1,75 @@
+/// @ref gtc_color_space
+/// @file glm/gtc/color_space.inl
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_rgbToSrgb
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const& ColorRGB, T GammaCorrection)
+               {
+                       vecType<T, P> const ClampedColor(clamp(ColorRGB, static_cast<T>(0), static_cast<T>(1)));
+
+                       return mix(
+                               pow(ClampedColor, vecType<T, P>(GammaCorrection)) * static_cast<T>(1.055) - static_cast<T>(0.055),
+                               ClampedColor * static_cast<T>(12.92),
+                               lessThan(ClampedColor, vecType<T, P>(static_cast<T>(0.0031308))));
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_rgbToSrgb<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const& ColorRGB, T GammaCorrection)
+               {
+                       return tvec4<T, P>(compute_rgbToSrgb<T, P, tvec3>::call(tvec3<T, P>(ColorRGB), GammaCorrection), ColorRGB.w);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_srgbToRgb
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const& ColorSRGB, T Gamma)
+               {
+                       return mix(
+                               pow((ColorSRGB + static_cast<T>(0.055)) * static_cast<T>(0.94786729857819905213270142180095), vecType<T, P>(Gamma)),
+                               ColorSRGB * static_cast<T>(0.07739938080495356037151702786378),
+                               lessThanEqual(ColorSRGB, vecType<T, P>(static_cast<T>(0.04045))));
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_srgbToRgb<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<T, P> call(tvec4<T, P> const& ColorSRGB, T Gamma)
+               {
+                       return tvec4<T, P>(compute_srgbToRgb<T, P, tvec3>::call(tvec3<T, P>(ColorSRGB), Gamma), ColorSRGB.w);
+               }
+       };
+}//namespace detail
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> convertLinearToSRGB(vecType<T, P> const& ColorLinear)
+       {
+               return detail::compute_rgbToSrgb<T, P, vecType>::call(ColorLinear, static_cast<T>(0.41666));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> convertLinearToSRGB(vecType<T, P> const& ColorLinear, T Gamma)
+       {
+               return detail::compute_rgbToSrgb<T, P, vecType>::call(ColorLinear, static_cast<T>(1) / Gamma);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> convertSRGBToLinear(vecType<T, P> const& ColorSRGB)
+       {
+               return detail::compute_srgbToRgb<T, P, vecType>::call(ColorSRGB, static_cast<T>(2.4));
+       }
+       
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> convertSRGBToLinear(vecType<T, P> const& ColorSRGB, T Gamma)
+       {
+               return detail::compute_srgbToRgb<T, P, vecType>::call(ColorSRGB, Gamma);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/constants.hpp b/core/deps/glm/glm/gtc/constants.hpp
new file mode 100755 (executable)
index 0000000..d3358c7
--- /dev/null
@@ -0,0 +1,176 @@
+/// @ref gtc_constants
+/// @file glm/gtc/constants.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+///
+/// @defgroup gtc_constants GLM_GTC_constants
+/// @ingroup gtc
+/// 
+/// @brief Provide a list of constants and precomputed useful values.
+/// 
+/// <glm/gtc/constants.hpp> need to be included to use these features.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_constants extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_constants
+       /// @{
+
+       /// Return the epsilon constant for floating point types.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType epsilon();
+
+       /// Return 0.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType zero();
+
+       /// Return 1.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType one();
+
+       /// Return the pi constant.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType pi();
+
+       /// Return pi * 2.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType two_pi();
+
+       /// Return square root of pi.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_pi();
+
+       /// Return pi / 2.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType half_pi();
+
+       /// Return pi / 2 * 3.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType three_over_two_pi();
+
+       /// Return pi / 4.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType quarter_pi();
+
+       /// Return 1 / pi.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_pi();
+
+       /// Return 1 / (pi * 2).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_two_pi();
+
+       /// Return 2 / pi.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_pi();
+
+       /// Return 4 / pi.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType four_over_pi();
+
+       /// Return 2 / sqrt(pi).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType two_over_root_pi();
+
+       /// Return 1 / sqrt(2).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType one_over_root_two();
+
+       /// Return sqrt(pi / 2).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_half_pi();
+
+       /// Return sqrt(2 * pi).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_two_pi();
+
+       /// Return sqrt(ln(4)).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_ln_four();
+
+       /// Return e constant.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType e();
+
+       /// Return Euler's constant.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType euler();
+
+       /// Return sqrt(2).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_two();
+
+       /// Return sqrt(3).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_three();
+
+       /// Return sqrt(5).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType root_five();
+
+       /// Return ln(2).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType ln_two();
+
+       /// Return ln(10).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ten();
+
+       /// Return ln(ln(2)).
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType ln_ln_two();
+
+       /// Return 1 / 3.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType third();
+
+       /// Return 2 / 3.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType two_thirds();
+
+       /// Return the golden ratio constant.
+       /// @see gtc_constants
+       template <typename genType>
+       GLM_FUNC_DECL GLM_CONSTEXPR genType golden_ratio();
+
+       /// @}
+} //namespace glm
+
+#include "constants.inl"
diff --git a/core/deps/glm/glm/gtc/constants.inl b/core/deps/glm/glm/gtc/constants.inl
new file mode 100755 (executable)
index 0000000..cb451d0
--- /dev/null
@@ -0,0 +1,181 @@
+/// @ref gtc_constants
+/// @file glm/gtc/constants.inl
+
+#include <limits>
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType epsilon()
+       {
+               return std::numeric_limits<genType>::epsilon();
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType zero()
+       {
+               return genType(0);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one()
+       {
+               return genType(1);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType pi()
+       {
+               return genType(3.14159265358979323846264338327950288);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_pi()
+       {
+               return genType(6.28318530717958647692528676655900576);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_pi()
+       {
+               return genType(1.772453850905516027);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType half_pi()
+       {
+               return genType(1.57079632679489661923132169163975144);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType three_over_two_pi()
+       {
+               return genType(4.71238898038468985769396507491925432);           
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType quarter_pi()
+       {
+               return genType(0.785398163397448309615660845819875721);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_pi()
+       {
+               return genType(0.318309886183790671537767526745028724);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_two_pi()
+       {
+               return genType(0.159154943091895335768883763372514362);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_pi()
+       {
+               return genType(0.636619772367581343075535053490057448);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType four_over_pi()
+       {
+               return genType(1.273239544735162686151070106980114898);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_over_root_pi()
+       {
+               return genType(1.12837916709551257389615890312154517);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType one_over_root_two()
+       {
+               return genType(0.707106781186547524400844362104849039);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_half_pi()
+       {
+               return genType(1.253314137315500251);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two_pi()
+       {
+               return genType(2.506628274631000502);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_ln_four()
+       {
+               return genType(1.17741002251547469);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType e()
+       {
+               return genType(2.71828182845904523536);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType euler()
+       {
+               return genType(0.577215664901532860606);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_two()
+       {
+               return genType(1.41421356237309504880168872420969808);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_three()
+       {
+               return genType(1.73205080756887729352744634150587236);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType root_five()
+       {
+               return genType(2.23606797749978969640917366873127623);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_two()
+       {
+               return genType(0.693147180559945309417232121458176568);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ten()
+       {
+               return genType(2.30258509299404568401799145468436421);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType ln_ln_two()
+       {
+               return genType(-0.3665129205816643);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType third()
+       {
+               return genType(0.3333333333333333333333333333333333333333);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType two_thirds()
+       {
+               return genType(0.666666666666666666666666666666666666667);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR genType golden_ratio()
+       {
+               return genType(1.61803398874989484820458683436563811);
+       }
+} //namespace glm
diff --git a/core/deps/glm/glm/gtc/epsilon.hpp b/core/deps/glm/glm/gtc/epsilon.hpp
new file mode 100755 (executable)
index 0000000..289f5b7
--- /dev/null
@@ -0,0 +1,73 @@
+/// @ref gtc_epsilon
+/// @file glm/gtc/epsilon.hpp
+/// 
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtc_epsilon GLM_GTC_epsilon
+/// @ingroup gtc
+/// 
+/// @brief Comparison functions for a user defined epsilon values.
+/// 
+/// <glm/gtc/epsilon.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_epsilon extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_epsilon
+       /// @{
+
+       /// Returns the component-wise comparison of |x - y| < epsilon.
+       /// True if this expression is satisfied.
+       ///
+       /// @see gtc_epsilon
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> epsilonEqual(
+               vecType<T, P> const & x,
+               vecType<T, P> const & y,
+               T const & epsilon);
+
+       /// Returns the component-wise comparison of |x - y| < epsilon.
+       /// True if this expression is satisfied.
+       ///
+       /// @see gtc_epsilon
+       template <typename genType>
+       GLM_FUNC_DECL bool epsilonEqual(
+               genType const & x,
+               genType const & y,
+               genType const & epsilon);
+
+       /// Returns the component-wise comparison of |x - y| < epsilon.
+       /// True if this expression is not satisfied.
+       ///
+       /// @see gtc_epsilon
+       template <typename genType>
+       GLM_FUNC_DECL typename genType::boolType epsilonNotEqual(
+               genType const & x,
+               genType const & y,
+               typename genType::value_type const & epsilon);
+
+       /// Returns the component-wise comparison of |x - y| >= epsilon.
+       /// True if this expression is not satisfied.
+       ///
+       /// @see gtc_epsilon
+       template <typename genType>
+       GLM_FUNC_DECL bool epsilonNotEqual(
+               genType const & x,
+               genType const & y,
+               genType const & epsilon);
+
+       /// @}
+}//namespace glm
+
+#include "epsilon.inl"
diff --git a/core/deps/glm/glm/gtc/epsilon.inl b/core/deps/glm/glm/gtc/epsilon.inl
new file mode 100755 (executable)
index 0000000..b5577d9
--- /dev/null
@@ -0,0 +1,125 @@
+/// @ref gtc_epsilon
+/// @file glm/gtc/epsilon.inl
+
+// Dependency:
+#include "quaternion.hpp"
+#include "../vector_relational.hpp"
+#include "../common.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+
+namespace glm
+{
+       template <>
+       GLM_FUNC_QUALIFIER bool epsilonEqual
+       (
+               float const & x,
+               float const & y,
+               float const & epsilon
+       )
+       {
+               return abs(x - y) < epsilon;
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER bool epsilonEqual
+       (
+               double const & x,
+               double const & y,
+               double const & epsilon
+       )
+       {
+               return abs(x - y) < epsilon;
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER bool epsilonNotEqual
+       (
+               float const & x,
+               float const & y,
+               float const & epsilon
+       )
+       {
+               return abs(x - y) >= epsilon;
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER bool epsilonNotEqual
+       (
+               double const & x,
+               double const & y,
+               double const & epsilon
+       )
+       {
+               return abs(x - y) >= epsilon;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> epsilonEqual
+       (
+               vecType<T, P> const & x,
+               vecType<T, P> const & y,
+               T const & epsilon
+       )
+       {
+               return lessThan(abs(x - y), vecType<T, P>(epsilon));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> epsilonEqual
+       (
+               vecType<T, P> const & x,
+               vecType<T, P> const & y,
+               vecType<T, P> const & epsilon
+       )
+       {
+               return lessThan(abs(x - y), vecType<T, P>(epsilon));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> epsilonNotEqual
+       (
+               vecType<T, P> const & x,
+               vecType<T, P> const & y,
+               T const & epsilon
+       )
+       {
+               return greaterThanEqual(abs(x - y), vecType<T, P>(epsilon));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> epsilonNotEqual
+       (
+               vecType<T, P> const & x,
+               vecType<T, P> const & y,
+               vecType<T, P> const & epsilon
+       )
+       {
+               return greaterThanEqual(abs(x - y), vecType<T, P>(epsilon));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> epsilonEqual
+       (
+               tquat<T, P> const & x,
+               tquat<T, P> const & y,
+               T const & epsilon
+       )
+       {
+               tvec4<T, P> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);
+               return lessThan(abs(v), tvec4<T, P>(epsilon));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> epsilonNotEqual
+       (
+               tquat<T, P> const & x,
+               tquat<T, P> const & y,
+               T const & epsilon
+       )
+       {
+               tvec4<T, P> v(x.x - y.x, x.y - y.y, x.z - y.z, x.w - y.w);
+               return greaterThanEqual(abs(v), tvec4<T, P>(epsilon));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/functions.hpp b/core/deps/glm/glm/gtc/functions.hpp
new file mode 100755 (executable)
index 0000000..ab1590b
--- /dev/null
@@ -0,0 +1,53 @@
+/// @ref gtc_functions
+/// @file glm/gtc/functions.hpp
+/// 
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtc_functions GLM_GTC_functions
+/// @ingroup gtc
+/// 
+/// @brief List of useful common functions.
+/// 
+/// <glm/gtc/functions.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/type_vec2.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_functions extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_functions
+       /// @{
+
+       /// 1D gauss function
+       ///
+       /// @see gtc_epsilon
+       template <typename T>
+       GLM_FUNC_DECL T gauss(
+               T x,
+               T ExpectedValue,
+               T StandardDeviation);
+
+       /// 2D gauss function
+       ///
+       /// @see gtc_epsilon
+       template <typename T, precision P>
+       GLM_FUNC_DECL T gauss(
+               tvec2<T, P> const& Coord,
+               tvec2<T, P> const& ExpectedValue,
+               tvec2<T, P> const& StandardDeviation);
+
+       /// @}
+}//namespace glm
+
+#include "functions.inl"
+
diff --git a/core/deps/glm/glm/gtc/functions.inl b/core/deps/glm/glm/gtc/functions.inl
new file mode 100755 (executable)
index 0000000..1dbc496
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref gtc_functions
+/// @file glm/gtc/functions.inl
+
+#include "../detail/func_exponential.hpp"
+
+namespace glm
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER T gauss
+       (
+               T x,
+               T ExpectedValue,
+               T StandardDeviation
+       )
+       {
+               return exp(-((x - ExpectedValue) * (x - ExpectedValue)) / (static_cast<T>(2) * StandardDeviation * StandardDeviation)) / (StandardDeviation * sqrt(static_cast<T>(6.28318530717958647692528676655900576)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T gauss
+       (
+               tvec2<T, P> const& Coord,
+               tvec2<T, P> const& ExpectedValue,
+               tvec2<T, P> const& StandardDeviation
+       )
+       {
+               tvec2<T, P> const Squared = ((Coord - ExpectedValue) * (Coord - ExpectedValue)) / (static_cast<T>(2) * StandardDeviation * StandardDeviation);
+               return exp(-(Squared.x + Squared.y));
+       }
+}//namespace glm
+
diff --git a/core/deps/glm/glm/gtc/integer.hpp b/core/deps/glm/glm/gtc/integer.hpp
new file mode 100755 (executable)
index 0000000..69ffb1d
--- /dev/null
@@ -0,0 +1,102 @@
+/// @ref gtc_integer
+/// @file glm/gtc/integer.hpp
+///
+/// @see core (dependence)
+/// @see gtc_integer (dependence)
+///
+/// @defgroup gtc_integer GLM_GTC_integer
+/// @ingroup gtc
+///
+/// @brief Allow to perform bit operations on integer values
+///
+/// <glm/gtc/integer.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/func_common.hpp"
+#include "../detail/func_integer.hpp"
+#include "../detail/func_exponential.hpp"
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_integer extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_integer
+       /// @{
+
+       /// Returns the log2 of x for integer values. Can be reliably using to compute mipmap count from the texture size.
+       /// @see gtc_integer
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType log2(genIUType x);
+
+       /// Modulus. Returns x % y
+       /// for each component in x using the floating point value y.
+       ///
+       /// @tparam genIUType Integer-point scalar or vector types.
+       ///
+       /// @see gtc_integer
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml">GLSL mod man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType mod(genIUType x, genIUType y);
+
+       /// Modulus. Returns x % y
+       /// for each component in x using the floating point value y.
+       ///
+       /// @tparam T Integer scalar types.
+       /// @tparam vecType vector types.
+       ///
+       /// @see gtc_integer
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml">GLSL mod man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mod(vecType<T, P> const & x, T y);
+
+       /// Modulus. Returns x % y
+       /// for each component in x using the floating point value y.
+       ///
+       /// @tparam T Integer scalar types.
+       /// @tparam vecType vector types.
+       ///
+       /// @see gtc_integer
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml">GLSL mod man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> mod(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Returns a value equal to the nearest integer to x.
+       /// The fraction 0.5 will round in a direction chosen by the
+       /// implementation, presumably the direction that is fastest.
+       /// 
+       /// @param x The values of the argument must be greater or equal to zero.
+       /// @tparam T floating point scalar types.
+       /// @tparam vecType vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml">GLSL round man page</a>
+       /// @see gtc_integer
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<int, P> iround(vecType<T, P> const & x);
+
+       /// Returns a value equal to the nearest integer to x.
+       /// The fraction 0.5 will round in a direction chosen by the
+       /// implementation, presumably the direction that is fastest.
+       /// 
+       /// @param x The values of the argument must be greater or equal to zero.
+       /// @tparam T floating point scalar types.
+       /// @tparam vecType vector types.
+       /// 
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/round.xml">GLSL round man page</a>
+       /// @see gtc_integer
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<uint, P> uround(vecType<T, P> const & x);
+
+       /// @}
+} //namespace glm
+
+#include "integer.inl"
diff --git a/core/deps/glm/glm/gtc/integer.inl b/core/deps/glm/glm/gtc/integer.inl
new file mode 100755 (executable)
index 0000000..7ce2918
--- /dev/null
@@ -0,0 +1,71 @@
+/// @ref gtc_integer
+/// @file glm/gtc/integer.inl
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <typename, precision> class vecType, bool Aligned>
+       struct compute_log2<T, P, vecType, false, Aligned>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & vec)
+               {
+                       //Equivalent to return findMSB(vec); but save one function call in ASM with VC
+                       //return findMSB(vec);
+                       return vecType<T, P>(detail::compute_findMSB_vec<T, P, vecType, sizeof(T) * 8>::call(vec));
+               }
+       };
+
+#      if GLM_HAS_BITSCAN_WINDOWS
+               template <precision P, bool Aligned>
+               struct compute_log2<int, P, tvec4, false, Aligned>
+               {
+                       GLM_FUNC_QUALIFIER static tvec4<int, P> call(tvec4<int, P> const & vec)
+                       {
+                               tvec4<int, P> Result(glm::uninitialize);
+
+                               _BitScanReverse(reinterpret_cast<unsigned long*>(&Result.x), vec.x);
+                               _BitScanReverse(reinterpret_cast<unsigned long*>(&Result.y), vec.y);
+                               _BitScanReverse(reinterpret_cast<unsigned long*>(&Result.z), vec.z);
+                               _BitScanReverse(reinterpret_cast<unsigned long*>(&Result.w), vec.w);
+
+                               return Result;
+                       }
+               };
+#      endif//GLM_HAS_BITSCAN_WINDOWS
+}//namespace detail
+       template <typename genType>
+       GLM_FUNC_QUALIFIER int iround(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'iround' only accept floating-point inputs");
+               assert(static_cast<genType>(0.0) <= x);
+
+               return static_cast<int>(x + static_cast<genType>(0.5));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<int, P> iround(vecType<T, P> const& x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'iround' only accept floating-point inputs");
+               assert(all(lessThanEqual(vecType<T, P>(0), x)));
+
+               return vecType<int, P>(x + static_cast<T>(0.5));
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER uint uround(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'uround' only accept floating-point inputs");
+               assert(static_cast<genType>(0.0) <= x);
+
+               return static_cast<uint>(x + static_cast<genType>(0.5));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uint, P> uround(vecType<T, P> const& x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'uround' only accept floating-point inputs");
+               assert(all(lessThanEqual(vecType<T, P>(0), x)));
+
+               return vecType<uint, P>(x + static_cast<T>(0.5));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/matrix_access.hpp b/core/deps/glm/glm/gtc/matrix_access.hpp
new file mode 100755 (executable)
index 0000000..e4156ef
--- /dev/null
@@ -0,0 +1,59 @@
+/// @ref gtc_matrix_access
+/// @file glm/gtc/matrix_access.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_matrix_access GLM_GTC_matrix_access
+/// @ingroup gtc
+/// 
+/// Defines functions to access rows or columns of a matrix easily.
+/// <glm/gtc/matrix_access.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../detail/setup.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_matrix_access extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_matrix_access
+       /// @{
+
+       /// Get a specific row of a matrix.
+       /// @see gtc_matrix_access
+       template <typename genType>
+       GLM_FUNC_DECL typename genType::row_type row(
+               genType const & m,
+               length_t index);
+
+       /// Set a specific row to a matrix.
+       /// @see gtc_matrix_access
+       template <typename genType>
+       GLM_FUNC_DECL genType row(
+               genType const & m,
+               length_t index,
+               typename genType::row_type const & x);
+
+       /// Get a specific column of a matrix.
+       /// @see gtc_matrix_access
+       template <typename genType>
+       GLM_FUNC_DECL typename genType::col_type column(
+               genType const & m,
+               length_t index);
+
+       /// Set a specific column to a matrix.
+       /// @see gtc_matrix_access
+       template <typename genType>
+       GLM_FUNC_DECL genType column(
+               genType const & m,
+               length_t index,
+               typename genType::col_type const & x);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_access.inl"
diff --git a/core/deps/glm/glm/gtc/matrix_access.inl b/core/deps/glm/glm/gtc/matrix_access.inl
new file mode 100755 (executable)
index 0000000..831b940
--- /dev/null
@@ -0,0 +1,63 @@
+/// @ref gtc_matrix_access
+/// @file glm/gtc/matrix_access.inl
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType row
+       (
+               genType const & m,
+               length_t index,
+               typename genType::row_type const & x
+       )
+       {
+               assert(index >= 0 && index < m[0].length());
+
+               genType Result = m;
+               for(length_t i = 0; i < m.length(); ++i)
+                       Result[i][index] = x[i];
+               return Result;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER typename genType::row_type row
+       (
+               genType const & m,
+               length_t index
+       )
+       {
+               assert(index >= 0 && index < m[0].length());
+
+               typename genType::row_type Result;
+               for(length_t i = 0; i < m.length(); ++i)
+                       Result[i] = m[i][index];
+               return Result;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType column
+       (
+               genType const & m,
+               length_t index,
+               typename genType::col_type const & x
+       )
+       {
+               assert(index >= 0 && index < m.length());
+
+               genType Result = m;
+               Result[index] = x;
+               return Result;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER typename genType::col_type column
+       (
+               genType const & m,
+               length_t index
+       )
+       {
+               assert(index >= 0 && index < m.length());
+
+               return m[index];
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/matrix_integer.hpp b/core/deps/glm/glm/gtc/matrix_integer.hpp
new file mode 100755 (executable)
index 0000000..fdc816d
--- /dev/null
@@ -0,0 +1,486 @@
+/// @ref gtc_matrix_integer
+/// @file glm/gtc/matrix_integer.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_matrix_integer GLM_GTC_matrix_integer
+/// @ingroup gtc
+///
+/// Defines a number of matrices with integer types.
+/// <glm/gtc/matrix_integer.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../mat2x2.hpp"
+#include "../mat2x3.hpp"
+#include "../mat2x4.hpp"
+#include "../mat3x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat3x4.hpp"
+#include "../mat4x2.hpp"
+#include "../mat4x3.hpp"
+#include "../mat4x4.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_matrix_integer extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_matrix_integer
+       /// @{
+
+       /// High-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, highp>                             highp_imat2;
+
+       /// High-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, highp>                             highp_imat3;
+
+       /// High-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, highp>                             highp_imat4;
+
+       /// High-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, highp>                             highp_imat2x2;
+
+       /// High-precision signed integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<int, highp>                             highp_imat2x3;
+
+       /// High-precision signed integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<int, highp>                             highp_imat2x4;
+
+       /// High-precision signed integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<int, highp>                             highp_imat3x2;
+
+       /// High-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, highp>                             highp_imat3x3;
+
+       /// High-precision signed integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<int, highp>                             highp_imat3x4;
+
+       /// High-precision signed integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<int, highp>                             highp_imat4x2;
+
+       /// High-precision signed integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<int, highp>                             highp_imat4x3;
+
+       /// High-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, highp>                             highp_imat4x4;
+
+
+       /// Medium-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, mediump>                   mediump_imat2;
+
+       /// Medium-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, mediump>                   mediump_imat3;
+
+       /// Medium-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, mediump>                   mediump_imat4;
+
+
+       /// Medium-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, mediump>                   mediump_imat2x2;
+
+       /// Medium-precision signed integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<int, mediump>                   mediump_imat2x3;
+
+       /// Medium-precision signed integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<int, mediump>                   mediump_imat2x4;
+
+       /// Medium-precision signed integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<int, mediump>                   mediump_imat3x2;
+
+       /// Medium-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, mediump>                   mediump_imat3x3;
+
+       /// Medium-precision signed integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<int, mediump>                   mediump_imat3x4;
+
+       /// Medium-precision signed integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<int, mediump>                   mediump_imat4x2;
+
+       /// Medium-precision signed integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<int, mediump>                   mediump_imat4x3;
+
+       /// Medium-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, mediump>                   mediump_imat4x4;
+
+
+       /// Low-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, lowp>                              lowp_imat2;
+       
+       /// Low-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, lowp>                              lowp_imat3;
+
+       /// Low-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, lowp>                              lowp_imat4;
+
+
+       /// Low-precision signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<int, lowp>                              lowp_imat2x2;
+
+       /// Low-precision signed integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<int, lowp>                              lowp_imat2x3;
+
+       /// Low-precision signed integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<int, lowp>                              lowp_imat2x4;
+
+       /// Low-precision signed integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<int, lowp>                              lowp_imat3x2;
+
+       /// Low-precision signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<int, lowp>                              lowp_imat3x3;
+
+       /// Low-precision signed integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<int, lowp>                              lowp_imat3x4;
+
+       /// Low-precision signed integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<int, lowp>                              lowp_imat4x2;
+
+       /// Low-precision signed integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<int, lowp>                              lowp_imat4x3;
+
+       /// Low-precision signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<int, lowp>                              lowp_imat4x4;
+
+
+       /// High-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, highp>                            highp_umat2;    
+
+       /// High-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, highp>                            highp_umat3;
+
+       /// High-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, highp>                            highp_umat4;
+
+       /// High-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, highp>                            highp_umat2x2;
+
+       /// High-precision unsigned integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<uint, highp>                            highp_umat2x3;
+
+       /// High-precision unsigned integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<uint, highp>                            highp_umat2x4;
+
+       /// High-precision unsigned integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<uint, highp>                            highp_umat3x2;
+
+       /// High-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, highp>                            highp_umat3x3;
+
+       /// High-precision unsigned integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<uint, highp>                            highp_umat3x4;
+
+       /// High-precision unsigned integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<uint, highp>                            highp_umat4x2;
+
+       /// High-precision unsigned integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<uint, highp>                            highp_umat4x3;
+
+       /// High-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, highp>                            highp_umat4x4;
+
+
+       /// Medium-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, mediump>                  mediump_umat2;
+
+       /// Medium-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, mediump>                  mediump_umat3;
+
+       /// Medium-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, mediump>                  mediump_umat4;
+
+
+       /// Medium-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, mediump>                  mediump_umat2x2;
+
+       /// Medium-precision unsigned integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<uint, mediump>                  mediump_umat2x3;
+
+       /// Medium-precision unsigned integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<uint, mediump>                  mediump_umat2x4;
+
+       /// Medium-precision unsigned integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<uint, mediump>                  mediump_umat3x2;
+
+       /// Medium-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, mediump>                  mediump_umat3x3;
+
+       /// Medium-precision unsigned integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<uint, mediump>                  mediump_umat3x4;
+
+       /// Medium-precision unsigned integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<uint, mediump>                  mediump_umat4x2;
+
+       /// Medium-precision unsigned integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<uint, mediump>                  mediump_umat4x3;
+
+       /// Medium-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, mediump>                  mediump_umat4x4;
+
+
+       /// Low-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, lowp>                             lowp_umat2;
+       
+       /// Low-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, lowp>                             lowp_umat3;
+
+       /// Low-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, lowp>                             lowp_umat4;
+
+
+       /// Low-precision unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x2<uint, lowp>                             lowp_umat2x2;
+
+       /// Low-precision unsigned integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x3<uint, lowp>                             lowp_umat2x3;
+
+       /// Low-precision unsigned integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat2x4<uint, lowp>                             lowp_umat2x4;
+
+       /// Low-precision unsigned integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x2<uint, lowp>                             lowp_umat3x2;
+
+       /// Low-precision unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x3<uint, lowp>                             lowp_umat3x3;
+
+       /// Low-precision unsigned integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat3x4<uint, lowp>                             lowp_umat3x4;
+
+       /// Low-precision unsigned integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x2<uint, lowp>                             lowp_umat4x2;
+
+       /// Low-precision unsigned integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x3<uint, lowp>                             lowp_umat4x3;
+
+       /// Low-precision unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef tmat4x4<uint, lowp>                             lowp_umat4x4;
+
+#if(defined(GLM_PRECISION_HIGHP_INT))
+       typedef highp_imat2                                                             imat2;
+       typedef highp_imat3                                                             imat3;
+       typedef highp_imat4                                                             imat4;
+       typedef highp_imat2x2                                                   imat2x2;
+       typedef highp_imat2x3                                                   imat2x3;
+       typedef highp_imat2x4                                                   imat2x4;
+       typedef highp_imat3x2                                                   imat3x2;
+       typedef highp_imat3x3                                                   imat3x3;
+       typedef highp_imat3x4                                                   imat3x4;
+       typedef highp_imat4x2                                                   imat4x2;
+       typedef highp_imat4x3                                                   imat4x3;
+       typedef highp_imat4x4                                                   imat4x4;
+#elif(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_imat2                                                              imat2;
+       typedef lowp_imat3                                                              imat3;
+       typedef lowp_imat4                                                              imat4;
+       typedef lowp_imat2x2                                                    imat2x2;
+       typedef lowp_imat2x3                                                    imat2x3;
+       typedef lowp_imat2x4                                                    imat2x4;
+       typedef lowp_imat3x2                                                    imat3x2;
+       typedef lowp_imat3x3                                                    imat3x3;
+       typedef lowp_imat3x4                                                    imat3x4;
+       typedef lowp_imat4x2                                                    imat4x2;
+       typedef lowp_imat4x3                                                    imat4x3;
+       typedef lowp_imat4x4                                                    imat4x4;
+#else //if(defined(GLM_PRECISION_MEDIUMP_INT))
+
+       /// Signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat2                                                   imat2;
+
+       /// Signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat3                                                   imat3;
+
+       /// Signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat4                                                   imat4;
+
+       /// Signed integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat2x2                                                 imat2x2;
+
+       /// Signed integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat2x3                                                 imat2x3;
+
+       /// Signed integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat2x4                                                 imat2x4;
+
+       /// Signed integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat3x2                                                 imat3x2;
+
+       /// Signed integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat3x3                                                 imat3x3;
+
+       /// Signed integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat3x4                                                 imat3x4;
+
+       /// Signed integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat4x2                                                 imat4x2;
+
+       /// Signed integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat4x3                                                 imat4x3;
+
+       /// Signed integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_imat4x4                                                 imat4x4;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_HIGHP_UINT))
+       typedef highp_umat2                                                             umat2;
+       typedef highp_umat3                                                             umat3;
+       typedef highp_umat4                                                             umat4;
+       typedef highp_umat2x2                                                   umat2x2;
+       typedef highp_umat2x3                                                   umat2x3;
+       typedef highp_umat2x4                                                   umat2x4;
+       typedef highp_umat3x2                                                   umat3x2;
+       typedef highp_umat3x3                                                   umat3x3;
+       typedef highp_umat3x4                                                   umat3x4;
+       typedef highp_umat4x2                                                   umat4x2;
+       typedef highp_umat4x3                                                   umat4x3;
+       typedef highp_umat4x4                                                   umat4x4;
+#elif(defined(GLM_PRECISION_LOWP_UINT))
+       typedef lowp_umat2                                                              umat2;
+       typedef lowp_umat3                                                              umat3;
+       typedef lowp_umat4                                                              umat4;
+       typedef lowp_umat2x2                                                    umat2x2;
+       typedef lowp_umat2x3                                                    umat2x3;
+       typedef lowp_umat2x4                                                    umat2x4;
+       typedef lowp_umat3x2                                                    umat3x2;
+       typedef lowp_umat3x3                                                    umat3x3;
+       typedef lowp_umat3x4                                                    umat3x4;
+       typedef lowp_umat4x2                                                    umat4x2;
+       typedef lowp_umat4x3                                                    umat4x3;
+       typedef lowp_umat4x4                                                    umat4x4;
+#else //if(defined(GLM_PRECISION_MEDIUMP_UINT))
+       
+       /// Unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat2                                                   umat2;
+
+       /// Unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat3                                                   umat3;
+
+       /// Unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat4                                                   umat4;
+
+       /// Unsigned integer 2x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat2x2                                                 umat2x2;
+
+       /// Unsigned integer 2x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat2x3                                                 umat2x3;
+
+       /// Unsigned integer 2x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat2x4                                                 umat2x4;
+
+       /// Unsigned integer 3x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat3x2                                                 umat3x2;
+
+       /// Unsigned integer 3x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat3x3                                                 umat3x3;
+
+       /// Unsigned integer 3x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat3x4                                                 umat3x4;
+
+       /// Unsigned integer 4x2 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat4x2                                                 umat4x2;
+
+       /// Unsigned integer 4x3 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat4x3                                                 umat4x3;
+
+       /// Unsigned integer 4x4 matrix.
+       /// @see gtc_matrix_integer
+       typedef mediump_umat4x4                                                 umat4x4;
+#endif//GLM_PRECISION
+
+       /// @}
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/matrix_inverse.hpp b/core/deps/glm/glm/gtc/matrix_inverse.hpp
new file mode 100755 (executable)
index 0000000..589381d
--- /dev/null
@@ -0,0 +1,49 @@
+/// @ref gtc_matrix_inverse
+/// @file glm/gtc/matrix_inverse.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_matrix_inverse GLM_GTC_matrix_inverse
+/// @ingroup gtc
+///
+/// Defines additional matrix inverting functions.
+/// <glm/gtc/matrix_inverse.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../matrix.hpp"
+#include "../mat2x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat4x4.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_matrix_inverse extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_matrix_inverse
+       /// @{
+
+       /// Fast matrix inverse for affine matrix.
+       /// 
+       /// @param m Input matrix to invert.
+       /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-precision floating point value is highly innacurate.
+       /// @see gtc_matrix_inverse
+       template <typename genType> 
+       GLM_FUNC_DECL genType affineInverse(genType const & m);
+
+       /// Compute the inverse transpose of a matrix.
+       /// 
+       /// @param m Input matrix to invert transpose.
+       /// @tparam genType Squared floating-point matrix: half, float or double. Inverse of matrix based of half-precision floating point value is highly innacurate.
+       /// @see gtc_matrix_inverse
+       template <typename genType>
+       GLM_FUNC_DECL genType inverseTranspose(genType const & m);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_inverse.inl"
diff --git a/core/deps/glm/glm/gtc/matrix_inverse.inl b/core/deps/glm/glm/gtc/matrix_inverse.inl
new file mode 100755 (executable)
index 0000000..36c9bf7
--- /dev/null
@@ -0,0 +1,120 @@
+/// @ref gtc_matrix_inverse
+/// @file glm/gtc/matrix_inverse.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> affineInverse(tmat3x3<T, P> const & m)
+       {
+               tmat2x2<T, P> const Inv(inverse(tmat2x2<T, P>(m)));
+
+               return tmat3x3<T, P>(
+                       tvec3<T, P>(Inv[0], static_cast<T>(0)),
+                       tvec3<T, P>(Inv[1], static_cast<T>(0)),
+                       tvec3<T, P>(-Inv * tvec2<T, P>(m[2]), static_cast<T>(1)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> affineInverse(tmat4x4<T, P> const & m)
+       {
+               tmat3x3<T, P> const Inv(inverse(tmat3x3<T, P>(m)));
+
+               return tmat4x4<T, P>(
+                       tvec4<T, P>(Inv[0], static_cast<T>(0)),
+                       tvec4<T, P>(Inv[1], static_cast<T>(0)),
+                       tvec4<T, P>(Inv[2], static_cast<T>(0)),
+                       tvec4<T, P>(-Inv * tvec3<T, P>(m[3]), static_cast<T>(1)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> inverseTranspose(tmat2x2<T, P> const & m)
+       {
+               T Determinant = m[0][0] * m[1][1] - m[1][0] * m[0][1];
+
+               tmat2x2<T, P> Inverse(
+                       + m[1][1] / Determinant,
+                       - m[0][1] / Determinant,
+                       - m[1][0] / Determinant,
+                       + m[0][0] / Determinant);
+
+               return Inverse;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> inverseTranspose(tmat3x3<T, P> const & m)
+       {
+               T Determinant =
+                       + m[0][0] * (m[1][1] * m[2][2] - m[1][2] * m[2][1])
+                       - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0])
+                       + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]);
+
+               tmat3x3<T, P> Inverse(uninitialize);
+               Inverse[0][0] = + (m[1][1] * m[2][2] - m[2][1] * m[1][2]);
+               Inverse[0][1] = - (m[1][0] * m[2][2] - m[2][0] * m[1][2]);
+               Inverse[0][2] = + (m[1][0] * m[2][1] - m[2][0] * m[1][1]);
+               Inverse[1][0] = - (m[0][1] * m[2][2] - m[2][1] * m[0][2]);
+               Inverse[1][1] = + (m[0][0] * m[2][2] - m[2][0] * m[0][2]);
+               Inverse[1][2] = - (m[0][0] * m[2][1] - m[2][0] * m[0][1]);
+               Inverse[2][0] = + (m[0][1] * m[1][2] - m[1][1] * m[0][2]);
+               Inverse[2][1] = - (m[0][0] * m[1][2] - m[1][0] * m[0][2]);
+               Inverse[2][2] = + (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
+               Inverse /= Determinant;
+
+               return Inverse;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> inverseTranspose(tmat4x4<T, P> const & m)
+       {
+               T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               T SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+               T SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+               T SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+               T SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+               T SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+               T SubFactor11 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+               T SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+               T SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+               T SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+               T SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+               T SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+               T SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+               T SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+               tmat4x4<T, P> Inverse(uninitialize);
+               Inverse[0][0] = + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02);
+               Inverse[0][1] = - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04);
+               Inverse[0][2] = + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05);
+               Inverse[0][3] = - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05);
+
+               Inverse[1][0] = - (m[0][1] * SubFactor00 - m[0][2] * SubFactor01 + m[0][3] * SubFactor02);
+               Inverse[1][1] = + (m[0][0] * SubFactor00 - m[0][2] * SubFactor03 + m[0][3] * SubFactor04);
+               Inverse[1][2] = - (m[0][0] * SubFactor01 - m[0][1] * SubFactor03 + m[0][3] * SubFactor05);
+               Inverse[1][3] = + (m[0][0] * SubFactor02 - m[0][1] * SubFactor04 + m[0][2] * SubFactor05);
+
+               Inverse[2][0] = + (m[0][1] * SubFactor06 - m[0][2] * SubFactor07 + m[0][3] * SubFactor08);
+               Inverse[2][1] = - (m[0][0] * SubFactor06 - m[0][2] * SubFactor09 + m[0][3] * SubFactor10);
+               Inverse[2][2] = + (m[0][0] * SubFactor11 - m[0][1] * SubFactor09 + m[0][3] * SubFactor12);
+               Inverse[2][3] = - (m[0][0] * SubFactor08 - m[0][1] * SubFactor10 + m[0][2] * SubFactor12);
+
+               Inverse[3][0] = - (m[0][1] * SubFactor13 - m[0][2] * SubFactor14 + m[0][3] * SubFactor15);
+               Inverse[3][1] = + (m[0][0] * SubFactor13 - m[0][2] * SubFactor16 + m[0][3] * SubFactor17);
+               Inverse[3][2] = - (m[0][0] * SubFactor14 - m[0][1] * SubFactor16 + m[0][3] * SubFactor18);
+               Inverse[3][3] = + (m[0][0] * SubFactor15 - m[0][1] * SubFactor17 + m[0][2] * SubFactor18);
+
+               T Determinant =
+                       + m[0][0] * Inverse[0][0]
+                       + m[0][1] * Inverse[0][1]
+                       + m[0][2] * Inverse[0][2]
+                       + m[0][3] * Inverse[0][3];
+
+               Inverse /= Determinant;
+
+               return Inverse;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/matrix_transform.hpp b/core/deps/glm/glm/gtc/matrix_transform.hpp
new file mode 100755 (executable)
index 0000000..c97b89a
--- /dev/null
@@ -0,0 +1,465 @@
+/// @ref gtc_matrix_transform
+/// @file glm/gtc/matrix_transform.hpp
+///
+/// @see core (dependence)
+/// @see gtx_transform
+/// @see gtx_transform2
+/// 
+/// @defgroup gtc_matrix_transform GLM_GTC_matrix_transform
+/// @ingroup gtc
+///
+/// @brief Defines functions that generate common transformation matrices.
+///
+/// The matrices generated by this extension use standard OpenGL fixed-function
+/// conventions. For example, the lookAt function generates a transform from world
+/// space into the specific eye space that the projective matrix functions 
+/// (perspective, ortho, etc) are designed to expect. The OpenGL compatibility
+/// specifications defines the particular layout of this eye space.
+///
+/// <glm/gtc/matrix_transform.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../mat4x4.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../gtc/constants.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_matrix_transform extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_matrix_transform
+       /// @{
+
+       /// Builds a translation 4 * 4 matrix created from a vector of 3 components.
+       /// 
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param v Coordinates of a translation vector.
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @code
+       /// #include <glm/glm.hpp>
+       /// #include <glm/gtc/matrix_transform.hpp>
+       /// ...
+       /// glm::mat4 m = glm::translate(glm::mat4(1.0f), glm::vec3(1.0f));
+       /// // m[0][0] == 1.0f, m[0][1] == 0.0f, m[0][2] == 0.0f, m[0][3] == 0.0f
+       /// // m[1][0] == 0.0f, m[1][1] == 1.0f, m[1][2] == 0.0f, m[1][3] == 0.0f
+       /// // m[2][0] == 0.0f, m[2][1] == 0.0f, m[2][2] == 1.0f, m[2][3] == 0.0f
+       /// // m[3][0] == 1.0f, m[3][1] == 1.0f, m[3][2] == 1.0f, m[3][3] == 1.0f
+       /// @endcode
+       /// @see gtc_matrix_transform
+       /// @see - translate(tmat4x4<T, P> const & m, T x, T y, T z)
+       /// @see - translate(tvec3<T, P> const & v)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> translate(
+               tmat4x4<T, P> const & m,
+               tvec3<T, P> const & v);
+               
+       /// Builds a rotation 4 * 4 matrix created from an axis vector and an angle. 
+       /// 
+       /// @param m Input matrix multiplied by this rotation matrix.
+       /// @param angle Rotation angle expressed in radians.
+       /// @param axis Rotation axis, recommended to be normalized.
+       /// @tparam T Value type used to build the matrix. Supported: half, float or double.
+       /// @see gtc_matrix_transform
+       /// @see - rotate(tmat4x4<T, P> const & m, T angle, T x, T y, T z) 
+       /// @see - rotate(T angle, tvec3<T, P> const & v) 
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> rotate(
+               tmat4x4<T, P> const & m,
+               T angle,
+               tvec3<T, P> const & axis);
+
+       /// Builds a scale 4 * 4 matrix created from 3 scalars. 
+       /// 
+       /// @param m Input matrix multiplied by this scale matrix.
+       /// @param v Ratio of scaling for each axis.
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       /// @see - scale(tmat4x4<T, P> const & m, T x, T y, T z)
+       /// @see - scale(tvec3<T, P> const & v)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> scale(
+               tmat4x4<T, P> const & m,
+               tvec3<T, P> const & v);
+
+       /// Creates a matrix for an orthographic parallel viewing volume, using the default handedness.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param zNear
+       /// @param zFar
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       /// @see - glm::ortho(T const & left, T const & right, T const & bottom, T const & top)
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> ortho(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T zNear,
+               T zFar);
+
+       /// Creates a matrix for an orthographic parallel viewing volume, using left-handedness.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param zNear
+       /// @param zFar
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       /// @see - glm::ortho(T const & left, T const & right, T const & bottom, T const & top)
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> orthoLH(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T zNear,
+               T zFar);
+
+       /// Creates a matrix for an orthographic parallel viewing volume, using right-handedness.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param zNear
+       /// @param zFar
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       /// @see - glm::ortho(T const & left, T const & right, T const & bottom, T const & top)
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> orthoRH(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T zNear,
+               T zFar);
+
+       /// Creates a matrix for projecting two-dimensional coordinates onto the screen.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       /// @see - glm::ortho(T const & left, T const & right, T const & bottom, T const & top, T const & zNear, T const & zFar)
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> ortho(
+               T left,
+               T right,
+               T bottom,
+               T top);
+
+       /// Creates a frustum matrix with default handedness.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param near
+       /// @param far
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> frustum(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T near,
+               T far);
+
+       /// Creates a left handed frustum matrix.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param near
+       /// @param far
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> frustumLH(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T near,
+               T far);
+
+       /// Creates a right handed frustum matrix.
+       ///
+       /// @param left
+       /// @param right
+       /// @param bottom
+       /// @param top
+       /// @param near
+       /// @param far
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> frustumRH(
+               T left,
+               T right,
+               T bottom,
+               T top,
+               T near,
+               T far);
+
+       /// Creates a matrix for a symetric perspective-view frustum based on the default handedness.
+       /// 
+       /// @param fovy Specifies the field of view angle in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspective(
+               T fovy,
+               T aspect,
+               T near,
+               T far);
+
+       /// Creates a matrix for a right handed, symetric perspective-view frustum.
+       /// 
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspectiveRH(
+               T fovy,
+               T aspect,
+               T near,
+               T far);
+
+       /// Creates a matrix for a left handed, symetric perspective-view frustum.
+       /// 
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspectiveLH(
+               T fovy,
+               T aspect,
+               T near,
+               T far);
+
+       /// Builds a perspective projection matrix based on a field of view and the default handedness.
+       /// 
+       /// @param fov Expressed in radians.
+       /// @param width 
+       /// @param height 
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspectiveFov(
+               T fov,
+               T width,
+               T height,
+               T near,
+               T far);
+
+       /// Builds a right handed perspective projection matrix based on a field of view.
+       /// 
+       /// @param fov Expressed in radians.
+       /// @param width 
+       /// @param height 
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspectiveFovRH(
+               T fov,
+               T width,
+               T height,
+               T near,
+               T far);
+
+       /// Builds a left handed perspective projection matrix based on a field of view.
+       /// 
+       /// @param fov Expressed in radians.
+       /// @param width 
+       /// @param height 
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param far Specifies the distance from the viewer to the far clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> perspectiveFovLH(
+               T fov,
+               T width,
+               T height,
+               T near,
+               T far);
+
+       /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite with default handedness.
+       ///
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> infinitePerspective(
+               T fovy, T aspect, T near);
+
+       /// Creates a matrix for a left handed, symmetric perspective-view frustum with far plane at infinite.
+       ///
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> infinitePerspectiveLH(
+               T fovy, T aspect, T near);
+
+       /// Creates a matrix for a right handed, symmetric perspective-view frustum with far plane at infinite.
+       ///
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> infinitePerspectiveRH(
+               T fovy, T aspect, T near);
+
+       /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping.
+       /// 
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> tweakedInfinitePerspective(
+               T fovy, T aspect, T near);
+
+       /// Creates a matrix for a symmetric perspective-view frustum with far plane at infinite for graphics hardware that doesn't support depth clamping.
+       /// 
+       /// @param fovy Specifies the field of view angle, in degrees, in the y direction. Expressed in radians.
+       /// @param aspect Specifies the aspect ratio that determines the field of view in the x direction. The aspect ratio is the ratio of x (width) to y (height).
+       /// @param near Specifies the distance from the viewer to the near clipping plane (always positive).
+       /// @param ep 
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// @see gtc_matrix_transform
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> tweakedInfinitePerspective(
+               T fovy, T aspect, T near, T ep);
+
+       /// Map the specified object coordinates (obj.x, obj.y, obj.z) into window coordinates.
+       /// 
+       /// @param obj Specify the object coordinates.
+       /// @param model Specifies the current modelview matrix
+       /// @param proj Specifies the current projection matrix
+       /// @param viewport Specifies the current viewport
+       /// @return Return the computed window coordinates.
+       /// @tparam T Native type used for the computation. Currently supported: half (not recommanded), float or double.
+       /// @tparam U Currently supported: Floating-point types and integer types.
+       /// @see gtc_matrix_transform
+       template <typename T, typename U, precision P>
+       GLM_FUNC_DECL tvec3<T, P> project(
+               tvec3<T, P> const & obj,
+               tmat4x4<T, P> const & model,
+               tmat4x4<T, P> const & proj,
+               tvec4<U, P> const & viewport);
+
+       /// Map the specified window coordinates (win.x, win.y, win.z) into object coordinates.
+       ///
+       /// @param win Specify the window coordinates to be mapped.
+       /// @param model Specifies the modelview matrix
+       /// @param proj Specifies the projection matrix
+       /// @param viewport Specifies the viewport
+       /// @return Returns the computed object coordinates.
+       /// @tparam T Native type used for the computation. Currently supported: half (not recommanded), float or double.
+       /// @tparam U Currently supported: Floating-point types and integer types.
+       /// @see gtc_matrix_transform
+       template <typename T, typename U, precision P>
+       GLM_FUNC_DECL tvec3<T, P> unProject(
+               tvec3<T, P> const & win,
+               tmat4x4<T, P> const & model,
+               tmat4x4<T, P> const & proj,
+               tvec4<U, P> const & viewport);
+
+       /// Define a picking region
+       ///
+       /// @param center
+       /// @param delta
+       /// @param viewport
+       /// @tparam T Native type used for the computation. Currently supported: half (not recommanded), float or double.
+       /// @tparam U Currently supported: Floating-point types and integer types.
+       /// @see gtc_matrix_transform
+       template <typename T, precision P, typename U>
+       GLM_FUNC_DECL tmat4x4<T, P> pickMatrix(
+               tvec2<T, P> const & center,
+               tvec2<T, P> const & delta,
+               tvec4<U, P> const & viewport);
+
+       /// Build a look at view matrix based on the default handedness.
+       ///
+       /// @param eye Position of the camera
+       /// @param center Position where the camera is looking at
+       /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)
+       /// @see gtc_matrix_transform
+       /// @see - frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal) frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> lookAt(
+               tvec3<T, P> const & eye,
+               tvec3<T, P> const & center,
+               tvec3<T, P> const & up);
+
+       /// Build a right handed look at view matrix.
+       ///
+       /// @param eye Position of the camera
+       /// @param center Position where the camera is looking at
+       /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)
+       /// @see gtc_matrix_transform
+       /// @see - frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal) frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> lookAtRH(
+               tvec3<T, P> const & eye,
+               tvec3<T, P> const & center,
+               tvec3<T, P> const & up);
+
+       /// Build a left handed look at view matrix.
+       ///
+       /// @param eye Position of the camera
+       /// @param center Position where the camera is looking at
+       /// @param up Normalized up vector, how the camera is oriented. Typically (0, 0, 1)
+       /// @see gtc_matrix_transform
+       /// @see - frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal) frustum(T const & left, T const & right, T const & bottom, T const & top, T const & nearVal, T const & farVal)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> lookAtLH(
+               tvec3<T, P> const & eye,
+               tvec3<T, P> const & center,
+               tvec3<T, P> const & up);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_transform.inl"
diff --git a/core/deps/glm/glm/gtc/matrix_transform.inl b/core/deps/glm/glm/gtc/matrix_transform.inl
new file mode 100755 (executable)
index 0000000..b9ff418
--- /dev/null
@@ -0,0 +1,575 @@
+/// @ref gtc_matrix_transform
+/// @file glm/gtc/matrix_transform.inl
+
+#include "../geometric.hpp"
+#include "../trigonometric.hpp"
+#include "../matrix.hpp"
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> translate(tmat4x4<T, P> const & m, tvec3<T, P> const & v)
+       {
+               tmat4x4<T, P> Result(m);
+               Result[3] = m[0] * v[0] + m[1] * v[1] + m[2] * v[2] + m[3];
+               return Result;
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rotate(tmat4x4<T, P> const & m, T angle, tvec3<T, P> const & v)
+       {
+               T const a = angle;
+               T const c = cos(a);
+               T const s = sin(a);
+
+               tvec3<T, P> axis(normalize(v));
+               tvec3<T, P> temp((T(1) - c) * axis);
+
+               tmat4x4<T, P> Rotate(uninitialize);
+               Rotate[0][0] = c + temp[0] * axis[0];
+               Rotate[0][1] = temp[0] * axis[1] + s * axis[2];
+               Rotate[0][2] = temp[0] * axis[2] - s * axis[1];
+
+               Rotate[1][0] = temp[1] * axis[0] - s * axis[2];
+               Rotate[1][1] = c + temp[1] * axis[1];
+               Rotate[1][2] = temp[1] * axis[2] + s * axis[0];
+
+               Rotate[2][0] = temp[2] * axis[0] + s * axis[1];
+               Rotate[2][1] = temp[2] * axis[1] - s * axis[0];
+               Rotate[2][2] = c + temp[2] * axis[2];
+
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
+               Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
+               Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
+               Result[3] = m[3];
+               return Result;
+       }
+               
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rotate_slow(tmat4x4<T, P> const & m, T angle, tvec3<T, P> const & v)
+       {
+               T const a = angle;
+               T const c = cos(a);
+               T const s = sin(a);
+               tmat4x4<T, P> Result;
+
+               tvec3<T, P> axis = normalize(v);
+
+               Result[0][0] = c + (static_cast<T>(1) - c)      * axis.x     * axis.x;
+               Result[0][1] = (static_cast<T>(1) - c) * axis.x * axis.y + s * axis.z;
+               Result[0][2] = (static_cast<T>(1) - c) * axis.x * axis.z - s * axis.y;
+               Result[0][3] = static_cast<T>(0);
+
+               Result[1][0] = (static_cast<T>(1) - c) * axis.y * axis.x - s * axis.z;
+               Result[1][1] = c + (static_cast<T>(1) - c) * axis.y * axis.y;
+               Result[1][2] = (static_cast<T>(1) - c) * axis.y * axis.z + s * axis.x;
+               Result[1][3] = static_cast<T>(0);
+
+               Result[2][0] = (static_cast<T>(1) - c) * axis.z * axis.x + s * axis.y;
+               Result[2][1] = (static_cast<T>(1) - c) * axis.z * axis.y - s * axis.x;
+               Result[2][2] = c + (static_cast<T>(1) - c) * axis.z * axis.z;
+               Result[2][3] = static_cast<T>(0);
+
+               Result[3] = tvec4<T, P>(0, 0, 0, 1);
+               return m * Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> scale(tmat4x4<T, P> const & m, tvec3<T, P> const & v)
+       {
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0] = m[0] * v[0];
+               Result[1] = m[1] * v[1];
+               Result[2] = m[2] * v[2];
+               Result[3] = m[3];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> scale_slow(tmat4x4<T, P> const & m, tvec3<T, P> const & v)
+       {
+               tmat4x4<T, P> Result(T(1));
+               Result[0][0] = v.x;
+               Result[1][1] = v.y;
+               Result[2][2] = v.z;
+               return m * Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> ortho
+       (
+               T left, T right,
+               T bottom, T top,
+               T zNear, T zFar
+       )
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return orthoLH(left, right, bottom, top, zNear, zFar);
+#              else
+                       return orthoRH(left, right, bottom, top, zNear, zFar);
+#              endif
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> orthoLH
+       (
+               T left, T right,
+               T bottom, T top,
+               T zNear, T zFar
+       )
+       {
+               tmat4x4<T, defaultp> Result(1);
+               Result[0][0] = static_cast<T>(2) / (right - left);
+               Result[1][1] = static_cast<T>(2) / (top - bottom);
+               Result[3][0] = - (right + left) / (right - left);
+               Result[3][1] = - (top + bottom) / (top - bottom);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = static_cast<T>(1) / (zFar - zNear);
+                       Result[3][2] = - zNear / (zFar - zNear);
+#              else
+                       Result[2][2] = static_cast<T>(2) / (zFar - zNear);
+                       Result[3][2] = - (zFar + zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> orthoRH
+       (
+               T left, T right,
+               T bottom, T top,
+               T zNear, T zFar
+       )
+       {
+               tmat4x4<T, defaultp> Result(1);
+               Result[0][0] = static_cast<T>(2) / (right - left);
+               Result[1][1] = static_cast<T>(2) / (top - bottom);
+               Result[3][0] = - (right + left) / (right - left);
+               Result[3][1] = - (top + bottom) / (top - bottom);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = - static_cast<T>(1) / (zFar - zNear);
+                       Result[3][2] = - zNear / (zFar - zNear);
+#              else
+                       Result[2][2] = - static_cast<T>(2) / (zFar - zNear);
+                       Result[3][2] = - (zFar + zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> ortho
+       (
+               T left, T right,
+               T bottom, T top
+       )
+       {
+               tmat4x4<T, defaultp> Result(static_cast<T>(1));
+               Result[0][0] = static_cast<T>(2) / (right - left);
+               Result[1][1] = static_cast<T>(2) / (top - bottom);
+               Result[2][2] = - static_cast<T>(1);
+               Result[3][0] = - (right + left) / (right - left);
+               Result[3][1] = - (top + bottom) / (top - bottom);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> frustum
+       (
+               T left, T right,
+               T bottom, T top,
+               T nearVal, T farVal
+       )
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return frustumLH(left, right, bottom, top, nearVal, farVal);
+#              else
+                       return frustumRH(left, right, bottom, top, nearVal, farVal);
+#              endif
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> frustumLH
+       (
+               T left, T right,
+               T bottom, T top,
+               T nearVal, T farVal
+       )
+       {
+               tmat4x4<T, defaultp> Result(0);
+               Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
+               Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
+               Result[2][0] = (right + left) / (right - left);
+               Result[2][1] = (top + bottom) / (top - bottom);
+               Result[2][3] = static_cast<T>(1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = farVal / (farVal - nearVal);
+                       Result[3][2] = -(farVal * nearVal) / (farVal - nearVal);
+#              else
+                       Result[2][2] = (farVal + nearVal) / (farVal - nearVal);
+                       Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> frustumRH
+       (
+               T left, T right,
+               T bottom, T top,
+               T nearVal, T farVal
+       )
+       {
+               tmat4x4<T, defaultp> Result(0);
+               Result[0][0] = (static_cast<T>(2) * nearVal) / (right - left);
+               Result[1][1] = (static_cast<T>(2) * nearVal) / (top - bottom);
+               Result[2][0] = (right + left) / (right - left);
+               Result[2][1] = (top + bottom) / (top - bottom);
+               Result[2][3] = static_cast<T>(-1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = farVal / (nearVal - farVal);
+                       Result[3][2] = -(farVal * nearVal) / (farVal - nearVal);
+#              else
+                       Result[2][2] = - (farVal + nearVal) / (farVal - nearVal);
+                       Result[3][2] = - (static_cast<T>(2) * farVal * nearVal) / (farVal - nearVal);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspective(T fovy, T aspect, T zNear, T zFar)
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return perspectiveLH(fovy, aspect, zNear, zFar);
+#              else
+                       return perspectiveRH(fovy, aspect, zNear, zFar);
+#              endif
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspectiveRH(T fovy, T aspect, T zNear, T zFar)
+       {
+               assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
+
+               T const tanHalfFovy = tan(fovy / static_cast<T>(2));
+
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
+               Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
+               Result[2][3] = - static_cast<T>(1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = zFar / (zNear - zFar);
+                       Result[3][2] = -(zFar * zNear) / (zFar - zNear);
+#              else
+                       Result[2][2] = - (zFar + zNear) / (zFar - zNear);
+                       Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+       
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspectiveLH(T fovy, T aspect, T zNear, T zFar)
+       {
+               assert(abs(aspect - std::numeric_limits<T>::epsilon()) > static_cast<T>(0));
+
+               T const tanHalfFovy = tan(fovy / static_cast<T>(2));
+               
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = static_cast<T>(1) / (aspect * tanHalfFovy);
+               Result[1][1] = static_cast<T>(1) / (tanHalfFovy);
+               Result[2][3] = static_cast<T>(1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = zFar / (zFar - zNear);
+                       Result[3][2] = -(zFar * zNear) / (zFar - zNear);
+#              else
+                       Result[2][2] = (zFar + zNear) / (zFar - zNear);
+                       Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspectiveFov(T fov, T width, T height, T zNear, T zFar)
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return perspectiveFovLH(fov, width, height, zNear, zFar);
+#              else
+                       return perspectiveFovRH(fov, width, height, zNear, zFar);
+#              endif
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspectiveFovRH(T fov, T width, T height, T zNear, T zFar)
+       {
+               assert(width > static_cast<T>(0));
+               assert(height > static_cast<T>(0));
+               assert(fov > static_cast<T>(0));
+       
+               T const rad = fov;
+               T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
+               T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
+
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = w;
+               Result[1][1] = h;
+               Result[2][3] = - static_cast<T>(1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = zFar / (zNear - zFar);
+                       Result[3][2] = -(zFar * zNear) / (zFar - zNear);
+#              else
+                       Result[2][2] = - (zFar + zNear) / (zFar - zNear);
+                       Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> perspectiveFovLH(T fov, T width, T height, T zNear, T zFar)
+       {
+               assert(width > static_cast<T>(0));
+               assert(height > static_cast<T>(0));
+               assert(fov > static_cast<T>(0));
+       
+               T const rad = fov;
+               T const h = glm::cos(static_cast<T>(0.5) * rad) / glm::sin(static_cast<T>(0.5) * rad);
+               T const w = h * height / width; ///todo max(width , Height) / min(width , Height)?
+
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = w;
+               Result[1][1] = h;
+               Result[2][3] = static_cast<T>(1);
+
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       Result[2][2] = zFar / (zFar - zNear);
+                       Result[3][2] = -(zFar * zNear) / (zFar - zNear);
+#              else
+                       Result[2][2] = (zFar + zNear) / (zFar - zNear);
+                       Result[3][2] = - (static_cast<T>(2) * zFar * zNear) / (zFar - zNear);
+#              endif
+
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> infinitePerspective(T fovy, T aspect, T zNear)
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return infinitePerspectiveLH(fovy, aspect, zNear);
+#              else
+                       return infinitePerspectiveRH(fovy, aspect, zNear);
+#              endif
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> infinitePerspectiveRH(T fovy, T aspect, T zNear)
+       {
+               T const range = tan(fovy / static_cast<T>(2)) * zNear;
+               T const left = -range * aspect;
+               T const right = range * aspect;
+               T const bottom = -range;
+               T const top = range;
+
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
+               Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
+               Result[2][2] = - static_cast<T>(1);
+               Result[2][3] = - static_cast<T>(1);
+               Result[3][2] = - static_cast<T>(2) * zNear;
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> infinitePerspectiveLH(T fovy, T aspect, T zNear)
+       {
+               T const range = tan(fovy / static_cast<T>(2)) * zNear;
+               T const left = -range * aspect;
+               T const right = range * aspect;
+               T const bottom = -range;
+               T const top = range;
+
+               tmat4x4<T, defaultp> Result(T(0));
+               Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
+               Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
+               Result[2][2] = static_cast<T>(1);
+               Result[2][3] = static_cast<T>(1);
+               Result[3][2] = - static_cast<T>(2) * zNear;
+               return Result;
+       }
+
+       // Infinite projection matrix: http://www.terathon.com/gdc07_lengyel.pdf
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear, T ep)
+       {
+               T const range = tan(fovy / static_cast<T>(2)) * zNear;  
+               T const left = -range * aspect;
+               T const right = range * aspect;
+               T const bottom = -range;
+               T const top = range;
+
+               tmat4x4<T, defaultp> Result(static_cast<T>(0));
+               Result[0][0] = (static_cast<T>(2) * zNear) / (right - left);
+               Result[1][1] = (static_cast<T>(2) * zNear) / (top - bottom);
+               Result[2][2] = ep - static_cast<T>(1);
+               Result[2][3] = static_cast<T>(-1);
+               Result[3][2] = (ep - static_cast<T>(2)) * zNear;
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> tweakedInfinitePerspective(T fovy, T aspect, T zNear)
+       {
+               return tweakedInfinitePerspective(fovy, aspect, zNear, epsilon<T>());
+       }
+
+       template <typename T, typename U, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> project
+       (
+               tvec3<T, P> const & obj,
+               tmat4x4<T, P> const & model,
+               tmat4x4<T, P> const & proj,
+               tvec4<U, P> const & viewport
+       )
+       {
+               tvec4<T, P> tmp = tvec4<T, P>(obj, static_cast<T>(1));
+               tmp = model * tmp;
+               tmp = proj * tmp;
+
+               tmp /= tmp.w;
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       tmp.x = tmp.x * static_cast<T>(0.5) + static_cast<T>(0.5);
+                       tmp.y = tmp.y * static_cast<T>(0.5) + static_cast<T>(0.5);
+#              else
+                       tmp = tmp * static_cast<T>(0.5) + static_cast<T>(0.5);
+#              endif
+               tmp[0] = tmp[0] * T(viewport[2]) + T(viewport[0]);
+               tmp[1] = tmp[1] * T(viewport[3]) + T(viewport[1]);
+
+               return tvec3<T, P>(tmp);
+       }
+
+       template <typename T, typename U, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> unProject
+       (
+               tvec3<T, P> const & win,
+               tmat4x4<T, P> const & model,
+               tmat4x4<T, P> const & proj,
+               tvec4<U, P> const & viewport
+       )
+       {
+               tmat4x4<T, P> Inverse = inverse(proj * model);
+
+               tvec4<T, P> tmp = tvec4<T, P>(win, T(1));
+               tmp.x = (tmp.x - T(viewport[0])) / T(viewport[2]);
+               tmp.y = (tmp.y - T(viewport[1])) / T(viewport[3]);
+#              if GLM_DEPTH_CLIP_SPACE == GLM_DEPTH_ZERO_TO_ONE
+                       tmp.x = tmp.x * static_cast<T>(2) - static_cast<T>(1);
+                       tmp.y = tmp.y * static_cast<T>(2) - static_cast<T>(1);
+#              else
+                       tmp = tmp * static_cast<T>(2) - static_cast<T>(1);
+#              endif
+
+               tvec4<T, P> obj = Inverse * tmp;
+               obj /= obj.w;
+
+               return tvec3<T, P>(obj);
+       }
+
+       template <typename T, precision P, typename U>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> pickMatrix(tvec2<T, P> const & center, tvec2<T, P> const & delta, tvec4<U, P> const & viewport)
+       {
+               assert(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0));
+               tmat4x4<T, P> Result(static_cast<T>(1));
+
+               if(!(delta.x > static_cast<T>(0) && delta.y > static_cast<T>(0)))
+                       return Result; // Error
+
+               tvec3<T, P> Temp(
+                       (static_cast<T>(viewport[2]) - static_cast<T>(2) * (center.x - static_cast<T>(viewport[0]))) / delta.x,
+                       (static_cast<T>(viewport[3]) - static_cast<T>(2) * (center.y - static_cast<T>(viewport[1]))) / delta.y,
+                       static_cast<T>(0));
+
+               // Translate and scale the picked region to the entire window
+               Result = translate(Result, Temp);
+               return scale(Result, tvec3<T, P>(static_cast<T>(viewport[2]) / delta.x, static_cast<T>(viewport[3]) / delta.y, static_cast<T>(1)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> lookAt(tvec3<T, P> const & eye, tvec3<T, P> const & center, tvec3<T, P> const & up)
+       {
+#              if GLM_COORDINATE_SYSTEM == GLM_LEFT_HANDED
+                       return lookAtLH(eye, center, up);
+#              else
+                       return lookAtRH(eye, center, up);
+#              endif
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> lookAtRH
+       (
+               tvec3<T, P> const & eye,
+               tvec3<T, P> const & center,
+               tvec3<T, P> const & up
+       )
+       {
+               tvec3<T, P> const f(normalize(center - eye));
+               tvec3<T, P> const s(normalize(cross(f, up)));
+               tvec3<T, P> const u(cross(s, f));
+
+               tmat4x4<T, P> Result(1);
+               Result[0][0] = s.x;
+               Result[1][0] = s.y;
+               Result[2][0] = s.z;
+               Result[0][1] = u.x;
+               Result[1][1] = u.y;
+               Result[2][1] = u.z;
+               Result[0][2] =-f.x;
+               Result[1][2] =-f.y;
+               Result[2][2] =-f.z;
+               Result[3][0] =-dot(s, eye);
+               Result[3][1] =-dot(u, eye);
+               Result[3][2] = dot(f, eye);
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> lookAtLH
+       (
+               tvec3<T, P> const & eye,
+               tvec3<T, P> const & center,
+               tvec3<T, P> const & up
+       )
+       {
+               tvec3<T, P> const f(normalize(center - eye));
+               tvec3<T, P> const s(normalize(cross(up, f)));
+               tvec3<T, P> const u(cross(f, s));
+
+               tmat4x4<T, P> Result(1);
+               Result[0][0] = s.x;
+               Result[1][0] = s.y;
+               Result[2][0] = s.z;
+               Result[0][1] = u.x;
+               Result[1][1] = u.y;
+               Result[2][1] = u.z;
+               Result[0][2] = f.x;
+               Result[1][2] = f.y;
+               Result[2][2] = f.z;
+               Result[3][0] = -dot(s, eye);
+               Result[3][1] = -dot(u, eye);
+               Result[3][2] = -dot(f, eye);
+               return Result;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/noise.hpp b/core/deps/glm/glm/gtc/noise.hpp
new file mode 100755 (executable)
index 0000000..aec4f18
--- /dev/null
@@ -0,0 +1,60 @@
+/// @ref gtc_noise
+/// @file glm/gtc/noise.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_noise GLM_GTC_noise
+/// @ingroup gtc
+///
+/// Defines 2D, 3D and 4D procedural noise functions 
+/// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": 
+/// https://github.com/ashima/webgl-noise 
+/// Following Stefan Gustavson's paper "Simplex noise demystified": 
+/// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
+/// <glm/gtc/noise.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/_noise.hpp"
+#include "../geometric.hpp"
+#include "../common.hpp"
+#include "../vector_relational.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_noise extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_noise
+       /// @{
+
+       /// Classic perlin noise.
+       /// @see gtc_noise
+       template <typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_DECL T perlin(
+               vecType<T, P> const & p);
+               
+       /// Periodic perlin noise.
+       /// @see gtc_noise
+       template <typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_DECL T perlin(
+               vecType<T, P> const & p,
+               vecType<T, P> const & rep);
+
+       /// Simplex noise.
+       /// @see gtc_noise
+       template <typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_DECL T simplex(
+               vecType<T, P> const & p);
+
+       /// @}
+}//namespace glm
+
+#include "noise.inl"
diff --git a/core/deps/glm/glm/gtc/noise.inl b/core/deps/glm/glm/gtc/noise.inl
new file mode 100755 (executable)
index 0000000..4f2731c
--- /dev/null
@@ -0,0 +1,808 @@
+/// @ref gtc_noise
+/// @file glm/gtc/noise.inl
+///
+// Based on the work of Stefan Gustavson and Ashima Arts on "webgl-noise": 
+// https://github.com/ashima/webgl-noise 
+// Following Stefan Gustavson's paper "Simplex noise demystified": 
+// http://www.itn.liu.se/~stegu/simplexnoise/simplexnoise.pdf
+
+namespace glm{
+namespace gtc
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> grad4(T const & j, tvec4<T, P> const & ip)
+       {
+               tvec3<T, P> pXYZ = floor(fract(tvec3<T, P>(j) * tvec3<T, P>(ip)) * T(7)) * ip[2] - T(1);
+               T pW = static_cast<T>(1.5) - dot(abs(pXYZ), tvec3<T, P>(1));
+               tvec4<T, P> s = tvec4<T, P>(lessThan(tvec4<T, P>(pXYZ, pW), tvec4<T, P>(0.0)));
+               pXYZ = pXYZ + (tvec3<T, P>(s) * T(2) - T(1)) * s.w; 
+               return tvec4<T, P>(pXYZ, pW);
+       }
+}//namespace gtc
+
+       // Classic Perlin noise
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec2<T, P> const & Position)
+       {
+               tvec4<T, P> Pi = glm::floor(tvec4<T, P>(Position.x, Position.y, Position.x, Position.y)) + tvec4<T, P>(0.0, 0.0, 1.0, 1.0);
+               tvec4<T, P> Pf = glm::fract(tvec4<T, P>(Position.x, Position.y, Position.x, Position.y)) - tvec4<T, P>(0.0, 0.0, 1.0, 1.0);
+               Pi = mod(Pi, tvec4<T, P>(289)); // To avoid truncation effects in permutation
+               tvec4<T, P> ix(Pi.x, Pi.z, Pi.x, Pi.z);
+               tvec4<T, P> iy(Pi.y, Pi.y, Pi.w, Pi.w);
+               tvec4<T, P> fx(Pf.x, Pf.z, Pf.x, Pf.z);
+               tvec4<T, P> fy(Pf.y, Pf.y, Pf.w, Pf.w);
+
+               tvec4<T, P> i = detail::permute(detail::permute(ix) + iy);
+
+               tvec4<T, P> gx = static_cast<T>(2) * glm::fract(i / T(41)) - T(1);
+               tvec4<T, P> gy = glm::abs(gx) - T(0.5);
+               tvec4<T, P> tx = glm::floor(gx + T(0.5));
+               gx = gx - tx;
+
+               tvec2<T, P> g00(gx.x, gy.x);
+               tvec2<T, P> g10(gx.y, gy.y);
+               tvec2<T, P> g01(gx.z, gy.z);
+               tvec2<T, P> g11(gx.w, gy.w);
+
+               tvec4<T, P> norm = detail::taylorInvSqrt(tvec4<T, P>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
+               g00 *= norm.x;
+               g01 *= norm.y;
+               g10 *= norm.z;
+               g11 *= norm.w;
+
+               T n00 = dot(g00, tvec2<T, P>(fx.x, fy.x));
+               T n10 = dot(g10, tvec2<T, P>(fx.y, fy.y));
+               T n01 = dot(g01, tvec2<T, P>(fx.z, fy.z));
+               T n11 = dot(g11, tvec2<T, P>(fx.w, fy.w));
+
+               tvec2<T, P> fade_xy = detail::fade(tvec2<T, P>(Pf.x, Pf.y));
+               tvec2<T, P> n_x = mix(tvec2<T, P>(n00, n01), tvec2<T, P>(n10, n11), fade_xy.x);
+               T n_xy = mix(n_x.x, n_x.y, fade_xy.y);
+               return T(2.3) * n_xy;
+       }
+
+       // Classic Perlin noise
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec3<T, P> const & Position)
+       {
+               tvec3<T, P> Pi0 = floor(Position); // Integer part for indexing
+               tvec3<T, P> Pi1 = Pi0 + T(1); // Integer part + 1
+               Pi0 = detail::mod289(Pi0);
+               Pi1 = detail::mod289(Pi1);
+               tvec3<T, P> Pf0 = fract(Position); // Fractional part for interpolation
+               tvec3<T, P> Pf1 = Pf0 - T(1); // Fractional part - 1.0
+               tvec4<T, P> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+               tvec4<T, P> iy = tvec4<T, P>(tvec2<T, P>(Pi0.y), tvec2<T, P>(Pi1.y));
+               tvec4<T, P> iz0(Pi0.z);
+               tvec4<T, P> iz1(Pi1.z);
+
+               tvec4<T, P> ixy = detail::permute(detail::permute(ix) + iy);
+               tvec4<T, P> ixy0 = detail::permute(ixy + iz0);
+               tvec4<T, P> ixy1 = detail::permute(ixy + iz1);
+
+               tvec4<T, P> gx0 = ixy0 * T(1.0 / 7.0);
+               tvec4<T, P> gy0 = fract(floor(gx0) * T(1.0 / 7.0)) - T(0.5);
+               gx0 = fract(gx0);
+               tvec4<T, P> gz0 = tvec4<T, P>(0.5) - abs(gx0) - abs(gy0);
+               tvec4<T, P> sz0 = step(gz0, tvec4<T, P>(0.0));
+               gx0 -= sz0 * (step(T(0), gx0) - T(0.5));
+               gy0 -= sz0 * (step(T(0), gy0) - T(0.5));
+
+               tvec4<T, P> gx1 = ixy1 * T(1.0 / 7.0);
+               tvec4<T, P> gy1 = fract(floor(gx1) * T(1.0 / 7.0)) - T(0.5);
+               gx1 = fract(gx1);
+               tvec4<T, P> gz1 = tvec4<T, P>(0.5) - abs(gx1) - abs(gy1);
+               tvec4<T, P> sz1 = step(gz1, tvec4<T, P>(0.0));
+               gx1 -= sz1 * (step(T(0), gx1) - T(0.5));
+               gy1 -= sz1 * (step(T(0), gy1) - T(0.5));
+
+               tvec3<T, P> g000(gx0.x, gy0.x, gz0.x);
+               tvec3<T, P> g100(gx0.y, gy0.y, gz0.y);
+               tvec3<T, P> g010(gx0.z, gy0.z, gz0.z);
+               tvec3<T, P> g110(gx0.w, gy0.w, gz0.w);
+               tvec3<T, P> g001(gx1.x, gy1.x, gz1.x);
+               tvec3<T, P> g101(gx1.y, gy1.y, gz1.y);
+               tvec3<T, P> g011(gx1.z, gy1.z, gz1.z);
+               tvec3<T, P> g111(gx1.w, gy1.w, gz1.w);
+
+               tvec4<T, P> norm0 = detail::taylorInvSqrt(tvec4<T, P>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+               g000 *= norm0.x;
+               g010 *= norm0.y;
+               g100 *= norm0.z;
+               g110 *= norm0.w;
+               tvec4<T, P> norm1 = detail::taylorInvSqrt(tvec4<T, P>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+               g001 *= norm1.x;
+               g011 *= norm1.y;
+               g101 *= norm1.z;
+               g111 *= norm1.w;
+
+               T n000 = dot(g000, Pf0);
+               T n100 = dot(g100, tvec3<T, P>(Pf1.x, Pf0.y, Pf0.z));
+               T n010 = dot(g010, tvec3<T, P>(Pf0.x, Pf1.y, Pf0.z));
+               T n110 = dot(g110, tvec3<T, P>(Pf1.x, Pf1.y, Pf0.z));
+               T n001 = dot(g001, tvec3<T, P>(Pf0.x, Pf0.y, Pf1.z));
+               T n101 = dot(g101, tvec3<T, P>(Pf1.x, Pf0.y, Pf1.z));
+               T n011 = dot(g011, tvec3<T, P>(Pf0.x, Pf1.y, Pf1.z));
+               T n111 = dot(g111, Pf1);
+
+               tvec3<T, P> fade_xyz = detail::fade(Pf0);
+               tvec4<T, P> n_z = mix(tvec4<T, P>(n000, n100, n010, n110), tvec4<T, P>(n001, n101, n011, n111), fade_xyz.z);
+               tvec2<T, P> n_yz = mix(tvec2<T, P>(n_z.x, n_z.y), tvec2<T, P>(n_z.z, n_z.w), fade_xyz.y);
+               T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 
+               return T(2.2) * n_xyz;
+       }
+       /*
+       // Classic Perlin noise
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec3<T, P> const & P)
+       {
+               tvec3<T, P> Pi0 = floor(P); // Integer part for indexing
+               tvec3<T, P> Pi1 = Pi0 + T(1); // Integer part + 1
+               Pi0 = mod(Pi0, T(289));
+               Pi1 = mod(Pi1, T(289));
+               tvec3<T, P> Pf0 = fract(P); // Fractional part for interpolation
+               tvec3<T, P> Pf1 = Pf0 - T(1); // Fractional part - 1.0
+               tvec4<T, P> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+               tvec4<T, P> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y);
+               tvec4<T, P> iz0(Pi0.z);
+               tvec4<T, P> iz1(Pi1.z);
+
+               tvec4<T, P> ixy = permute(permute(ix) + iy);
+               tvec4<T, P> ixy0 = permute(ixy + iz0);
+               tvec4<T, P> ixy1 = permute(ixy + iz1);
+
+               tvec4<T, P> gx0 = ixy0 / T(7);
+               tvec4<T, P> gy0 = fract(floor(gx0) / T(7)) - T(0.5);
+               gx0 = fract(gx0);
+               tvec4<T, P> gz0 = tvec4<T, P>(0.5) - abs(gx0) - abs(gy0);
+               tvec4<T, P> sz0 = step(gz0, tvec4<T, P>(0.0));
+               gx0 -= sz0 * (step(0.0, gx0) - T(0.5));
+               gy0 -= sz0 * (step(0.0, gy0) - T(0.5));
+
+               tvec4<T, P> gx1 = ixy1 / T(7);
+               tvec4<T, P> gy1 = fract(floor(gx1) / T(7)) - T(0.5);
+               gx1 = fract(gx1);
+               tvec4<T, P> gz1 = tvec4<T, P>(0.5) - abs(gx1) - abs(gy1);
+               tvec4<T, P> sz1 = step(gz1, tvec4<T, P>(0.0));
+               gx1 -= sz1 * (step(T(0), gx1) - T(0.5));
+               gy1 -= sz1 * (step(T(0), gy1) - T(0.5));
+
+               tvec3<T, P> g000(gx0.x, gy0.x, gz0.x);
+               tvec3<T, P> g100(gx0.y, gy0.y, gz0.y);
+               tvec3<T, P> g010(gx0.z, gy0.z, gz0.z);
+               tvec3<T, P> g110(gx0.w, gy0.w, gz0.w);
+               tvec3<T, P> g001(gx1.x, gy1.x, gz1.x);
+               tvec3<T, P> g101(gx1.y, gy1.y, gz1.y);
+               tvec3<T, P> g011(gx1.z, gy1.z, gz1.z);
+               tvec3<T, P> g111(gx1.w, gy1.w, gz1.w);
+
+               tvec4<T, P> norm0 = taylorInvSqrt(tvec4<T, P>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+               g000 *= norm0.x;
+               g010 *= norm0.y;
+               g100 *= norm0.z;
+               g110 *= norm0.w;
+               tvec4<T, P> norm1 = taylorInvSqrt(tvec4<T, P>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+               g001 *= norm1.x;
+               g011 *= norm1.y;
+               g101 *= norm1.z;
+               g111 *= norm1.w;
+
+               T n000 = dot(g000, Pf0);
+               T n100 = dot(g100, tvec3<T, P>(Pf1.x, Pf0.y, Pf0.z));
+               T n010 = dot(g010, tvec3<T, P>(Pf0.x, Pf1.y, Pf0.z));
+               T n110 = dot(g110, tvec3<T, P>(Pf1.x, Pf1.y, Pf0.z));
+               T n001 = dot(g001, tvec3<T, P>(Pf0.x, Pf0.y, Pf1.z));
+               T n101 = dot(g101, tvec3<T, P>(Pf1.x, Pf0.y, Pf1.z));
+               T n011 = dot(g011, tvec3<T, P>(Pf0.x, Pf1.y, Pf1.z));
+               T n111 = dot(g111, Pf1);
+
+               tvec3<T, P> fade_xyz = fade(Pf0);
+               tvec4<T, P> n_z = mix(tvec4<T, P>(n000, n100, n010, n110), tvec4<T, P>(n001, n101, n011, n111), fade_xyz.z);
+               tvec2<T, P> n_yz = mix(
+                       tvec2<T, P>(n_z.x, n_z.y), 
+                       tvec2<T, P>(n_z.z, n_z.w), fade_xyz.y);
+               T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x); 
+               return T(2.2) * n_xyz;
+       }
+       */
+       // Classic Perlin noise
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec4<T, P> const & Position)
+       {
+               tvec4<T, P> Pi0 = floor(Position);      // Integer part for indexing
+               tvec4<T, P> Pi1 = Pi0 + T(1);           // Integer part + 1
+               Pi0 = mod(Pi0, tvec4<T, P>(289));
+               Pi1 = mod(Pi1, tvec4<T, P>(289));
+               tvec4<T, P> Pf0 = fract(Position);      // Fractional part for interpolation
+               tvec4<T, P> Pf1 = Pf0 - T(1);           // Fractional part - 1.0
+               tvec4<T, P> ix(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+               tvec4<T, P> iy(Pi0.y, Pi0.y, Pi1.y, Pi1.y);
+               tvec4<T, P> iz0(Pi0.z);
+               tvec4<T, P> iz1(Pi1.z);
+               tvec4<T, P> iw0(Pi0.w);
+               tvec4<T, P> iw1(Pi1.w);
+
+               tvec4<T, P> ixy = detail::permute(detail::permute(ix) + iy);
+               tvec4<T, P> ixy0 = detail::permute(ixy + iz0);
+               tvec4<T, P> ixy1 = detail::permute(ixy + iz1);
+               tvec4<T, P> ixy00 = detail::permute(ixy0 + iw0);
+               tvec4<T, P> ixy01 = detail::permute(ixy0 + iw1);
+               tvec4<T, P> ixy10 = detail::permute(ixy1 + iw0);
+               tvec4<T, P> ixy11 = detail::permute(ixy1 + iw1);
+
+               tvec4<T, P> gx00 = ixy00 / T(7);
+               tvec4<T, P> gy00 = floor(gx00) / T(7);
+               tvec4<T, P> gz00 = floor(gy00) / T(6);
+               gx00 = fract(gx00) - T(0.5);
+               gy00 = fract(gy00) - T(0.5);
+               gz00 = fract(gz00) - T(0.5);
+               tvec4<T, P> gw00 = tvec4<T, P>(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
+               tvec4<T, P> sw00 = step(gw00, tvec4<T, P>(0.0));
+               gx00 -= sw00 * (step(T(0), gx00) - T(0.5));
+               gy00 -= sw00 * (step(T(0), gy00) - T(0.5));
+
+               tvec4<T, P> gx01 = ixy01 / T(7);
+               tvec4<T, P> gy01 = floor(gx01) / T(7);
+               tvec4<T, P> gz01 = floor(gy01) / T(6);
+               gx01 = fract(gx01) - T(0.5);
+               gy01 = fract(gy01) - T(0.5);
+               gz01 = fract(gz01) - T(0.5);
+               tvec4<T, P> gw01 = tvec4<T, P>(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
+               tvec4<T, P> sw01 = step(gw01, tvec4<T, P>(0.0));
+               gx01 -= sw01 * (step(T(0), gx01) - T(0.5));
+               gy01 -= sw01 * (step(T(0), gy01) - T(0.5));
+
+               tvec4<T, P> gx10 = ixy10 / T(7);
+               tvec4<T, P> gy10 = floor(gx10) / T(7);
+               tvec4<T, P> gz10 = floor(gy10) / T(6);
+               gx10 = fract(gx10) - T(0.5);
+               gy10 = fract(gy10) - T(0.5);
+               gz10 = fract(gz10) - T(0.5);
+               tvec4<T, P> gw10 = tvec4<T, P>(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
+               tvec4<T, P> sw10 = step(gw10, tvec4<T, P>(0));
+               gx10 -= sw10 * (step(T(0), gx10) - T(0.5));
+               gy10 -= sw10 * (step(T(0), gy10) - T(0.5));
+
+               tvec4<T, P> gx11 = ixy11 / T(7);
+               tvec4<T, P> gy11 = floor(gx11) / T(7);
+               tvec4<T, P> gz11 = floor(gy11) / T(6);
+               gx11 = fract(gx11) - T(0.5);
+               gy11 = fract(gy11) - T(0.5);
+               gz11 = fract(gz11) - T(0.5);
+               tvec4<T, P> gw11 = tvec4<T, P>(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
+               tvec4<T, P> sw11 = step(gw11, tvec4<T, P>(0.0));
+               gx11 -= sw11 * (step(T(0), gx11) - T(0.5));
+               gy11 -= sw11 * (step(T(0), gy11) - T(0.5));
+
+               tvec4<T, P> g0000(gx00.x, gy00.x, gz00.x, gw00.x);
+               tvec4<T, P> g1000(gx00.y, gy00.y, gz00.y, gw00.y);
+               tvec4<T, P> g0100(gx00.z, gy00.z, gz00.z, gw00.z);
+               tvec4<T, P> g1100(gx00.w, gy00.w, gz00.w, gw00.w);
+               tvec4<T, P> g0010(gx10.x, gy10.x, gz10.x, gw10.x);
+               tvec4<T, P> g1010(gx10.y, gy10.y, gz10.y, gw10.y);
+               tvec4<T, P> g0110(gx10.z, gy10.z, gz10.z, gw10.z);
+               tvec4<T, P> g1110(gx10.w, gy10.w, gz10.w, gw10.w);
+               tvec4<T, P> g0001(gx01.x, gy01.x, gz01.x, gw01.x);
+               tvec4<T, P> g1001(gx01.y, gy01.y, gz01.y, gw01.y);
+               tvec4<T, P> g0101(gx01.z, gy01.z, gz01.z, gw01.z);
+               tvec4<T, P> g1101(gx01.w, gy01.w, gz01.w, gw01.w);
+               tvec4<T, P> g0011(gx11.x, gy11.x, gz11.x, gw11.x);
+               tvec4<T, P> g1011(gx11.y, gy11.y, gz11.y, gw11.y);
+               tvec4<T, P> g0111(gx11.z, gy11.z, gz11.z, gw11.z);
+               tvec4<T, P> g1111(gx11.w, gy11.w, gz11.w, gw11.w);
+
+               tvec4<T, P> norm00 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
+               g0000 *= norm00.x;
+               g0100 *= norm00.y;
+               g1000 *= norm00.z;
+               g1100 *= norm00.w;
+
+               tvec4<T, P> norm01 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
+               g0001 *= norm01.x;
+               g0101 *= norm01.y;
+               g1001 *= norm01.z;
+               g1101 *= norm01.w;
+
+               tvec4<T, P> norm10 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
+               g0010 *= norm10.x;
+               g0110 *= norm10.y;
+               g1010 *= norm10.z;
+               g1110 *= norm10.w;
+
+               tvec4<T, P> norm11 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
+               g0011 *= norm11.x;
+               g0111 *= norm11.y;
+               g1011 *= norm11.z;
+               g1111 *= norm11.w;
+
+               T n0000 = dot(g0000, Pf0);
+               T n1000 = dot(g1000, tvec4<T, P>(Pf1.x, Pf0.y, Pf0.z, Pf0.w));
+               T n0100 = dot(g0100, tvec4<T, P>(Pf0.x, Pf1.y, Pf0.z, Pf0.w));
+               T n1100 = dot(g1100, tvec4<T, P>(Pf1.x, Pf1.y, Pf0.z, Pf0.w));
+               T n0010 = dot(g0010, tvec4<T, P>(Pf0.x, Pf0.y, Pf1.z, Pf0.w));
+               T n1010 = dot(g1010, tvec4<T, P>(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
+               T n0110 = dot(g0110, tvec4<T, P>(Pf0.x, Pf1.y, Pf1.z, Pf0.w));
+               T n1110 = dot(g1110, tvec4<T, P>(Pf1.x, Pf1.y, Pf1.z, Pf0.w));
+               T n0001 = dot(g0001, tvec4<T, P>(Pf0.x, Pf0.y, Pf0.z, Pf1.w));
+               T n1001 = dot(g1001, tvec4<T, P>(Pf1.x, Pf0.y, Pf0.z, Pf1.w));
+               T n0101 = dot(g0101, tvec4<T, P>(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
+               T n1101 = dot(g1101, tvec4<T, P>(Pf1.x, Pf1.y, Pf0.z, Pf1.w));
+               T n0011 = dot(g0011, tvec4<T, P>(Pf0.x, Pf0.y, Pf1.z, Pf1.w));
+               T n1011 = dot(g1011, tvec4<T, P>(Pf1.x, Pf0.y, Pf1.z, Pf1.w));
+               T n0111 = dot(g0111, tvec4<T, P>(Pf0.x, Pf1.y, Pf1.z, Pf1.w));
+               T n1111 = dot(g1111, Pf1);
+
+               tvec4<T, P> fade_xyzw = detail::fade(Pf0);
+               tvec4<T, P> n_0w = mix(tvec4<T, P>(n0000, n1000, n0100, n1100), tvec4<T, P>(n0001, n1001, n0101, n1101), fade_xyzw.w);
+               tvec4<T, P> n_1w = mix(tvec4<T, P>(n0010, n1010, n0110, n1110), tvec4<T, P>(n0011, n1011, n0111, n1111), fade_xyzw.w);
+               tvec4<T, P> n_zw = mix(n_0w, n_1w, fade_xyzw.z);
+               tvec2<T, P> n_yzw = mix(tvec2<T, P>(n_zw.x, n_zw.y), tvec2<T, P>(n_zw.z, n_zw.w), fade_xyzw.y);
+               T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
+               return T(2.2) * n_xyzw;
+       }
+
+       // Classic Perlin noise, periodic variant
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec2<T, P> const & Position, tvec2<T, P> const & rep)
+       {
+               tvec4<T, P> Pi = floor(tvec4<T, P>(Position.x, Position.y, Position.x, Position.y)) + tvec4<T, P>(0.0, 0.0, 1.0, 1.0);
+               tvec4<T, P> Pf = fract(tvec4<T, P>(Position.x, Position.y, Position.x, Position.y)) - tvec4<T, P>(0.0, 0.0, 1.0, 1.0);
+               Pi = mod(Pi, tvec4<T, P>(rep.x, rep.y, rep.x, rep.y)); // To create noise with explicit period
+               Pi = mod(Pi, tvec4<T, P>(289)); // To avoid truncation effects in permutation
+               tvec4<T, P> ix(Pi.x, Pi.z, Pi.x, Pi.z);
+               tvec4<T, P> iy(Pi.y, Pi.y, Pi.w, Pi.w);
+               tvec4<T, P> fx(Pf.x, Pf.z, Pf.x, Pf.z);
+               tvec4<T, P> fy(Pf.y, Pf.y, Pf.w, Pf.w);
+
+               tvec4<T, P> i = detail::permute(detail::permute(ix) + iy);
+
+               tvec4<T, P> gx = static_cast<T>(2) * fract(i / T(41)) - T(1);
+               tvec4<T, P> gy = abs(gx) - T(0.5);
+               tvec4<T, P> tx = floor(gx + T(0.5));
+               gx = gx - tx;
+
+               tvec2<T, P> g00(gx.x, gy.x);
+               tvec2<T, P> g10(gx.y, gy.y);
+               tvec2<T, P> g01(gx.z, gy.z);
+               tvec2<T, P> g11(gx.w, gy.w);
+
+               tvec4<T, P> norm = detail::taylorInvSqrt(tvec4<T, P>(dot(g00, g00), dot(g01, g01), dot(g10, g10), dot(g11, g11)));
+               g00 *= norm.x;
+               g01 *= norm.y;
+               g10 *= norm.z;
+               g11 *= norm.w;
+
+               T n00 = dot(g00, tvec2<T, P>(fx.x, fy.x));
+               T n10 = dot(g10, tvec2<T, P>(fx.y, fy.y));
+               T n01 = dot(g01, tvec2<T, P>(fx.z, fy.z));
+               T n11 = dot(g11, tvec2<T, P>(fx.w, fy.w));
+
+               tvec2<T, P> fade_xy = detail::fade(tvec2<T, P>(Pf.x, Pf.y));
+               tvec2<T, P> n_x = mix(tvec2<T, P>(n00, n01), tvec2<T, P>(n10, n11), fade_xy.x);
+               T n_xy = mix(n_x.x, n_x.y, fade_xy.y);
+               return T(2.3) * n_xy;
+       }
+
+       // Classic Perlin noise, periodic variant
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec3<T, P> const & Position, tvec3<T, P> const & rep)
+       {
+               tvec3<T, P> Pi0 = mod(floor(Position), rep); // Integer part, modulo period
+               tvec3<T, P> Pi1 = mod(Pi0 + tvec3<T, P>(T(1)), rep); // Integer part + 1, mod period
+               Pi0 = mod(Pi0, tvec3<T, P>(289));
+               Pi1 = mod(Pi1, tvec3<T, P>(289));
+               tvec3<T, P> Pf0 = fract(Position); // Fractional part for interpolation
+               tvec3<T, P> Pf1 = Pf0 - tvec3<T, P>(T(1)); // Fractional part - 1.0
+               tvec4<T, P> ix = tvec4<T, P>(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+               tvec4<T, P> iy = tvec4<T, P>(Pi0.y, Pi0.y, Pi1.y, Pi1.y);
+               tvec4<T, P> iz0(Pi0.z);
+               tvec4<T, P> iz1(Pi1.z);
+
+               tvec4<T, P> ixy = detail::permute(detail::permute(ix) + iy);
+               tvec4<T, P> ixy0 = detail::permute(ixy + iz0);
+               tvec4<T, P> ixy1 = detail::permute(ixy + iz1);
+
+               tvec4<T, P> gx0 = ixy0 / T(7);
+               tvec4<T, P> gy0 = fract(floor(gx0) / T(7)) - T(0.5);
+               gx0 = fract(gx0);
+               tvec4<T, P> gz0 = tvec4<T, P>(0.5) - abs(gx0) - abs(gy0);
+               tvec4<T, P> sz0 = step(gz0, tvec4<T, P>(0));
+               gx0 -= sz0 * (step(T(0), gx0) - T(0.5));
+               gy0 -= sz0 * (step(T(0), gy0) - T(0.5));
+
+               tvec4<T, P> gx1 = ixy1 / T(7);
+               tvec4<T, P> gy1 = fract(floor(gx1) / T(7)) - T(0.5);
+               gx1 = fract(gx1);
+               tvec4<T, P> gz1 = tvec4<T, P>(0.5) - abs(gx1) - abs(gy1);
+               tvec4<T, P> sz1 = step(gz1, tvec4<T, P>(T(0)));
+               gx1 -= sz1 * (step(T(0), gx1) - T(0.5));
+               gy1 -= sz1 * (step(T(0), gy1) - T(0.5));
+
+               tvec3<T, P> g000 = tvec3<T, P>(gx0.x, gy0.x, gz0.x);
+               tvec3<T, P> g100 = tvec3<T, P>(gx0.y, gy0.y, gz0.y);
+               tvec3<T, P> g010 = tvec3<T, P>(gx0.z, gy0.z, gz0.z);
+               tvec3<T, P> g110 = tvec3<T, P>(gx0.w, gy0.w, gz0.w);
+               tvec3<T, P> g001 = tvec3<T, P>(gx1.x, gy1.x, gz1.x);
+               tvec3<T, P> g101 = tvec3<T, P>(gx1.y, gy1.y, gz1.y);
+               tvec3<T, P> g011 = tvec3<T, P>(gx1.z, gy1.z, gz1.z);
+               tvec3<T, P> g111 = tvec3<T, P>(gx1.w, gy1.w, gz1.w);
+
+               tvec4<T, P> norm0 = detail::taylorInvSqrt(tvec4<T, P>(dot(g000, g000), dot(g010, g010), dot(g100, g100), dot(g110, g110)));
+               g000 *= norm0.x;
+               g010 *= norm0.y;
+               g100 *= norm0.z;
+               g110 *= norm0.w;
+               tvec4<T, P> norm1 = detail::taylorInvSqrt(tvec4<T, P>(dot(g001, g001), dot(g011, g011), dot(g101, g101), dot(g111, g111)));
+               g001 *= norm1.x;
+               g011 *= norm1.y;
+               g101 *= norm1.z;
+               g111 *= norm1.w;
+
+               T n000 = dot(g000, Pf0);
+               T n100 = dot(g100, tvec3<T, P>(Pf1.x, Pf0.y, Pf0.z));
+               T n010 = dot(g010, tvec3<T, P>(Pf0.x, Pf1.y, Pf0.z));
+               T n110 = dot(g110, tvec3<T, P>(Pf1.x, Pf1.y, Pf0.z));
+               T n001 = dot(g001, tvec3<T, P>(Pf0.x, Pf0.y, Pf1.z));
+               T n101 = dot(g101, tvec3<T, P>(Pf1.x, Pf0.y, Pf1.z));
+               T n011 = dot(g011, tvec3<T, P>(Pf0.x, Pf1.y, Pf1.z));
+               T n111 = dot(g111, Pf1);
+
+               tvec3<T, P> fade_xyz = detail::fade(Pf0);
+               tvec4<T, P> n_z = mix(tvec4<T, P>(n000, n100, n010, n110), tvec4<T, P>(n001, n101, n011, n111), fade_xyz.z);
+               tvec2<T, P> n_yz = mix(tvec2<T, P>(n_z.x, n_z.y), tvec2<T, P>(n_z.z, n_z.w), fade_xyz.y);
+               T n_xyz = mix(n_yz.x, n_yz.y, fade_xyz.x);
+               return T(2.2) * n_xyz;
+       }
+
+       // Classic Perlin noise, periodic version
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T perlin(tvec4<T, P> const & Position, tvec4<T, P> const & rep)
+       {
+               tvec4<T, P> Pi0 = mod(floor(Position), rep); // Integer part modulo rep
+               tvec4<T, P> Pi1 = mod(Pi0 + T(1), rep); // Integer part + 1 mod rep
+               tvec4<T, P> Pf0 = fract(Position); // Fractional part for interpolation
+               tvec4<T, P> Pf1 = Pf0 - T(1); // Fractional part - 1.0
+               tvec4<T, P> ix = tvec4<T, P>(Pi0.x, Pi1.x, Pi0.x, Pi1.x);
+               tvec4<T, P> iy = tvec4<T, P>(Pi0.y, Pi0.y, Pi1.y, Pi1.y);
+               tvec4<T, P> iz0(Pi0.z);
+               tvec4<T, P> iz1(Pi1.z);
+               tvec4<T, P> iw0(Pi0.w);
+               tvec4<T, P> iw1(Pi1.w);
+
+               tvec4<T, P> ixy = detail::permute(detail::permute(ix) + iy);
+               tvec4<T, P> ixy0 = detail::permute(ixy + iz0);
+               tvec4<T, P> ixy1 = detail::permute(ixy + iz1);
+               tvec4<T, P> ixy00 = detail::permute(ixy0 + iw0);
+               tvec4<T, P> ixy01 = detail::permute(ixy0 + iw1);
+               tvec4<T, P> ixy10 = detail::permute(ixy1 + iw0);
+               tvec4<T, P> ixy11 = detail::permute(ixy1 + iw1);
+
+               tvec4<T, P> gx00 = ixy00 / T(7);
+               tvec4<T, P> gy00 = floor(gx00) / T(7);
+               tvec4<T, P> gz00 = floor(gy00) / T(6);
+               gx00 = fract(gx00) - T(0.5);
+               gy00 = fract(gy00) - T(0.5);
+               gz00 = fract(gz00) - T(0.5);
+               tvec4<T, P> gw00 = tvec4<T, P>(0.75) - abs(gx00) - abs(gy00) - abs(gz00);
+               tvec4<T, P> sw00 = step(gw00, tvec4<T, P>(0));
+               gx00 -= sw00 * (step(T(0), gx00) - T(0.5));
+               gy00 -= sw00 * (step(T(0), gy00) - T(0.5));
+
+               tvec4<T, P> gx01 = ixy01 / T(7);
+               tvec4<T, P> gy01 = floor(gx01) / T(7);
+               tvec4<T, P> gz01 = floor(gy01) / T(6);
+               gx01 = fract(gx01) - T(0.5);
+               gy01 = fract(gy01) - T(0.5);
+               gz01 = fract(gz01) - T(0.5);
+               tvec4<T, P> gw01 = tvec4<T, P>(0.75) - abs(gx01) - abs(gy01) - abs(gz01);
+               tvec4<T, P> sw01 = step(gw01, tvec4<T, P>(0.0));
+               gx01 -= sw01 * (step(T(0), gx01) - T(0.5));
+               gy01 -= sw01 * (step(T(0), gy01) - T(0.5));
+
+               tvec4<T, P> gx10 = ixy10 / T(7);
+               tvec4<T, P> gy10 = floor(gx10) / T(7);
+               tvec4<T, P> gz10 = floor(gy10) / T(6);
+               gx10 = fract(gx10) - T(0.5);
+               gy10 = fract(gy10) - T(0.5);
+               gz10 = fract(gz10) - T(0.5);
+               tvec4<T, P> gw10 = tvec4<T, P>(0.75) - abs(gx10) - abs(gy10) - abs(gz10);
+               tvec4<T, P> sw10 = step(gw10, tvec4<T, P>(0.0));
+               gx10 -= sw10 * (step(T(0), gx10) - T(0.5));
+               gy10 -= sw10 * (step(T(0), gy10) - T(0.5));
+
+               tvec4<T, P> gx11 = ixy11 / T(7);
+               tvec4<T, P> gy11 = floor(gx11) / T(7);
+               tvec4<T, P> gz11 = floor(gy11) / T(6);
+               gx11 = fract(gx11) - T(0.5);
+               gy11 = fract(gy11) - T(0.5);
+               gz11 = fract(gz11) - T(0.5);
+               tvec4<T, P> gw11 = tvec4<T, P>(0.75) - abs(gx11) - abs(gy11) - abs(gz11);
+               tvec4<T, P> sw11 = step(gw11, tvec4<T, P>(T(0)));
+               gx11 -= sw11 * (step(T(0), gx11) - T(0.5));
+               gy11 -= sw11 * (step(T(0), gy11) - T(0.5));
+
+               tvec4<T, P> g0000(gx00.x, gy00.x, gz00.x, gw00.x);
+               tvec4<T, P> g1000(gx00.y, gy00.y, gz00.y, gw00.y);
+               tvec4<T, P> g0100(gx00.z, gy00.z, gz00.z, gw00.z);
+               tvec4<T, P> g1100(gx00.w, gy00.w, gz00.w, gw00.w);
+               tvec4<T, P> g0010(gx10.x, gy10.x, gz10.x, gw10.x);
+               tvec4<T, P> g1010(gx10.y, gy10.y, gz10.y, gw10.y);
+               tvec4<T, P> g0110(gx10.z, gy10.z, gz10.z, gw10.z);
+               tvec4<T, P> g1110(gx10.w, gy10.w, gz10.w, gw10.w);
+               tvec4<T, P> g0001(gx01.x, gy01.x, gz01.x, gw01.x);
+               tvec4<T, P> g1001(gx01.y, gy01.y, gz01.y, gw01.y);
+               tvec4<T, P> g0101(gx01.z, gy01.z, gz01.z, gw01.z);
+               tvec4<T, P> g1101(gx01.w, gy01.w, gz01.w, gw01.w);
+               tvec4<T, P> g0011(gx11.x, gy11.x, gz11.x, gw11.x);
+               tvec4<T, P> g1011(gx11.y, gy11.y, gz11.y, gw11.y);
+               tvec4<T, P> g0111(gx11.z, gy11.z, gz11.z, gw11.z);
+               tvec4<T, P> g1111(gx11.w, gy11.w, gz11.w, gw11.w);
+
+               tvec4<T, P> norm00 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0000, g0000), dot(g0100, g0100), dot(g1000, g1000), dot(g1100, g1100)));
+               g0000 *= norm00.x;
+               g0100 *= norm00.y;
+               g1000 *= norm00.z;
+               g1100 *= norm00.w;
+
+               tvec4<T, P> norm01 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0001, g0001), dot(g0101, g0101), dot(g1001, g1001), dot(g1101, g1101)));
+               g0001 *= norm01.x;
+               g0101 *= norm01.y;
+               g1001 *= norm01.z;
+               g1101 *= norm01.w;
+
+               tvec4<T, P> norm10 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0010, g0010), dot(g0110, g0110), dot(g1010, g1010), dot(g1110, g1110)));
+               g0010 *= norm10.x;
+               g0110 *= norm10.y;
+               g1010 *= norm10.z;
+               g1110 *= norm10.w;
+
+               tvec4<T, P> norm11 = detail::taylorInvSqrt(tvec4<T, P>(dot(g0011, g0011), dot(g0111, g0111), dot(g1011, g1011), dot(g1111, g1111)));
+               g0011 *= norm11.x;
+               g0111 *= norm11.y;
+               g1011 *= norm11.z;
+               g1111 *= norm11.w;
+
+               T n0000 = dot(g0000, Pf0);
+               T n1000 = dot(g1000, tvec4<T, P>(Pf1.x, Pf0.y, Pf0.z, Pf0.w));
+               T n0100 = dot(g0100, tvec4<T, P>(Pf0.x, Pf1.y, Pf0.z, Pf0.w));
+               T n1100 = dot(g1100, tvec4<T, P>(Pf1.x, Pf1.y, Pf0.z, Pf0.w));
+               T n0010 = dot(g0010, tvec4<T, P>(Pf0.x, Pf0.y, Pf1.z, Pf0.w));
+               T n1010 = dot(g1010, tvec4<T, P>(Pf1.x, Pf0.y, Pf1.z, Pf0.w));
+               T n0110 = dot(g0110, tvec4<T, P>(Pf0.x, Pf1.y, Pf1.z, Pf0.w));
+               T n1110 = dot(g1110, tvec4<T, P>(Pf1.x, Pf1.y, Pf1.z, Pf0.w));
+               T n0001 = dot(g0001, tvec4<T, P>(Pf0.x, Pf0.y, Pf0.z, Pf1.w));
+               T n1001 = dot(g1001, tvec4<T, P>(Pf1.x, Pf0.y, Pf0.z, Pf1.w));
+               T n0101 = dot(g0101, tvec4<T, P>(Pf0.x, Pf1.y, Pf0.z, Pf1.w));
+               T n1101 = dot(g1101, tvec4<T, P>(Pf1.x, Pf1.y, Pf0.z, Pf1.w));
+               T n0011 = dot(g0011, tvec4<T, P>(Pf0.x, Pf0.y, Pf1.z, Pf1.w));
+               T n1011 = dot(g1011, tvec4<T, P>(Pf1.x, Pf0.y, Pf1.z, Pf1.w));
+               T n0111 = dot(g0111, tvec4<T, P>(Pf0.x, Pf1.y, Pf1.z, Pf1.w));
+               T n1111 = dot(g1111, Pf1);
+
+               tvec4<T, P> fade_xyzw = detail::fade(Pf0);
+               tvec4<T, P> n_0w = mix(tvec4<T, P>(n0000, n1000, n0100, n1100), tvec4<T, P>(n0001, n1001, n0101, n1101), fade_xyzw.w);
+               tvec4<T, P> n_1w = mix(tvec4<T, P>(n0010, n1010, n0110, n1110), tvec4<T, P>(n0011, n1011, n0111, n1111), fade_xyzw.w);
+               tvec4<T, P> n_zw = mix(n_0w, n_1w, fade_xyzw.z);
+               tvec2<T, P> n_yzw = mix(tvec2<T, P>(n_zw.x, n_zw.y), tvec2<T, P>(n_zw.z, n_zw.w), fade_xyzw.y);
+               T n_xyzw = mix(n_yzw.x, n_yzw.y, fade_xyzw.x);
+               return T(2.2) * n_xyzw;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T simplex(glm::tvec2<T, P> const & v)
+       {
+               tvec4<T, P> const C = tvec4<T, P>(
+                       T( 0.211324865405187),  // (3.0 -  sqrt(3.0)) / 6.0
+                       T( 0.366025403784439),  //  0.5 * (sqrt(3.0)  - 1.0)
+                       T(-0.577350269189626),  // -1.0 + 2.0 * C.x
+                       T( 0.024390243902439)); //  1.0 / 41.0
+
+               // First corner
+               tvec2<T, P> i  = floor(v + dot(v, tvec2<T, P>(C[1])));
+               tvec2<T, P> x0 = v -   i + dot(i, tvec2<T, P>(C[0]));
+
+               // Other corners
+               //i1.x = step( x0.y, x0.x ); // x0.x > x0.y ? 1.0 : 0.0
+               //i1.y = 1.0 - i1.x;
+               tvec2<T, P> i1 = (x0.x > x0.y) ? tvec2<T, P>(1, 0) : tvec2<T, P>(0, 1);
+               // x0 = x0 - 0.0 + 0.0 * C.xx ;
+               // x1 = x0 - i1 + 1.0 * C.xx ;
+               // x2 = x0 - 1.0 + 2.0 * C.xx ;
+               tvec4<T, P> x12 = tvec4<T, P>(x0.x, x0.y, x0.x, x0.y) + tvec4<T, P>(C.x, C.x, C.z, C.z);
+               x12 = tvec4<T, P>(tvec2<T, P>(x12) - i1, x12.z, x12.w);
+
+               // Permutations
+               i = mod(i, tvec2<T, P>(289)); // Avoid truncation effects in permutation
+               tvec3<T, P> p = detail::permute(
+                       detail::permute(i.y + tvec3<T, P>(T(0), i1.y, T(1)))
+                       + i.x + tvec3<T, P>(T(0), i1.x, T(1)));
+
+               tvec3<T, P> m = max(tvec3<T, P>(0.5) - tvec3<T, P>(
+                       dot(x0, x0),
+                       dot(tvec2<T, P>(x12.x, x12.y), tvec2<T, P>(x12.x, x12.y)), 
+                       dot(tvec2<T, P>(x12.z, x12.w), tvec2<T, P>(x12.z, x12.w))), tvec3<T, P>(0));
+               m = m * m ;
+               m = m * m ;
+
+               // Gradients: 41 points uniformly over a line, mapped onto a diamond.
+               // The ring size 17*17 = 289 is close to a multiple of 41 (41*7 = 287)
+
+               tvec3<T, P> x = static_cast<T>(2) * fract(p * C.w) - T(1);
+               tvec3<T, P> h = abs(x) - T(0.5);
+               tvec3<T, P> ox = floor(x + T(0.5));
+               tvec3<T, P> a0 = x - ox;
+
+               // Normalise gradients implicitly by scaling m
+               // Inlined for speed: m *= taylorInvSqrt( a0*a0 + h*h );
+               m *= static_cast<T>(1.79284291400159) - T(0.85373472095314) * (a0 * a0 + h * h);
+
+               // Compute final noise value at P
+               tvec3<T, P> g;
+               g.x  = a0.x  * x0.x  + h.x  * x0.y;
+               //g.yz = a0.yz * x12.xz + h.yz * x12.yw;
+               g.y = a0.y * x12.x + h.y * x12.y;
+               g.z = a0.z * x12.z + h.z * x12.w;
+               return T(130) * dot(m, g);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T simplex(tvec3<T, P> const & v)
+       {
+               tvec2<T, P> const C(1.0 / 6.0, 1.0 / 3.0);
+               tvec4<T, P> const D(0.0, 0.5, 1.0, 2.0);
+
+               // First corner
+               tvec3<T, P> i(floor(v + dot(v, tvec3<T, P>(C.y))));
+               tvec3<T, P> x0(v - i + dot(i, tvec3<T, P>(C.x)));
+
+               // Other corners
+               tvec3<T, P> g(step(tvec3<T, P>(x0.y, x0.z, x0.x), x0));
+               tvec3<T, P> l(T(1) - g);
+               tvec3<T, P> i1(min(g, tvec3<T, P>(l.z, l.x, l.y)));
+               tvec3<T, P> i2(max(g, tvec3<T, P>(l.z, l.x, l.y)));
+
+               //   x0 = x0 - 0.0 + 0.0 * C.xxx;
+               //   x1 = x0 - i1  + 1.0 * C.xxx;
+               //   x2 = x0 - i2  + 2.0 * C.xxx;
+               //   x3 = x0 - 1.0 + 3.0 * C.xxx;
+               tvec3<T, P> x1(x0 - i1 + C.x);
+               tvec3<T, P> x2(x0 - i2 + C.y); // 2.0*C.x = 1/3 = C.y
+               tvec3<T, P> x3(x0 - D.y);      // -1.0+3.0*C.x = -0.5 = -D.y
+
+               // Permutations
+               i = detail::mod289(i);
+               tvec4<T, P> p(detail::permute(detail::permute(detail::permute(
+                       i.z + tvec4<T, P>(T(0), i1.z, i2.z, T(1))) +
+                       i.y + tvec4<T, P>(T(0), i1.y, i2.y, T(1))) +
+                       i.x + tvec4<T, P>(T(0), i1.x, i2.x, T(1))));
+
+               // Gradients: 7x7 points over a square, mapped onto an octahedron.
+               // The ring size 17*17 = 289 is close to a multiple of 49 (49*6 = 294)
+               T n_ = static_cast<T>(0.142857142857); // 1.0/7.0
+               tvec3<T, P> ns(n_ * tvec3<T, P>(D.w, D.y, D.z) - tvec3<T, P>(D.x, D.z, D.x));
+
+               tvec4<T, P> j(p - T(49) * floor(p * ns.z * ns.z));  //  mod(p,7*7)
+
+               tvec4<T, P> x_(floor(j * ns.z));
+               tvec4<T, P> y_(floor(j - T(7) * x_));    // mod(j,N)
+
+               tvec4<T, P> x(x_ * ns.x + ns.y);
+               tvec4<T, P> y(y_ * ns.x + ns.y);
+               tvec4<T, P> h(T(1) - abs(x) - abs(y));
+
+               tvec4<T, P> b0(x.x, x.y, y.x, y.y);
+               tvec4<T, P> b1(x.z, x.w, y.z, y.w);
+
+               // vec4 s0 = vec4(lessThan(b0,0.0))*2.0 - 1.0;
+               // vec4 s1 = vec4(lessThan(b1,0.0))*2.0 - 1.0;
+               tvec4<T, P> s0(floor(b0) * T(2) + T(1));
+               tvec4<T, P> s1(floor(b1) * T(2) + T(1));
+               tvec4<T, P> sh(-step(h, tvec4<T, P>(0.0)));
+
+               tvec4<T, P> a0 = tvec4<T, P>(b0.x, b0.z, b0.y, b0.w) + tvec4<T, P>(s0.x, s0.z, s0.y, s0.w) * tvec4<T, P>(sh.x, sh.x, sh.y, sh.y);
+               tvec4<T, P> a1 = tvec4<T, P>(b1.x, b1.z, b1.y, b1.w) + tvec4<T, P>(s1.x, s1.z, s1.y, s1.w) * tvec4<T, P>(sh.z, sh.z, sh.w, sh.w);
+
+               tvec3<T, P> p0(a0.x, a0.y, h.x);
+               tvec3<T, P> p1(a0.z, a0.w, h.y);
+               tvec3<T, P> p2(a1.x, a1.y, h.z);
+               tvec3<T, P> p3(a1.z, a1.w, h.w);
+
+               // Normalise gradients
+               tvec4<T, P> norm = detail::taylorInvSqrt(tvec4<T, P>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
+               p0 *= norm.x;
+               p1 *= norm.y;
+               p2 *= norm.z;
+               p3 *= norm.w;
+
+               // Mix final noise value
+               tvec4<T, P> m = max(T(0.6) - tvec4<T, P>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), tvec4<T, P>(0));
+               m = m * m;
+               return T(42) * dot(m * m, tvec4<T, P>(dot(p0, x0), dot(p1, x1), dot(p2, x2), dot(p3, x3)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T simplex(tvec4<T, P> const & v)
+       {
+               tvec4<T, P> const C(
+                       0.138196601125011,  // (5 - sqrt(5))/20  G4
+                       0.276393202250021,  // 2 * G4
+                       0.414589803375032,  // 3 * G4
+                       -0.447213595499958); // -1 + 4 * G4
+
+               // (sqrt(5) - 1)/4 = F4, used once below
+               T const F4 = static_cast<T>(0.309016994374947451);
+
+               // First corner
+               tvec4<T, P> i  = floor(v + dot(v, vec4(F4)));
+               tvec4<T, P> x0 = v -   i + dot(i, vec4(C.x));
+
+               // Other corners
+
+               // Rank sorting originally contributed by Bill Licea-Kane, AMD (formerly ATI)
+               tvec4<T, P> i0;
+               tvec3<T, P> isX = step(tvec3<T, P>(x0.y, x0.z, x0.w), tvec3<T, P>(x0.x));
+               tvec3<T, P> isYZ = step(tvec3<T, P>(x0.z, x0.w, x0.w), tvec3<T, P>(x0.y, x0.y, x0.z));
+               //  i0.x = dot(isX, vec3(1.0));
+               //i0.x = isX.x + isX.y + isX.z;
+               //i0.yzw = static_cast<T>(1) - isX;
+               i0 = tvec4<T, P>(isX.x + isX.y + isX.z, T(1) - isX);
+               //  i0.y += dot(isYZ.xy, vec2(1.0));
+               i0.y += isYZ.x + isYZ.y;
+               //i0.zw += 1.0 - tvec2<T, P>(isYZ.x, isYZ.y);
+               i0.z += static_cast<T>(1) - isYZ.x;
+               i0.w += static_cast<T>(1) - isYZ.y;
+               i0.z += isYZ.z;
+               i0.w += static_cast<T>(1) - isYZ.z;
+
+               // i0 now contains the unique values 0,1,2,3 in each channel
+               tvec4<T, P> i3 = clamp(i0, T(0), T(1));
+               tvec4<T, P> i2 = clamp(i0 - T(1), T(0), T(1));
+               tvec4<T, P> i1 = clamp(i0 - T(2), T(0), T(1));
+
+               //  x0 = x0 - 0.0 + 0.0 * C.xxxx
+               //  x1 = x0 - i1  + 0.0 * C.xxxx
+               //  x2 = x0 - i2  + 0.0 * C.xxxx
+               //  x3 = x0 - i3  + 0.0 * C.xxxx
+               //  x4 = x0 - 1.0 + 4.0 * C.xxxx
+               tvec4<T, P> x1 = x0 - i1 + C.x;
+               tvec4<T, P> x2 = x0 - i2 + C.y;
+               tvec4<T, P> x3 = x0 - i3 + C.z;
+               tvec4<T, P> x4 = x0 + C.w;
+
+               // Permutations
+               i = mod(i, tvec4<T, P>(289)); 
+               T j0 = detail::permute(detail::permute(detail::permute(detail::permute(i.w) + i.z) + i.y) + i.x);
+               tvec4<T, P> j1 = detail::permute(detail::permute(detail::permute(detail::permute(
+                       i.w + tvec4<T, P>(i1.w, i2.w, i3.w, T(1))) +
+                       i.z + tvec4<T, P>(i1.z, i2.z, i3.z, T(1))) +
+                       i.y + tvec4<T, P>(i1.y, i2.y, i3.y, T(1))) +
+                       i.x + tvec4<T, P>(i1.x, i2.x, i3.x, T(1)));
+
+               // Gradients: 7x7x6 points over a cube, mapped onto a 4-cross polytope
+               // 7*7*6 = 294, which is close to the ring size 17*17 = 289.
+               tvec4<T, P> ip = tvec4<T, P>(T(1) / T(294), T(1) / T(49), T(1) / T(7), T(0));
+
+               tvec4<T, P> p0 = gtc::grad4(j0,   ip);
+               tvec4<T, P> p1 = gtc::grad4(j1.x, ip);
+               tvec4<T, P> p2 = gtc::grad4(j1.y, ip);
+               tvec4<T, P> p3 = gtc::grad4(j1.z, ip);
+               tvec4<T, P> p4 = gtc::grad4(j1.w, ip);
+
+               // Normalise gradients
+               tvec4<T, P> norm = detail::taylorInvSqrt(tvec4<T, P>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
+               p0 *= norm.x;
+               p1 *= norm.y;
+               p2 *= norm.z;
+               p3 *= norm.w;
+               p4 *= detail::taylorInvSqrt(dot(p4, p4));
+
+               // Mix contributions from the five corners
+               tvec3<T, P> m0 = max(T(0.6) - tvec3<T, P>(dot(x0, x0), dot(x1, x1), dot(x2, x2)), tvec3<T, P>(0));
+               tvec2<T, P> m1 = max(T(0.6) - tvec2<T, P>(dot(x3, x3), dot(x4, x4)             ), tvec2<T, P>(0));
+               m0 = m0 * m0;
+               m1 = m1 * m1;
+               return T(49) * 
+                       (dot(m0 * m0, tvec3<T, P>(dot(p0, x0), dot(p1, x1), dot(p2, x2))) + 
+                       dot(m1 * m1, tvec2<T, P>(dot(p3, x3), dot(p4, x4))));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/packing.hpp b/core/deps/glm/glm/gtc/packing.hpp
new file mode 100755 (executable)
index 0000000..1389d95
--- /dev/null
@@ -0,0 +1,579 @@
+/// @ref gtc_packing
+/// @file glm/gtc/packing.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_packing GLM_GTC_packing
+/// @ingroup gtc
+///
+/// @brief This extension provides a set of function to convert vertors to packed
+/// formats.
+///
+/// <glm/gtc/packing.hpp> need to be included to use these features.
+
+#pragma once
+
+// Dependency:
+#include "type_precision.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_packing extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_packing
+       /// @{
+
+       /// First, converts the normalized floating-point value v into a 8-bit integer value.
+       /// Then, the results are packed into the returned 8-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm1x8:       round(clamp(c, 0, +1) * 255.0)
+       ///
+       /// @see gtc_packing
+       /// @see uint16 packUnorm2x8(vec2 const & v)
+       /// @see uint32 packUnorm4x8(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml">GLSL packUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint8 packUnorm1x8(float v);
+
+       /// Convert a single 8-bit integer to a normalized floating-point value.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnorm4x8: f / 255.0
+       /// 
+       /// @see gtc_packing
+       /// @see vec2 unpackUnorm2x8(uint16 p)
+       /// @see vec4 unpackUnorm4x8(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml">GLSL unpackUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL float unpackUnorm1x8(uint8 p);
+
+       /// First, converts each component of the normalized floating-point value v into 8-bit integer values.
+       /// Then, the results are packed into the returned 16-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm2x8:       round(clamp(c, 0, +1) * 255.0)
+       ///
+       /// The first component of the vector will be written to the least significant bits of the output;
+       /// the last component will be written to the most significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see uint8 packUnorm1x8(float const & v)
+       /// @see uint32 packUnorm4x8(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml">GLSL packUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint16 packUnorm2x8(vec2 const & v);
+
+       /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit unsigned integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnorm4x8: f / 255.0
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see float unpackUnorm1x8(uint8 v)
+       /// @see vec4 unpackUnorm4x8(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm4x8.xml">GLSL unpackUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec2 unpackUnorm2x8(uint16 p);
+       
+       /// First, converts the normalized floating-point value v into 8-bit integer value.
+       /// Then, the results are packed into the returned 8-bit unsigned integer.
+       ///
+       /// The conversion to fixed point is done as follows:
+       /// packSnorm1x8:       round(clamp(s, -1, +1) * 127.0)
+       ///
+       /// @see gtc_packing
+       /// @see uint16 packSnorm2x8(vec2 const & v)
+       /// @see uint32 packSnorm4x8(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml">GLSL packSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint8 packSnorm1x8(float s);
+
+       /// First, unpacks a single 8-bit unsigned integer p into a single 8-bit signed integers. 
+       /// Then, the value is converted to a normalized floating-point value to generate the returned scalar.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm1x8: clamp(f / 127.0, -1, +1)
+       /// 
+       /// @see gtc_packing
+       /// @see vec2 unpackSnorm2x8(uint16 p)
+       /// @see vec4 unpackSnorm4x8(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml">GLSL unpackSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL float unpackSnorm1x8(uint8 p);
+       
+       /// First, converts each component of the normalized floating-point value v into 8-bit integer values.
+       /// Then, the results are packed into the returned 16-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packSnorm2x8:       round(clamp(c, -1, +1) * 127.0)
+       ///
+       /// The first component of the vector will be written to the least significant bits of the output;
+       /// the last component will be written to the most significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see uint8 packSnorm1x8(float const & v)
+       /// @see uint32 packSnorm4x8(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml">GLSL packSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint16 packSnorm2x8(vec2 const & v);
+
+       /// First, unpacks a single 16-bit unsigned integer p into a pair of 8-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned two-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm2x8: clamp(f / 127.0, -1, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see float unpackSnorm1x8(uint8 p)
+       /// @see vec4 unpackSnorm4x8(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm4x8.xml">GLSL unpackSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec2 unpackSnorm2x8(uint16 p);
+       
+       /// First, converts the normalized floating-point value v into a 16-bit integer value.
+       /// Then, the results are packed into the returned 16-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm1x16:      round(clamp(c, 0, +1) * 65535.0)
+       ///
+       /// @see gtc_packing
+       /// @see uint16 packSnorm1x16(float const & v)
+       /// @see uint64 packSnorm4x16(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml">GLSL packUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint16 packUnorm1x16(float v);
+
+       /// First, unpacks a single 16-bit unsigned integer p into a of 16-bit unsigned integers. 
+       /// Then, the value is converted to a normalized floating-point value to generate the returned scalar.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnorm1x16: f / 65535.0 
+       /// 
+       /// @see gtc_packing
+       /// @see vec2 unpackUnorm2x16(uint32 p)
+       /// @see vec4 unpackUnorm4x16(uint64 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml">GLSL unpackUnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL float unpackUnorm1x16(uint16 p);
+
+       /// First, converts each component of the normalized floating-point value v into 16-bit integer values.
+       /// Then, the results are packed into the returned 64-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm4x16:      round(clamp(c, 0, +1) * 65535.0)
+       ///
+       /// The first component of the vector will be written to the least significant bits of the output;
+       /// the last component will be written to the most significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see uint16 packUnorm1x16(float const & v)
+       /// @see uint32 packUnorm2x16(vec2 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packUnorm4x8.xml">GLSL packUnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint64 packUnorm4x16(vec4 const & v);
+
+       /// First, unpacks a single 64-bit unsigned integer p into four 16-bit unsigned integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackUnormx4x16: f / 65535.0 
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see float unpackUnorm1x16(uint16 p)
+       /// @see vec2 unpackUnorm2x16(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackUnorm2x16.xml">GLSL unpackUnorm2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec4 unpackUnorm4x16(uint64 p);
+
+       /// First, converts the normalized floating-point value v into 16-bit integer value.
+       /// Then, the results are packed into the returned 16-bit unsigned integer.
+       ///
+       /// The conversion to fixed point is done as follows:
+       /// packSnorm1x8:       round(clamp(s, -1, +1) * 32767.0)
+       ///
+       /// @see gtc_packing
+       /// @see uint32 packSnorm2x16(vec2 const & v)
+       /// @see uint64 packSnorm4x16(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml">GLSL packSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint16 packSnorm1x16(float v);
+
+       /// First, unpacks a single 16-bit unsigned integer p into a single 16-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned scalar.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm1x16: clamp(f / 32767.0, -1, +1)
+       /// 
+       /// @see gtc_packing
+       /// @see vec2 unpackSnorm2x16(uint32 p)
+       /// @see vec4 unpackSnorm4x16(uint64 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm1x16.xml">GLSL unpackSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL float unpackSnorm1x16(uint16 p);
+
+       /// First, converts each component of the normalized floating-point value v into 16-bit integer values.
+       /// Then, the results are packed into the returned 64-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packSnorm2x8:       round(clamp(c, -1, +1) * 32767.0)
+       ///
+       /// The first component of the vector will be written to the least significant bits of the output;
+       /// the last component will be written to the most significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see uint16 packSnorm1x16(float const & v)
+       /// @see uint32 packSnorm2x16(vec2 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packSnorm4x8.xml">GLSL packSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint64 packSnorm4x16(vec4 const & v);
+
+       /// First, unpacks a single 64-bit unsigned integer p into four 16-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm4x16: clamp(f / 32767.0, -1, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see float unpackSnorm1x16(uint16 p)
+       /// @see vec2 unpackSnorm2x16(uint32 p)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackSnorm2x16.xml">GLSL unpackSnorm4x8 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec4 unpackSnorm4x16(uint64 p);
+       
+       /// Returns an unsigned integer obtained by converting the components of a floating-point scalar
+       /// to the 16-bit floating-point representation found in the OpenGL Specification,
+       /// and then packing this 16-bit value into a 16-bit unsigned integer.
+       ///
+       /// @see gtc_packing
+       /// @see uint32 packHalf2x16(vec2 const & v)
+       /// @see uint64 packHalf4x16(vec4 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml">GLSL packHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint16 packHalf1x16(float v);
+       
+       /// Returns a floating-point scalar with components obtained by unpacking a 16-bit unsigned integer into a 16-bit value,
+       /// interpreted as a 16-bit floating-point number according to the OpenGL Specification,
+       /// and converting it to 32-bit floating-point values.
+       ///
+       /// @see gtc_packing
+       /// @see vec2 unpackHalf2x16(uint32 const & v)
+       /// @see vec4 unpackHalf4x16(uint64 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml">GLSL unpackHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL float unpackHalf1x16(uint16 v);
+
+       /// Returns an unsigned integer obtained by converting the components of a four-component floating-point vector 
+       /// to the 16-bit floating-point representation found in the OpenGL Specification, 
+       /// and then packing these four 16-bit values into a 64-bit unsigned integer.
+       /// The first vector component specifies the 16 least-significant bits of the result; 
+       /// the forth component specifies the 16 most-significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint16 packHalf1x16(float const & v)
+       /// @see uint32 packHalf2x16(vec2 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/packHalf2x16.xml">GLSL packHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL uint64 packHalf4x16(vec4 const & v);
+       
+       /// Returns a four-component floating-point vector with components obtained by unpacking a 64-bit unsigned integer into four 16-bit values,
+       /// interpreting those values as 16-bit floating-point numbers according to the OpenGL Specification, 
+       /// and converting them to 32-bit floating-point values.
+       /// The first component of the vector is obtained from the 16 least-significant bits of v; 
+       /// the forth component is obtained from the 16 most-significant bits of v.
+       /// 
+       /// @see gtc_packing
+       /// @see float unpackHalf1x16(uint16 const & v)
+       /// @see vec2 unpackHalf2x16(uint32 const & v)
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/unpackHalf2x16.xml">GLSL unpackHalf2x16 man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       GLM_FUNC_DECL vec4 unpackHalf4x16(uint64 p);
+
+       /// Returns an unsigned integer obtained by converting the components of a four-component signed integer vector 
+       /// to the 10-10-10-2-bit signed integer representation found in the OpenGL Specification, 
+       /// and then packing these four values into a 32-bit unsigned integer.
+       /// The first vector component specifies the 10 least-significant bits of the result; 
+       /// the forth component specifies the 2 most-significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packI3x10_1x2(uvec4 const & v)
+       /// @see uint32 packSnorm3x10_1x2(vec4 const & v)
+       /// @see uint32 packUnorm3x10_1x2(vec4 const & v)
+       /// @see ivec4 unpackI3x10_1x2(uint32 const & p)
+       GLM_FUNC_DECL uint32 packI3x10_1x2(ivec4 const & v);
+
+       /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit signed integers. 
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packU3x10_1x2(uvec4 const & v)
+       /// @see vec4 unpackSnorm3x10_1x2(uint32 const & p);
+       /// @see uvec4 unpackI3x10_1x2(uint32 const & p);
+       GLM_FUNC_DECL ivec4 unpackI3x10_1x2(uint32 p);
+
+       /// Returns an unsigned integer obtained by converting the components of a four-component unsigned integer vector 
+       /// to the 10-10-10-2-bit unsigned integer representation found in the OpenGL Specification, 
+       /// and then packing these four values into a 32-bit unsigned integer.
+       /// The first vector component specifies the 10 least-significant bits of the result; 
+       /// the forth component specifies the 2 most-significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packI3x10_1x2(ivec4 const & v)
+       /// @see uint32 packSnorm3x10_1x2(vec4 const & v)
+       /// @see uint32 packUnorm3x10_1x2(vec4 const & v)
+       /// @see ivec4 unpackU3x10_1x2(uint32 const & p)
+       GLM_FUNC_DECL uint32 packU3x10_1x2(uvec4 const & v);
+
+       /// Unpacks a single 32-bit unsigned integer p into three 10-bit and one 2-bit unsigned integers. 
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packU3x10_1x2(uvec4 const & v)
+       /// @see vec4 unpackSnorm3x10_1x2(uint32 const & p);
+       /// @see uvec4 unpackI3x10_1x2(uint32 const & p);
+       GLM_FUNC_DECL uvec4 unpackU3x10_1x2(uint32 p);
+
+       /// First, converts the first three components of the normalized floating-point value v into 10-bit signed integer values.
+       /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed integer values.
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packSnorm3x10_1x2(xyz):     round(clamp(c, -1, +1) * 511.0)
+       /// packSnorm3x10_1x2(w):       round(clamp(c, -1, +1) * 1.0)
+       ///
+       /// The first vector component specifies the 10 least-significant bits of the result; 
+       /// the forth component specifies the 2 most-significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see vec4 unpackSnorm3x10_1x2(uint32 const & p)
+       /// @see uint32 packUnorm3x10_1x2(vec4 const & v)
+       /// @see uint32 packU3x10_1x2(uvec4 const & v)
+       /// @see uint32 packI3x10_1x2(ivec4 const & v)
+       GLM_FUNC_DECL uint32 packSnorm3x10_1x2(vec4 const & v);
+
+       /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm3x10_1x2(xyz): clamp(f / 511.0, -1, +1)
+       /// unpackSnorm3x10_1x2(w): clamp(f / 511.0, -1, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packSnorm3x10_1x2(vec4 const & v)
+       /// @see vec4 unpackUnorm3x10_1x2(uint32 const & p))
+       /// @see uvec4 unpackI3x10_1x2(uint32 const & p)
+       /// @see uvec4 unpackU3x10_1x2(uint32 const & p)
+       GLM_FUNC_DECL vec4 unpackSnorm3x10_1x2(uint32 p);
+
+       /// First, converts the first three components of the normalized floating-point value v into 10-bit unsigned integer values.
+       /// Then, converts the forth component of the normalized floating-point value v into 2-bit signed uninteger values.
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       ///
+       /// The conversion for component c of v to fixed point is done as follows:
+       /// packUnorm3x10_1x2(xyz):     round(clamp(c, 0, +1) * 1023.0)
+       /// packUnorm3x10_1x2(w):       round(clamp(c, 0, +1) * 3.0)
+       ///
+       /// The first vector component specifies the 10 least-significant bits of the result; 
+       /// the forth component specifies the 2 most-significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see vec4 unpackUnorm3x10_1x2(uint32 const & p)
+       /// @see uint32 packUnorm3x10_1x2(vec4 const & v)
+       /// @see uint32 packU3x10_1x2(uvec4 const & v)
+       /// @see uint32 packI3x10_1x2(ivec4 const & v)
+       GLM_FUNC_DECL uint32 packUnorm3x10_1x2(vec4 const & v);
+
+       /// First, unpacks a single 32-bit unsigned integer p into four 16-bit signed integers. 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned four-component vector.
+       /// 
+       /// The conversion for unpacked fixed-point value f to floating point is done as follows:
+       /// unpackSnorm3x10_1x2(xyz): clamp(f / 1023.0, 0, +1)
+       /// unpackSnorm3x10_1x2(w): clamp(f / 3.0, 0, +1)
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packSnorm3x10_1x2(vec4 const & v)
+       /// @see vec4 unpackInorm3x10_1x2(uint32 const & p))
+       /// @see uvec4 unpackI3x10_1x2(uint32 const & p)
+       /// @see uvec4 unpackU3x10_1x2(uint32 const & p)
+       GLM_FUNC_DECL vec4 unpackUnorm3x10_1x2(uint32 p);
+
+       /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values.
+       /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value.
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       ///
+       /// The first vector component specifies the 11 least-significant bits of the result; 
+       /// the last component specifies the 10 most-significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see vec3 unpackF2x11_1x10(uint32 const & p)
+       GLM_FUNC_DECL uint32 packF2x11_1x10(vec3 const & v);
+
+       /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector.
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packF2x11_1x10(vec3 const & v)
+       GLM_FUNC_DECL vec3 unpackF2x11_1x10(uint32 p);
+
+
+       /// First, converts the first two components of the normalized floating-point value v into 11-bit signless floating-point values.
+       /// Then, converts the third component of the normalized floating-point value v into a 10-bit signless floating-point value.
+       /// Then, the results are packed into the returned 32-bit unsigned integer.
+       ///
+       /// The first vector component specifies the 11 least-significant bits of the result; 
+       /// the last component specifies the 10 most-significant bits.
+       ///
+       /// @see gtc_packing
+       /// @see vec3 unpackF3x9_E1x5(uint32 const & p)
+       GLM_FUNC_DECL uint32 packF3x9_E1x5(vec3 const & v);
+
+       /// First, unpacks a single 32-bit unsigned integer p into two 11-bit signless floating-point values and one 10-bit signless floating-point value . 
+       /// Then, each component is converted to a normalized floating-point value to generate the returned three-component vector.
+       /// 
+       /// The first component of the returned vector will be extracted from the least significant bits of the input; 
+       /// the last component will be extracted from the most significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see uint32 packF3x9_E1x5(vec3 const & v)
+       GLM_FUNC_DECL vec3 unpackF3x9_E1x5(uint32 p);
+
+       /// Returns an unsigned integer vector obtained by converting the components of a floating-point vector
+       /// to the 16-bit floating-point representation found in the OpenGL Specification.
+       /// The first vector component specifies the 16 least-significant bits of the result; 
+       /// the forth component specifies the 16 most-significant bits.
+       /// 
+       /// @see gtc_packing
+       /// @see vecType<float, P> unpackHalf(vecType<uint16, P> const & p)
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<uint16, P> packHalf(vecType<float, P> const & v);
+
+       /// Returns a floating-point vector with components obtained by reinterpreting an integer vector as 16-bit floating-point numbers and converting them to 32-bit floating-point values.
+       /// The first component of the vector is obtained from the 16 least-significant bits of v;
+       /// the forth component is obtained from the 16 most-significant bits of v.
+       /// 
+       /// @see gtc_packing
+       /// @see vecType<uint16, P> packHalf(vecType<float, P> const & v)
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.4 Floating-Point Pack and Unpack Functions</a>
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<float, P> unpackHalf(vecType<uint16, P> const & p);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vecType<floatType, P> unpackUnorm(vecType<intType, P> const & p);
+       template <typename uintType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<uintType, P> packUnorm(vecType<floatType, P> const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see vecType<intType, P> packUnorm(vecType<floatType, P> const & v)
+       template <typename uintType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<floatType, P> unpackUnorm(vecType<uintType, P> const & v);
+
+       /// Convert each component of the normalized floating-point vector into signed integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vecType<floatType, P> unpackSnorm(vecType<intType, P> const & p);
+       template <typename intType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<intType, P> packSnorm(vecType<floatType, P> const & v);
+
+       /// Convert each signed integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see vecType<intType, P> packSnorm(vecType<floatType, P> const & v)
+       template <typename intType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<floatType, P> unpackSnorm(vecType<intType, P> const & v);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vec2 unpackUnorm2x4(uint8 p)
+       GLM_FUNC_DECL uint8 packUnorm2x4(vec2 const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see uint8 packUnorm2x4(vec2 const & v)
+       GLM_FUNC_DECL vec2 unpackUnorm2x4(uint8 p);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vec4 unpackUnorm4x4(uint16 p)
+       GLM_FUNC_DECL uint16 packUnorm4x4(vec4 const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see uint16 packUnorm4x4(vec4 const & v)
+       GLM_FUNC_DECL vec4 unpackUnorm4x4(uint16 p);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vec3 unpackUnorm1x5_1x6_1x5(uint16 p)
+       GLM_FUNC_DECL uint16 packUnorm1x5_1x6_1x5(vec3 const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see uint16 packUnorm1x5_1x6_1x5(vec3 const & v)
+       GLM_FUNC_DECL vec3 unpackUnorm1x5_1x6_1x5(uint16 p);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vec4 unpackUnorm3x5_1x1(uint16 p)
+       GLM_FUNC_DECL uint16 packUnorm3x5_1x1(vec4 const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see uint16 packUnorm3x5_1x1(vec4 const & v)
+       GLM_FUNC_DECL vec4 unpackUnorm3x5_1x1(uint16 p);
+
+       /// Convert each component of the normalized floating-point vector into unsigned integer values.
+       ///
+       /// @see gtc_packing
+       /// @see vec3 unpackUnorm2x3_1x2(uint8 p)
+       GLM_FUNC_DECL uint8 packUnorm2x3_1x2(vec3 const & v);
+
+       /// Convert each unsigned integer components of a vector to normalized floating-point values.
+       /// 
+       /// @see gtc_packing
+       /// @see uint8 packUnorm2x3_1x2(vec3 const & v)
+       GLM_FUNC_DECL vec3 unpackUnorm2x3_1x2(uint8 p);
+       /// @}
+}// namespace glm
+
+#include "packing.inl"
diff --git a/core/deps/glm/glm/gtc/packing.inl b/core/deps/glm/glm/gtc/packing.inl
new file mode 100755 (executable)
index 0000000..618fb9e
--- /dev/null
@@ -0,0 +1,781 @@
+/// @ref gtc_packing
+/// @file glm/gtc/packing.inl
+
+#include "../common.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../detail/type_half.hpp"
+#include <cstring>
+#include <limits>
+
+namespace glm{
+namespace detail
+{
+       GLM_FUNC_QUALIFIER glm::uint16 float2half(glm::uint32 f)
+       {
+               // 10 bits    =>                         EE EEEFFFFF
+               // 11 bits    =>                        EEE EEFFFFFF
+               // Half bits  =>                   SEEEEEFF FFFFFFFF
+               // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+
+               // 0x00007c00 => 00000000 00000000 01111100 00000000
+               // 0x000003ff => 00000000 00000000 00000011 11111111
+               // 0x38000000 => 00111000 00000000 00000000 00000000
+               // 0x7f800000 => 01111111 10000000 00000000 00000000
+               // 0x00008000 => 00000000 00000000 10000000 00000000
+               return
+                       ((f >> 16) & 0x8000) | // sign
+                       ((((f & 0x7f800000) - 0x38000000) >> 13) & 0x7c00) | // exponential
+                       ((f >> 13) & 0x03ff); // Mantissa
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint32 float2packed11(glm::uint32 f)
+       {
+               // 10 bits    =>                         EE EEEFFFFF
+               // 11 bits    =>                        EEE EEFFFFFF
+               // Half bits  =>                   SEEEEEFF FFFFFFFF
+               // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+
+               // 0x000007c0 => 00000000 00000000 00000111 11000000
+               // 0x00007c00 => 00000000 00000000 01111100 00000000
+               // 0x000003ff => 00000000 00000000 00000011 11111111
+               // 0x38000000 => 00111000 00000000 00000000 00000000
+               // 0x7f800000 => 01111111 10000000 00000000 00000000
+               // 0x00008000 => 00000000 00000000 10000000 00000000
+               return
+                       ((((f & 0x7f800000) - 0x38000000) >> 17) & 0x07c0) | // exponential
+                       ((f >> 17) & 0x003f); // Mantissa
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint32 packed11ToFloat(glm::uint32 p)
+       {
+               // 10 bits    =>                         EE EEEFFFFF
+               // 11 bits    =>                        EEE EEFFFFFF
+               // Half bits  =>                   SEEEEEFF FFFFFFFF
+               // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+
+               // 0x000007c0 => 00000000 00000000 00000111 11000000
+               // 0x00007c00 => 00000000 00000000 01111100 00000000
+               // 0x000003ff => 00000000 00000000 00000011 11111111
+               // 0x38000000 => 00111000 00000000 00000000 00000000
+               // 0x7f800000 => 01111111 10000000 00000000 00000000
+               // 0x00008000 => 00000000 00000000 10000000 00000000
+               return
+                       ((((p & 0x07c0) << 17) + 0x38000000) & 0x7f800000) | // exponential
+                       ((p & 0x003f) << 17); // Mantissa
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint32 float2packed10(glm::uint32 f)
+       {
+               // 10 bits    =>                         EE EEEFFFFF
+               // 11 bits    =>                        EEE EEFFFFFF
+               // Half bits  =>                   SEEEEEFF FFFFFFFF
+               // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+
+               // 0x0000001F => 00000000 00000000 00000000 00011111
+               // 0x0000003F => 00000000 00000000 00000000 00111111
+               // 0x000003E0 => 00000000 00000000 00000011 11100000
+               // 0x000007C0 => 00000000 00000000 00000111 11000000
+               // 0x00007C00 => 00000000 00000000 01111100 00000000
+               // 0x000003FF => 00000000 00000000 00000011 11111111
+               // 0x38000000 => 00111000 00000000 00000000 00000000
+               // 0x7f800000 => 01111111 10000000 00000000 00000000
+               // 0x00008000 => 00000000 00000000 10000000 00000000
+               return
+                       ((((f & 0x7f800000) - 0x38000000) >> 18) & 0x03E0) | // exponential
+                       ((f >> 18) & 0x001f); // Mantissa
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint32 packed10ToFloat(glm::uint32 p)
+       {
+               // 10 bits    =>                         EE EEEFFFFF
+               // 11 bits    =>                        EEE EEFFFFFF
+               // Half bits  =>                   SEEEEEFF FFFFFFFF
+               // Float bits => SEEEEEEE EFFFFFFF FFFFFFFF FFFFFFFF
+
+               // 0x0000001F => 00000000 00000000 00000000 00011111
+               // 0x0000003F => 00000000 00000000 00000000 00111111
+               // 0x000003E0 => 00000000 00000000 00000011 11100000
+               // 0x000007C0 => 00000000 00000000 00000111 11000000
+               // 0x00007C00 => 00000000 00000000 01111100 00000000
+               // 0x000003FF => 00000000 00000000 00000011 11111111
+               // 0x38000000 => 00111000 00000000 00000000 00000000
+               // 0x7f800000 => 01111111 10000000 00000000 00000000
+               // 0x00008000 => 00000000 00000000 10000000 00000000
+               return
+                       ((((p & 0x03E0) << 18) + 0x38000000) & 0x7f800000) | // exponential
+                       ((p & 0x001f) << 18); // Mantissa
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint half2float(glm::uint h)
+       {
+               return ((h & 0x8000) << 16) | ((( h & 0x7c00) + 0x1C000) << 13) | ((h & 0x03FF) << 13);
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint floatTo11bit(float x)
+       {
+               if(x == 0.0f)
+                       return 0u;
+               else if(glm::isnan(x))
+                       return ~0u;
+               else if(glm::isinf(x))
+                       return 0x1Fu << 6u;
+
+               uint Pack = 0u;
+               memcpy(&Pack, &x, sizeof(Pack));
+               return float2packed11(Pack);
+       }
+
+       GLM_FUNC_QUALIFIER float packed11bitToFloat(glm::uint x)
+       {
+               if(x == 0)
+                       return 0.0f;
+               else if(x == ((1 << 11) - 1))
+                       return ~0;//NaN
+               else if(x == (0x1f << 6))
+                       return ~0;//Inf
+
+               uint Result = packed11ToFloat(x);
+
+               float Temp = 0;
+               memcpy(&Temp, &Result, sizeof(Temp));
+               return Temp;
+       }
+
+       GLM_FUNC_QUALIFIER glm::uint floatTo10bit(float x)
+       {
+               if(x == 0.0f)
+                       return 0u;
+               else if(glm::isnan(x))
+                       return ~0u;
+               else if(glm::isinf(x))
+                       return 0x1Fu << 5u;
+
+               uint Pack = 0;
+               memcpy(&Pack, &x, sizeof(Pack));
+               return float2packed10(Pack);
+       }
+
+       GLM_FUNC_QUALIFIER float packed10bitToFloat(glm::uint x)
+       {
+               if(x == 0)
+                       return 0.0f;
+               else if(x == ((1 << 10) - 1))
+                       return ~0;//NaN
+               else if(x == (0x1f << 5))
+                       return ~0;//Inf
+
+               uint Result = packed10ToFloat(x);
+
+               float Temp = 0;
+               memcpy(&Temp, &Result, sizeof(Temp));
+               return Temp;
+       }
+
+//     GLM_FUNC_QUALIFIER glm::uint f11_f11_f10(float x, float y, float z)
+//     {
+//             return ((floatTo11bit(x) & ((1 << 11) - 1)) << 0) |  ((floatTo11bit(y) & ((1 << 11) - 1)) << 11) | ((floatTo10bit(z) & ((1 << 10) - 1)) << 22);
+//     }
+
+       union u3u3u2
+       {
+               struct
+               {
+                       uint x : 3;
+                       uint y : 3;
+                       uint z : 2;
+               } data;
+               uint8 pack;
+       };
+
+       union u4u4
+       {
+               struct
+               {
+                       uint x : 4;
+                       uint y : 4;
+               } data;
+               uint8 pack;
+       };
+
+       union u4u4u4u4
+       {
+               struct
+               {
+                       uint x : 4;
+                       uint y : 4;
+                       uint z : 4;
+                       uint w : 4;
+               } data;
+               uint16 pack;
+       };
+
+       union u5u6u5
+       {
+               struct
+               {
+                       uint x : 5;
+                       uint y : 6;
+                       uint z : 5;
+               } data;
+               uint16 pack;
+       };
+
+       union u5u5u5u1
+       {
+               struct
+               {
+                       uint x : 5;
+                       uint y : 5;
+                       uint z : 5;
+                       uint w : 1;
+               } data;
+               uint16 pack;
+       };
+
+       union u10u10u10u2
+       {
+               struct
+               {
+                       uint x : 10;
+                       uint y : 10;
+                       uint z : 10;
+                       uint w : 2;
+               } data;
+               uint32 pack;
+       };
+
+       union i10i10i10i2
+       {
+               struct
+               {
+                       int x : 10;
+                       int y : 10;
+                       int z : 10;
+                       int w : 2;
+               } data;
+               uint32 pack;
+       };
+
+       union u9u9u9e5
+       {
+               struct
+               {
+                       uint x : 9;
+                       uint y : 9;
+                       uint z : 9;
+                       uint w : 5;
+               } data;
+               uint32 pack;
+       };
+
+       template <precision P, template <typename, precision> class vecType>
+       struct compute_half
+       {};
+
+       template <precision P>
+       struct compute_half<P, tvec1>
+       {
+               GLM_FUNC_QUALIFIER static tvec1<uint16, P> pack(tvec1<float, P> const & v)
+               {
+                       int16 const Unpack(detail::toFloat16(v.x));
+                       u16vec1 Packed(uninitialize);
+                       memcpy(&Packed, &Unpack, sizeof(Packed));
+                       return Packed;
+               }
+
+               GLM_FUNC_QUALIFIER static tvec1<float, P> unpack(tvec1<uint16, P> const & v)
+               {
+                       i16vec1 Unpack(uninitialize);
+                       memcpy(&Unpack, &v, sizeof(Unpack));
+                       return tvec1<float, P>(detail::toFloat32(v.x));
+               }
+       };
+
+       template <precision P>
+       struct compute_half<P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<uint16, P> pack(tvec2<float, P> const & v)
+               {
+                       tvec2<int16, P> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y));
+                       u16vec2 Packed(uninitialize);
+                       memcpy(&Packed, &Unpack, sizeof(Packed));
+                       return Packed;
+               }
+
+               GLM_FUNC_QUALIFIER static tvec2<float, P> unpack(tvec2<uint16, P> const & v)
+               {
+                       i16vec2 Unpack(uninitialize);
+                       memcpy(&Unpack, &v, sizeof(Unpack));
+                       return tvec2<float, P>(detail::toFloat32(v.x), detail::toFloat32(v.y));
+               }
+       };
+
+       template <precision P>
+       struct compute_half<P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<uint16, P> pack(tvec3<float, P> const & v)
+               {
+                       tvec3<int16, P> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z));
+                       u16vec3 Packed(uninitialize);
+                       memcpy(&Packed, &Unpack, sizeof(Packed));
+                       return Packed;
+               }
+
+               GLM_FUNC_QUALIFIER static tvec3<float, P> unpack(tvec3<uint16, P> const & v)
+               {
+                       i16vec3 Unpack(uninitialize);
+                       memcpy(&Unpack, &v, sizeof(Unpack));
+                       return tvec3<float, P>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z));
+               }
+       };
+
+       template <precision P>
+       struct compute_half<P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint16, P> pack(tvec4<float, P> const & v)
+               {
+                       tvec4<int16, P> const Unpack(detail::toFloat16(v.x), detail::toFloat16(v.y), detail::toFloat16(v.z), detail::toFloat16(v.w));
+                       u16vec4 Packed(uninitialize);
+                       memcpy(&Packed, &Unpack, sizeof(Packed));
+                       return Packed;
+               }
+
+               GLM_FUNC_QUALIFIER static tvec4<float, P> unpack(tvec4<uint16, P> const & v)
+               {
+                       i16vec4 Unpack(uninitialize);
+                       memcpy(&Unpack, &v, sizeof(Unpack));
+                       return tvec4<float, P>(detail::toFloat32(v.x), detail::toFloat32(v.y), detail::toFloat32(v.z), detail::toFloat32(v.w));
+               }
+       };
+}//namespace detail
+
+       GLM_FUNC_QUALIFIER uint8 packUnorm1x8(float v)
+       {
+               return static_cast<uint8>(round(clamp(v, 0.0f, 1.0f) * 255.0f));
+       }
+       
+       GLM_FUNC_QUALIFIER float unpackUnorm1x8(uint8 p)
+       {
+               float const Unpack(p);
+               return Unpack * static_cast<float>(0.0039215686274509803921568627451); // 1 / 255
+       }
+       
+       GLM_FUNC_QUALIFIER uint16 packUnorm2x8(vec2 const & v)
+       {
+               u8vec2 const Topack(round(clamp(v, 0.0f, 1.0f) * 255.0f));
+
+               uint16 Unpack = 0;
+               memcpy(&Unpack, &Topack, sizeof(Unpack));
+               return Unpack;
+       }
+       
+       GLM_FUNC_QUALIFIER vec2 unpackUnorm2x8(uint16 p)
+       {
+               u8vec2 Unpack(uninitialize);
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return vec2(Unpack) * float(0.0039215686274509803921568627451); // 1 / 255
+       }
+
+       GLM_FUNC_QUALIFIER uint8 packSnorm1x8(float v)
+       {
+               int8 const Topack(static_cast<int8>(round(clamp(v ,-1.0f, 1.0f) * 127.0f)));
+               uint8 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+       
+       GLM_FUNC_QUALIFIER float unpackSnorm1x8(uint8 p)
+       {
+               int8 Unpack = 0;
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return clamp(
+                       static_cast<float>(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f
+                       -1.0f, 1.0f);
+       }
+       
+       GLM_FUNC_QUALIFIER uint16 packSnorm2x8(vec2 const & v)
+       {
+               i8vec2 const Topack(round(clamp(v, -1.0f, 1.0f) * 127.0f));
+               uint16 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+       
+       GLM_FUNC_QUALIFIER vec2 unpackSnorm2x8(uint16 p)
+       {
+               i8vec2 Unpack(uninitialize);
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return clamp(
+                       vec2(Unpack) * 0.00787401574803149606299212598425f, // 1.0f / 127.0f
+                       -1.0f, 1.0f);
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packUnorm1x16(float s)
+       {
+               return static_cast<uint16>(round(clamp(s, 0.0f, 1.0f) * 65535.0f));
+       }
+
+       GLM_FUNC_QUALIFIER float unpackUnorm1x16(uint16 p)
+       {
+               float const Unpack(p);
+               return Unpack * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0
+       }
+
+       GLM_FUNC_QUALIFIER uint64 packUnorm4x16(vec4 const & v)
+       {
+               u16vec4 const Topack(round(clamp(v , 0.0f, 1.0f) * 65535.0f));
+               uint64 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackUnorm4x16(uint64 p)
+       {
+               u16vec4 Unpack(uninitialize);
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return vec4(Unpack) * 1.5259021896696421759365224689097e-5f; // 1.0 / 65535.0
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packSnorm1x16(float v)
+       {
+               int16 const Topack = static_cast<int16>(round(clamp(v ,-1.0f, 1.0f) * 32767.0f));
+               uint16 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+
+       GLM_FUNC_QUALIFIER float unpackSnorm1x16(uint16 p)
+       {
+               int16 Unpack = 0;
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return clamp(
+                       static_cast<float>(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f, 
+                       -1.0f, 1.0f);
+       }
+
+       GLM_FUNC_QUALIFIER uint64 packSnorm4x16(vec4 const & v)
+       {
+               i16vec4 const Topack(round(clamp(v ,-1.0f, 1.0f) * 32767.0f));
+               uint64 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackSnorm4x16(uint64 p)
+       {
+               i16vec4 Unpack(uninitialize);
+               memcpy(&Unpack, &p, sizeof(Unpack));
+               return clamp(
+                       vec4(Unpack) * 3.0518509475997192297128208258309e-5f, //1.0f / 32767.0f,
+                       -1.0f, 1.0f);
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packHalf1x16(float v)
+       {
+               int16 const Topack(detail::toFloat16(v));
+               uint16 Packed = 0;
+               memcpy(&Packed, &Topack, sizeof(Packed));
+               return Packed;
+       }
+
+       GLM_FUNC_QUALIFIER float unpackHalf1x16(uint16 v)
+       {
+               int16 Unpack = 0;
+               memcpy(&Unpack, &v, sizeof(Unpack));
+               return detail::toFloat32(Unpack);
+       }
+
+       GLM_FUNC_QUALIFIER uint64 packHalf4x16(glm::vec4 const & v)
+       {
+               i16vec4 const Unpack(
+                       detail::toFloat16(v.x),
+                       detail::toFloat16(v.y),
+                       detail::toFloat16(v.z),
+                       detail::toFloat16(v.w));
+               uint64 Packed = 0;
+               memcpy(&Packed, &Unpack, sizeof(Packed));
+               return Packed;
+       }
+
+       GLM_FUNC_QUALIFIER glm::vec4 unpackHalf4x16(uint64 v)
+       {
+               i16vec4 Unpack(uninitialize);
+               memcpy(&Unpack, &v, sizeof(Unpack));
+               return vec4(
+                       detail::toFloat32(Unpack.x),
+                       detail::toFloat32(Unpack.y),
+                       detail::toFloat32(Unpack.z),
+                       detail::toFloat32(Unpack.w));
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packI3x10_1x2(ivec4 const & v)
+       {
+               detail::i10i10i10i2 Result;
+               Result.data.x = v.x;
+               Result.data.y = v.y;
+               Result.data.z = v.z;
+               Result.data.w = v.w;
+               return Result.pack; 
+       }
+
+       GLM_FUNC_QUALIFIER ivec4 unpackI3x10_1x2(uint32 v)
+       {
+               detail::i10i10i10i2 Unpack;
+               Unpack.pack = v;
+               return ivec4(
+                       Unpack.data.x,
+                       Unpack.data.y,
+                       Unpack.data.z,
+                       Unpack.data.w);
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packU3x10_1x2(uvec4 const & v)
+       {
+               detail::u10u10u10u2 Result;
+               Result.data.x = v.x;
+               Result.data.y = v.y;
+               Result.data.z = v.z;
+               Result.data.w = v.w;
+               return Result.pack; 
+       }
+
+       GLM_FUNC_QUALIFIER uvec4 unpackU3x10_1x2(uint32 v)
+       {
+               detail::u10u10u10u2 Unpack;
+               Unpack.pack = v;
+               return uvec4(
+                       Unpack.data.x,
+                       Unpack.data.y,
+                       Unpack.data.z,
+                       Unpack.data.w);
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packSnorm3x10_1x2(vec4 const & v)
+       {
+               detail::i10i10i10i2 Result;
+               Result.data.x = int(round(clamp(v.x,-1.0f, 1.0f) * 511.f));
+               Result.data.y = int(round(clamp(v.y,-1.0f, 1.0f) * 511.f));
+               Result.data.z = int(round(clamp(v.z,-1.0f, 1.0f) * 511.f));
+               Result.data.w = int(round(clamp(v.w,-1.0f, 1.0f) *   1.f));
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackSnorm3x10_1x2(uint32 v)
+       {
+               detail::i10i10i10i2 Unpack;
+               Unpack.pack = v;
+               vec4 Result;
+               Result.x = clamp(float(Unpack.data.x) / 511.f, -1.0f, 1.0f);
+               Result.y = clamp(float(Unpack.data.y) / 511.f, -1.0f, 1.0f);
+               Result.z = clamp(float(Unpack.data.z) / 511.f, -1.0f, 1.0f);
+               Result.w = clamp(float(Unpack.data.w) /   1.f, -1.0f, 1.0f);
+               return Result;
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packUnorm3x10_1x2(vec4 const & v)
+       {
+               uvec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(1023.f, 1023.f, 1023.f, 3.f)));
+
+               detail::u10u10u10u2 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               Result.data.z = Unpack.z;
+               Result.data.w = Unpack.w;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackUnorm3x10_1x2(uint32 v)
+       {
+               vec4 const ScaleFactors(1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 1023.f, 1.0f / 3.f);
+
+               detail::u10u10u10u2 Unpack;
+               Unpack.pack = v;
+               return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactors;
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packF2x11_1x10(vec3 const & v)
+       {
+               return
+                       ((detail::floatTo11bit(v.x) & ((1 << 11) - 1)) <<  0) |
+                       ((detail::floatTo11bit(v.y) & ((1 << 11) - 1)) << 11) |
+                       ((detail::floatTo10bit(v.z) & ((1 << 10) - 1)) << 22);
+       }
+
+       GLM_FUNC_QUALIFIER vec3 unpackF2x11_1x10(uint32 v)
+       {
+               return vec3(
+                       detail::packed11bitToFloat(v >> 0),
+                       detail::packed11bitToFloat(v >> 11),
+                       detail::packed10bitToFloat(v >> 22));
+       }
+
+       GLM_FUNC_QUALIFIER uint32 packF3x9_E1x5(vec3 const & v)
+       {
+               float const SharedExpMax = (pow(2.0f, 9.0f - 1.0f) / pow(2.0f, 9.0f)) * pow(2.0f, 31.f - 15.f);
+               vec3 const Color = clamp(v, 0.0f, SharedExpMax);
+               float const MaxColor = max(Color.x, max(Color.y, Color.z));
+
+               float const ExpSharedP = max(-15.f - 1.f, floor(log2(MaxColor))) + 1.0f + 15.f;
+               float const MaxShared = floor(MaxColor / pow(2.0f, (ExpSharedP - 16.f - 9.f)) + 0.5f);
+               float const ExpShared = MaxShared == pow(2.0f, 9.0f) ? ExpSharedP + 1.0f : ExpSharedP;
+
+               uvec3 const ColorComp(floor(Color / pow(2.f, (ExpShared - 15.f - 9.f)) + 0.5f));
+
+               detail::u9u9u9e5 Unpack;
+               Unpack.data.x = ColorComp.x;
+               Unpack.data.y = ColorComp.y;
+               Unpack.data.z = ColorComp.z;
+               Unpack.data.w = uint(ExpShared);
+               return Unpack.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec3 unpackF3x9_E1x5(uint32 v)
+       {
+               detail::u9u9u9e5 Unpack;
+               Unpack.pack = v;
+
+               return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * pow(2.0f, Unpack.data.w - 15.f - 9.f);
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uint16, P> packHalf(vecType<float, P> const & v)
+       {
+               return detail::compute_half<P, vecType>::pack(v);
+       }
+
+       template <precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<float, P> unpackHalf(vecType<uint16, P> const & v)
+       {
+               return detail::compute_half<P, vecType>::unpack(v);
+       }
+
+       template <typename uintType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uintType, P> packUnorm(vecType<floatType, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<uintType>::is_integer, "uintType must be an integer type");
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "floatType must be a floating point type");
+
+               return vecType<uintType, P>(round(clamp(v, static_cast<floatType>(0), static_cast<floatType>(1)) * static_cast<floatType>(std::numeric_limits<uintType>::max())));
+       }
+
+       template <typename uintType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<floatType, P> unpackUnorm(vecType<uintType, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<uintType>::is_integer, "uintType must be an integer type");
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "floatType must be a floating point type");
+
+               return vecType<float, P>(v) * (static_cast<floatType>(1) / static_cast<floatType>(std::numeric_limits<uintType>::max()));
+       }
+
+       template <typename intType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<intType, P> packSnorm(vecType<floatType, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<intType>::is_integer, "uintType must be an integer type");
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "floatType must be a floating point type");
+
+               return vecType<intType, P>(round(clamp(v , static_cast<floatType>(-1), static_cast<floatType>(1)) * static_cast<floatType>(std::numeric_limits<intType>::max())));
+       }
+
+       template <typename intType, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<floatType, P> unpackSnorm(vecType<intType, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<intType>::is_integer, "uintType must be an integer type");
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "floatType must be a floating point type");
+
+               return clamp(vecType<floatType, P>(v) * (static_cast<floatType>(1) / static_cast<floatType>(std::numeric_limits<intType>::max())), static_cast<floatType>(-1), static_cast<floatType>(1));
+       }
+
+       GLM_FUNC_QUALIFIER uint8 packUnorm2x4(vec2 const & v)
+       {
+               u32vec2 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f));
+               detail::u4u4 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec2 unpackUnorm2x4(uint8 v)
+       {
+               float const ScaleFactor(1.f / 15.f);
+               detail::u4u4 Unpack;
+               Unpack.pack = v;
+               return vec2(Unpack.data.x, Unpack.data.y) * ScaleFactor;
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packUnorm4x4(vec4 const & v)
+       {
+               u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * 15.0f));
+               detail::u4u4u4u4 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               Result.data.z = Unpack.z;
+               Result.data.w = Unpack.w;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackUnorm4x4(uint16 v)
+       {
+               float const ScaleFactor(1.f / 15.f);
+               detail::u4u4u4u4 Unpack;
+               Unpack.pack = v;
+               return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor;
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packUnorm1x5_1x6_1x5(vec3 const & v)
+       {
+               u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(31.f, 63.f, 31.f)));
+               detail::u5u6u5 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               Result.data.z = Unpack.z;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec3 unpackUnorm1x5_1x6_1x5(uint16 v)
+       {
+               vec3 const ScaleFactor(1.f / 31.f, 1.f / 63.f, 1.f / 31.f);
+               detail::u5u6u5 Unpack;
+               Unpack.pack = v;
+               return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor;
+       }
+
+       GLM_FUNC_QUALIFIER uint16 packUnorm3x5_1x1(vec4 const & v)
+       {
+               u32vec4 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec4(31.f, 31.f, 31.f, 1.f)));
+               detail::u5u5u5u1 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               Result.data.z = Unpack.z;
+               Result.data.w = Unpack.w;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec4 unpackUnorm3x5_1x1(uint16 v)
+       {
+               vec4 const ScaleFactor(1.f / 31.f, 1.f / 31.f, 1.f / 31.f, 1.f);
+               detail::u5u5u5u1 Unpack;
+               Unpack.pack = v;
+               return vec4(Unpack.data.x, Unpack.data.y, Unpack.data.z, Unpack.data.w) * ScaleFactor;
+       }
+
+       GLM_FUNC_QUALIFIER uint8 packUnorm2x3_1x2(vec3 const & v)
+       {
+               u32vec3 const Unpack(round(clamp(v, 0.0f, 1.0f) * vec3(7.f, 7.f, 3.f)));
+               detail::u3u3u2 Result;
+               Result.data.x = Unpack.x;
+               Result.data.y = Unpack.y;
+               Result.data.z = Unpack.z;
+               return Result.pack;
+       }
+
+       GLM_FUNC_QUALIFIER vec3 unpackUnorm2x3_1x2(uint8 v)
+       {
+               vec3 const ScaleFactor(1.f / 7.f, 1.f / 7.f, 1.f / 3.f);
+               detail::u3u3u2 Unpack;
+               Unpack.pack = v;
+               return vec3(Unpack.data.x, Unpack.data.y, Unpack.data.z) * ScaleFactor;
+       }
+}//namespace glm
+
diff --git a/core/deps/glm/glm/gtc/quaternion.hpp b/core/deps/glm/glm/gtc/quaternion.hpp
new file mode 100755 (executable)
index 0000000..8af1c8b
--- /dev/null
@@ -0,0 +1,397 @@
+/// @ref gtc_quaternion
+/// @file glm/gtc/quaternion.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_constants (dependence)
+///
+/// @defgroup gtc_quaternion GLM_GTC_quaternion
+/// @ingroup gtc
+///
+/// @brief Defines a templated quaternion type and several quaternion operations.
+///
+/// <glm/gtc/quaternion.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../mat3x3.hpp"
+#include "../mat4x4.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../gtc/constants.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_quaternion extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_quaternion
+       /// @{
+
+       template <typename T, precision P = defaultp>
+       struct tquat
+       {
+               // -- Implementation detail --
+
+               typedef tquat<T, P> type;
+               typedef T value_type;
+
+               // -- Data --
+
+#              if GLM_HAS_ALIGNED_TYPE
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic push
+#                              pragma GCC diagnostic ignored "-Wpedantic"
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic push
+#                              pragma clang diagnostic ignored "-Wgnu-anonymous-struct"
+#                              pragma clang diagnostic ignored "-Wnested-anon-types"
+#                      endif
+               
+                       union
+                       {
+                               struct { T x, y, z, w;};
+                               typename detail::storage<T, sizeof(T) * 4, detail::is_aligned<P>::value>::type data;
+                       };
+               
+#                      if GLM_COMPILER & GLM_COMPILER_CLANG
+#                              pragma clang diagnostic pop
+#                      endif
+#                      if GLM_COMPILER & GLM_COMPILER_GCC
+#                              pragma GCC diagnostic pop
+#                      endif
+#              else
+                       T x, y, z, w;
+#              endif
+
+               // -- Component accesses --
+
+               typedef length_t length_type;
+               /// Return the count of components of a quaternion
+               GLM_FUNC_DECL static length_type length(){return 4;}
+
+               GLM_FUNC_DECL T & operator[](length_type i);
+               GLM_FUNC_DECL T const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR tquat() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR tquat(tquat<T, P> const & q) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR tquat(tquat<T, Q> const & q);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tquat(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR tquat(T const & s, tvec3<T, P> const & v);
+               GLM_FUNC_DECL GLM_CONSTEXPR tquat(T const & w, T const & x, T const & y, T const & z);
+
+               // -- Conversion constructors --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tquat(tquat<U, Q> const & q);
+
+               /// Explicit conversion operators
+#              if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS
+                       GLM_FUNC_DECL explicit operator tmat3x3<T, P>();
+                       GLM_FUNC_DECL explicit operator tmat4x4<T, P>();
+#              endif
+
+               /// Create a quaternion from two normalized axis
+               ///
+               /// @param u A first normalized axis
+               /// @param v A second normalized axis
+               /// @see gtc_quaternion
+               /// @see http://lolengine.net/blog/2013/09/18/beautiful-maths-quaternion-from-vectors
+               GLM_FUNC_DECL tquat(tvec3<T, P> const & u, tvec3<T, P> const & v);
+
+               /// Build a quaternion from euler angles (pitch, yaw, roll), in radians.
+               GLM_FUNC_DECL GLM_EXPLICIT tquat(tvec3<T, P> const & eulerAngles);
+               GLM_FUNC_DECL GLM_EXPLICIT tquat(tmat3x3<T, P> const & m);
+               GLM_FUNC_DECL GLM_EXPLICIT tquat(tmat4x4<T, P> const & m);
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tquat<T, P> & operator=(tquat<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator=(tquat<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator+=(tquat<U, P> const & q);
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator-=(tquat<U, P> const & q);
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator*=(tquat<U, P> const & q);
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tquat<T, P> & operator/=(U s);
+       };
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator+(tquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator-(tquat<T, P> const & q);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator+(tquat<T, P> const & q, tquat<T, P> const & p);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator*(tquat<T, P> const & q, tquat<T, P> const & p);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tquat<T, P> const & q, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec3<T, P> const & v, tquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tquat<T, P> const & q, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec4<T, P> const & v, tquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator*(tquat<T, P> const & q, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator*(T const & s, tquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> operator/(tquat<T, P> const & q, T const & s);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tquat<T, P> const & q1, tquat<T, P> const & q2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tquat<T, P> const & q1, tquat<T, P> const & q2);
+
+       /// Returns the length of the quaternion.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL T length(tquat<T, P> const & q);
+
+       /// Returns the normalized quaternion.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> normalize(tquat<T, P> const & q);
+               
+       /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ...
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P, template <typename, precision> class quatType>
+       GLM_FUNC_DECL T dot(quatType<T, P> const & x, quatType<T, P> const & y);
+
+       /// Spherical linear interpolation of two quaternions.
+       /// The interpolation is oriented and the rotation is performed at constant speed.
+       /// For short path spherical linear interpolation, use the slerp function.
+       /// 
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtc_quaternion
+       /// @see - slerp(tquat<T, P> const & x, tquat<T, P> const & y, T const & a)
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> mix(tquat<T, P> const & x, tquat<T, P> const & y, T a);
+
+       /// Linear interpolation of two quaternions.
+       /// The interpolation is oriented.
+       /// 
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined in the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> lerp(tquat<T, P> const & x, tquat<T, P> const & y, T a);
+
+       /// Spherical linear interpolation of two quaternions.
+       /// The interpolation always take the short path and the rotation is performed at constant speed.
+       /// 
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> slerp(tquat<T, P> const & x, tquat<T, P> const & y, T a);
+
+       /// Returns the q conjugate.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> conjugate(tquat<T, P> const & q);
+
+       /// Returns the q inverse.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> inverse(tquat<T, P> const & q);
+
+       /// Rotates a quaternion from a vector of 3 components axis and an angle.
+       /// 
+       /// @param q Source orientation
+       /// @param angle Angle expressed in radians.
+       /// @param axis Axis of the rotation
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> rotate(tquat<T, P> const & q, T const & angle, tvec3<T, P> const & axis);
+
+       /// Returns euler angles, pitch as x, yaw as y, roll as z.
+       /// The result is expressed in radians if GLM_FORCE_RADIANS is defined or degrees otherwise.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> eulerAngles(tquat<T, P> const & x);
+
+       /// Returns roll value of euler angles expressed in radians.
+       ///
+       /// @see gtx_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL T roll(tquat<T, P> const & x);
+
+       /// Returns pitch value of euler angles expressed in radians.
+       ///
+       /// @see gtx_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL T pitch(tquat<T, P> const & x);
+
+       /// Returns yaw value of euler angles expressed in radians.
+       ///
+       /// @see gtx_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL T yaw(tquat<T, P> const & x);
+
+       /// Converts a quaternion to a 3 * 3 matrix.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> mat3_cast(tquat<T, P> const & x);
+
+       /// Converts a quaternion to a 4 * 4 matrix.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> mat4_cast(tquat<T, P> const & x);
+
+       /// Converts a 3 * 3 matrix to a quaternion.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> quat_cast(tmat3x3<T, P> const & x);
+
+       /// Converts a 4 * 4 matrix to a quaternion.
+       /// 
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> quat_cast(tmat4x4<T, P> const & x);
+
+       /// Returns the quaternion rotation angle.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL T angle(tquat<T, P> const & x);
+
+       /// Returns the q rotation axis.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> axis(tquat<T, P> const & x);
+
+       /// Build a quaternion from an angle and a normalized axis.
+       ///
+       /// @param angle Angle expressed in radians.
+       /// @param axis Axis of the quaternion, must be normalized.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> angleAxis(T const & angle, tvec3<T, P> const & axis);
+
+       /// Returns the component-wise comparison result of x < y.
+       /// 
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> lessThan(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x <= y.
+       ///
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> lessThanEqual(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x > y.
+       ///
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> greaterThan(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x >= y.
+       ///
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> greaterThanEqual(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x == y.
+       ///
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> equal(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns the component-wise comparison of result x != y.
+       /// 
+       /// @tparam quatType Floating-point quaternion types.
+       ///
+       /// @see gtc_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> notEqual(tquat<T, P> const & x, tquat<T, P> const & y);
+
+       /// Returns true if x holds a NaN (not a number)
+       /// representation in the underlying implementation's set of
+       /// floating point representations. Returns false otherwise,
+       /// including for implementations with no NaN
+       /// representations.
+       /// 
+       /// /!\ When using compiler fast math, this function may fail.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> isnan(tquat<T, P> const & x);
+
+       /// Returns true if x holds a positive infinity or negative
+       /// infinity representation in the underlying implementation's
+       /// set of floating point representations. Returns false
+       /// otherwise, including for implementations with no infinity
+       /// representations.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<bool, P> isinf(tquat<T, P> const & x);
+
+       /// @}
+} //namespace glm
+
+#include "quaternion.inl"
diff --git a/core/deps/glm/glm/gtc/quaternion.inl b/core/deps/glm/glm/gtc/quaternion.inl
new file mode 100755 (executable)
index 0000000..c9b2af7
--- /dev/null
@@ -0,0 +1,795 @@
+/// @ref gtc_quaternion
+/// @file glm/gtc/quaternion.inl
+
+#include "../trigonometric.hpp"
+#include "../geometric.hpp"
+#include "../exponential.hpp"
+#include <limits>
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, bool Aligned>
+       struct compute_dot<tquat, T, P, Aligned>
+       {
+               static GLM_FUNC_QUALIFIER T call(tquat<T, P> const& x, tquat<T, P> const& y)
+               {
+                       tvec4<T, P> tmp(x.x * y.x, x.y * y.y, x.z * y.z, x.w * y.w);
+                       return (tmp.x + tmp.y) + (tmp.z + tmp.w);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_quat_add
+       {
+               static tquat<T, P> call(tquat<T, P> const& q, tquat<T, P> const& p)
+               {
+                       return tquat<T, P>(q.w + p.w, q.x + p.x, q.y + p.y, q.z + p.z);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_quat_sub
+       {
+               static tquat<T, P> call(tquat<T, P> const& q, tquat<T, P> const& p)
+               {
+                       return tquat<T, P>(q.w - p.w, q.x - p.x, q.y - p.y, q.z - p.z);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_quat_mul_scalar
+       {
+               static tquat<T, P> call(tquat<T, P> const& q, T s)
+               {
+                       return tquat<T, P>(q.w * s, q.x * s, q.y * s, q.z * s);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_quat_div_scalar
+       {
+               static tquat<T, P> call(tquat<T, P> const& q, T s)
+               {
+                       return tquat<T, P>(q.w / s, q.x / s, q.y / s, q.z / s);
+               }
+       };
+
+       template <typename T, precision P, bool Aligned>
+       struct compute_quat_mul_vec4
+       {
+               static tvec4<T, P> call(tquat<T, P> const & q, tvec4<T, P> const & v)
+               {
+                       return tvec4<T, P>(q * tvec3<T, P>(v), v.w);
+               }
+       };
+}//namespace detail
+
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T & tquat<T, P>::operator[](typename tquat<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T const & tquat<T, P>::operator[](typename tquat<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&x)[i];
+       }
+
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT
+                               : x(0), y(0), z(0), w(1)
+#                      endif
+               {}
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<T, P> const & q)
+                       : x(q.x), y(q.y), z(q.z), w(q.w)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<T, Q> const & q)
+               : x(q.x), y(q.y), z(q.z), w(q.w)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tquat<T, P>::tquat(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(T const & s, tvec3<T, P> const & v)
+               : x(v.x), y(v.y), z(v.z), w(s)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(T const & w, T const & x, T const & y, T const & z)
+               : x(x), y(y), z(z), w(w)
+       {}
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tquat<T, P>::tquat(tquat<U, Q> const & q)
+               : x(static_cast<T>(q.x))
+               , y(static_cast<T>(q.y))
+               , z(static_cast<T>(q.z))
+               , w(static_cast<T>(q.w))
+       {}
+
+       //template <typename valType> 
+       //GLM_FUNC_QUALIFIER tquat<valType>::tquat
+       //(
+       //      valType const & pitch,
+       //      valType const & yaw,
+       //      valType const & roll
+       //)
+       //{
+       //      tvec3<valType> eulerAngle(pitch * valType(0.5), yaw * valType(0.5), roll * valType(0.5));
+       //      tvec3<valType> c = glm::cos(eulerAngle * valType(0.5));
+       //      tvec3<valType> s = glm::sin(eulerAngle * valType(0.5));
+       //      
+       //      this->w = c.x * c.y * c.z + s.x * s.y * s.z;
+       //      this->x = s.x * c.y * c.z - c.x * s.y * s.z;
+       //      this->y = c.x * s.y * c.z + s.x * c.y * s.z;
+       //      this->z = c.x * c.y * s.z - s.x * s.y * c.z;
+       //}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tvec3<T, P> const & u, tvec3<T, P> const & v)
+       {
+               tvec3<T, P> const LocalW(cross(u, v));
+               T Dot = detail::compute_dot<tvec3, T, P, detail::is_aligned<P>::value>::call(u, v);
+               tquat<T, P> q(T(1) + Dot, LocalW.x, LocalW.y, LocalW.z);
+
+               *this = normalize(q);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tvec3<T, P> const & eulerAngle)
+       {
+               tvec3<T, P> c = glm::cos(eulerAngle * T(0.5));
+               tvec3<T, P> s = glm::sin(eulerAngle * T(0.5));
+               
+               this->w = c.x * c.y * c.z + s.x * s.y * s.z;
+               this->x = s.x * c.y * c.z - c.x * s.y * s.z;
+               this->y = c.x * s.y * c.z + s.x * c.y * s.z;
+               this->z = c.x * c.y * s.z - s.x * s.y * c.z;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tmat3x3<T, P> const & m)
+       {
+               *this = quat_cast(m);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P>::tquat(tmat4x4<T, P> const & m)
+       {
+               *this = quat_cast(m);
+       }
+
+#      if GLM_HAS_EXPLICIT_CONVERSION_OPERATORS
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P>::operator tmat3x3<T, P>()
+       {
+               return mat3_cast(*this);
+       }
+       
+       template <typename T, precision P>      
+       GLM_FUNC_QUALIFIER tquat<T, P>::operator tmat4x4<T, P>()
+       {
+               return mat4_cast(*this);
+       }
+#      endif//GLM_HAS_EXPLICIT_CONVERSION_OPERATORS
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> conjugate(tquat<T, P> const & q)
+       {
+               return tquat<T, P>(q.w, -q.x, -q.y, -q.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> inverse(tquat<T, P> const & q)
+       {
+               return conjugate(q) / dot(q, q);
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator=(tquat<T, P> const & q)
+               {
+                       this->w = q.w;
+                       this->x = q.x;
+                       this->y = q.y;
+                       this->z = q.z;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator=(tquat<U, P> const & q)
+       {
+               this->w = static_cast<T>(q.w);
+               this->x = static_cast<T>(q.x);
+               this->y = static_cast<T>(q.y);
+               this->z = static_cast<T>(q.z);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator+=(tquat<U, P> const& q)
+       {
+               return (*this = detail::compute_quat_add<T, P, detail::is_aligned<P>::value>::call(*this, tquat<T, P>(q)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator-=(tquat<U, P> const& q)
+       {
+               return (*this = detail::compute_quat_sub<T, P, detail::is_aligned<P>::value>::call(*this, tquat<T, P>(q)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator*=(tquat<U, P> const & r)
+       {
+               tquat<T, P> const p(*this);
+               tquat<T, P> const q(r);
+
+               this->w = p.w * q.w - p.x * q.x - p.y * q.y - p.z * q.z;
+               this->x = p.w * q.x + p.x * q.w + p.y * q.z - p.z * q.y;
+               this->y = p.w * q.y + p.y * q.w + p.z * q.x - p.x * q.z;
+               this->z = p.w * q.z + p.z * q.w + p.x * q.y - p.y * q.x;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator*=(U s)
+       {
+               return (*this = detail::compute_quat_mul_scalar<T, P, detail::is_aligned<P>::value>::call(*this, static_cast<U>(s)));
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tquat<T, P> & tquat<T, P>::operator/=(U s)
+       {
+               return (*this = detail::compute_quat_div_scalar<T, P, detail::is_aligned<P>::value>::call(*this, static_cast<U>(s)));
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator+(tquat<T, P> const & q)
+       {
+               return q;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator-(tquat<T, P> const & q)
+       {
+               return tquat<T, P>(-q.w, -q.x, -q.y, -q.z);
+       }
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator+(tquat<T, P> const & q, tquat<T, P> const & p)
+       {
+               return tquat<T, P>(q) += p;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator*(tquat<T, P> const & q, tquat<T, P> const & p)
+       {
+               return tquat<T, P>(q) *= p;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tquat<T, P> const & q, tvec3<T, P> const & v)
+       {
+               tvec3<T, P> const QuatVector(q.x, q.y, q.z);
+               tvec3<T, P> const uv(glm::cross(QuatVector, v));
+               tvec3<T, P> const uuv(glm::cross(QuatVector, uv));
+
+               return v + ((uv * q.w) + uuv) * static_cast<T>(2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v, tquat<T, P> const & q)
+       {
+               return glm::inverse(q) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tquat<T, P> const& q, tvec4<T, P> const& v)
+       {
+               return detail::compute_quat_mul_vec4<T, P, detail::is_aligned<P>::value>::call(q, v);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v, tquat<T, P> const & q)
+       {
+               return glm::inverse(q) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator*(tquat<T, P> const & q, T const & s)
+       {
+               return tquat<T, P>(
+                       q.w * s, q.x * s, q.y * s, q.z * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator*(T const & s, tquat<T, P> const & q)
+       {
+               return q * s;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> operator/(tquat<T, P> const & q, T const & s)
+       {
+               return tquat<T, P>(
+                       q.w / s, q.x / s, q.y / s, q.z / s);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tquat<T, P> const & q1, tquat<T, P> const & q2)
+       {
+               return (q1.x == q2.x) && (q1.y == q2.y) && (q1.z == q2.z) && (q1.w == q2.w);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tquat<T, P> const & q1, tquat<T, P> const & q2)
+       {
+               return (q1.x != q2.x) || (q1.y != q2.y) || (q1.z != q2.z) || (q1.w != q2.w);
+       }
+
+       // -- Operations --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T length(tquat<T, P> const & q)
+       {
+               return glm::sqrt(dot(q, q));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> normalize(tquat<T, P> const & q)
+       {
+               T len = length(q);
+               if(len <= T(0)) // Problem
+                       return tquat<T, P>(1, 0, 0, 0);
+               T oneOverLen = T(1) / len;
+               return tquat<T, P>(q.w * oneOverLen, q.x * oneOverLen, q.y * oneOverLen, q.z * oneOverLen);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> cross(tquat<T, P> const & q1, tquat<T, P> const & q2)
+       {
+               return tquat<T, P>(
+                       q1.w * q2.w - q1.x * q2.x - q1.y * q2.y - q1.z * q2.z,
+                       q1.w * q2.x + q1.x * q2.w + q1.y * q2.z - q1.z * q2.y,
+                       q1.w * q2.y + q1.y * q2.w + q1.z * q2.x - q1.x * q2.z,
+                       q1.w * q2.z + q1.z * q2.w + q1.x * q2.y - q1.y * q2.x);
+       }
+/*
+       // (x * sin(1 - a) * angle / sin(angle)) + (y * sin(a) * angle / sin(angle))
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> mix(tquat<T, P> const & x, tquat<T, P> const & y, T const & a)
+       {
+               if(a <= T(0)) return x;
+               if(a >= T(1)) return y;
+
+               float fCos = dot(x, y);
+               tquat<T, P> y2(y); //BUG!!! tquat<T, P> y2;
+               if(fCos < T(0))
+               {
+                       y2 = -y;
+                       fCos = -fCos;
+               }
+
+               //if(fCos > 1.0f) // problem
+               float k0, k1;
+               if(fCos > T(0.9999))
+               {
+                       k0 = T(1) - a;
+                       k1 = T(0) + a; //BUG!!! 1.0f + a;
+               }
+               else
+               {
+                       T fSin = sqrt(T(1) - fCos * fCos);
+                       T fAngle = atan(fSin, fCos);
+                       T fOneOverSin = static_cast<T>(1) / fSin;
+                       k0 = sin((T(1) - a) * fAngle) * fOneOverSin;
+                       k1 = sin((T(0) + a) * fAngle) * fOneOverSin;
+               }
+
+               return tquat<T, P>(
+                       k0 * x.w + k1 * y2.w,
+                       k0 * x.x + k1 * y2.x,
+                       k0 * x.y + k1 * y2.y,
+                       k0 * x.z + k1 * y2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> mix2
+       (
+               tquat<T, P> const & x, 
+               tquat<T, P> const & y, 
+               T const & a
+       )
+       {
+               bool flip = false;
+               if(a <= static_cast<T>(0)) return x;
+               if(a >= static_cast<T>(1)) return y;
+
+               T cos_t = dot(x, y);
+               if(cos_t < T(0))
+               {
+                       cos_t = -cos_t;
+                       flip = true;
+               }
+
+               T alpha(0), beta(0);
+
+               if(T(1) - cos_t < 1e-7)
+                       beta = static_cast<T>(1) - alpha;
+               else
+               {
+                       T theta = acos(cos_t);
+                       T sin_t = sin(theta);
+                       beta = sin(theta * (T(1) - alpha)) / sin_t;
+                       alpha = sin(alpha * theta) / sin_t;
+               }
+
+               if(flip)
+                       alpha = -alpha;
+               
+               return normalize(beta * x + alpha * y);
+       }
+*/
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> mix(tquat<T, P> const & x, tquat<T, P> const & y, T a)
+       {
+               T cosTheta = dot(x, y);
+
+               // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator
+               if(cosTheta > T(1) - epsilon<T>())
+               {
+                       // Linear interpolation
+                       return tquat<T, P>(
+                               mix(x.w, y.w, a),
+                               mix(x.x, y.x, a),
+                               mix(x.y, y.y, a),
+                               mix(x.z, y.z, a));
+               }
+               else
+               {
+                       // Essential Mathematics, page 467
+                       T angle = acos(cosTheta);
+                       return (sin((T(1) - a) * angle) * x + sin(a * angle) * y) / sin(angle);
+               }
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> lerp(tquat<T, P> const & x, tquat<T, P> const & y, T a)
+       {
+               // Lerp is only defined in [0, 1]
+               assert(a >= static_cast<T>(0));
+               assert(a <= static_cast<T>(1));
+
+               return x * (T(1) - a) + (y * a);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> slerp(tquat<T, P> const & x,     tquat<T, P> const & y, T a)
+       {
+               tquat<T, P> z = y;
+
+               T cosTheta = dot(x, y);
+
+               // If cosTheta < 0, the interpolation will take the long way around the sphere. 
+               // To fix this, one quat must be negated.
+               if (cosTheta < T(0))
+               {
+                       z        = -y;
+                       cosTheta = -cosTheta;
+               }
+
+               // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator
+               if(cosTheta > T(1) - epsilon<T>())
+               {
+                       // Linear interpolation
+                       return tquat<T, P>(
+                               mix(x.w, z.w, a),
+                               mix(x.x, z.x, a),
+                               mix(x.y, z.y, a),
+                               mix(x.z, z.z, a));
+               }
+               else
+               {
+                       // Essential Mathematics, page 467
+                       T angle = acos(cosTheta);
+                       return (sin((T(1) - a) * angle) * x + sin(a * angle) * z) / sin(angle);
+               }
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> rotate(tquat<T, P> const & q, T const & angle, tvec3<T, P> const & v)
+       {
+               tvec3<T, P> Tmp = v;
+
+               // Axis of rotation must be normalised
+               T len = glm::length(Tmp);
+               if(abs(len - T(1)) > T(0.001))
+               {
+                       T oneOverLen = static_cast<T>(1) / len;
+                       Tmp.x *= oneOverLen;
+                       Tmp.y *= oneOverLen;
+                       Tmp.z *= oneOverLen;
+               }
+
+               T const AngleRad(angle);
+               T const Sin = sin(AngleRad * T(0.5));
+
+               return q * tquat<T, P>(cos(AngleRad * T(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);
+               //return gtc::quaternion::cross(q, tquat<T, P>(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> eulerAngles(tquat<T, P> const & x)
+       {
+               return tvec3<T, P>(pitch(x), yaw(x), roll(x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T roll(tquat<T, P> const & q)
+       {
+               return T(atan(T(2) * (q.x * q.y + q.w * q.z), q.w * q.w + q.x * q.x - q.y * q.y - q.z * q.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T pitch(tquat<T, P> const & q)
+       {
+               return T(atan(T(2) * (q.y * q.z + q.w * q.x), q.w * q.w - q.x * q.x - q.y * q.y + q.z * q.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T yaw(tquat<T, P> const & q)
+       {
+               return asin(clamp(T(-2) * (q.x * q.z - q.w * q.y), T(-1), T(1)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> mat3_cast(tquat<T, P> const & q)
+       {
+               tmat3x3<T, P> Result(T(1));
+               T qxx(q.x * q.x);
+               T qyy(q.y * q.y);
+               T qzz(q.z * q.z);
+               T qxz(q.x * q.z);
+               T qxy(q.x * q.y);
+               T qyz(q.y * q.z);
+               T qwx(q.w * q.x);
+               T qwy(q.w * q.y);
+               T qwz(q.w * q.z);
+
+               Result[0][0] = T(1) - T(2) * (qyy +  qzz);
+               Result[0][1] = T(2) * (qxy + qwz);
+               Result[0][2] = T(2) * (qxz - qwy);
+
+               Result[1][0] = T(2) * (qxy - qwz);
+               Result[1][1] = T(1) - T(2) * (qxx +  qzz);
+               Result[1][2] = T(2) * (qyz + qwx);
+
+               Result[2][0] = T(2) * (qxz + qwy);
+               Result[2][1] = T(2) * (qyz - qwx);
+               Result[2][2] = T(1) - T(2) * (qxx +  qyy);
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> mat4_cast(tquat<T, P> const & q)
+       {
+               return tmat4x4<T, P>(mat3_cast(q));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> quat_cast(tmat3x3<T, P> const & m)
+       {
+               T fourXSquaredMinus1 = m[0][0] - m[1][1] - m[2][2];
+               T fourYSquaredMinus1 = m[1][1] - m[0][0] - m[2][2];
+               T fourZSquaredMinus1 = m[2][2] - m[0][0] - m[1][1];
+               T fourWSquaredMinus1 = m[0][0] + m[1][1] + m[2][2];
+
+               int biggestIndex = 0;
+               T fourBiggestSquaredMinus1 = fourWSquaredMinus1;
+               if(fourXSquaredMinus1 > fourBiggestSquaredMinus1)
+               {
+                       fourBiggestSquaredMinus1 = fourXSquaredMinus1;
+                       biggestIndex = 1;
+               }
+               if(fourYSquaredMinus1 > fourBiggestSquaredMinus1)
+               {
+                       fourBiggestSquaredMinus1 = fourYSquaredMinus1;
+                       biggestIndex = 2;
+               }
+               if(fourZSquaredMinus1 > fourBiggestSquaredMinus1)
+               {
+                       fourBiggestSquaredMinus1 = fourZSquaredMinus1;
+                       biggestIndex = 3;
+               }
+
+               T biggestVal = sqrt(fourBiggestSquaredMinus1 + T(1)) * T(0.5);
+               T mult = static_cast<T>(0.25) / biggestVal;
+
+               tquat<T, P> Result(uninitialize);
+               switch(biggestIndex)
+               {
+               case 0:
+                       Result.w = biggestVal;
+                       Result.x = (m[1][2] - m[2][1]) * mult;
+                       Result.y = (m[2][0] - m[0][2]) * mult;
+                       Result.z = (m[0][1] - m[1][0]) * mult;
+                       break;
+               case 1:
+                       Result.w = (m[1][2] - m[2][1]) * mult;
+                       Result.x = biggestVal;
+                       Result.y = (m[0][1] + m[1][0]) * mult;
+                       Result.z = (m[2][0] + m[0][2]) * mult;
+                       break;
+               case 2:
+                       Result.w = (m[2][0] - m[0][2]) * mult;
+                       Result.x = (m[0][1] + m[1][0]) * mult;
+                       Result.y = biggestVal;
+                       Result.z = (m[1][2] + m[2][1]) * mult;
+                       break;
+               case 3:
+                       Result.w = (m[0][1] - m[1][0]) * mult;
+                       Result.x = (m[2][0] + m[0][2]) * mult;
+                       Result.y = (m[1][2] + m[2][1]) * mult;
+                       Result.z = biggestVal;
+                       break;
+                       
+               default:                                        // Silence a -Wswitch-default warning in GCC. Should never actually get here. Assert is just for sanity.
+                       assert(false);
+                       break;
+               }
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> quat_cast(tmat4x4<T, P> const & m4)
+       {
+               return quat_cast(tmat3x3<T, P>(m4));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T angle(tquat<T, P> const & x)
+       {
+               return acos(x.w) * T(2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> axis(tquat<T, P> const & x)
+       {
+               T tmp1 = static_cast<T>(1) - x.w * x.w;
+               if(tmp1 <= static_cast<T>(0))
+                       return tvec3<T, P>(0, 0, 1);
+               T tmp2 = static_cast<T>(1) / sqrt(tmp1);
+               return tvec3<T, P>(x.x * tmp2, x.y * tmp2, x.z * tmp2);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> angleAxis(T const & angle, tvec3<T, P> const & v)
+       {
+               tquat<T, P> Result(uninitialize);
+
+               T const a(angle);
+               T const s = glm::sin(a * static_cast<T>(0.5));
+
+               Result.w = glm::cos(a * static_cast<T>(0.5));
+               Result.x = v.x * s;
+               Result.y = v.y * s;
+               Result.z = v.z * s;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> lessThan(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] < y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> lessThanEqual(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] <= y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> greaterThan(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] > y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> greaterThanEqual(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] >= y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> equal(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] == y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> notEqual(tquat<T, P> const & x, tquat<T, P> const & y)
+       {
+               tvec4<bool, P> Result(uninitialize);
+               for(length_t i = 0; i < x.length(); ++i)
+                       Result[i] = x[i] != y[i];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> isnan(tquat<T, P> const& q)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isnan' only accept floating-point inputs");
+
+               return tvec4<bool, P>(isnan(q.x), isnan(q.y), isnan(q.z), isnan(q.w));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> isinf(tquat<T, P> const& q)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isinf' only accept floating-point inputs");
+
+               return tvec4<bool, P>(isinf(q.x), isinf(q.y), isinf(q.z), isinf(q.w));
+       }
+}//namespace glm
+
+#if GLM_ARCH != GLM_ARCH_PURE && GLM_HAS_ALIGNED_TYPE
+#      include "quaternion_simd.inl"
+#endif
+
diff --git a/core/deps/glm/glm/gtc/quaternion_simd.inl b/core/deps/glm/glm/gtc/quaternion_simd.inl
new file mode 100755 (executable)
index 0000000..cca874b
--- /dev/null
@@ -0,0 +1,198 @@
+/// @ref core
+/// @file glm/gtc/quaternion_simd.inl
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+namespace glm{
+namespace detail
+{
+/*
+       template <precision P>
+       struct compute_quat_mul<float, P, true>
+       {
+               static tquat<float, P> call(tquat<float, P> const& q1, tquat<float, P> const& q2)
+               {
+                       // SSE2 STATS: 11 shuffle, 8 mul, 8 add
+                       // SSE4 STATS: 3 shuffle, 4 mul, 4 dpps
+
+                       __m128 const mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3)));
+                       __m128 const mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2)));
+                       __m128 const mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1)));
+                       __m128 const mul3 = _mm_mul_ps(q1.Data, q2.Data);
+
+#                      if GLM_ARCH & GLM_ARCH_SSE41_BIT
+                               __m128 const add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f), 0xff);
+                               __m128 const add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f), 0xff);
+                               __m128 const add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f), 0xff);
+                               __m128 const add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff);
+#                      else
+                               __m128 const mul4 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f));
+                               __m128 const add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul4, mul4));
+                               __m128 const add4 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1));
+
+                               __m128 const mul5 = _mm_mul_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f));
+                               __m128 const add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul5, mul5));
+                               __m128 const add5 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1));
+
+                               __m128 const mul6 = _mm_mul_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f));
+                               __m128 const add2 = _mm_add_ps(mul6, _mm_movehl_ps(mul6, mul6));
+                               __m128 const add6 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1));
+
+                               __m128 const mul7 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f));
+                               __m128 const add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul7, mul7));
+                               __m128 const add7 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1));
+               #endif
+
+                       // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than
+                       // the final code below. I'll keep this here for reference - maybe somebody else can do something better...
+                       //
+                       //__m128 xxyy = _mm_shuffle_ps(add4, add5, _MM_SHUFFLE(0, 0, 0, 0));
+                       //__m128 zzww = _mm_shuffle_ps(add6, add7, _MM_SHUFFLE(0, 0, 0, 0));
+                       //
+                       //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0));
+
+                       tquat<float, P> Result(uninitialize);
+                       _mm_store_ss(&Result.x, add4);
+                       _mm_store_ss(&Result.y, add5);
+                       _mm_store_ss(&Result.z, add6);
+                       _mm_store_ss(&Result.w, add7);
+                       return Result;
+               }
+       };
+*/
+
+       template <precision P>
+       struct compute_dot<tquat, float, P, true>
+       {
+               static GLM_FUNC_QUALIFIER float call(tquat<float, P> const& x, tquat<float, P> const& y)
+               {
+                       return _mm_cvtss_f32(glm_vec1_dot(x.data, y.data));
+               }
+       };
+
+       template <precision P>
+       struct compute_quat_add<float, P, true>
+       {
+               static tquat<float, P> call(tquat<float, P> const& q, tquat<float, P> const& p)
+               {
+                       tquat<float, P> Result(uninitialize);
+                       Result.data = _mm_add_ps(q.data, p.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_quat_add<double, P, true>
+       {
+               static tquat<double, P> call(tquat<double, P> const & a, tquat<double, P> const & b)
+               {
+                       tquat<double, P> Result(uninitialize);
+                       Result.data = _mm256_add_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_quat_sub<float, P, true>
+       {
+               static tquat<float, P> call(tquat<float, P> const& q, tquat<float, P> const& p)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_sub_ps(q.data, p.data);
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_quat_sub<double, P, true>
+       {
+               static tquat<double, P> call(tquat<double, P> const & a, tquat<double, P> const & b)
+               {
+                       tquat<double, P> Result(uninitialize);
+                       Result.data = _mm256_sub_pd(a.data, b.data);
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_quat_mul_scalar<float, P, true>
+       {
+               static tquat<float, P> call(tquat<float, P> const& q, float s)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_mul_ps(q.data, _mm_set_ps1(s));
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_quat_mul_scalar<double, P, true>
+       {
+               static tquat<double, P> call(tquat<double, P> const& q, double s)
+               {
+                       tquat<double, P> Result(uninitialize);
+                       Result.data = _mm256_mul_pd(q.data, _mm_set_ps1(s));
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_quat_div_scalar<float, P, true>
+       {
+               static tquat<float, P> call(tquat<float, P> const& q, float s)
+               {
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_div_ps(q.data, _mm_set_ps1(s));
+                       return Result;
+               }
+       };
+
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+       template <precision P>
+       struct compute_quat_div_scalar<double, P, true>
+       {
+               static tquat<double, P> call(tquat<double, P> const& q, double s)
+               {
+                       tquat<double, P> Result(uninitialize);
+                       Result.data = _mm256_div_pd(q.data, _mm_set_ps1(s));
+                       return Result;
+               }
+       };
+#      endif
+
+       template <precision P>
+       struct compute_quat_mul_vec4<float, P, true>
+       {
+               static tvec4<float, P> call(tquat<float, P> const& q, tvec4<float, P> const& v)
+               {
+                       __m128 const q_wwww = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 3, 3, 3));
+                       __m128 const q_swp0 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 0, 2, 1));
+                       __m128 const q_swp1 = _mm_shuffle_ps(q.data, q.data, _MM_SHUFFLE(3, 1, 0, 2));
+                       __m128 const v_swp0 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 0, 2, 1));
+                       __m128 const v_swp1 = _mm_shuffle_ps(v.data, v.data, _MM_SHUFFLE(3, 1, 0, 2));
+       
+                       __m128 uv      = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0));
+                       __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1));
+                       __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2));
+                       __m128 uuv     = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0));
+
+                       __m128 const two = _mm_set1_ps(2.0f);
+                       uv  = _mm_mul_ps(uv, _mm_mul_ps(q_wwww, two));
+                       uuv = _mm_mul_ps(uuv, two);
+
+                       tvec4<float, P> Result(uninitialize);
+                       Result.data = _mm_add_ps(v.Data, _mm_add_ps(uv, uuv));
+                       return Result;
+               }
+       };
+}//namespace detail
+}//namespace glm
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
+
diff --git a/core/deps/glm/glm/gtc/random.hpp b/core/deps/glm/glm/gtc/random.hpp
new file mode 100755 (executable)
index 0000000..fa3956e
--- /dev/null
@@ -0,0 +1,98 @@
+/// @ref gtc_random
+/// @file glm/gtc/random.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtx_random (extended)
+///
+/// @defgroup gtc_random GLM_GTC_random
+/// @ingroup gtc
+///
+/// @brief Generate random number from various distribution methods.
+///
+/// <glm/gtc/random.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_random extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_random
+       /// @{
+       
+       /// Generate random numbers in the interval [Min, Max], according a linear distribution 
+       /// 
+       /// @param Min 
+       /// @param Max 
+       /// @tparam genType Value type. Currently supported: float or double scalars.
+       /// @see gtc_random
+       template <typename genTYpe>
+       GLM_FUNC_DECL genTYpe linearRand(
+               genTYpe Min,
+               genTYpe Max);
+
+       /// Generate random numbers in the interval [Min, Max], according a linear distribution 
+       /// 
+       /// @param Min 
+       /// @param Max 
+       /// @tparam T Value type. Currently supported: float or double.
+       /// @tparam vecType A vertor type: tvec1, tvec2, tvec3, tvec4 or compatible
+       /// @see gtc_random
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> linearRand(
+               vecType<T, P> const & Min,
+               vecType<T, P> const & Max);
+
+       /// Generate random numbers in the interval [Min, Max], according a gaussian distribution 
+       /// 
+       /// @param Mean
+       /// @param Deviation
+       /// @see gtc_random
+       template <typename genType>
+       GLM_FUNC_DECL genType gaussRand(
+               genType Mean,
+               genType Deviation);
+       
+       /// Generate a random 2D vector which coordinates are regulary distributed on a circle of a given radius
+       /// 
+       /// @param Radius 
+       /// @see gtc_random
+       template <typename T>
+       GLM_FUNC_DECL tvec2<T, defaultp> circularRand(
+               T Radius);
+       
+       /// Generate a random 3D vector which coordinates are regulary distributed on a sphere of a given radius
+       /// 
+       /// @param Radius
+       /// @see gtc_random
+       template <typename T>
+       GLM_FUNC_DECL tvec3<T, defaultp> sphericalRand(
+               T Radius);
+       
+       /// Generate a random 2D vector which coordinates are regulary distributed within the area of a disk of a given radius
+       /// 
+       /// @param Radius
+       /// @see gtc_random
+       template <typename T>
+       GLM_FUNC_DECL tvec2<T, defaultp> diskRand(
+               T Radius);
+       
+       /// Generate a random 3D vector which coordinates are regulary distributed within the volume of a ball of a given radius
+       /// 
+       /// @param Radius
+       /// @see gtc_random
+       template <typename T>
+       GLM_FUNC_DECL tvec3<T, defaultp> ballRand(
+               T Radius);
+       
+       /// @}
+}//namespace glm
+
+#include "random.inl"
diff --git a/core/deps/glm/glm/gtc/random.inl b/core/deps/glm/glm/gtc/random.inl
new file mode 100755 (executable)
index 0000000..ad5926e
--- /dev/null
@@ -0,0 +1,350 @@
+/// @ref gtc_random
+/// @file glm/gtc/random.inl
+
+#include "../geometric.hpp"
+#include "../exponential.hpp"
+#include <cstdlib>
+#include <ctime>
+#include <cassert>
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <class, precision> class vecType>
+       struct compute_rand
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call();
+       };
+
+       template <precision P>
+       struct compute_rand<uint8, P, tvec1>
+       {
+               GLM_FUNC_QUALIFIER static tvec1<uint8, P> call()
+               {
+                       return tvec1<uint8, P>(
+                               std::rand() % std::numeric_limits<uint8>::max());
+               }
+       };
+
+       template <precision P>
+       struct compute_rand<uint8, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<uint8, P> call()
+               {
+                       return tvec2<uint8, P>(
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max());
+               }
+       };
+
+       template <precision P>
+       struct compute_rand<uint8, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<uint8, P> call()
+               {
+                       return tvec3<uint8, P>(
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max());
+               }
+       };
+
+       template <precision P>
+       struct compute_rand<uint8, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<uint8, P> call()
+               {
+                       return tvec4<uint8, P>(
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max(),
+                               std::rand() % std::numeric_limits<uint8>::max());
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_rand<uint16, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint16, P> call()
+               {
+                       return
+                               (vecType<uint16, P>(compute_rand<uint8, P, vecType>::call()) << static_cast<uint16>(8)) |
+                               (vecType<uint16, P>(compute_rand<uint8, P, vecType>::call()) << static_cast<uint16>(0));
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_rand<uint32, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint32, P> call()
+               {
+                       return
+                               (vecType<uint32, P>(compute_rand<uint16, P, vecType>::call()) << static_cast<uint32>(16)) |
+                               (vecType<uint32, P>(compute_rand<uint16, P, vecType>::call()) << static_cast<uint32>(0));
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_rand<uint64, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint64, P> call()
+               {
+                       return
+                               (vecType<uint64, P>(compute_rand<uint32, P, vecType>::call()) << static_cast<uint64>(32)) |
+                               (vecType<uint64, P>(compute_rand<uint32, P, vecType>::call()) << static_cast<uint64>(0));
+               }
+       };
+
+       template <typename T, precision P, template <class, precision> class vecType>
+       struct compute_linearRand
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & Min, vecType<T, P> const & Max);
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<int8, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<int8, P> call(vecType<int8, P> const & Min, vecType<int8, P> const & Max)
+               {
+                       return (vecType<int8, P>(compute_rand<uint8, P, vecType>::call() % vecType<uint8, P>(Max + static_cast<int8>(1) - Min))) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<uint8, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint8, P> call(vecType<uint8, P> const & Min, vecType<uint8, P> const & Max)
+               {
+                       return (compute_rand<uint8, P, vecType>::call() % (Max + static_cast<uint8>(1) - Min)) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<int16, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<int16, P> call(vecType<int16, P> const & Min, vecType<int16, P> const & Max)
+               {
+                       return (vecType<int16, P>(compute_rand<uint16, P, vecType>::call() % vecType<uint16, P>(Max + static_cast<int16>(1) - Min))) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<uint16, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint16, P> call(vecType<uint16, P> const & Min, vecType<uint16, P> const & Max)
+               {
+                       return (compute_rand<uint16, P, vecType>::call() % (Max + static_cast<uint16>(1) - Min)) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<int32, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<int32, P> call(vecType<int32, P> const & Min, vecType<int32, P> const & Max)
+               {
+                       return (vecType<int32, P>(compute_rand<uint32, P, vecType>::call() % vecType<uint32, P>(Max + static_cast<int32>(1) - Min))) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<uint32, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint32, P> call(vecType<uint32, P> const & Min, vecType<uint32, P> const & Max)
+               {
+                       return (compute_rand<uint32, P, vecType>::call() % (Max + static_cast<uint32>(1) - Min)) + Min;
+               }
+       };
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<int64, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<int64, P> call(vecType<int64, P> const & Min, vecType<int64, P> const & Max)
+               {
+                       return (vecType<int64, P>(compute_rand<uint64, P, vecType>::call() % vecType<uint64, P>(Max + static_cast<int64>(1) - Min))) + Min;
+               }
+       };
+
+       template <precision P, template <class, precision> class vecType>
+       struct compute_linearRand<uint64, P, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<uint64, P> call(vecType<uint64, P> const & Min, vecType<uint64, P> const & Max)
+               {
+                       return (compute_rand<uint64, P, vecType>::call() % (Max + static_cast<uint64>(1) - Min)) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<float, lowp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<float, lowp> call(vecType<float, lowp> const & Min, vecType<float, lowp> const & Max)
+               {
+                       return vecType<float, lowp>(compute_rand<uint8, lowp, vecType>::call()) / static_cast<float>(std::numeric_limits<uint8>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<float, mediump, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<float, mediump> call(vecType<float, mediump> const & Min, vecType<float, mediump> const & Max)
+               {
+                       return vecType<float, mediump>(compute_rand<uint16, mediump, vecType>::call()) / static_cast<float>(std::numeric_limits<uint16>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<float, highp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<float, highp> call(vecType<float, highp> const & Min, vecType<float, highp> const & Max)
+               {
+                       return vecType<float, highp>(compute_rand<uint32, highp, vecType>::call()) / static_cast<float>(std::numeric_limits<uint32>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<double, lowp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<double, lowp> call(vecType<double, lowp> const & Min, vecType<double, lowp> const & Max)
+               {
+                       return vecType<double, lowp>(compute_rand<uint16, lowp, vecType>::call()) / static_cast<double>(std::numeric_limits<uint16>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<double, mediump, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<double, mediump> call(vecType<double, mediump> const & Min, vecType<double, mediump> const & Max)
+               {
+                       return vecType<double, mediump>(compute_rand<uint32, mediump, vecType>::call()) / static_cast<double>(std::numeric_limits<uint32>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<double, highp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<double, highp> call(vecType<double, highp> const & Min, vecType<double, highp> const & Max)
+               {
+                       return vecType<double, highp>(compute_rand<uint64, highp, vecType>::call()) / static_cast<double>(std::numeric_limits<uint64>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<long double, lowp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<long double, lowp> call(vecType<long double, lowp> const & Min, vecType<long double, lowp> const & Max)
+               {
+                       return vecType<long double, lowp>(compute_rand<uint32, lowp, vecType>::call()) / static_cast<long double>(std::numeric_limits<uint32>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<long double, mediump, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<long double, mediump> call(vecType<long double, mediump> const & Min, vecType<long double, mediump> const & Max)
+               {
+                       return vecType<long double, mediump>(compute_rand<uint64, mediump, vecType>::call()) / static_cast<long double>(std::numeric_limits<uint64>::max()) * (Max - Min) + Min;
+               }
+       };
+
+       template <template <class, precision> class vecType>
+       struct compute_linearRand<long double, highp, vecType>
+       {
+               GLM_FUNC_QUALIFIER static vecType<long double, highp> call(vecType<long double, highp> const & Min, vecType<long double, highp> const & Max)
+               {
+                       return vecType<long double, highp>(compute_rand<uint64, highp, vecType>::call()) / static_cast<long double>(std::numeric_limits<uint64>::max()) * (Max - Min) + Min;
+               }
+       };
+}//namespace detail
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType linearRand(genType Min, genType Max)
+       {
+               return detail::compute_linearRand<genType, highp, tvec1>::call(
+                       tvec1<genType, highp>(Min),
+                       tvec1<genType, highp>(Max)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> linearRand(vecType<T, P> const & Min, vecType<T, P> const & Max)
+       {
+               return detail::compute_linearRand<T, P, vecType>::call(Min, Max);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType gaussRand(genType Mean, genType Deviation)
+       {
+               genType w, x1, x2;
+       
+               do
+               {
+                       x1 = linearRand(genType(-1), genType(1));
+                       x2 = linearRand(genType(-1), genType(1));
+               
+                       w = x1 * x1 + x2 * x2;
+               } while(w > genType(1));
+       
+               return x2 * Deviation * Deviation * sqrt((genType(-2) * log(w)) / w) + Mean;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> gaussRand(vecType<T, P> const & Mean, vecType<T, P> const & Deviation)
+       {
+               return detail::functor2<T, P, vecType>::call(gaussRand, Mean, Deviation);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec2<T, defaultp> diskRand(T Radius)
+       {               
+               tvec2<T, defaultp> Result(T(0));
+               T LenRadius(T(0));
+               
+               do
+               {
+                       Result = linearRand(
+                               tvec2<T, defaultp>(-Radius),
+                               tvec2<T, defaultp>(Radius));
+                       LenRadius = length(Result);
+               }
+               while(LenRadius > Radius);
+               
+               return Result;
+       }
+       
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec3<T, defaultp> ballRand(T Radius)
+       {               
+               tvec3<T, defaultp> Result(T(0));
+               T LenRadius(T(0));
+               
+               do
+               {
+                       Result = linearRand(
+                               tvec3<T, defaultp>(-Radius),
+                               tvec3<T, defaultp>(Radius));
+                       LenRadius = length(Result);
+               }
+               while(LenRadius > Radius);
+               
+               return Result;
+       }
+       
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec2<T, defaultp> circularRand(T Radius)
+       {
+               T a = linearRand(T(0), T(6.283185307179586476925286766559f));
+               return tvec2<T, defaultp>(cos(a), sin(a)) * Radius;             
+       }
+       
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec3<T, defaultp> sphericalRand(T Radius)
+       {
+               T z = linearRand(T(-1), T(1));
+               T a = linearRand(T(0), T(6.283185307179586476925286766559f));
+       
+               T r = sqrt(T(1) - z * z);
+       
+               T x = r * cos(a);
+               T y = r * sin(a);
+       
+               return tvec3<T, defaultp>(x, y, z) * Radius;    
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/reciprocal.hpp b/core/deps/glm/glm/gtc/reciprocal.hpp
new file mode 100755 (executable)
index 0000000..c14a4fe
--- /dev/null
@@ -0,0 +1,135 @@
+/// @ref gtc_reciprocal
+/// @file glm/gtc/reciprocal.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_reciprocal GLM_GTC_reciprocal
+/// @ingroup gtc
+///
+/// @brief Define secant, cosecant and cotangent functions.
+///
+/// <glm/gtc/reciprocal.hpp> need to be included to use these features.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_reciprocal extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_reciprocal
+       /// @{
+
+       /// Secant function.
+       /// hypotenuse / adjacent or 1 / cos(x)
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType sec(genType angle);
+
+       /// Cosecant function.
+       /// hypotenuse / opposite or 1 / sin(x)
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType> 
+       GLM_FUNC_DECL genType csc(genType angle);
+               
+       /// Cotangent function.
+       /// adjacent / opposite or 1 / tan(x)
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType cot(genType angle);
+
+       /// Inverse secant function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType asec(genType x);
+
+       /// Inverse cosecant function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType acsc(genType x);
+               
+       /// Inverse cotangent function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType acot(genType x);
+
+       /// Secant hyperbolic function.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType sech(genType angle);
+
+       /// Cosecant hyperbolic function.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType csch(genType angle);
+               
+       /// Cotangent hyperbolic function.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType coth(genType angle);
+
+       /// Inverse secant hyperbolic function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType asech(genType x);
+
+       /// Inverse cosecant hyperbolic function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType acsch(genType x);
+               
+       /// Inverse cotangent hyperbolic function.
+       /// 
+       /// @return Return an angle expressed in radians.
+       /// @tparam genType Floating-point scalar or vector types.
+       /// 
+       /// @see gtc_reciprocal
+       template <typename genType>
+       GLM_FUNC_DECL genType acoth(genType x);
+
+       /// @}
+}//namespace glm
+
+#include "reciprocal.inl"
diff --git a/core/deps/glm/glm/gtc/reciprocal.inl b/core/deps/glm/glm/gtc/reciprocal.inl
new file mode 100755 (executable)
index 0000000..c625ac9
--- /dev/null
@@ -0,0 +1,192 @@
+/// @ref gtc_reciprocal
+/// @file glm/gtc/reciprocal.inl
+
+#include "../trigonometric.hpp"
+#include <limits>
+
+namespace glm
+{
+       // sec
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType sec(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'sec' only accept floating-point values");
+               return genType(1) / glm::cos(angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sec(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'sec' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(sec, x);
+       }
+
+       // csc
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType csc(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'csc' only accept floating-point values");
+               return genType(1) / glm::sin(angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> csc(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'csc' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(csc, x);
+       }
+
+       // cot
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType cot(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'cot' only accept floating-point values");
+       
+               genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0);
+               return glm::tan(pi_over_2 - angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> cot(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'cot' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(cot, x);
+       }
+
+       // asec
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType asec(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'asec' only accept floating-point values");
+               return acos(genType(1) / x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> asec(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'asec' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(asec, x);
+       }
+
+       // acsc
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType acsc(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'acsc' only accept floating-point values");
+               return asin(genType(1) / x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acsc(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'acsc' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(acsc, x);
+       }
+
+       // acot
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType acot(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'acot' only accept floating-point values");
+
+               genType const pi_over_2 = genType(3.1415926535897932384626433832795 / 2.0);
+               return pi_over_2 - atan(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acot(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'acot' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(acot, x);
+       }
+
+       // sech
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType sech(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'sech' only accept floating-point values");
+               return genType(1) / glm::cosh(angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> sech(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'sech' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(sech, x);
+       }
+
+       // csch
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType csch(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'csch' only accept floating-point values");
+               return genType(1) / glm::sinh(angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> csch(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'csch' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(csch, x);
+       }
+
+       // coth
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType coth(genType angle)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'coth' only accept floating-point values");
+               return glm::cosh(angle) / glm::sinh(angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> coth(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'coth' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(coth, x);
+       }
+
+       // asech
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType asech(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'asech' only accept floating-point values");
+               return acosh(genType(1) / x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> asech(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'asech' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(asech, x);
+       }
+
+       // acsch
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType acsch(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'acsch' only accept floating-point values");
+               return acsch(genType(1) / x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acsch(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'acsch' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(acsch, x);
+       }
+
+       // acoth
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType acoth(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'acoth' only accept floating-point values");
+               return atanh(genType(1) / x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> acoth(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'acoth' only accept floating-point inputs");
+               return detail::functor1<T, T, P, vecType>::call(acoth, x);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/round.hpp b/core/deps/glm/glm/gtc/round.hpp
new file mode 100755 (executable)
index 0000000..a583592
--- /dev/null
@@ -0,0 +1,174 @@
+/// @ref gtc_round
+/// @file glm/gtc/round.hpp
+///
+/// @see core (dependence)
+/// @see gtc_round (dependence)
+///
+/// @defgroup gtc_round GLM_GTC_round
+/// @ingroup gtc
+///
+/// @brief rounding value to specific boundings
+///
+/// <glm/gtc/round.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/_vectorize.hpp"
+#include "../vector_relational.hpp"
+#include "../common.hpp"
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_integer extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_round
+       /// @{
+
+       /// Return true if the value is a power of two number.
+       ///
+       /// @see gtc_round
+       template <typename genIUType>
+       GLM_FUNC_DECL bool isPowerOfTwo(genIUType Value);
+
+       /// Return true if the value is a power of two number.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isPowerOfTwo(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is just higher the input value,
+       /// round up to a power of two.
+       ///
+       /// @see gtc_round
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType ceilPowerOfTwo(genIUType Value);
+
+       /// Return the power of two number which value is just higher the input value,
+       /// round up to a power of two.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> ceilPowerOfTwo(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is just lower the input value,
+       /// round down to a power of two.
+       ///
+       /// @see gtc_round
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType floorPowerOfTwo(genIUType Value);
+
+       /// Return the power of two number which value is just lower the input value,
+       /// round down to a power of two.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> floorPowerOfTwo(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is the closet to the input value.
+       ///
+       /// @see gtc_round
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType roundPowerOfTwo(genIUType Value);
+
+       /// Return the power of two number which value is the closet to the input value.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> roundPowerOfTwo(vecType<T, P> const & value);
+
+       /// Return true if the 'Value' is a multiple of 'Multiple'.
+       ///
+       /// @see gtc_round
+       template <typename genIUType>
+       GLM_FUNC_DECL bool isMultiple(genIUType Value, genIUType Multiple);
+
+       /// Return true if the 'Value' is a multiple of 'Multiple'.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isMultiple(vecType<T, P> const & Value, T Multiple);
+
+       /// Return true if the 'Value' is a multiple of 'Multiple'.
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isMultiple(vecType<T, P> const & Value, vecType<T, P> const & Multiple);
+
+       /// Higher multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename genType>
+       GLM_FUNC_DECL genType ceilMultiple(genType Source, genType Multiple);
+
+       /// Higher multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> ceilMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple);
+
+       /// Lower multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename genType>
+       GLM_FUNC_DECL genType floorMultiple(
+               genType Source,
+               genType Multiple);
+
+       /// Lower multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> floorMultiple(
+               vecType<T, P> const & Source,
+               vecType<T, P> const & Multiple);
+
+       /// Lower multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename genType>
+       GLM_FUNC_DECL genType roundMultiple(
+               genType Source,
+               genType Multiple);
+
+       /// Lower multiple number of Source.
+       ///
+       /// @tparam genType Floating-point or integer scalar or vector types.
+       /// @param Source 
+       /// @param Multiple Must be a null or positive value
+       ///
+       /// @see gtc_round
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> roundMultiple(
+               vecType<T, P> const & Source,
+               vecType<T, P> const & Multiple);
+
+       /// @}
+} //namespace glm
+
+#include "round.inl"
diff --git a/core/deps/glm/glm/gtc/round.inl b/core/deps/glm/glm/gtc/round.inl
new file mode 100755 (executable)
index 0000000..f583c40
--- /dev/null
@@ -0,0 +1,344 @@
+/// @ref gtc_round
+/// @file glm/gtc/round.inl
+
+#include "../detail/func_integer.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <typename, precision> class vecType, bool compute = false>
+       struct compute_ceilShift
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T)
+               {
+                       return v;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_ceilShift<T, P, vecType, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T Shift)
+               {
+                       return v | (v >> Shift);
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType, bool isSigned = true>
+       struct compute_ceilPowerOfTwo
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs");
+
+                       vecType<T, P> const Sign(sign(x));
+
+                       vecType<T, P> v(abs(x));
+
+                       v = v - static_cast<T>(1);
+                       v = v | (v >> static_cast<T>(1));
+                       v = v | (v >> static_cast<T>(2));
+                       v = v | (v >> static_cast<T>(4));
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 2>::call(v, 8);
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 4>::call(v, 16);
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 8>::call(v, 32);
+                       return (v + static_cast<T>(1)) * Sign;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_ceilPowerOfTwo<T, P, vecType, false>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x)
+               {
+                       GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs");
+
+                       vecType<T, P> v(x);
+
+                       v = v - static_cast<T>(1);
+                       v = v | (v >> static_cast<T>(1));
+                       v = v | (v >> static_cast<T>(2));
+                       v = v | (v >> static_cast<T>(4));
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 2>::call(v, 8);
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 4>::call(v, 16);
+                       v = compute_ceilShift<T, P, vecType, sizeof(T) >= 8>::call(v, 32);
+                       return v + static_cast<T>(1);
+               }
+       };
+
+       template <bool is_float, bool is_signed>
+       struct compute_ceilMultiple{};
+
+       template <>
+       struct compute_ceilMultiple<true, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source > genType(0))
+                               return Source + (Multiple - std::fmod(Source, Multiple));
+                       else
+                               return Source + std::fmod(-Source, Multiple);
+               }
+       };
+
+       template <>
+       struct compute_ceilMultiple<false, false>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       genType Tmp = Source - genType(1);
+                       return Tmp + (Multiple - (Tmp % Multiple));
+               }
+       };
+
+       template <>
+       struct compute_ceilMultiple<false, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source > genType(0))
+                       {
+                               genType Tmp = Source - genType(1);
+                               return Tmp + (Multiple - (Tmp % Multiple));
+                       }
+                       else
+                               return Source + (-Source % Multiple);
+               }
+       };
+
+       template <bool is_float, bool is_signed>
+       struct compute_floorMultiple{};
+
+       template <>
+       struct compute_floorMultiple<true, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - std::fmod(Source, Multiple);
+                       else
+                               return Source - std::fmod(Source, Multiple) - Multiple;
+               }
+       };
+
+       template <>
+       struct compute_floorMultiple<false, false>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - Source % Multiple;
+                       else
+                       {
+                               genType Tmp = Source + genType(1);
+                               return Tmp - Tmp % Multiple - Multiple;
+                       }
+               }
+       };
+
+       template <>
+       struct compute_floorMultiple<false, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - Source % Multiple;
+                       else
+                       {
+                               genType Tmp = Source + genType(1);
+                               return Tmp - Tmp % Multiple - Multiple;
+                       }
+               }
+       };
+
+       template <bool is_float, bool is_signed>
+       struct compute_roundMultiple{};
+
+       template <>
+       struct compute_roundMultiple<true, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - std::fmod(Source, Multiple);
+                       else
+                       {
+                               genType Tmp = Source + genType(1);
+                               return Tmp - std::fmod(Tmp, Multiple) - Multiple;
+                       }
+               }
+       };
+
+       template <>
+       struct compute_roundMultiple<false, false>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - Source % Multiple;
+                       else
+                       {
+                               genType Tmp = Source + genType(1);
+                               return Tmp - Tmp % Multiple - Multiple;
+                       }
+               }
+       };
+
+       template <>
+       struct compute_roundMultiple<false, true>
+       {
+               template <typename genType>
+               GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple)
+               {
+                       if(Source >= genType(0))
+                               return Source - Source % Multiple;
+                       else
+                       {
+                               genType Tmp = Source + genType(1);
+                               return Tmp - Tmp % Multiple - Multiple;
+                       }
+               }
+       };
+}//namespace detail
+
+       ////////////////
+       // isPowerOfTwo
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool isPowerOfTwo(genType Value)
+       {
+               genType const Result = glm::abs(Value);
+               return !(Result & (Result - 1));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isPowerOfTwo(vecType<T, P> const & Value)
+       {
+               vecType<T, P> const Result(abs(Value));
+               return equal(Result & (Result - 1), vecType<T, P>(0));
+       }
+
+       //////////////////
+       // ceilPowerOfTwo
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value)
+       {
+               return detail::compute_ceilPowerOfTwo<genType, defaultp, tvec1, std::numeric_limits<genType>::is_signed>::call(tvec1<genType, defaultp>(value)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> ceilPowerOfTwo(vecType<T, P> const & v)
+       {
+               return detail::compute_ceilPowerOfTwo<T, P, vecType, std::numeric_limits<T>::is_signed>::call(v);
+       }
+
+       ///////////////////
+       // floorPowerOfTwo
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value)
+       {
+               return isPowerOfTwo(value) ? value : static_cast<genType>(1) << findMSB(value);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> floorPowerOfTwo(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(floorPowerOfTwo, v);
+       }
+
+       ///////////////////
+       // roundPowerOfTwo
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value)
+       {
+               if(isPowerOfTwo(value))
+                       return value;
+
+               genIUType const prev = static_cast<genIUType>(1) << findMSB(value);
+               genIUType const next = prev << static_cast<genIUType>(1);
+               return (next - value) < (value - prev) ? next : prev;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> roundPowerOfTwo(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(roundPowerOfTwo, v);
+       }
+
+       ////////////////
+       // isMultiple
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool isMultiple(genType Value, genType Multiple)
+       {
+               return isMultiple(tvec1<genType>(Value), tvec1<genType>(Multiple)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isMultiple(vecType<T, P> const & Value, T Multiple)
+       {
+               return (Value % Multiple) == vecType<T, P>(0);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isMultiple(vecType<T, P> const & Value, vecType<T, P> const & Multiple)
+       {
+               return (Value % Multiple) == vecType<T, P>(0);
+       }
+
+       //////////////////////
+       // ceilMultiple
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple)
+       {
+               return detail::compute_ceilMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> ceilMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple)
+       {
+               return detail::functor2<T, P, vecType>::call(ceilMultiple, Source, Multiple);
+       }
+
+       //////////////////////
+       // floorMultiple
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple)
+       {
+               return detail::compute_floorMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> floorMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple)
+       {
+               return detail::functor2<T, P, vecType>::call(floorMultiple, Source, Multiple);
+       }
+
+       //////////////////////
+       // roundMultiple
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple)
+       {
+               return detail::compute_roundMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> roundMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple)
+       {
+               return detail::functor2<T, P, vecType>::call(roundMultiple, Source, Multiple);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/type_aligned.hpp b/core/deps/glm/glm/gtc/type_aligned.hpp
new file mode 100755 (executable)
index 0000000..2e4503c
--- /dev/null
@@ -0,0 +1,362 @@
+/// @ref gtc_type_aligned
+/// @file glm/gtc/type_aligned.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_type_aligned GLM_GTC_type_aligned
+/// @ingroup gtc
+///
+/// @brief Aligned types.
+/// <glm/gtc/type_aligned.hpp> need to be included to use these features.
+
+#pragma once
+
+#if !GLM_HAS_ALIGNED_TYPE
+#      error "GLM: Aligned types are not supported on this platform"
+#endif
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+# pragma message("GLM: GLM_GTC_type_aligned extension included")
+#endif
+
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../gtc/vec1.hpp"
+
+namespace glm
+{
+       template <typename T, precision P> struct tvec1;
+       template <typename T, precision P> struct tvec2;
+       template <typename T, precision P> struct tvec3;
+       template <typename T, precision P> struct tvec4;
+       /// @addtogroup gtc_type_aligned
+       /// @{
+
+       // -- *vec1 --
+
+       typedef tvec1<float, aligned_highp>             aligned_highp_vec1;
+       typedef tvec1<float, aligned_mediump>   aligned_mediump_vec1;
+       typedef tvec1<float, aligned_lowp>              aligned_lowp_vec1;
+       typedef tvec1<double, aligned_highp>    aligned_highp_dvec1;
+       typedef tvec1<double, aligned_mediump>  aligned_mediump_dvec1;
+       typedef tvec1<double, aligned_lowp>             aligned_lowp_dvec1;
+       typedef tvec1<int, aligned_highp>               aligned_highp_ivec1;
+       typedef tvec1<int, aligned_mediump>             aligned_mediump_ivec1;
+       typedef tvec1<int, aligned_lowp>                aligned_lowp_ivec1;
+       typedef tvec1<uint, aligned_highp>              aligned_highp_uvec1;
+       typedef tvec1<uint, aligned_mediump>    aligned_mediump_uvec1;
+       typedef tvec1<uint, aligned_lowp>               aligned_lowp_uvec1;
+       typedef tvec1<bool, aligned_highp>              aligned_highp_bvec1;
+       typedef tvec1<bool, aligned_mediump>    aligned_mediump_bvec1;
+       typedef tvec1<bool, aligned_lowp>               aligned_lowp_bvec1;
+
+       typedef tvec1<float, packed_highp>              packed_highp_vec1;
+       typedef tvec1<float, packed_mediump>    packed_mediump_vec1;
+       typedef tvec1<float, packed_lowp>               packed_lowp_vec1;
+       typedef tvec1<double, packed_highp>             packed_highp_dvec1;
+       typedef tvec1<double, packed_mediump>   packed_mediump_dvec1;
+       typedef tvec1<double, packed_lowp>              packed_lowp_dvec1;
+       typedef tvec1<int, packed_highp>                packed_highp_ivec1;
+       typedef tvec1<int, packed_mediump>              packed_mediump_ivec1;
+       typedef tvec1<int, packed_lowp>                 packed_lowp_ivec1;
+       typedef tvec1<uint, packed_highp>               packed_highp_uvec1;
+       typedef tvec1<uint, packed_mediump>             packed_mediump_uvec1;
+       typedef tvec1<uint, packed_lowp>                packed_lowp_uvec1;
+       typedef tvec1<bool, packed_highp>               packed_highp_bvec1;
+       typedef tvec1<bool, packed_mediump>             packed_mediump_bvec1;
+       typedef tvec1<bool, packed_lowp>                packed_lowp_bvec1;
+
+       // -- *vec2 --
+
+       /// 2 components vector of high single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<float, aligned_highp>             aligned_highp_vec2;
+
+       /// 2 components vector of medium single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<float, aligned_mediump>   aligned_mediump_vec2;
+
+       /// 2 components vector of low single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<float, aligned_lowp>              aligned_lowp_vec2;
+
+       /// 2 components vector of high double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<double, aligned_highp>    aligned_highp_dvec2;
+
+       /// 2 components vector of medium double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<double, aligned_mediump>  aligned_mediump_dvec2;
+
+       /// 2 components vector of low double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<double, aligned_lowp>             aligned_lowp_dvec2;
+
+       /// 2 components vector of high precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<int, aligned_highp>               aligned_highp_ivec2;
+
+       /// 2 components vector of medium precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<int, aligned_mediump>             aligned_mediump_ivec2;
+
+       /// 2 components vector of low precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<int, aligned_lowp>                aligned_lowp_ivec2;
+
+       /// 2 components vector of high precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<uint, aligned_highp>              aligned_highp_uvec2;
+
+       /// 2 components vector of medium precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<uint, aligned_mediump>    aligned_mediump_uvec2;
+
+       /// 2 components vector of low precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<uint, aligned_lowp>               aligned_lowp_uvec2;
+
+       /// 2 components vector of high precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<bool, aligned_highp>              aligned_highp_bvec2;
+
+       /// 2 components vector of medium precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<bool, aligned_mediump>    aligned_mediump_bvec2;
+
+       /// 2 components vector of low precision bool numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec2<bool, aligned_lowp>               aligned_lowp_bvec2;
+
+       // -- *vec3 --
+
+       /// 3 components vector of high single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<float, aligned_highp>             aligned_highp_vec3;
+
+       /// 3 components vector of medium single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<float, aligned_mediump>   aligned_mediump_vec3;
+
+       /// 3 components vector of low single-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<float, aligned_lowp>              aligned_lowp_vec3;
+
+       /// 3 components vector of high double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<double, aligned_highp>    aligned_highp_dvec3;
+
+       /// 3 components vector of medium double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<double, aligned_mediump>  aligned_mediump_dvec3;
+
+       /// 3 components vector of low double-precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<double, aligned_lowp>             aligned_lowp_dvec3;
+
+       /// 3 components vector of high precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<int, aligned_highp>               aligned_highp_ivec3;
+
+       /// 3 components vector of medium precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<int, aligned_mediump>             aligned_mediump_ivec3;
+
+       /// 3 components vector of low precision signed integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<int, aligned_lowp>                aligned_lowp_ivec3;
+
+       /// 3 components vector of high precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<uint, aligned_highp>              aligned_highp_uvec3;
+
+       /// 3 components vector of medium precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<uint, aligned_mediump>    aligned_mediump_uvec3;
+
+       /// 3 components vector of low precision unsigned integer numbers.
+       /// There is no guarantee on the actual precision.
+       typedef tvec3<uint, aligned_lowp>               aligned_lowp_uvec3;
+
+       /// 3 components vector of high precision bool numbers.
+       typedef tvec3<bool, aligned_highp>              aligned_highp_bvec3;
+
+       /// 3 components vector of medium precision bool numbers.
+       typedef tvec3<bool, aligned_mediump>    aligned_mediump_bvec3;
+
+       /// 3 components vector of low precision bool numbers.
+       typedef tvec3<bool, aligned_lowp>               aligned_lowp_bvec3;
+
+       // -- *vec4 --
+
+       /// 4 components vector of high single-precision floating-point numbers.
+       typedef tvec4<float, aligned_highp>             aligned_highp_vec4;
+
+       /// 4 components vector of medium single-precision floating-point numbers.
+       typedef tvec4<float, aligned_mediump>   aligned_mediump_vec4;
+
+       /// 4 components vector of low single-precision floating-point numbers.
+       typedef tvec4<float, aligned_lowp>              aligned_lowp_vec4;
+
+       /// 4 components vector of high double-precision floating-point numbers.
+       typedef tvec4<double, aligned_highp>    aligned_highp_dvec4;
+
+       /// 4 components vector of medium double-precision floating-point numbers.
+       typedef tvec4<double, aligned_mediump>  aligned_mediump_dvec4;
+
+       /// 4 components vector of low double-precision floating-point numbers.
+       typedef tvec4<double, aligned_lowp>             aligned_lowp_dvec4;
+
+       /// 4 components vector of high precision signed integer numbers.
+       typedef tvec4<int, aligned_highp>               aligned_highp_ivec4;
+
+       /// 4 components vector of medium precision signed integer numbers.
+       typedef tvec4<int, aligned_mediump>             aligned_mediump_ivec4;
+
+       /// 4 components vector of low precision signed integer numbers.
+       typedef tvec4<int, aligned_lowp>                aligned_lowp_ivec4;
+
+       /// 4 components vector of high precision unsigned integer numbers.
+       typedef tvec4<uint, aligned_highp>              aligned_highp_uvec4;
+
+       /// 4 components vector of medium precision unsigned integer numbers.
+       typedef tvec4<uint, aligned_mediump>    aligned_mediump_uvec4;
+
+       /// 4 components vector of low precision unsigned integer numbers.
+       typedef tvec4<uint, aligned_lowp>               aligned_lowp_uvec4;
+
+       /// 4 components vector of high precision bool numbers.
+       typedef tvec4<bool, aligned_highp>              aligned_highp_bvec4;
+
+       /// 4 components vector of medium precision bool numbers.
+       typedef tvec4<bool, aligned_mediump>    aligned_mediump_bvec4;
+
+       /// 4 components vector of low precision bool numbers.
+       typedef tvec4<bool, aligned_lowp>               aligned_lowp_bvec4;
+
+       // -- default --
+
+#if(defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef aligned_lowp_vec1                       aligned_vec1;
+       typedef aligned_lowp_vec2                       aligned_vec2;
+       typedef aligned_lowp_vec3                       aligned_vec3;
+       typedef aligned_lowp_vec4                       aligned_vec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+       typedef aligned_mediump_vec1            aligned_vec1;
+       typedef aligned_mediump_vec2            aligned_vec2;
+       typedef aligned_mediump_vec3            aligned_vec3;
+       typedef aligned_mediump_vec4            aligned_vec4;
+#else //defined(GLM_PRECISION_HIGHP_FLOAT)
+       /// 1 component vector of floating-point numbers.
+       typedef aligned_highp_vec1                      aligned_vec1;
+
+       /// 2 components vector of floating-point numbers.
+       typedef aligned_highp_vec2                      aligned_vec2;
+
+       /// 3 components vector of floating-point numbers.
+       typedef aligned_highp_vec3                      aligned_vec3;
+
+       /// 4 components vector of floating-point numbers.
+       typedef aligned_highp_vec4                      aligned_vec4;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef aligned_lowp_dvec1                      aligned_dvec1;
+       typedef aligned_lowp_dvec2                      aligned_dvec2;
+       typedef aligned_lowp_dvec3                      aligned_dvec3;
+       typedef aligned_lowp_dvec4                      aligned_dvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))
+       typedef aligned_mediump_dvec1           aligned_dvec1;
+       typedef aligned_mediump_dvec2           aligned_dvec2;
+       typedef aligned_mediump_dvec3           aligned_dvec3;
+       typedef aligned_mediump_dvec4           aligned_dvec4;
+#else //defined(GLM_PRECISION_HIGHP_DOUBLE)
+       /// 1 component vector of double-precision floating-point numbers.
+       typedef aligned_highp_dvec1                     aligned_dvec1;
+
+       /// 2 components vector of double-precision floating-point numbers.
+       typedef aligned_highp_dvec2                     aligned_dvec2;
+
+       /// 3 components vector of double-precision floating-point numbers.
+       typedef aligned_highp_dvec3                     aligned_dvec3;
+
+       /// 4 components vector of double-precision floating-point numbers.
+       typedef aligned_highp_dvec4                     aligned_dvec4;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_LOWP_INT))
+       typedef aligned_lowp_ivec1                      aligned_ivec1;
+       typedef aligned_lowp_ivec2                      aligned_ivec2;
+       typedef aligned_lowp_ivec3                      aligned_ivec3;
+       typedef aligned_lowp_ivec4                      aligned_ivec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef aligned_mediump_ivec1           aligned_ivec1;
+       typedef aligned_mediump_ivec2           aligned_ivec2;
+       typedef aligned_mediump_ivec3           aligned_ivec3;
+       typedef aligned_mediump_ivec4           aligned_ivec4;
+#else //defined(GLM_PRECISION_HIGHP_INT)
+       /// 1 component vector of signed integer numbers.
+       typedef aligned_highp_ivec1                     aligned_ivec1;
+
+       /// 2 components vector of signed integer numbers.
+       typedef aligned_highp_ivec2                     aligned_ivec2;
+
+       /// 3 components vector of signed integer numbers.
+       typedef aligned_highp_ivec3                     aligned_ivec3;
+
+       /// 4 components vector of signed integer numbers.
+       typedef aligned_highp_ivec4                     aligned_ivec4;
+#endif//GLM_PRECISION
+
+       // -- Unsigned integer definition --
+
+#if(defined(GLM_PRECISION_LOWP_UINT))
+       typedef aligned_lowp_uvec1                      aligned_uvec1;
+       typedef aligned_lowp_uvec2                      aligned_uvec2;
+       typedef aligned_lowp_uvec3                      aligned_uvec3;
+       typedef aligned_lowp_uvec4                      aligned_uvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_UINT))
+       typedef aligned_mediump_uvec1           aligned_uvec1;
+       typedef aligned_mediump_uvec2           aligned_uvec2;
+       typedef aligned_mediump_uvec3           aligned_uvec3;
+       typedef aligned_mediump_uvec4           aligned_uvec4;
+#else //defined(GLM_PRECISION_HIGHP_UINT)
+       /// 1 component vector of unsigned integer numbers.
+       typedef aligned_highp_uvec1                     aligned_uvec1;
+
+       /// 2 components vector of unsigned integer numbers.
+       typedef aligned_highp_uvec2                     aligned_uvec2;
+
+       /// 3 components vector of unsigned integer numbers.
+       typedef aligned_highp_uvec3                     aligned_uvec3;
+
+       /// 4 components vector of unsigned integer numbers.
+       typedef aligned_highp_uvec4                     aligned_uvec4;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_LOWP_BOOL))
+       typedef aligned_lowp_bvec1                      aligned_bvec1;
+       typedef aligned_lowp_bvec2                      aligned_bvec2;
+       typedef aligned_lowp_bvec3                      aligned_bvec3;
+       typedef aligned_lowp_bvec4                      aligned_bvec4;
+#elif(defined(GLM_PRECISION_MEDIUMP_BOOL))
+       typedef aligned_mediump_bvec1           aligned_bvec1;
+       typedef aligned_mediump_bvec2           aligned_bvec2;
+       typedef aligned_mediump_bvec3           aligned_bvec3;
+       typedef aligned_mediump_bvec4           aligned_bvec4;
+#else //defined(GLM_PRECISION_HIGHP_BOOL)
+       /// 1 component vector of boolean.
+       typedef aligned_highp_bvec1                     aligned_bvec1;
+
+       /// 2 components vector of boolean.
+       typedef aligned_highp_bvec2                     aligned_bvec2;
+
+       /// 3 components vector of boolean.
+       typedef aligned_highp_bvec3                     aligned_bvec3;
+
+       /// 4 components vector of boolean.
+       typedef aligned_highp_bvec4                     aligned_bvec4;
+#endif//GLM_PRECISION
+
+       /// @}
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/type_precision.hpp b/core/deps/glm/glm/gtc/type_precision.hpp
new file mode 100755 (executable)
index 0000000..a2dbb66
--- /dev/null
@@ -0,0 +1,861 @@
+/// @ref gtc_type_precision
+/// @file glm/gtc/type_precision.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtc_type_precision GLM_GTC_type_precision
+/// @ingroup gtc
+///
+/// @brief Defines specific C++-based precision types.
+/// 
+/// @ref core_precision defines types based on GLSL's precision qualifiers. This
+/// extension defines types based on explicitly-sized C++ data types.
+///
+/// <glm/gtc/type_precision.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../gtc/quaternion.hpp"
+#include "../gtc/vec1.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../mat2x2.hpp"
+#include "../mat2x3.hpp"
+#include "../mat2x4.hpp"
+#include "../mat3x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat3x4.hpp"
+#include "../mat4x2.hpp"
+#include "../mat4x3.hpp"
+#include "../mat4x4.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_type_precision extension included")
+#endif
+
+namespace glm
+{
+       ///////////////////////////
+       // Signed int vector types 
+
+       /// @addtogroup gtc_type_precision
+       /// @{
+
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_int8;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_int16;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_int32;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_int64;
+
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_int8_t;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_int16_t;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_int32_t;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_int64_t;
+
+       /// Low precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 lowp_i8;
+       
+       /// Low precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 lowp_i16;
+
+       /// Low precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 lowp_i32;
+
+       /// Low precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 lowp_i64;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_int8;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_int16;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_int32;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_int64;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_int8_t;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_int16_t;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_int32_t;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_int64_t;
+
+       /// Medium precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 mediump_i8;
+       
+       /// Medium precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 mediump_i16;
+
+       /// Medium precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 mediump_i32;
+
+       /// Medium precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 mediump_i64;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_int8;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_int16;
+
+       /// High precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_int32;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_int64;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_int8_t;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_int16_t;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_int32_t;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_int64_t;
+
+       /// High precision 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 highp_i8;
+       
+       /// High precision 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 highp_i16;
+
+       /// High precision 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 highp_i32;
+
+       /// High precision 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 highp_i64;
+       
+
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 int8;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 int16;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 int32;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 int64;
+
+#if GLM_HAS_EXTENDED_INTEGER_TYPE
+       using std::int8_t;
+       using std::int16_t;
+       using std::int32_t;
+       using std::int64_t;
+#else
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 int8_t;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 int16_t;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 int32_t;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 int64_t;
+#endif
+
+       /// 8 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int8 i8;
+       
+       /// 16 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int16 i16;
+
+       /// 32 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int32 i32;
+
+       /// 64 bit signed integer type.
+       /// @see gtc_type_precision
+       typedef detail::int64 i64;
+
+
+       /// 8 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i8, defaultp> i8vec1;
+       
+       /// 8 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i8, defaultp> i8vec2;
+
+       /// 8 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i8, defaultp> i8vec3;
+
+       /// 8 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i8, defaultp> i8vec4;
+
+
+       /// 16 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i16, defaultp> i16vec1;
+       
+       /// 16 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i16, defaultp> i16vec2;
+
+       /// 16 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i16, defaultp> i16vec3;
+
+       /// 16 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i16, defaultp> i16vec4;
+
+
+       /// 32 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i32, defaultp> i32vec1;
+       
+       /// 32 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i32, defaultp> i32vec2;
+
+       /// 32 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i32, defaultp> i32vec3;
+
+       /// 32 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i32, defaultp> i32vec4;
+
+
+       /// 64 bit signed integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<i64, defaultp> i64vec1;
+       
+       /// 64 bit signed integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<i64, defaultp> i64vec2;
+
+       /// 64 bit signed integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<i64, defaultp> i64vec3;
+
+       /// 64 bit signed integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<i64, defaultp> i64vec4;
+
+
+       /////////////////////////////
+       // Unsigned int vector types
+
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_uint8;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_uint16;
+
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_uint32;
+
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_uint64;
+
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_uint8_t;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_uint16_t;
+
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_uint32_t;
+
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_uint64_t;
+
+       /// Low precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 lowp_u8;
+       
+       /// Low precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 lowp_u16;
+
+       /// Low precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 lowp_u32;
+
+       /// Low precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 lowp_u64;
+       
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_uint8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_uint16;
+
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_uint32;
+
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_uint64;
+
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_uint8_t;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_uint16_t;
+
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_uint32_t;
+
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_uint64_t;
+
+       /// Medium precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 mediump_u8;
+       
+       /// Medium precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 mediump_u16;
+
+       /// Medium precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 mediump_u32;
+
+       /// Medium precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 mediump_u64;
+       
+       /// High precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_uint8;
+       
+       /// High precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_uint16;
+
+       /// High precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_uint32;
+
+       /// High precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_uint64;
+
+       /// High precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_uint8_t;
+       
+       /// High precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_uint16_t;
+
+       /// High precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_uint32_t;
+
+       /// High precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_uint64_t;
+
+       /// High precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 highp_u8;
+       
+       /// High precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 highp_u16;
+
+       /// High precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 highp_u32;
+
+       /// High precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 highp_u64;
+
+       /// Default precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 uint8;
+       
+       /// Default precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 uint16;
+
+       /// Default precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 uint32;
+
+       /// Default precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 uint64;
+
+#if GLM_HAS_EXTENDED_INTEGER_TYPE
+       using std::uint8_t;
+       using std::uint16_t;
+       using std::uint32_t;
+       using std::uint64_t;
+#else
+       /// Default precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 uint8_t;
+       
+       /// Default precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 uint16_t;
+
+       /// Default precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 uint32_t;
+
+       /// Default precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 uint64_t;
+#endif
+
+       /// Default precision 8 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint8 u8;
+       
+       /// Default precision 16 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint16 u16;
+
+       /// Default precision 32 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint32 u32;
+
+       /// Default precision 64 bit unsigned integer type.
+       /// @see gtc_type_precision
+       typedef detail::uint64 u64;
+
+
+
+       /// Default precision 8 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u8, defaultp> u8vec1;
+       
+       /// Default precision 8 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u8, defaultp> u8vec2;
+
+       /// Default precision 8 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u8, defaultp> u8vec3;
+
+       /// Default precision 8 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u8, defaultp> u8vec4;
+
+
+       /// Default precision 16 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u16, defaultp> u16vec1;
+       
+       /// Default precision 16 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u16, defaultp> u16vec2;
+
+       /// Default precision 16 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u16, defaultp> u16vec3;
+
+       /// Default precision 16 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u16, defaultp> u16vec4;
+
+
+       /// Default precision 32 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u32, defaultp> u32vec1;
+       
+       /// Default precision 32 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u32, defaultp> u32vec2;
+
+       /// Default precision 32 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u32, defaultp> u32vec3;
+
+       /// Default precision 32 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u32, defaultp> u32vec4;
+
+
+       /// Default precision 64 bit unsigned integer scalar type.
+       /// @see gtc_type_precision
+       typedef tvec1<u64, defaultp> u64vec1;
+       
+       /// Default precision 64 bit unsigned integer vector of 2 components type.
+       /// @see gtc_type_precision
+       typedef tvec2<u64, defaultp> u64vec2;
+
+       /// Default precision 64 bit unsigned integer vector of 3 components type.
+       /// @see gtc_type_precision
+       typedef tvec3<u64, defaultp> u64vec3;
+
+       /// Default precision 64 bit unsigned integer vector of 4 components type.
+       /// @see gtc_type_precision
+       typedef tvec4<u64, defaultp> u64vec4;
+
+
+       //////////////////////
+       // Float vector types
+
+       /// 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 float32;
+
+       /// 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 float64;
+
+
+       /// 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float32 float32_t;
+
+       /// 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef detail::float64 float64_t;
+
+
+       /// 32 bit single-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float32 f32;
+
+       /// 64 bit double-precision floating-point scalar.
+       /// @see gtc_type_precision
+       typedef float64 f64;
+
+
+       /// Single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<float, defaultp> fvec1;
+
+       /// Single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<float, defaultp> fvec2;
+
+       /// Single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<float, defaultp> fvec3;
+
+       /// Single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<float, defaultp> fvec4;
+
+       
+       /// Single-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f32, defaultp> f32vec1;
+
+       /// Single-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f32, defaultp> f32vec2;
+
+       /// Single-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f32, defaultp> f32vec3;
+
+       /// Single-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f32, defaultp> f32vec4;
+
+
+       /// Double-precision floating-point vector of 1 component.
+       /// @see gtc_type_precision
+       typedef tvec1<f64, defaultp> f64vec1;
+
+       /// Double-precision floating-point vector of 2 components.
+       /// @see gtc_type_precision
+       typedef tvec2<f64, defaultp> f64vec2;
+
+       /// Double-precision floating-point vector of 3 components.
+       /// @see gtc_type_precision
+       typedef tvec3<f64, defaultp> f64vec3;
+
+       /// Double-precision floating-point vector of 4 components.
+       /// @see gtc_type_precision
+       typedef tvec4<f64, defaultp> f64vec4;
+
+
+       //////////////////////
+       // Float matrix types 
+
+       /// Single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f32> fmat1;
+
+       /// Single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, defaultp> fmat2;
+
+       /// Single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, defaultp> fmat3;
+
+       /// Single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, defaultp> fmat4;
+
+
+       /// Single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f32 fmat1x1;
+
+       /// Single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, defaultp> fmat2x2;
+
+       /// Single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, defaultp> fmat2x3;
+
+       /// Single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, defaultp> fmat2x4;
+
+       /// Single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, defaultp> fmat3x2;
+
+       /// Single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, defaultp> fmat3x3;
+
+       /// Single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, defaultp> fmat3x4;
+
+       /// Single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, defaultp> fmat4x2;
+
+       /// Single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, defaultp> fmat4x3;
+
+       /// Single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, defaultp> fmat4x4;
+
+
+       /// Single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f32, defaultp> f32mat1;
+
+       /// Single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, defaultp> f32mat2;
+
+       /// Single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, defaultp> f32mat3;
+
+       /// Single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, defaultp> f32mat4;
+
+
+       /// Single-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f32 f32mat1x1;
+
+       /// Single-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f32, defaultp> f32mat2x2;
+
+       /// Single-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f32, defaultp> f32mat2x3;
+
+       /// Single-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f32, defaultp> f32mat2x4;
+
+       /// Single-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f32, defaultp> f32mat3x2;
+
+       /// Single-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f32, defaultp> f32mat3x3;
+
+       /// Single-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f32, defaultp> f32mat3x4;
+
+       /// Single-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f32, defaultp> f32mat4x2;
+
+       /// Single-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f32, defaultp> f32mat4x3;
+
+       /// Single-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f32, defaultp> f32mat4x4;
+
+
+       /// Double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef detail::tmat1x1<f64, defaultp> f64mat1;
+
+       /// Double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f64, defaultp> f64mat2;
+
+       /// Double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f64, defaultp> f64mat3;
+
+       /// Double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f64, defaultp> f64mat4;
+
+
+       /// Double-precision floating-point 1x1 matrix.
+       /// @see gtc_type_precision
+       //typedef f64 f64mat1x1;
+
+       /// Double-precision floating-point 2x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x2<f64, defaultp> f64mat2x2;
+
+       /// Double-precision floating-point 2x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x3<f64, defaultp> f64mat2x3;
+
+       /// Double-precision floating-point 2x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat2x4<f64, defaultp> f64mat2x4;
+
+       /// Double-precision floating-point 3x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x2<f64, defaultp> f64mat3x2;
+
+       /// Double-precision floating-point 3x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x3<f64, defaultp> f64mat3x3;
+
+       /// Double-precision floating-point 3x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat3x4<f64, defaultp> f64mat3x4;
+
+       /// Double-precision floating-point 4x2 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x2<f64, defaultp> f64mat4x2;
+
+       /// Double-precision floating-point 4x3 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x3<f64, defaultp> f64mat4x3;
+
+       /// Double-precision floating-point 4x4 matrix.
+       /// @see gtc_type_precision
+       typedef tmat4x4<f64, defaultp> f64mat4x4;
+
+
+       //////////////////////////
+       // Quaternion types
+
+       /// Single-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f32, defaultp> f32quat;
+
+       /// Double-precision floating-point quaternion.
+       /// @see gtc_type_precision
+       typedef tquat<f64, defaultp> f64quat;
+
+       /// @}
+}//namespace glm
+
+#include "type_precision.inl"
diff --git a/core/deps/glm/glm/gtc/type_precision.inl b/core/deps/glm/glm/gtc/type_precision.inl
new file mode 100755 (executable)
index 0000000..cbfd4d8
--- /dev/null
@@ -0,0 +1,7 @@
+/// @ref gtc_swizzle
+/// @file glm/gtc/swizzle.inl
+
+namespace glm
+{
+
+}
diff --git a/core/deps/glm/glm/gtc/type_ptr.hpp b/core/deps/glm/glm/gtc/type_ptr.hpp
new file mode 100755 (executable)
index 0000000..008665e
--- /dev/null
@@ -0,0 +1,149 @@
+/// @ref gtc_type_ptr
+/// @file glm/gtc/type_ptr.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtc_type_ptr GLM_GTC_type_ptr
+/// @ingroup gtc
+///
+/// @brief Handles the interaction between pointers and vector, matrix types.
+///
+/// This extension defines an overloaded function, glm::value_ptr, which
+/// takes any of the \ref core_template "core template types". It returns
+/// a pointer to the memory layout of the object. Matrix types store their values
+/// in column-major order.
+/// 
+/// This is useful for uploading data to matrices or copying data to buffer objects.
+///
+/// Example:
+/// @code
+/// #include <glm/glm.hpp>
+/// #include <glm/gtc/type_ptr.hpp>
+///
+/// glm::vec3 aVector(3);
+/// glm::mat4 someMatrix(1.0);
+///
+/// glUniform3fv(uniformLoc, 1, glm::value_ptr(aVector));
+/// glUniformMatrix4fv(uniformMatrixLoc, 1, GL_FALSE, glm::value_ptr(someMatrix));
+/// @endcode
+///
+/// <glm/gtc/type_ptr.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../gtc/quaternion.hpp"
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../mat2x2.hpp"
+#include "../mat2x3.hpp"
+#include "../mat2x4.hpp"
+#include "../mat3x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat3x4.hpp"
+#include "../mat4x2.hpp"
+#include "../mat4x3.hpp"
+#include "../mat4x4.hpp"
+#include <cstring>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_type_ptr extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_type_ptr
+       /// @{
+
+       /// Return the constant address to the data of the input parameter.
+       /// @see gtc_type_ptr
+       template<typename genType>
+       GLM_FUNC_DECL typename genType::value_type const * value_ptr(genType const & vec);
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tvec2<T, defaultp> make_vec2(T const * const ptr);
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tvec3<T, defaultp> make_vec3(T const * const ptr);
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tvec4<T, defaultp> make_vec4(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat2x2<T, defaultp> make_mat2x2(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat2x3<T, defaultp> make_mat2x3(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat2x4<T, defaultp> make_mat2x4(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat3x2<T, defaultp> make_mat3x2(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat3x3<T, defaultp> make_mat3x3(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat3x4<T, defaultp> make_mat3x4(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat4x2<T, defaultp> make_mat4x2(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat4x3<T, defaultp> make_mat4x3(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> make_mat4x4(T const * const ptr);
+       
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat2x2<T, defaultp> make_mat2(T const * const ptr);
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat3x3<T, defaultp> make_mat3(T const * const ptr);
+               
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> make_mat4(T const * const ptr);
+
+       /// Build a quaternion from a pointer.
+       /// @see gtc_type_ptr
+       template<typename T>
+       GLM_FUNC_DECL tquat<T, defaultp> make_quat(T const * const ptr);
+
+       /// @}
+}//namespace glm
+
+#include "type_ptr.inl"
diff --git a/core/deps/glm/glm/gtc/type_ptr.inl b/core/deps/glm/glm/gtc/type_ptr.inl
new file mode 100755 (executable)
index 0000000..3aa6ae6
--- /dev/null
@@ -0,0 +1,450 @@
+/// @ref gtc_type_ptr
+/// @file glm/gtc/type_ptr.inl
+
+#include <cstring>
+
+namespace glm
+{
+       /// @addtogroup gtc_type_ptr
+       /// @{
+
+       /// Return the constant address to the data of the vector input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tvec2<T, P> const & vec
+       )
+       {
+               return &(vec.x);
+       }
+
+       //! Return the address to the data of the vector input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tvec2<T, P> & vec
+       )
+       {
+               return &(vec.x);
+       }
+
+       /// Return the constant address to the data of the vector input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tvec3<T, P> const & vec
+       )
+       {
+               return &(vec.x);
+       }
+
+       //! Return the address to the data of the vector input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tvec3<T, P> & vec
+       )
+       {
+               return &(vec.x);
+       }
+               
+       /// Return the constant address to the data of the vector input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (       
+               tvec4<T, P> const & vec
+       )
+       {
+               return &(vec.x);
+       }
+
+       //! Return the address to the data of the vector input.
+       //! From GLM_GTC_type_ptr extension.
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (       
+               tvec4<T, P> & vec
+       )
+       {
+               return &(vec.x);
+       }
+
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat2x2<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat2x2<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat3x3<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat3x3<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat4x4<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       //! From GLM_GTC_type_ptr extension.
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat4x4<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat2x3<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat2x3<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat3x2<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat3x2<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat2x4<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat2x4<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat4x2<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (       
+               tmat4x2<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat3x4<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       //! Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tmat3x4<T, P> & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+               
+       /// Return the constant address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tmat4x3<T, P> const & mat
+       )
+       {
+               return &(mat[0].x);
+       }
+
+       /// Return the address to the data of the matrix input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr(tmat4x3<T, P> & mat)
+       {
+               return &(mat[0].x);
+       }
+
+       /// Return the constant address to the data of the input parameter.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T const * value_ptr
+       (
+               tquat<T, P> const & q
+       )
+       {
+               return &(q[0]);
+       }
+
+       /// Return the address to the data of the quaternion input.
+       /// @see gtc_type_ptr
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER T * value_ptr
+       (
+               tquat<T, P> & q
+       )
+       {
+               return &(q[0]);
+       }
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec2<T, defaultp> make_vec2(T const * const ptr)
+       {
+               tvec2<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tvec2<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec3<T, defaultp> make_vec3(T const * const ptr)
+       {
+               tvec3<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tvec3<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a vector from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tvec4<T, defaultp> make_vec4(T const * const ptr)
+       {
+               tvec4<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tvec4<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat2x2<T, defaultp> make_mat2x2(T const * const ptr)
+       {
+               tmat2x2<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat2x2<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat2x3<T, defaultp> make_mat2x3(T const * const ptr)
+       {
+               tmat2x3<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat2x3<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat2x4<T, defaultp> make_mat2x4(T const * const ptr)
+       {
+               tmat2x4<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat2x4<T, defaultp>));
+               return Result;
+       }
+
+       /// Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat3x2<T, defaultp> make_mat3x2(T const * const ptr)
+       {
+               tmat3x2<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat3x2<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat3x3<T, defaultp> make_mat3x3(T const * const ptr)
+       {
+               tmat3x3<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat3x3<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat3x4<T, defaultp> make_mat3x4(T const * const ptr)
+       {
+               tmat3x4<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat3x4<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x2<T, defaultp> make_mat4x2(T const * const ptr)
+       {
+               tmat4x2<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat4x2<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x3<T, defaultp> make_mat4x3(T const * const ptr)
+       {
+               tmat4x3<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat4x3<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> make_mat4x4(T const * const ptr)
+       {
+               tmat4x4<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tmat4x4<T, defaultp>));
+               return Result;
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat2x2<T, defaultp> make_mat2(T const * const ptr)
+       {
+               return make_mat2x2(ptr);
+       }
+
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat3x3<T, defaultp> make_mat3(T const * const ptr)
+       {
+               return make_mat3x3(ptr);
+       }
+               
+       //! Build a matrix from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> make_mat4(T const * const ptr)
+       {
+               return make_mat4x4(ptr);
+       }
+
+       //! Build a quaternion from a pointer.
+       /// @see gtc_type_ptr
+       template <typename T>
+       GLM_FUNC_QUALIFIER tquat<T, defaultp> make_quat(T const * const ptr)
+       {
+               tquat<T, defaultp> Result;
+               memcpy(value_ptr(Result), ptr, sizeof(tquat<T, defaultp>));
+               return Result;
+       }
+
+       /// @}
+}//namespace glm
+
diff --git a/core/deps/glm/glm/gtc/ulp.hpp b/core/deps/glm/glm/gtc/ulp.hpp
new file mode 100755 (executable)
index 0000000..a82fa4e
--- /dev/null
@@ -0,0 +1,63 @@
+/// @ref gtc_ulp
+/// @file glm/gtc/ulp.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_ulp GLM_GTC_ulp
+/// @ingroup gtc
+///
+/// @brief Allow the measurement of the accuracy of a function against a reference 
+/// implementation. This extension works on floating-point data and provide results 
+/// in ULP.
+/// <glm/gtc/ulp.hpp> need to be included to use these features.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+#include "../detail/type_int.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_ulp extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtc_ulp
+       /// @{
+
+       /// Return the next ULP value(s) after the input value(s).
+       /// @see gtc_ulp
+       template <typename genType>
+       GLM_FUNC_DECL genType next_float(genType const & x);
+
+       /// Return the previous ULP value(s) before the input value(s).
+       /// @see gtc_ulp
+       template <typename genType>
+       GLM_FUNC_DECL genType prev_float(genType const & x);
+
+       /// Return the value(s) ULP distance after the input value(s).
+       /// @see gtc_ulp
+       template <typename genType>
+       GLM_FUNC_DECL genType next_float(genType const & x, uint const & Distance);
+
+       /// Return the value(s) ULP distance before the input value(s).
+       /// @see gtc_ulp
+       template <typename genType>
+       GLM_FUNC_DECL genType prev_float(genType const & x, uint const & Distance);
+       
+       /// Return the distance in the number of ULP between 2 scalars.
+       /// @see gtc_ulp
+       template <typename T>
+       GLM_FUNC_DECL uint float_distance(T const & x, T const & y);
+
+       /// Return the distance in the number of ULP between 2 vectors.
+       /// @see gtc_ulp
+       template<typename T, template<typename> class vecType>
+       GLM_FUNC_DECL vecType<uint> float_distance(vecType<T> const & x, vecType<T> const & y);
+       
+       /// @}
+}// namespace glm
+
+#include "ulp.inl"
diff --git a/core/deps/glm/glm/gtc/ulp.inl b/core/deps/glm/glm/gtc/ulp.inl
new file mode 100755 (executable)
index 0000000..54c914a
--- /dev/null
@@ -0,0 +1,321 @@
+/// @ref gtc_ulp
+/// @file glm/gtc/ulp.inl
+///
+/// Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
+///
+/// Developed at SunPro, a Sun Microsystems, Inc. business.
+/// Permission to use, copy, modify, and distribute this
+/// software is freely granted, provided that this notice
+/// is preserved.
+
+#include "../detail/type_int.hpp"
+#include <cmath>
+#include <cfloat>
+#include <limits>
+
+#if(GLM_COMPILER & GLM_COMPILER_VC)
+#      pragma warning(push)
+#      pragma warning(disable : 4127)
+#endif
+
+typedef union
+{
+       float value;
+       /* FIXME: Assumes 32 bit int.  */
+       unsigned int word;
+} ieee_float_shape_type;
+
+typedef union
+{
+       double value;
+       struct
+       {
+               glm::detail::int32 lsw;
+               glm::detail::int32 msw;
+       } parts;
+} ieee_double_shape_type;
+
+#define GLM_EXTRACT_WORDS(ix0,ix1,d)           \
+       do {                                                                    \
+               ieee_double_shape_type ew_u;            \
+               ew_u.value = (d);                                       \
+               (ix0) = ew_u.parts.msw;                         \
+               (ix1) = ew_u.parts.lsw;                         \
+       } while (0)
+
+#define GLM_GET_FLOAT_WORD(i,d)                                \
+       do {                                                                    \
+               ieee_float_shape_type gf_u;                     \
+               gf_u.value = (d);                                       \
+               (i) = gf_u.word;                                        \
+       } while (0)
+
+#define GLM_SET_FLOAT_WORD(d,i)                                \
+       do {                                                                    \
+               ieee_float_shape_type sf_u;                     \
+               sf_u.word = (i);                                        \
+               (d) = sf_u.value;                                       \
+       } while (0)
+
+#define GLM_INSERT_WORDS(d,ix0,ix1)                    \
+       do {                                                                    \
+               ieee_double_shape_type iw_u;            \
+               iw_u.parts.msw = (ix0);                         \
+               iw_u.parts.lsw = (ix1);                         \
+               (d) = iw_u.value;                                       \
+       } while (0)
+
+namespace glm{
+namespace detail
+{
+       GLM_FUNC_QUALIFIER float nextafterf(float x, float y)
+       {
+               volatile float t;
+               glm::detail::int32 hx, hy, ix, iy;
+
+               GLM_GET_FLOAT_WORD(hx, x);
+               GLM_GET_FLOAT_WORD(hy, y);
+               ix = hx&0x7fffffff;             // |x|
+               iy = hy&0x7fffffff;             // |y|
+
+               if((ix>0x7f800000) ||   // x is nan 
+                       (iy>0x7f800000))        // y is nan 
+                       return x+y;
+               if(x==y) return y;              // x=y, return y
+               if(ix==0) {                             // x == 0
+                       GLM_SET_FLOAT_WORD(x,(hy&0x80000000)|1);// return +-minsubnormal
+                       t = x*x;
+                       if(t==x) return t; else return x;       // raise underflow flag
+               }
+               if(hx>=0) {                             // x > 0 
+                       if(hx>hy) {                     // x > y, x -= ulp
+                               hx -= 1;
+                       } else {                        // x < y, x += ulp
+                               hx += 1;
+                       }
+               } else {                                // x < 0
+                       if(hy>=0||hx>hy){       // x < y, x -= ulp
+                               hx -= 1;
+                       } else {                        // x > y, x += ulp
+                               hx += 1;
+                       }
+               }
+               hy = hx&0x7f800000;
+               if(hy>=0x7f800000) return x+x;  // overflow
+               if(hy<0x00800000) {             // underflow
+                       t = x*x;
+                       if(t!=x) {          // raise underflow flag
+                               GLM_SET_FLOAT_WORD(y,hx);
+                               return y;
+                       }
+               }
+               GLM_SET_FLOAT_WORD(x,hx);
+               return x;
+       }
+
+       GLM_FUNC_QUALIFIER double nextafter(double x, double y)
+       {
+               volatile double t;
+               glm::detail::int32 hx, hy, ix, iy;
+               glm::detail::uint32 lx, ly;
+
+               GLM_EXTRACT_WORDS(hx, lx, x);
+               GLM_EXTRACT_WORDS(hy, ly, y);
+               ix = hx & 0x7fffffff;             // |x| 
+               iy = hy & 0x7fffffff;             // |y| 
+
+               if(((ix>=0x7ff00000)&&((ix-0x7ff00000)|lx)!=0) ||   // x is nan
+                       ((iy>=0x7ff00000)&&((iy-0x7ff00000)|ly)!=0))     // y is nan
+                       return x+y;
+               if(x==y) return y;              // x=y, return y
+               if((ix|lx)==0) {                        // x == 0 
+                       GLM_INSERT_WORDS(x, hy & 0x80000000, 1);    // return +-minsubnormal
+                       t = x*x;
+                       if(t==x) return t; else return x;   // raise underflow flag 
+               }
+               if(hx>=0) {                             // x > 0 
+                       if(hx>hy||((hx==hy)&&(lx>ly))) {    // x > y, x -= ulp 
+                               if(lx==0) hx -= 1;
+                               lx -= 1;
+                       } else {                            // x < y, x += ulp
+                               lx += 1;
+                               if(lx==0) hx += 1;
+                       }
+               } else {                                // x < 0 
+                       if(hy>=0||hx>hy||((hx==hy)&&(lx>ly))){// x < y, x -= ulp
+                               if(lx==0) hx -= 1;
+                               lx -= 1;
+                       } else {                            // x > y, x += ulp
+                               lx += 1;
+                               if(lx==0) hx += 1;
+                       }
+               }
+               hy = hx&0x7ff00000;
+               if(hy>=0x7ff00000) return x+x;  // overflow
+               if(hy<0x00100000) {             // underflow
+                       t = x*x;
+                       if(t!=x) {          // raise underflow flag
+                               GLM_INSERT_WORDS(y,hx,lx);
+                               return y;
+                       }
+               }
+               GLM_INSERT_WORDS(x,hx,lx);
+               return x;
+       }
+}//namespace detail
+}//namespace glm
+
+#if(GLM_COMPILER & GLM_COMPILER_VC)
+#      pragma warning(pop)
+#endif
+
+namespace glm
+{
+       template <>
+       GLM_FUNC_QUALIFIER float next_float(float const & x)
+       {
+#              if GLM_HAS_CXX11_STL
+                       return std::nextafter(x, std::numeric_limits<float>::max());
+#              elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
+                       return detail::nextafterf(x, FLT_MAX);
+#              elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+                       return __builtin_nextafterf(x, FLT_MAX);
+#              else
+                       return nextafterf(x, FLT_MAX);
+#              endif
+       }
+
+       template <>
+       GLM_FUNC_QUALIFIER double next_float(double const & x)
+       {
+#              if GLM_HAS_CXX11_STL
+                       return std::nextafter(x, std::numeric_limits<double>::max());
+#              elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
+                       return detail::nextafter(x, std::numeric_limits<double>::max());
+#              elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+                       return __builtin_nextafter(x, FLT_MAX);
+#              else
+                       return nextafter(x, DBL_MAX);
+#              endif
+       }
+
+       template<typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> next_float(vecType<T, P> const & x)
+       {
+               vecType<T, P> Result(uninitialize);
+               for(length_t i = 0, n = Result.length(); i < n; ++i)
+                       Result[i] = next_float(x[i]);
+               return Result;
+       }
+
+       GLM_FUNC_QUALIFIER float prev_float(float const & x)
+       {
+#              if GLM_HAS_CXX11_STL
+                       return std::nextafter(x, std::numeric_limits<float>::min());
+#              elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
+                       return detail::nextafterf(x, FLT_MIN);
+#              elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+                       return __builtin_nextafterf(x, FLT_MIN);
+#              else
+                       return nextafterf(x, FLT_MIN);
+#              endif
+       }
+
+       GLM_FUNC_QUALIFIER double prev_float(double const & x)
+       {
+#              if GLM_HAS_CXX11_STL
+                       return std::nextafter(x, std::numeric_limits<double>::min());
+#              elif((GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS)))
+                       return _nextafter(x, DBL_MIN);
+#              elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+                       return __builtin_nextafter(x, DBL_MIN);
+#              else
+                       return nextafter(x, DBL_MIN);
+#              endif
+       }
+
+       template<typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> prev_float(vecType<T, P> const & x)
+       {
+               vecType<T, P> Result(uninitialize);
+               for(length_t i = 0, n = Result.length(); i < n; ++i)
+                       Result[i] = prev_float(x[i]);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T next_float(T const & x, uint const & ulps)
+       {
+               T temp = x;
+               for(uint i = 0; i < ulps; ++i)
+                       temp = next_float(temp);
+               return temp;
+       }
+
+       template<typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> next_float(vecType<T, P> const & x, vecType<uint, P> const & ulps)
+       {
+               vecType<T, P> Result(uninitialize);
+               for(length_t i = 0, n = Result.length(); i < n; ++i)
+                       Result[i] = next_float(x[i], ulps[i]);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T prev_float(T const & x, uint const & ulps)
+       {
+               T temp = x;
+               for(uint i = 0; i < ulps; ++i)
+                       temp = prev_float(temp);
+               return temp;
+       }
+
+       template<typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> prev_float(vecType<T, P> const & x, vecType<uint, P> const & ulps)
+       {
+               vecType<T, P> Result(uninitialize);
+               for(length_t i = 0, n = Result.length(); i < n; ++i)
+                       Result[i] = prev_float(x[i], ulps[i]);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER uint float_distance(T const & x, T const & y)
+       {
+               uint ulp = 0;
+
+               if(x < y)
+               {
+                       T temp = x;
+                       while(temp != y)// && ulp < std::numeric_limits<std::size_t>::max())
+                       {
+                               ++ulp;
+                               temp = next_float(temp);
+                       }
+               }
+               else if(y < x)
+               {
+                       T temp = y;
+                       while(temp != x)// && ulp < std::numeric_limits<std::size_t>::max())
+                       {
+                               ++ulp;
+                               temp = next_float(temp);
+                       }
+               }
+               else // ==
+               {
+
+               }
+
+               return ulp;
+       }
+
+       template<typename T, precision P, template<typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<uint, P> float_distance(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               vecType<uint, P> Result(uninitialize);
+               for(length_t i = 0, n = Result.length(); i < n; ++i)
+                       Result[i] = float_distance(x[i], y[i]);
+               return Result;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtc/vec1.hpp b/core/deps/glm/glm/gtc/vec1.hpp
new file mode 100755 (executable)
index 0000000..f84ff97
--- /dev/null
@@ -0,0 +1,164 @@
+/// @ref gtc_vec1
+/// @file glm/gtc/vec1.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtc_vec1 GLM_GTC_vec1
+/// @ingroup gtc
+/// 
+/// @brief Add vec1, ivec1, uvec1 and bvec1 types.
+/// <glm/gtc/vec1.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../detail/type_vec1.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTC_vec1 extension included")
+#endif
+
+namespace glm
+{
+       /// 1 component vector of high precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef highp_vec1_t                    highp_vec1;
+
+       /// 1 component vector of medium precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef mediump_vec1_t                  mediump_vec1;
+
+       /// 1 component vector of low precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef lowp_vec1_t                             lowp_vec1;
+
+       /// 1 component vector of high precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef highp_dvec1_t                   highp_dvec1;
+
+       /// 1 component vector of medium precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef mediump_dvec1_t                 mediump_dvec1;
+
+       /// 1 component vector of low precision floating-point numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef lowp_dvec1_t                    lowp_dvec1;
+
+       /// 1 component vector of high precision signed integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef highp_ivec1_t                   highp_ivec1;
+
+       /// 1 component vector of medium precision signed integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef mediump_ivec1_t                 mediump_ivec1;
+
+       /// 1 component vector of low precision signed integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef lowp_ivec1_t                    lowp_ivec1;
+
+       /// 1 component vector of high precision unsigned integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef highp_uvec1_t                   highp_uvec1;
+
+       /// 1 component vector of medium precision unsigned integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef mediump_uvec1_t                 mediump_uvec1;
+
+       /// 1 component vector of low precision unsigned integer numbers. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef lowp_uvec1_t                    lowp_uvec1;
+
+       /// 1 component vector of high precision boolean. 
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef highp_bvec1_t                   highp_bvec1;
+
+       /// 1 component vector of medium precision boolean.
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef mediump_bvec1_t                 mediump_bvec1;
+
+       /// 1 component vector of low precision boolean.
+       /// There is no guarantee on the actual precision.
+       /// @see gtc_vec1 extension.
+       typedef lowp_bvec1_t                    lowp_bvec1;
+
+       //////////////////////////
+       // vec1 definition
+
+#if(defined(GLM_PRECISION_HIGHP_BOOL))
+       typedef highp_bvec1                             bvec1;
+#elif(defined(GLM_PRECISION_MEDIUMP_BOOL))
+       typedef mediump_bvec1                   bvec1;
+#elif(defined(GLM_PRECISION_LOWP_BOOL))
+       typedef lowp_bvec1                              bvec1;
+#else
+       /// 1 component vector of boolean.
+       /// @see gtc_vec1 extension.
+       typedef highp_bvec1                             bvec1;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_HIGHP_FLOAT))
+       typedef highp_vec1                              vec1;
+#elif(defined(GLM_PRECISION_MEDIUMP_FLOAT))
+       typedef mediump_vec1                    vec1;
+#elif(defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_vec1                               vec1;
+#else
+       /// 1 component vector of floating-point numbers.
+       /// @see gtc_vec1 extension.
+       typedef highp_vec1                              vec1;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_HIGHP_DOUBLE))
+       typedef highp_dvec1                             dvec1;
+#elif(defined(GLM_PRECISION_MEDIUMP_DOUBLE))
+       typedef mediump_dvec1                   dvec1;
+#elif(defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_dvec1                              dvec1;
+#else
+       /// 1 component vector of floating-point numbers.
+       /// @see gtc_vec1 extension.
+       typedef highp_dvec1                             dvec1;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_HIGHP_INT))
+       typedef highp_ivec1                     ivec1;
+#elif(defined(GLM_PRECISION_MEDIUMP_INT))
+       typedef mediump_ivec1           ivec1;
+#elif(defined(GLM_PRECISION_LOWP_INT))
+       typedef lowp_ivec1                      ivec1;
+#else
+       /// 1 component vector of signed integer numbers. 
+       /// @see gtc_vec1 extension.
+       typedef highp_ivec1                     ivec1;
+#endif//GLM_PRECISION
+
+#if(defined(GLM_PRECISION_HIGHP_UINT))
+       typedef highp_uvec1                     uvec1;
+#elif(defined(GLM_PRECISION_MEDIUMP_UINT))
+       typedef mediump_uvec1           uvec1;
+#elif(defined(GLM_PRECISION_LOWP_UINT))
+       typedef lowp_uvec1                      uvec1;
+#else
+       /// 1 component vector of unsigned integer numbers. 
+       /// @see gtc_vec1 extension.
+       typedef highp_uvec1                     uvec1;
+#endif//GLM_PRECISION
+
+}// namespace glm
+
+#include "vec1.inl"
diff --git a/core/deps/glm/glm/gtc/vec1.inl b/core/deps/glm/glm/gtc/vec1.inl
new file mode 100755 (executable)
index 0000000..5a6627c
--- /dev/null
@@ -0,0 +1,2 @@
+/// @ref gtc_vec1
+/// @file glm/gtc/vec1.inl
diff --git a/core/deps/glm/glm/gtx/associated_min_max.hpp b/core/deps/glm/glm/gtx/associated_min_max.hpp
new file mode 100755 (executable)
index 0000000..eb9d721
--- /dev/null
@@ -0,0 +1,202 @@
+/// @ref gtx_associated_min_max
+/// @file glm/gtx/associated_min_max.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_associated_min_max GLM_GTX_associated_min_max
+/// @ingroup gtx
+/// 
+/// @brief Min and max functions that return associated values not the compared onces.
+/// <glm/gtx/associated_min_max.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_associated_min_max extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_associated_min_max
+       /// @{
+
+       /// Minimum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P>
+       GLM_FUNC_DECL U associatedMin(T x, U a, T y, U b);
+
+       /// Minimum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL tvec2<U, P> associatedMin(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b);
+
+       /// Minimum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               T x, const vecType<U, P>& a,
+               T y, const vecType<U, P>& b);
+
+       /// Minimum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               vecType<T, P> const & x, U a,
+               vecType<T, P> const & y, U b);
+
+       /// Minimum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U>
+       GLM_FUNC_DECL U associatedMin(
+               T x, U a,
+               T y, U b,
+               T z, U c);
+
+       /// Minimum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b,
+               vecType<T, P> const & z, vecType<U, P> const & c);
+
+       /// Minimum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U>
+       GLM_FUNC_DECL U associatedMin(
+               T x, U a,
+               T y, U b,
+               T z, U c,
+               T w, U d);
+
+       /// Minimum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b,
+               vecType<T, P> const & z, vecType<U, P> const & c,
+               vecType<T, P> const & w, vecType<U, P> const & d);
+
+       /// Minimum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               T x, vecType<U, P> const & a,
+               T y, vecType<U, P> const & b,
+               T z, vecType<U, P> const & c,
+               T w, vecType<U, P> const & d);
+
+       /// Minimum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMin(
+               vecType<T, P> const & x, U a,
+               vecType<T, P> const & y, U b,
+               vecType<T, P> const & z, U c,
+               vecType<T, P> const & w, U d);
+
+       /// Maximum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U>
+       GLM_FUNC_DECL U associatedMax(T x, U a, T y, U b);
+
+       /// Maximum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL tvec2<U, P> associatedMax(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b);
+
+       /// Maximum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> associatedMax(
+               T x, vecType<U, P> const & a,
+               T y, vecType<U, P> const & b);
+
+       /// Maximum comparison between 2 variables and returns 2 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               vecType<T, P> const & x, U a,
+               vecType<T, P> const & y, U b);
+
+       /// Maximum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U>
+       GLM_FUNC_DECL U associatedMax(
+               T x, U a,
+               T y, U b,
+               T z, U c);
+
+       /// Maximum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b,
+               vecType<T, P> const & z, vecType<U, P> const & c);
+
+       /// Maximum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> associatedMax(
+               T x, vecType<U, P> const & a,
+               T y, vecType<U, P> const & b,
+               T z, vecType<U, P> const & c);
+
+       /// Maximum comparison between 3 variables and returns 3 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               vecType<T, P> const & x, U a,
+               vecType<T, P> const & y, U b,
+               vecType<T, P> const & z, U c);
+
+       /// Maximum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U>
+       GLM_FUNC_DECL U associatedMax(
+               T x, U a,
+               T y, U b,
+               T z, U c,
+               T w, U d);
+
+       /// Maximum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               vecType<T, P> const & x, vecType<U, P> const & a,
+               vecType<T, P> const & y, vecType<U, P> const & b,
+               vecType<T, P> const & z, vecType<U, P> const & c,
+               vecType<T, P> const & w, vecType<U, P> const & d);
+
+       /// Maximum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               T x, vecType<U, P> const & a,
+               T y, vecType<U, P> const & b,
+               T z, vecType<U, P> const & c,
+               T w, vecType<U, P> const & d);
+
+       /// Maximum comparison between 4 variables and returns 4 associated variable values
+       /// @see gtx_associated_min_max
+       template<typename T, typename U, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<U, P> associatedMax(
+               vecType<T, P> const & x, U a,
+               vecType<T, P> const & y, U b,
+               vecType<T, P> const & z, U c,
+               vecType<T, P> const & w, U d);
+
+       /// @}
+} //namespace glm
+
+#include "associated_min_max.inl"
diff --git a/core/deps/glm/glm/gtx/associated_min_max.inl b/core/deps/glm/glm/gtx/associated_min_max.inl
new file mode 100755 (executable)
index 0000000..6a57d48
--- /dev/null
@@ -0,0 +1,355 @@
+/// @ref gtx_associated_min_max
+/// @file glm/gtx/associated_min_max.inl
+
+namespace glm{
+
+// Min comparison between 2 variables
+template<typename T, typename U, precision P>
+GLM_FUNC_QUALIFIER U associatedMin(T x, U a, T y, U b)
+{
+       return x < y ? a : b;
+}
+
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER tvec2<U, P> associatedMin
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] < y[i] ? a[i] : b[i];
+       return Result;
+}
+
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       T x, const vecType<U, P>& a,
+       T y, const vecType<U, P>& b
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x < y ? a[i] : b[i];
+       return Result;
+}
+
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       vecType<T, P> const & x, U a,
+       vecType<T, P> const & y, U b
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] < y[i] ? a : b;
+       return Result;
+}
+
+// Min comparison between 3 variables
+template<typename T, typename U>
+GLM_FUNC_QUALIFIER U associatedMin
+(
+       T x, U a,
+       T y, U b,
+       T z, U c
+)
+{
+       U Result = x < y ? (x < z ? a : c) : (y < z ? b : c);
+       return Result;
+}
+
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b,
+       vecType<T, P> const & z, vecType<U, P> const & c
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] < y[i] ? (x[i] < z[i] ? a[i] : c[i]) : (y[i] < z[i] ? b[i] : c[i]);
+       return Result;
+}
+
+// Min comparison between 4 variables
+template<typename T, typename U>
+GLM_FUNC_QUALIFIER U associatedMin
+(
+       T x, U a,
+       T y, U b,
+       T z, U c,
+       T w, U d
+)
+{
+       T Test1 = min(x, y);
+       T Test2 = min(z, w);;
+       U Result1 = x < y ? a : b;
+       U Result2 = z < w ? c : d;
+       U Result = Test1 < Test2 ? Result1 : Result2;
+       return Result;
+}
+
+// Min comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b,
+       vecType<T, P> const & z, vecType<U, P> const & c,
+       vecType<T, P> const & w, vecType<U, P> const & d
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               T Test1 = min(x[i], y[i]);
+               T Test2 = min(z[i], w[i]);
+               U Result1 = x[i] < y[i] ? a[i] : b[i];
+               U Result2 = z[i] < w[i] ? c[i] : d[i];
+               Result[i] = Test1 < Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+
+// Min comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       T x, vecType<U, P> const & a,
+       T y, vecType<U, P> const & b,
+       T z, vecType<U, P> const & c,
+       T w, vecType<U, P> const & d
+)
+{
+       T Test1 = min(x, y);
+       T Test2 = min(z, w);
+
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               U Result1 = x < y ? a[i] : b[i];
+               U Result2 = z < w ? c[i] : d[i];
+               Result[i] = Test1 < Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+
+// Min comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMin
+(
+       vecType<T, P> const & x, U a,
+       vecType<T, P> const & y, U b,
+       vecType<T, P> const & z, U c,
+       vecType<T, P> const & w, U d
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               T Test1 = min(x[i], y[i]);
+               T Test2 = min(z[i], w[i]);;
+               U Result1 = x[i] < y[i] ? a : b;
+               U Result2 = z[i] < w[i] ? c : d;
+               Result[i] = Test1 < Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+
+// Max comparison between 2 variables
+template<typename T, typename U>
+GLM_FUNC_QUALIFIER U associatedMax(T x, U a, T y, U b)
+{
+       return x > y ? a : b;
+}
+
+// Max comparison between 2 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER tvec2<U, P> associatedMax
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] > y[i] ? a[i] : b[i];
+       return Result;
+}
+
+// Max comparison between 2 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<T, P> associatedMax
+(
+       T x, vecType<U, P> const & a,
+       T y, vecType<U, P> const & b
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x > y ? a[i] : b[i];
+       return Result;
+}
+
+// Max comparison between 2 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       vecType<T, P> const & x, U a,
+       vecType<T, P> const & y, U b
+)
+{
+       vecType<T, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] > y[i] ? a : b;
+       return Result;
+}
+
+// Max comparison between 3 variables
+template<typename T, typename U>
+GLM_FUNC_QUALIFIER U associatedMax
+(
+       T x, U a,
+       T y, U b,
+       T z, U c
+)
+{
+       U Result = x > y ? (x > z ? a : c) : (y > z ? b : c);
+       return Result;
+}
+
+// Max comparison between 3 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b,
+       vecType<T, P> const & z, vecType<U, P> const & c
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a[i] : c[i]) : (y[i] > z[i] ? b[i] : c[i]);
+       return Result;
+}
+
+// Max comparison between 3 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<T, P> associatedMax
+(
+       T x, vecType<U, P> const & a,
+       T y, vecType<U, P> const & b,
+       T z, vecType<U, P> const & c
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x > y ? (x > z ? a[i] : c[i]) : (y > z ? b[i] : c[i]);
+       return Result;
+}
+
+// Max comparison between 3 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       vecType<T, P> const & x, U a,
+       vecType<T, P> const & y, U b,
+       vecType<T, P> const & z, U c
+)
+{
+       vecType<T, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+               Result[i] = x[i] > y[i] ? (x[i] > z[i] ? a : c) : (y[i] > z[i] ? b : c);
+       return Result;
+}
+
+// Max comparison between 4 variables
+template<typename T, typename U>
+GLM_FUNC_QUALIFIER U associatedMax
+(
+       T x, U a,
+       T y, U b,
+       T z, U c,
+       T w, U d
+)
+{
+       T Test1 = max(x, y);
+       T Test2 = max(z, w);;
+       U Result1 = x > y ? a : b;
+       U Result2 = z > w ? c : d;
+       U Result = Test1 > Test2 ? Result1 : Result2;
+       return Result;
+}
+
+// Max comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       vecType<T, P> const & x, vecType<U, P> const & a,
+       vecType<T, P> const & y, vecType<U, P> const & b,
+       vecType<T, P> const & z, vecType<U, P> const & c,
+       vecType<T, P> const & w, vecType<U, P> const & d
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               T Test1 = max(x[i], y[i]);
+               T Test2 = max(z[i], w[i]);
+               U Result1 = x[i] > y[i] ? a[i] : b[i];
+               U Result2 = z[i] > w[i] ? c[i] : d[i];
+               Result[i] = Test1 > Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+
+// Max comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       T x, vecType<U, P> const & a,
+       T y, vecType<U, P> const & b,
+       T z, vecType<U, P> const & c,
+       T w, vecType<U, P> const & d
+)
+{
+       T Test1 = max(x, y);
+       T Test2 = max(z, w);
+
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               U Result1 = x > y ? a[i] : b[i];
+               U Result2 = z > w ? c[i] : d[i];
+               Result[i] = Test1 > Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+
+// Max comparison between 4 variables
+template<typename T, typename U, precision P, template <typename, precision> class vecType>
+GLM_FUNC_QUALIFIER vecType<U, P> associatedMax
+(
+       vecType<T, P> const & x, U a,
+       vecType<T, P> const & y, U b,
+       vecType<T, P> const & z, U c,
+       vecType<T, P> const & w, U d
+)
+{
+       vecType<U, P> Result(uninitialize);
+       for(length_t i = 0, n = Result.length(); i < n; ++i)
+       {
+               T Test1 = max(x[i], y[i]);
+               T Test2 = max(z[i], w[i]);;
+               U Result1 = x[i] > y[i] ? a : b;
+               U Result2 = z[i] > w[i] ? c : d;
+               Result[i] = Test1 > Test2 ? Result1 : Result2;
+       }
+       return Result;
+}
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/bit.hpp b/core/deps/glm/glm/gtx/bit.hpp
new file mode 100755 (executable)
index 0000000..17378f3
--- /dev/null
@@ -0,0 +1,95 @@
+/// @ref gtx_bit
+/// @file glm/gtx/bit.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+///
+/// @defgroup gtx_bit GLM_GTX_bit
+/// @ingroup gtx
+/// 
+/// @brief Allow to perform bit operations on integer values
+/// 
+/// <glm/gtx/bit.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../gtc/bitfield.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_bit extension is deprecated, include GLM_GTC_bitfield and GLM_GTC_integer instead")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_bit
+       /// @{
+
+       /// @see gtx_bit
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType highestBitValue(genIUType Value);
+
+       /// @see gtx_bit
+       template <typename genIUType>
+       GLM_FUNC_DECL genIUType lowestBitValue(genIUType Value);
+
+       /// Find the highest bit set to 1 in a integer variable and return its value.
+       ///
+       /// @see gtx_bit
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> highestBitValue(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is just higher the input value.
+       /// Deprecated, use ceilPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename genIUType>
+       GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoAbove(genIUType Value);
+
+       /// Return the power of two number which value is just higher the input value.
+       /// Deprecated, use ceilPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoAbove(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is just lower the input value.
+       /// Deprecated, use floorPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename genIUType>
+       GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoBelow(genIUType Value);
+
+       /// Return the power of two number which value is just lower the input value.
+       /// Deprecated, use floorPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoBelow(vecType<T, P> const & value);
+
+       /// Return the power of two number which value is the closet to the input value.
+       /// Deprecated, use roundPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename genIUType>
+       GLM_DEPRECATED GLM_FUNC_DECL genIUType powerOfTwoNearest(genIUType Value);
+
+       /// Return the power of two number which value is the closet to the input value.
+       /// Deprecated, use roundPowerOfTwo from GTC_round instead
+       ///
+       /// @see gtc_round
+       /// @see gtx_bit
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_DEPRECATED GLM_FUNC_DECL vecType<T, P> powerOfTwoNearest(vecType<T, P> const & value);
+
+       /// @}
+} //namespace glm
+
+
+#include "bit.inl"
+
diff --git a/core/deps/glm/glm/gtx/bit.inl b/core/deps/glm/glm/gtx/bit.inl
new file mode 100755 (executable)
index 0000000..10d5f7f
--- /dev/null
@@ -0,0 +1,93 @@
+/// @ref gtx_bit
+/// @file glm/gtx/bit.inl
+
+namespace glm
+{
+       ///////////////////
+       // highestBitValue
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType highestBitValue(genIUType Value)
+       {
+               genIUType tmp = Value;
+               genIUType result = genIUType(0);
+               while(tmp)
+               {
+                       result = (tmp & (~tmp + 1)); // grab lowest bit
+                       tmp &= ~result; // clear lowest bit
+               }
+               return result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> highestBitValue(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(highestBitValue, v);
+       }
+
+       ///////////////////
+       // lowestBitValue
+
+       template <typename genIUType>
+       GLM_FUNC_QUALIFIER genIUType lowestBitValue(genIUType Value)
+       {
+               return (Value & (~Value + 1));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> lowestBitValue(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(lowestBitValue, v);
+       }
+
+       ///////////////////
+       // powerOfTwoAbove
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType powerOfTwoAbove(genType value)
+       {
+               return isPowerOfTwo(value) ? value : highestBitValue(value) << 1;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> powerOfTwoAbove(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(powerOfTwoAbove, v);
+       }
+
+       ///////////////////
+       // powerOfTwoBelow
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType powerOfTwoBelow(genType value)
+       {
+               return isPowerOfTwo(value) ? value : highestBitValue(value);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> powerOfTwoBelow(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(powerOfTwoBelow, v);
+       }
+
+       /////////////////////
+       // powerOfTwoNearest
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType powerOfTwoNearest(genType value)
+       {
+               if(isPowerOfTwo(value))
+                       return value;
+
+               genType const prev = highestBitValue(value);
+               genType const next = prev << 1;
+               return (next - value) < (value - prev) ? next : prev;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> powerOfTwoNearest(vecType<T, P> const & v)
+       {
+               return detail::functor1<T, T, P, vecType>::call(powerOfTwoNearest, v);
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/closest_point.hpp b/core/deps/glm/glm/gtx/closest_point.hpp
new file mode 100755 (executable)
index 0000000..8d435b8
--- /dev/null
@@ -0,0 +1,45 @@
+/// @ref gtx_closest_point
+/// @file glm/gtx/closest_point.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_closest_point GLM_GTX_closest_point
+/// @ingroup gtx
+///
+/// @brief Find the point on a straight line which is the closet of a point.
+///
+/// <glm/gtx/closest_point.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_closest_point extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_closest_point
+       /// @{
+
+       /// Find the point on a straight line which is the closet of a point. 
+       /// @see gtx_closest_point
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> closestPointOnLine(
+               tvec3<T, P> const & point,
+               tvec3<T, P> const & a, 
+               tvec3<T, P> const & b);
+       
+       /// 2d lines work as well       
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> closestPointOnLine(
+               tvec2<T, P> const & point,
+               tvec2<T, P> const & a, 
+               tvec2<T, P> const & b); 
+
+       /// @}
+}// namespace glm
+
+#include "closest_point.inl"
diff --git a/core/deps/glm/glm/gtx/closest_point.inl b/core/deps/glm/glm/gtx/closest_point.inl
new file mode 100755 (executable)
index 0000000..5c6a879
--- /dev/null
@@ -0,0 +1,46 @@
+/// @ref gtx_closest_point
+/// @file glm/gtx/closest_point.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> closestPointOnLine
+       (
+               tvec3<T, P> const & point,
+               tvec3<T, P> const & a,
+               tvec3<T, P> const & b
+       )
+       {
+               T LineLength = distance(a, b);
+               tvec3<T, P> Vector = point - a;
+               tvec3<T, P> LineDirection = (b - a) / LineLength;
+
+               // Project Vector to LineDirection to get the distance of point from a
+               T Distance = dot(Vector, LineDirection);
+
+               if(Distance <= T(0)) return a;
+               if(Distance >= LineLength) return b;
+               return a + LineDirection * Distance;
+       }
+       
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> closestPointOnLine
+       (
+               tvec2<T, P> const & point,
+               tvec2<T, P> const & a,
+               tvec2<T, P> const & b
+       )
+       {
+               T LineLength = distance(a, b);
+               tvec2<T, P> Vector = point - a;
+               tvec2<T, P> LineDirection = (b - a) / LineLength;
+
+               // Project Vector to LineDirection to get the distance of point from a
+               T Distance = dot(Vector, LineDirection);
+
+               if(Distance <= T(0)) return a;
+               if(Distance >= LineLength) return b;
+               return a + LineDirection * Distance;
+       }
+       
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/color_space.hpp b/core/deps/glm/glm/gtx/color_space.hpp
new file mode 100755 (executable)
index 0000000..9ff08dc
--- /dev/null
@@ -0,0 +1,68 @@
+/// @ref gtx_color_space
+/// @file glm/gtx/color_space.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_color_space GLM_GTX_color_space
+/// @ingroup gtx
+///
+/// @brief Related to RGB to HSV conversions and operations.
+///
+/// <glm/gtx/color_space.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_color_space extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_color_space
+       /// @{
+
+       /// Converts a color from HSV color space to its color in RGB color space.
+       /// @see gtx_color_space
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rgbColor(
+               tvec3<T, P> const & hsvValue);
+
+       /// Converts a color from RGB color space to its color in HSV color space.
+       /// @see gtx_color_space
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> hsvColor(
+               tvec3<T, P> const & rgbValue);
+               
+       /// Build a saturation matrix.
+       /// @see gtx_color_space
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> saturation(
+               T const s);
+
+       /// Modify the saturation of a color.
+       /// @see gtx_color_space
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> saturation(
+               T const s,
+               tvec3<T, P> const & color);
+               
+       /// Modify the saturation of a color.
+       /// @see gtx_color_space
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> saturation(
+               T const s,
+               tvec4<T, P> const & color);
+               
+       /// Compute color luminosity associating ratios (0.33, 0.59, 0.11) to RGB canals.
+       /// @see gtx_color_space
+       template <typename T, precision P>
+       GLM_FUNC_DECL T luminosity(
+               tvec3<T, P> const & color);
+
+       /// @}
+}//namespace glm
+
+#include "color_space.inl"
diff --git a/core/deps/glm/glm/gtx/color_space.inl b/core/deps/glm/glm/gtx/color_space.inl
new file mode 100755 (executable)
index 0000000..e7cd58d
--- /dev/null
@@ -0,0 +1,141 @@
+/// @ref gtx_color_space
+/// @file glm/gtx/color_space.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rgbColor(const tvec3<T, P>& hsvColor)
+       {
+               tvec3<T, P> hsv = hsvColor;
+               tvec3<T, P> rgbColor;
+
+               if(hsv.y == static_cast<T>(0))
+                       // achromatic (grey)
+                       rgbColor = tvec3<T, P>(hsv.z);
+               else
+               {
+                       T sector = floor(hsv.x / T(60));
+                       T frac = (hsv.x / T(60)) - sector;
+                       // factorial part of h
+                       T o = hsv.z * (T(1) - hsv.y);
+                       T p = hsv.z * (T(1) - hsv.y * frac);
+                       T q = hsv.z * (T(1) - hsv.y * (T(1) - frac));
+
+                       switch(int(sector))
+                       {
+                       default:
+                       case 0:
+                               rgbColor.r = hsv.z;
+                               rgbColor.g = q;
+                               rgbColor.b = o;
+                               break;
+                       case 1:
+                               rgbColor.r = p;
+                               rgbColor.g = hsv.z;
+                               rgbColor.b = o;
+                               break;
+                       case 2:
+                               rgbColor.r = o;
+                               rgbColor.g = hsv.z;
+                               rgbColor.b = q;
+                               break;
+                       case 3:
+                               rgbColor.r = o;
+                               rgbColor.g = p;
+                               rgbColor.b = hsv.z;
+                               break;
+                       case 4:
+                               rgbColor.r = q; 
+                               rgbColor.g = o; 
+                               rgbColor.b = hsv.z;
+                               break;
+                       case 5:
+                               rgbColor.r = hsv.z; 
+                               rgbColor.g = o; 
+                               rgbColor.b = p;
+                               break;
+                       }
+               }
+
+               return rgbColor;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> hsvColor(const tvec3<T, P>& rgbColor)
+       {
+               tvec3<T, P> hsv = rgbColor;
+               float Min   = min(min(rgbColor.r, rgbColor.g), rgbColor.b);
+               float Max   = max(max(rgbColor.r, rgbColor.g), rgbColor.b);
+               float Delta = Max - Min;
+
+               hsv.z = Max;                               
+
+               if(Max != static_cast<T>(0))
+               {
+                       hsv.y = Delta / hsv.z;    
+                       T h = static_cast<T>(0);
+
+                       if(rgbColor.r == Max)
+                               // between yellow & magenta
+                               h = static_cast<T>(0) + T(60) * (rgbColor.g - rgbColor.b) / Delta;
+                       else if(rgbColor.g == Max)
+                               // between cyan & yellow
+                               h = static_cast<T>(120) + T(60) * (rgbColor.b - rgbColor.r) / Delta;
+                       else
+                               // between magenta & cyan
+                               h = static_cast<T>(240) + T(60) * (rgbColor.r - rgbColor.g) / Delta;
+
+                       if(h < T(0)) 
+                               hsv.x = h + T(360);
+                       else
+                               hsv.x = h;
+               }
+               else
+               {
+                       // If r = g = b = 0 then s = 0, h is undefined
+                       hsv.y = static_cast<T>(0);
+                       hsv.x = static_cast<T>(0);
+               }
+
+               return hsv;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> saturation(T const s)
+       {
+               tvec3<T, defaultp> rgbw = tvec3<T, defaultp>(T(0.2126), T(0.7152), T(0.0722));
+
+               tvec3<T, defaultp> const col((T(1) - s) * rgbw);
+
+               tmat4x4<T, defaultp> result(T(1));
+               result[0][0] = col.x + s;
+               result[0][1] = col.x;
+               result[0][2] = col.x;
+               result[1][0] = col.y;
+               result[1][1] = col.y + s;
+               result[1][2] = col.y;
+               result[2][0] = col.z;
+               result[2][1] = col.z;
+               result[2][2] = col.z + s;
+               return result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> saturation(const T s, const tvec3<T, P>& color)
+       {
+               return tvec3<T, P>(saturation(s) * tvec4<T, P>(color, T(0)));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> saturation(const T s, const tvec4<T, P>& color)
+       {
+               return saturation(s) * color;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER T luminosity(const tvec3<T, P>& color)
+       {
+               const tvec3<T, P> tmp = tvec3<T, P>(0.33, 0.59, 0.11);
+               return dot(color, tmp);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/color_space_YCoCg.hpp b/core/deps/glm/glm/gtx/color_space_YCoCg.hpp
new file mode 100755 (executable)
index 0000000..428ca6d
--- /dev/null
@@ -0,0 +1,56 @@
+/// @ref gtx_color_space_YCoCg
+/// @file glm/gtx/color_space_YCoCg.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_color_space_YCoCg GLM_GTX_color_space_YCoCg
+/// @ingroup gtx
+///
+/// @brief RGB to YCoCg conversions and operations
+///
+/// <glm/gtx/color_space_YCoCg.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_color_space_YCoCg extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_color_space_YCoCg
+       /// @{
+
+       /// Convert a color from RGB color space to YCoCg color space.
+       /// @see gtx_color_space_YCoCg
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rgb2YCoCg(
+               tvec3<T, P> const & rgbColor);
+
+       /// Convert a color from YCoCg color space to RGB color space.
+       /// @see gtx_color_space_YCoCg
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> YCoCg2rgb(
+               tvec3<T, P> const & YCoCgColor);
+
+       /// Convert a color from RGB color space to YCoCgR color space.
+       /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range"
+       /// @see gtx_color_space_YCoCg
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rgb2YCoCgR(
+               tvec3<T, P> const & rgbColor);
+
+       /// Convert a color from YCoCgR color space to RGB color space.
+       /// @see "YCoCg-R: A Color Space with RGB Reversibility and Low Dynamic Range"
+       /// @see gtx_color_space_YCoCg
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> YCoCgR2rgb(
+               tvec3<T, P> const & YCoCgColor);
+
+       /// @}
+}//namespace glm
+
+#include "color_space_YCoCg.inl"
diff --git a/core/deps/glm/glm/gtx/color_space_YCoCg.inl b/core/deps/glm/glm/gtx/color_space_YCoCg.inl
new file mode 100755 (executable)
index 0000000..1ca2e5b
--- /dev/null
@@ -0,0 +1,108 @@
+/// @ref gtx_color_space_YCoCg
+/// @file glm/gtx/color_space_YCoCg.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rgb2YCoCg
+       (
+               tvec3<T, P> const & rgbColor
+       )
+       {
+               tvec3<T, P> result;
+               result.x/*Y */ =   rgbColor.r / T(4) + rgbColor.g / T(2) + rgbColor.b / T(4);
+               result.y/*Co*/ =   rgbColor.r / T(2) + rgbColor.g * T(0) - rgbColor.b / T(2);
+               result.z/*Cg*/ = - rgbColor.r / T(4) + rgbColor.g / T(2) - rgbColor.b / T(4);
+               return result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> YCoCg2rgb
+       (
+               tvec3<T, P> const & YCoCgColor
+       )
+       {
+               tvec3<T, P> result;
+               result.r = YCoCgColor.x + YCoCgColor.y - YCoCgColor.z;
+               result.g = YCoCgColor.x                            + YCoCgColor.z;
+               result.b = YCoCgColor.x - YCoCgColor.y - YCoCgColor.z;
+               return result;
+       }
+
+       template <typename T, precision P, bool isInteger>
+       class compute_YCoCgR {
+       public:
+               static GLM_FUNC_QUALIFIER tvec3<T, P> rgb2YCoCgR
+               (
+                       tvec3<T, P> const & rgbColor
+               )
+               {
+                       tvec3<T, P> result;
+                       result.x/*Y */ = rgbColor.g / T(2) + (rgbColor.r + rgbColor.b) / T(4);
+                       result.y/*Co*/ = rgbColor.r - rgbColor.b;
+                       result.z/*Cg*/ = rgbColor.g - (rgbColor.r + rgbColor.b) / T(2);
+                       return result;
+               }
+
+               static GLM_FUNC_QUALIFIER tvec3<T, P> YCoCgR2rgb
+               (
+                       tvec3<T, P> const & YCoCgRColor
+               )
+               {
+                       tvec3<T, P> result;
+                       T tmp = YCoCgRColor.x - (YCoCgRColor.z / T(2));
+                       result.g = YCoCgRColor.z + tmp;
+                       result.b = tmp - (YCoCgRColor.y / T(2));
+                       result.r = result.b + YCoCgRColor.y;
+                       return result;
+               }
+       };
+
+       template <typename T, precision P>
+       class compute_YCoCgR<T, P, true> {
+       public:
+               static GLM_FUNC_QUALIFIER tvec3<T, P> rgb2YCoCgR
+               (
+                       tvec3<T, P> const & rgbColor
+               )
+               {
+                       tvec3<T, P> result;
+                       result.y/*Co*/ = rgbColor.r - rgbColor.b;
+                       T tmp = rgbColor.b + (result.y >> 1);
+                       result.z/*Cg*/ = rgbColor.g - tmp;
+                       result.x/*Y */ = tmp + (result.z >> 1);
+                       return result;
+               }
+
+               static GLM_FUNC_QUALIFIER tvec3<T, P> YCoCgR2rgb
+               (
+                       tvec3<T, P> const & YCoCgRColor
+               )
+               {
+                       tvec3<T, P> result;
+                       T tmp = YCoCgRColor.x - (YCoCgRColor.z >> 1);
+                       result.g = YCoCgRColor.z + tmp;
+                       result.b = tmp - (YCoCgRColor.y >> 1);
+                       result.r = result.b + YCoCgRColor.y;
+                       return result;
+               }
+       };
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rgb2YCoCgR
+       (
+               tvec3<T, P> const & rgbColor
+       )
+       {
+               return compute_YCoCgR<T, P, std::numeric_limits<T>::is_integer>::rgb2YCoCgR(rgbColor);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> YCoCgR2rgb
+       (
+               tvec3<T, P> const & YCoCgRColor
+       )
+       {
+               return compute_YCoCgR<T, P, std::numeric_limits<T>::is_integer>::YCoCgR2rgb(YCoCgRColor);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/common.hpp b/core/deps/glm/glm/gtx/common.hpp
new file mode 100755 (executable)
index 0000000..6533a54
--- /dev/null
@@ -0,0 +1,53 @@
+/// @ref gtx_common
+/// @file glm/gtx/common.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+///
+/// @defgroup gtx_common GLM_GTX_common
+/// @ingroup gtx
+///
+/// @brief Provide functions to increase the compatibility with Cg and HLSL languages
+///
+/// <glm/gtx/common.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies:
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../gtc/vec1.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_common extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_common
+       /// @{
+
+       /// Returns true if x is a denormalized number
+       /// Numbers whose absolute value is too small to be represented in the normal format are represented in an alternate, denormalized format.
+       /// This format is less precise but can represent values closer to zero.
+       /// 
+       /// @tparam genType Floating-point scalar or vector types.
+       ///
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/isnan.xml">GLSL isnan man page</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 8.3 Common Functions</a>
+       template <typename genType> 
+       GLM_FUNC_DECL typename genType::bool_type isdenormal(genType const & x);
+
+       /// Similar to 'mod' but with a different rounding and integer support.
+       /// Returns 'x - y * trunc(x/y)' instead of 'x - y * floor(x/y)'
+       /// 
+       /// @see <a href="http://stackoverflow.com/questions/7610631/glsl-mod-vs-hlsl-fmod">GLSL mod vs HLSL fmod</a>
+       /// @see <a href="http://www.opengl.org/sdk/docs/manglsl/xhtml/mod.xml">GLSL mod man page</a>
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fmod(vecType<T, P> const & v);
+
+       /// @}
+}//namespace glm
+
+#include "common.inl"
diff --git a/core/deps/glm/glm/gtx/common.inl b/core/deps/glm/glm/gtx/common.inl
new file mode 100755 (executable)
index 0000000..6c9cb65
--- /dev/null
@@ -0,0 +1,112 @@
+/// @ref gtx_common
+/// @file glm/gtx/common.inl
+
+#include <cmath>
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <class, precision> class vecType, bool isFloat = true>
+       struct compute_fmod
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & a, vecType<T, P> const & b)
+               {
+                       return detail::functor2<T, P, vecType>::call(std::fmod, a, b);
+               }
+       };
+
+       template <typename T, precision P, template <class, precision> class vecType>
+       struct compute_fmod<T, P, vecType, false>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & a, vecType<T, P> const & b)
+               {
+                       return a % b;
+               }
+       };
+}//namespace detail
+
+       template <typename T> 
+       GLM_FUNC_QUALIFIER bool isdenormal(T const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isdenormal' only accept floating-point inputs");
+
+#              if GLM_HAS_CXX11_STL
+                       return std::fpclassify(x) == FP_SUBNORMAL;
+#              else
+                       return x != static_cast<T>(0) && std::fabs(x) < std::numeric_limits<T>::min();
+#              endif
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tvec1<T, P>::bool_type isdenormal
+       (
+               tvec1<T, P> const & x
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isdenormal' only accept floating-point inputs");
+
+               return typename tvec1<T, P>::bool_type(
+                       isdenormal(x.x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tvec2<T, P>::bool_type isdenormal
+       (
+               tvec2<T, P> const & x
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isdenormal' only accept floating-point inputs");
+
+               return typename tvec2<T, P>::bool_type(
+                       isdenormal(x.x),
+                       isdenormal(x.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tvec3<T, P>::bool_type isdenormal
+       (
+               tvec3<T, P> const & x
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isdenormal' only accept floating-point inputs");
+
+               return typename tvec3<T, P>::bool_type(
+                       isdenormal(x.x),
+                       isdenormal(x.y),
+                       isdenormal(x.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tvec4<T, P>::bool_type isdenormal
+       (
+               tvec4<T, P> const & x
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isdenormal' only accept floating-point inputs");
+
+               return typename tvec4<T, P>::bool_type(
+                       isdenormal(x.x),
+                       isdenormal(x.y),
+                       isdenormal(x.z),
+                       isdenormal(x.w));
+       }
+
+       // fmod
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fmod(genType x, genType y)
+       {
+               return fmod(tvec1<genType>(x), y).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fmod(vecType<T, P> const & x, T y)
+       {
+               return detail::compute_fmod<T, P, vecType, std::numeric_limits<T>::is_iec559>::call(x, vecType<T, P>(y));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fmod(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return detail::compute_fmod<T, P, vecType, std::numeric_limits<T>::is_iec559>::call(x, y);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/compatibility.hpp b/core/deps/glm/glm/gtx/compatibility.hpp
new file mode 100755 (executable)
index 0000000..9f4819a
--- /dev/null
@@ -0,0 +1,130 @@
+/// @ref gtx_compatibility
+/// @file glm/gtx/compatibility.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+///
+/// @defgroup gtx_compatibility GLM_GTX_compatibility
+/// @ingroup gtx
+///
+/// @brief Provide functions to increase the compatibility with Cg and HLSL languages
+///
+/// <glm/gtx/compatibility.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_compatibility extension included")
+#endif
+
+#if GLM_COMPILER & GLM_COMPILER_VC
+#      include <cfloat>
+#elif GLM_COMPILER & GLM_COMPILER_GCC
+#      include <cmath>
+#      if(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+#              undef isfinite
+#      endif
+#endif//GLM_COMPILER
+
+namespace glm
+{
+       /// @addtogroup gtx_compatibility
+       /// @{
+
+       template <typename T> GLM_FUNC_QUALIFIER T lerp(T x, T y, T a){return mix(x, y, a);}                                                                                                                                                                    //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec2<T, P> lerp(const tvec2<T, P>& x, const tvec2<T, P>& y, T a){return mix(x, y, a);}                                                   //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec3<T, P> lerp(const tvec3<T, P>& x, const tvec3<T, P>& y, T a){return mix(x, y, a);}                                                   //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec4<T, P> lerp(const tvec4<T, P>& x, const tvec4<T, P>& y, T a){return mix(x, y, a);}                                                   //!< \brief Returns x * (1.0 - a) + y * a, i.e., the linear blend of x and y using the floating-point value a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec2<T, P> lerp(const tvec2<T, P>& x, const tvec2<T, P>& y, const tvec2<T, P>& a){return mix(x, y, a);}  //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec3<T, P> lerp(const tvec3<T, P>& x, const tvec3<T, P>& y, const tvec3<T, P>& a){return mix(x, y, a);}  //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec4<T, P> lerp(const tvec4<T, P>& x, const tvec4<T, P>& y, const tvec4<T, P>& a){return mix(x, y, a);}  //!< \brief Returns the component-wise result of x * (1.0 - a) + y * a, i.e., the linear blend of x and y using vector a. The value for a is not restricted to the range [0, 1]. (From GLM_GTX_compatibility)
+
+       template <typename T, precision P> GLM_FUNC_QUALIFIER T saturate(T x){return clamp(x, T(0), T(1));}                                                                                                             //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec2<T, P> saturate(const tvec2<T, P>& x){return clamp(x, T(0), T(1));}                                  //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec3<T, P> saturate(const tvec3<T, P>& x){return clamp(x, T(0), T(1));}                                  //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec4<T, P> saturate(const tvec4<T, P>& x){return clamp(x, T(0), T(1));}                                  //!< \brief Returns clamp(x, 0, 1) for each component in x. (From GLM_GTX_compatibility)
+
+       template <typename T, precision P> GLM_FUNC_QUALIFIER T atan2(T x, T y){return atan(x, y);}                                                                                                                             //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec2<T, P> atan2(const tvec2<T, P>& x, const tvec2<T, P>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec3<T, P> atan2(const tvec3<T, P>& x, const tvec3<T, P>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_QUALIFIER tvec4<T, P> atan2(const tvec4<T, P>& x, const tvec4<T, P>& y){return atan(x, y);} //!< \brief Arc tangent. Returns an angle whose tangent is y/x. The signs of x and y are used to determine what quadrant the angle is in. The range of values returned by this function is [-PI, PI]. Results are undefined if x and y are both 0. (From GLM_GTX_compatibility)
+
+       template <typename genType> GLM_FUNC_DECL bool isfinite(genType const & x);                                                                                     //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_DECL tvec1<bool, P> isfinite(const tvec1<T, P>& x);                         //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_DECL tvec2<bool, P> isfinite(const tvec2<T, P>& x);                         //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_DECL tvec3<bool, P> isfinite(const tvec3<T, P>& x);                         //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)
+       template <typename T, precision P> GLM_FUNC_DECL tvec4<bool, P> isfinite(const tvec4<T, P>& x);                         //!< \brief Test whether or not a scalar or each vector component is a finite value. (From GLM_GTX_compatibility)
+
+       typedef bool                                            bool1;                  //!< \brief boolean type with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tvec2<bool, highp>                      bool2;                  //!< \brief boolean type with 2 components. (From GLM_GTX_compatibility extension)
+       typedef tvec3<bool, highp>                      bool3;                  //!< \brief boolean type with 3 components. (From GLM_GTX_compatibility extension)
+       typedef tvec4<bool, highp>                      bool4;                  //!< \brief boolean type with 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef bool                                            bool1x1;                //!< \brief boolean matrix with 1 x 1 component. (From GLM_GTX_compatibility extension)
+       typedef tmat2x2<bool, highp>            bool2x2;                //!< \brief boolean matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x3<bool, highp>            bool2x3;                //!< \brief boolean matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x4<bool, highp>            bool2x4;                //!< \brief boolean matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x2<bool, highp>            bool3x2;                //!< \brief boolean matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x3<bool, highp>            bool3x3;                //!< \brief boolean matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x4<bool, highp>            bool3x4;                //!< \brief boolean matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x2<bool, highp>            bool4x2;                //!< \brief boolean matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x3<bool, highp>            bool4x3;                //!< \brief boolean matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x4<bool, highp>            bool4x4;                //!< \brief boolean matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef int                                                     int1;                   //!< \brief integer vector with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tvec2<int, highp>                       int2;                   //!< \brief integer vector with 2 components. (From GLM_GTX_compatibility extension)
+       typedef tvec3<int, highp>                       int3;                   //!< \brief integer vector with 3 components. (From GLM_GTX_compatibility extension)
+       typedef tvec4<int, highp>                       int4;                   //!< \brief integer vector with 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef int                                                     int1x1;                 //!< \brief integer matrix with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tmat2x2<int, highp>             int2x2;                 //!< \brief integer matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x3<int, highp>             int2x3;                 //!< \brief integer matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x4<int, highp>             int2x4;                 //!< \brief integer matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x2<int, highp>             int3x2;                 //!< \brief integer matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x3<int, highp>             int3x3;                 //!< \brief integer matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x4<int, highp>             int3x4;                 //!< \brief integer matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x2<int, highp>             int4x2;                 //!< \brief integer matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x3<int, highp>             int4x3;                 //!< \brief integer matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x4<int, highp>             int4x4;                 //!< \brief integer matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef float                                           float1;                 //!< \brief single-precision floating-point vector with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tvec2<float, highp>             float2;                 //!< \brief single-precision floating-point vector with 2 components. (From GLM_GTX_compatibility extension)
+       typedef tvec3<float, highp>             float3;                 //!< \brief single-precision floating-point vector with 3 components. (From GLM_GTX_compatibility extension)
+       typedef tvec4<float, highp>             float4;                 //!< \brief single-precision floating-point vector with 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef float                                           float1x1;               //!< \brief single-precision floating-point matrix with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tmat2x2<float, highp>           float2x2;               //!< \brief single-precision floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x3<float, highp>           float2x3;               //!< \brief single-precision floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x4<float, highp>           float2x4;               //!< \brief single-precision floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x2<float, highp>           float3x2;               //!< \brief single-precision floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x3<float, highp>           float3x3;               //!< \brief single-precision floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x4<float, highp>           float3x4;               //!< \brief single-precision floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x2<float, highp>           float4x2;               //!< \brief single-precision floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x3<float, highp>           float4x3;               //!< \brief single-precision floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x4<float, highp>           float4x4;               //!< \brief single-precision floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef double                                          double1;                //!< \brief double-precision floating-point vector with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tvec2<double, highp>            double2;                //!< \brief double-precision floating-point vector with 2 components. (From GLM_GTX_compatibility extension)
+       typedef tvec3<double, highp>            double3;                //!< \brief double-precision floating-point vector with 3 components. (From GLM_GTX_compatibility extension)
+       typedef tvec4<double, highp>            double4;                //!< \brief double-precision floating-point vector with 4 components. (From GLM_GTX_compatibility extension)
+
+       typedef double                                          double1x1;              //!< \brief double-precision floating-point matrix with 1 component. (From GLM_GTX_compatibility extension)
+       typedef tmat2x2<double, highp>          double2x2;              //!< \brief double-precision floating-point matrix with 2 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x3<double, highp>          double2x3;              //!< \brief double-precision floating-point matrix with 2 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat2x4<double, highp>          double2x4;              //!< \brief double-precision floating-point matrix with 2 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x2<double, highp>          double3x2;              //!< \brief double-precision floating-point matrix with 3 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x3<double, highp>          double3x3;              //!< \brief double-precision floating-point matrix with 3 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat3x4<double, highp>          double3x4;              //!< \brief double-precision floating-point matrix with 3 x 4 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x2<double, highp>          double4x2;              //!< \brief double-precision floating-point matrix with 4 x 2 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x3<double, highp>          double4x3;              //!< \brief double-precision floating-point matrix with 4 x 3 components. (From GLM_GTX_compatibility extension)
+       typedef tmat4x4<double, highp>          double4x4;              //!< \brief double-precision floating-point matrix with 4 x 4 components. (From GLM_GTX_compatibility extension)
+
+       /// @}
+}//namespace glm
+
+#include "compatibility.inl"
diff --git a/core/deps/glm/glm/gtx/compatibility.inl b/core/deps/glm/glm/gtx/compatibility.inl
new file mode 100755 (executable)
index 0000000..368527a
--- /dev/null
@@ -0,0 +1,65 @@
+/// @ref gtx_compatibility
+/// @file glm/gtx/compatibility.inl
+
+#include <limits>
+
+namespace glm
+{
+       // isfinite
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool isfinite(
+               genType const & x)
+       {
+#              if GLM_HAS_CXX11_STL
+                       return std::isfinite(x) != 0;
+#              elif GLM_COMPILER & GLM_COMPILER_VC
+                       return _finite(x);
+#              elif GLM_COMPILER & GLM_COMPILER_GCC && GLM_PLATFORM & GLM_PLATFORM_ANDROID
+                       return _isfinite(x) != 0;
+#              else
+                       if (std::numeric_limits<genType>::is_integer || std::denorm_absent == std::numeric_limits<genType>::has_denorm)
+                               return std::numeric_limits<genType>::min() <= x && std::numeric_limits<genType>::max() >= x;
+                       else
+                               return -std::numeric_limits<genType>::max() <= x && std::numeric_limits<genType>::max() >= x;
+#              endif
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec1<bool, P> isfinite(
+               tvec1<T, P> const & x)
+       {
+               return tvec1<bool, P>(
+                       isfinite(x.x));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<bool, P> isfinite(
+               tvec2<T, P> const & x)
+       {
+               return tvec2<bool, P>(
+                       isfinite(x.x),
+                       isfinite(x.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<bool, P> isfinite(
+               tvec3<T, P> const & x)
+       {
+               return tvec3<bool, P>(
+                       isfinite(x.x),
+                       isfinite(x.y),
+                       isfinite(x.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> isfinite(
+               tvec4<T, P> const & x)
+       {
+               return tvec4<bool, P>(
+                       isfinite(x.x),
+                       isfinite(x.y),
+                       isfinite(x.z),
+                       isfinite(x.w));
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/component_wise.hpp b/core/deps/glm/glm/gtx/component_wise.hpp
new file mode 100755 (executable)
index 0000000..c316f9e
--- /dev/null
@@ -0,0 +1,65 @@
+/// @ref gtx_component_wise
+/// @file glm/gtx/component_wise.hpp
+/// @date 2007-05-21 / 2011-06-07
+/// @author Christophe Riccio
+/// 
+/// @see core (dependence)
+///
+/// @defgroup gtx_component_wise GLM_GTX_component_wise
+/// @ingroup gtx
+///
+/// @brief Operations between components of a type
+///
+/// <glm/gtx/component_wise.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/precision.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_component_wise extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_component_wise
+       /// @{
+
+       /// Convert an integer vector to a normalized float vector.
+       /// If the parameter value type is already a floating precision type, the value is passed through.
+       /// @see gtx_component_wise
+       template <typename floatType, typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<floatType, P> compNormalize(vecType<T, P> const & v);
+
+       /// Convert a normalized float vector to an integer vector.
+       /// If the parameter value type is already a floating precision type, the value is passed through.
+       /// @see gtx_component_wise
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> compScale(vecType<floatType, P> const & v);
+
+       /// Add all vector components together. 
+       /// @see gtx_component_wise
+       template <typename genType> 
+       GLM_FUNC_DECL typename genType::value_type compAdd(genType const & v);
+
+       /// Multiply all vector components together. 
+       /// @see gtx_component_wise
+       template <typename genType> 
+       GLM_FUNC_DECL typename genType::value_type compMul(genType const & v);
+
+       /// Find the minimum value between single vector components.
+       /// @see gtx_component_wise
+       template <typename genType> 
+       GLM_FUNC_DECL typename genType::value_type compMin(genType const & v);
+
+       /// Find the maximum value between single vector components.
+       /// @see gtx_component_wise
+       template <typename genType> 
+       GLM_FUNC_DECL typename genType::value_type compMax(genType const & v);
+
+       /// @}
+}//namespace glm
+
+#include "component_wise.inl"
diff --git a/core/deps/glm/glm/gtx/component_wise.inl b/core/deps/glm/glm/gtx/component_wise.inl
new file mode 100755 (executable)
index 0000000..add3969
--- /dev/null
@@ -0,0 +1,128 @@
+/// @ref gtx_component_wise
+/// @file glm/gtx/component_wise.inl
+
+#include <limits>
+
+namespace glm{
+namespace detail
+{
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType, bool isInteger, bool signedType>
+       struct compute_compNormalize
+       {};
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compNormalize<T, floatType, P, vecType, true, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<floatType, P> call(vecType<T, P> const & v)
+               {
+                       floatType const Min = static_cast<floatType>(std::numeric_limits<T>::min());
+                       floatType const Max = static_cast<floatType>(std::numeric_limits<T>::max());
+                       return (vecType<floatType, P>(v) - Min) / (Max - Min) * static_cast<floatType>(2) - static_cast<floatType>(1);
+               }
+       };
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compNormalize<T, floatType, P, vecType, true, false>
+       {
+               GLM_FUNC_QUALIFIER static vecType<floatType, P> call(vecType<T, P> const & v)
+               {
+                       return vecType<floatType, P>(v) / static_cast<floatType>(std::numeric_limits<T>::max());
+               }
+       };
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compNormalize<T, floatType, P, vecType, false, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<floatType, P> call(vecType<T, P> const & v)
+               {
+                       return v;
+               }
+       };
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType, bool isInteger, bool signedType>
+       struct compute_compScale
+       {};
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compScale<T, floatType, P, vecType, true, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<floatType, P> const & v)
+               {
+                       floatType const Max = static_cast<floatType>(std::numeric_limits<T>::max()) + static_cast<floatType>(0.5);
+                       vecType<floatType, P> const Scaled(v * Max);
+                       vecType<T, P> const Result(Scaled - static_cast<floatType>(0.5));
+                       return Result;
+               }
+       };
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compScale<T, floatType, P, vecType, true, false>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<floatType, P> const & v)
+               {
+                       return vecType<T, P>(vecType<floatType, P>(v) * static_cast<floatType>(std::numeric_limits<T>::max()));
+               }
+       };
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       struct compute_compScale<T, floatType, P, vecType, false, true>
+       {
+               GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<floatType, P> const & v)
+               {
+                       return v;
+               }
+       };
+}//namespace detail
+
+       template <typename floatType, typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<floatType, P> compNormalize(vecType<T, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "'compNormalize' accepts only floating-point types for 'floatType' template parameter");
+
+               return detail::compute_compNormalize<T, floatType, P, vecType, std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed>::call(v);
+       }
+
+       template <typename T, typename floatType, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> compScale(vecType<floatType, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<floatType>::is_iec559, "'compScale' accepts only floating-point types for 'floatType' template parameter");
+
+               return detail::compute_compScale<T, floatType, P, vecType, std::numeric_limits<T>::is_integer, std::numeric_limits<T>::is_signed>::call(v);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T compAdd(vecType<T, P> const & v)
+       {
+               T Result(0);
+               for(length_t i = 0, n = v.length(); i < n; ++i)
+                       Result += v[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T compMul(vecType<T, P> const & v)
+       {
+               T Result(1);
+               for(length_t i = 0, n = v.length(); i < n; ++i)
+                       Result *= v[i];
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T compMin(vecType<T, P> const & v)
+       {
+               T Result(v[0]);
+               for(length_t i = 1, n = v.length(); i < n; ++i)
+                       Result = min(Result, v[i]);
+               return Result;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T compMax(vecType<T, P> const & v)
+       {
+               T Result(v[0]);
+               for(length_t i = 1, n = v.length(); i < n; ++i)
+                       Result = max(Result, v[i]);
+               return Result;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/dual_quaternion.hpp b/core/deps/glm/glm/gtx/dual_quaternion.hpp
new file mode 100755 (executable)
index 0000000..4d7b61e
--- /dev/null
@@ -0,0 +1,266 @@
+/// @ref gtx_dual_quaternion
+/// @file glm/gtx/dual_quaternion.hpp
+/// @author Maksim Vorobiev (msomeone@gmail.com)
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtc_constants (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtx_dual_quaternion GLM_GTX_dual_quaternion
+/// @ingroup gtx
+///
+/// @brief Defines a templated dual-quaternion type and several dual-quaternion operations.
+///
+/// <glm/gtx/dual_quaternion.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/constants.hpp"
+#include "../gtc/quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_dual_quaternion extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_dual_quaternion
+       /// @{
+
+       template <typename T, precision P = defaultp>
+       struct tdualquat
+       {
+               // -- Implementation detail --
+
+               typedef T value_type;
+               typedef glm::tquat<T, P> part_type;
+
+               // -- Data --
+
+               glm::tquat<T, P> real, dual;
+
+               // -- Component accesses --
+
+               typedef length_t length_type;
+               /// Return the count of components of a dual quaternion
+               GLM_FUNC_DECL static length_type length(){return 2;}
+
+               GLM_FUNC_DECL part_type & operator[](length_type i);
+               GLM_FUNC_DECL part_type const & operator[](length_type i) const;
+
+               // -- Implicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat() GLM_DEFAULT_CTOR;
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat<T, P> const & d) GLM_DEFAULT;
+               template <precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tdualquat<T, Q> const & d);
+
+               // -- Explicit basic constructors --
+
+               GLM_FUNC_DECL GLM_CONSTEXPR_CTOR explicit tdualquat(ctor);
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tquat<T, P> const & real);
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tquat<T, P> const & orientation, tvec3<T, P> const & translation);
+               GLM_FUNC_DECL GLM_CONSTEXPR tdualquat(tquat<T, P> const & real, tquat<T, P> const & dual);
+
+               // -- Conversion constructors --
+
+               template <typename U, precision Q>
+               GLM_FUNC_DECL GLM_CONSTEXPR GLM_EXPLICIT tdualquat(tdualquat<U, Q> const & q);
+
+               GLM_FUNC_DECL GLM_EXPLICIT tdualquat(tmat2x4<T, P> const & holder_mat);
+               GLM_FUNC_DECL GLM_EXPLICIT tdualquat(tmat3x4<T, P> const & aug_mat);
+
+               // -- Unary arithmetic operators --
+
+               GLM_FUNC_DECL tdualquat<T, P> & operator=(tdualquat<T, P> const & m) GLM_DEFAULT;
+
+               template <typename U>
+               GLM_FUNC_DECL tdualquat<T, P> & operator=(tdualquat<U, P> const & m);
+               template <typename U>
+               GLM_FUNC_DECL tdualquat<T, P> & operator*=(U s);
+               template <typename U>
+               GLM_FUNC_DECL tdualquat<T, P> & operator/=(U s);
+       };
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator+(tdualquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator-(tdualquat<T, P> const & q);
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator+(tdualquat<T, P> const & q, tdualquat<T, P> const & p);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator*(tdualquat<T, P> const & q, tdualquat<T, P> const & p);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tdualquat<T, P> const & q, tvec3<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> operator*(tvec3<T, P> const & v, tdualquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tdualquat<T, P> const & q, tvec4<T, P> const & v);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> operator*(tvec4<T, P> const & v, tdualquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator*(tdualquat<T, P> const & q, T const & s);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator*(T const & s, tdualquat<T, P> const & q);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> operator/(tdualquat<T, P> const & q, T const & s);
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator==(tdualquat<T, P> const & q1, tdualquat<T, P> const & q2);
+
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool operator!=(tdualquat<T, P> const & q1, tdualquat<T, P> const & q2);
+
+       /// Returns the normalized quaternion.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> normalize(tdualquat<T, P> const & q);
+
+       /// Returns the linear interpolation of two dual quaternion.
+       ///
+       /// @see gtc_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> lerp(tdualquat<T, P> const & x, tdualquat<T, P> const & y, T const & a);
+
+       /// Returns the q inverse.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> inverse(tdualquat<T, P> const & q);
+
+       /// Converts a quaternion to a 2 * 4 matrix.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> mat2x4_cast(tdualquat<T, P> const & x);
+
+       /// Converts a quaternion to a 3 * 4 matrix.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> mat3x4_cast(tdualquat<T, P> const & x);
+
+       /// Converts a 2 * 4 matrix (matrix which holds real and dual parts) to a quaternion.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> dualquat_cast(tmat2x4<T, P> const & x);
+
+       /// Converts a 3 * 4 matrix (augmented matrix rotation + translation) to a quaternion.
+       ///
+       /// @see gtx_dual_quaternion
+       template <typename T, precision P>
+       GLM_FUNC_DECL tdualquat<T, P> dualquat_cast(tmat3x4<T, P> const & x);
+
+
+       /// Dual-quaternion of low single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, lowp>          lowp_dualquat;
+
+       /// Dual-quaternion of medium single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, mediump>       mediump_dualquat;
+
+       /// Dual-quaternion of high single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, highp>         highp_dualquat;
+
+
+       /// Dual-quaternion of low single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, lowp>          lowp_fdualquat;
+
+       /// Dual-quaternion of medium single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, mediump>       mediump_fdualquat;
+
+       /// Dual-quaternion of high single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<float, highp>         highp_fdualquat;
+
+
+       /// Dual-quaternion of low double-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<double, lowp>         lowp_ddualquat;
+
+       /// Dual-quaternion of medium double-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<double, mediump>      mediump_ddualquat;
+
+       /// Dual-quaternion of high double-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef tdualquat<double, highp>        highp_ddualquat;
+
+
+#if(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       /// Dual-quaternion of floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef highp_fdualquat                 dualquat;
+
+       /// Dual-quaternion of single-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef highp_fdualquat                 fdualquat;
+#elif(defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef highp_fdualquat                 dualquat;
+       typedef highp_fdualquat                 fdualquat;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && defined(GLM_PRECISION_MEDIUMP_FLOAT) && !defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef mediump_fdualquat               dualquat;
+       typedef mediump_fdualquat               fdualquat;
+#elif(!defined(GLM_PRECISION_HIGHP_FLOAT) && !defined(GLM_PRECISION_MEDIUMP_FLOAT) && defined(GLM_PRECISION_LOWP_FLOAT))
+       typedef lowp_fdualquat                  dualquat;
+       typedef lowp_fdualquat                  fdualquat;
+#else
+#      error "GLM error: multiple default precision requested for single-precision floating-point types"
+#endif
+
+
+#if(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       /// Dual-quaternion of default double-precision floating-point numbers.
+       ///
+       /// @see gtx_dual_quaternion
+       typedef highp_ddualquat                 ddualquat;
+#elif(defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef highp_ddualquat                 ddualquat;
+#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && defined(GLM_PRECISION_MEDIUMP_DOUBLE) && !defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef mediump_ddualquat               ddualquat;
+#elif(!defined(GLM_PRECISION_HIGHP_DOUBLE) && !defined(GLM_PRECISION_MEDIUMP_DOUBLE) && defined(GLM_PRECISION_LOWP_DOUBLE))
+       typedef lowp_ddualquat                  ddualquat;
+#else
+#      error "GLM error: Multiple default precision requested for double-precision floating-point types"
+#endif
+
+       /// @}
+} //namespace glm
+
+#include "dual_quaternion.inl"
diff --git a/core/deps/glm/glm/gtx/dual_quaternion.inl b/core/deps/glm/glm/gtx/dual_quaternion.inl
new file mode 100755 (executable)
index 0000000..c3f2bc6
--- /dev/null
@@ -0,0 +1,351 @@
+/// @ref gtx_dual_quaternion
+/// @file glm/gtx/dual_quaternion.inl
+
+#include "../geometric.hpp"
+#include <limits>
+
+namespace glm
+{
+       // -- Component accesses --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tdualquat<T, P>::part_type & tdualquat<T, P>::operator[](typename tdualquat<T, P>::length_type i)
+       {
+               assert(i >= 0 && i < this->length());
+               return (&real)[i];
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER typename tdualquat<T, P>::part_type const & tdualquat<T, P>::operator[](typename tdualquat<T, P>::length_type i) const
+       {
+               assert(i >= 0 && i < this->length());
+               return (&real)[i];
+       }
+
+       // -- Implicit basic constructors --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat()
+#                      ifndef GLM_FORCE_NO_CTOR_INIT 
+                               : real(tquat<T, P>())
+                               , dual(tquat<T, P>(0, 0, 0, 0))
+#                      endif
+               {}
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tdualquat<T, P> const & d)
+                       : real(d.real)
+                       , dual(d.dual)
+               {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tdualquat<T, Q> const & d)
+               : real(d.real)
+               , dual(d.dual)
+       {}
+
+       // -- Explicit basic constructors --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR_CTOR tdualquat<T, P>::tdualquat(ctor)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tquat<T, P> const & r)
+               : real(r), dual(tquat<T, P>(0, 0, 0, 0))
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tquat<T, P> const & q, tvec3<T, P> const& p)
+               : real(q), dual(
+                       T(-0.5) * ( p.x*q.x + p.y*q.y + p.z*q.z),
+                       T(+0.5) * ( p.x*q.w + p.y*q.z - p.z*q.y),
+                       T(+0.5) * (-p.x*q.z + p.y*q.w + p.z*q.x),
+                       T(+0.5) * ( p.x*q.y - p.y*q.x + p.z*q.w))
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tquat<T, P> const & r, tquat<T, P> const & d)
+               : real(r), dual(d)
+       {}
+
+       // -- Conversion constructors --
+
+       template <typename T, precision P>
+       template <typename U, precision Q>
+       GLM_FUNC_QUALIFIER GLM_CONSTEXPR tdualquat<T, P>::tdualquat(tdualquat<U, Q> const & q)
+               : real(q.real)
+               , dual(q.dual)
+       {}
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P>::tdualquat(tmat2x4<T, P> const & m)
+       {
+               *this = dualquat_cast(m);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P>::tdualquat(tmat3x4<T, P> const & m)
+       {
+               *this = dualquat_cast(m);
+       }
+
+       // -- Unary arithmetic operators --
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+               template <typename T, precision P>
+               GLM_FUNC_QUALIFIER tdualquat<T, P> & tdualquat<T, P>::operator=(tdualquat<T, P> const & q)
+               {
+                       this->real = q.real;
+                       this->dual = q.dual;
+                       return *this;
+               }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> & tdualquat<T, P>::operator=(tdualquat<U, P> const & q)
+       {
+               this->real = q.real;
+               this->dual = q.dual;
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> & tdualquat<T, P>::operator*=(U s)
+       {
+               this->real *= static_cast<T>(s);
+               this->dual *= static_cast<T>(s);
+               return *this;
+       }
+
+       template <typename T, precision P>
+       template <typename U>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> & tdualquat<T, P>::operator/=(U s)
+       {
+               this->real /= static_cast<T>(s);
+               this->dual /= static_cast<T>(s);
+               return *this;
+       }
+
+       // -- Unary bit operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator+(tdualquat<T, P> const & q)
+       {
+               return q;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator-(tdualquat<T, P> const & q)
+       {
+               return tdualquat<T, P>(-q.real, -q.dual);
+       }
+
+       // -- Binary operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator+(tdualquat<T, P> const & q, tdualquat<T, P> const & p)
+       {
+               return tdualquat<T, P>(q.real + p.real,q.dual + p.dual);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator*(tdualquat<T, P> const & p, tdualquat<T, P> const & o)
+       {
+               return tdualquat<T, P>(p.real * o.real,p.real * o.dual + p.dual * o.real);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tdualquat<T, P> const & q, tvec3<T, P> const & v)
+       {
+               tvec3<T, P> const real_v3(q.real.x,q.real.y,q.real.z);
+               tvec3<T, P> const dual_v3(q.dual.x,q.dual.y,q.dual.z);
+               return (cross(real_v3, cross(real_v3,v) + v * q.real.w + dual_v3) + dual_v3 * q.real.w - real_v3 * q.dual.w) * T(2) + v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> operator*(tvec3<T, P> const & v, tdualquat<T, P> const & q)
+       {
+               return glm::inverse(q) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tdualquat<T, P> const & q, tvec4<T, P> const & v)
+       {
+               return tvec4<T, P>(q * tvec3<T, P>(v), v.w);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> operator*(tvec4<T, P> const & v, tdualquat<T, P> const & q)
+       {
+               return glm::inverse(q) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator*(tdualquat<T, P> const & q, T const & s)
+       {
+               return tdualquat<T, P>(q.real * s, q.dual * s);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator*(T const & s, tdualquat<T, P> const & q)
+       {
+               return q * s;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> operator/(tdualquat<T, P> const & q, T const & s)
+       {
+               return tdualquat<T, P>(q.real / s, q.dual / s);
+       }
+
+       // -- Boolean operators --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator==(tdualquat<T, P> const & q1, tdualquat<T, P> const & q2)
+       {
+               return (q1.real == q2.real) && (q1.dual == q2.dual);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool operator!=(tdualquat<T, P> const & q1, tdualquat<T, P> const & q2)
+       {
+               return (q1.real != q2.dual) || (q1.real != q2.dual);
+       }
+
+       // -- Operations --
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> normalize(tdualquat<T, P> const & q)
+       {
+               return q / length(q.real);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> lerp(tdualquat<T, P> const & x, tdualquat<T, P> const & y, T const & a)
+       {
+               // Dual Quaternion Linear blend aka DLB:
+               // Lerp is only defined in [0, 1]
+               assert(a >= static_cast<T>(0));
+               assert(a <= static_cast<T>(1));
+               T const k = dot(x.real,y.real) < static_cast<T>(0) ? -a : a;
+               T const one(1);
+               return tdualquat<T, P>(x * (one - a) + y * k);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> inverse(tdualquat<T, P> const & q)
+       {
+               const glm::tquat<T, P> real = conjugate(q.real);
+               const glm::tquat<T, P> dual = conjugate(q.dual);
+               return tdualquat<T, P>(real, dual + (real * (-2.0f * dot(real,dual))));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> mat2x4_cast(tdualquat<T, P> const & x)
+       {
+               return tmat2x4<T, P>( x[0].x, x[0].y, x[0].z, x[0].w, x[1].x, x[1].y, x[1].z, x[1].w );
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> mat3x4_cast(tdualquat<T, P> const & x)
+       {
+               tquat<T, P> r = x.real / length2(x.real);
+               
+               tquat<T, P> const rr(r.w * x.real.w, r.x * x.real.x, r.y * x.real.y, r.z * x.real.z);
+               r *= static_cast<T>(2);
+               
+               T const xy = r.x * x.real.y;
+               T const xz = r.x * x.real.z;
+               T const yz = r.y * x.real.z;
+               T const wx = r.w * x.real.x;
+               T const wy = r.w * x.real.y;
+               T const wz = r.w * x.real.z;
+               
+               tvec4<T, P> const a(
+                       rr.w + rr.x - rr.y - rr.z,
+                       xy - wz,
+                       xz + wy,
+                       -(x.dual.w * r.x - x.dual.x * r.w + x.dual.y * r.z - x.dual.z * r.y));
+               
+               tvec4<T, P> const b(
+                       xy + wz,
+                       rr.w + rr.y - rr.x - rr.z,
+                       yz - wx,
+                       -(x.dual.w * r.y - x.dual.x * r.z - x.dual.y * r.w + x.dual.z * r.x));
+               
+               tvec4<T, P> const c(
+                       xz - wy,
+                       yz + wx,
+                       rr.w + rr.z - rr.x - rr.y,
+                       -(x.dual.w * r.z + x.dual.x * r.y - x.dual.y * r.x - x.dual.z * r.w));
+               
+               return tmat3x4<T, P>(a, b, c);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> dualquat_cast(tmat2x4<T, P> const & x)
+       {
+               return tdualquat<T, P>(
+                       tquat<T, P>( x[0].w, x[0].x, x[0].y, x[0].z ),
+                       tquat<T, P>( x[1].w, x[1].x, x[1].y, x[1].z ));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tdualquat<T, P> dualquat_cast(tmat3x4<T, P> const & x)
+       {
+               tquat<T, P> real(uninitialize);
+               
+               T const trace = x[0].x + x[1].y + x[2].z;
+               if(trace > static_cast<T>(0))
+               {
+                       T const r = sqrt(T(1) + trace);
+                       T const invr = static_cast<T>(0.5) / r;
+                       real.w = static_cast<T>(0.5) * r;
+                       real.x = (x[2].y - x[1].z) * invr;
+                       real.y = (x[0].z - x[2].x) * invr;
+                       real.z = (x[1].x - x[0].y) * invr;
+               }
+               else if(x[0].x > x[1].y && x[0].x > x[2].z)
+               {
+                       T const r = sqrt(T(1) + x[0].x - x[1].y - x[2].z);
+                       T const invr = static_cast<T>(0.5) / r;
+                       real.x = static_cast<T>(0.5)*r;
+                       real.y = (x[1].x + x[0].y) * invr;
+                       real.z = (x[0].z + x[2].x) * invr;
+                       real.w = (x[2].y - x[1].z) * invr;
+               }
+               else if(x[1].y > x[2].z)
+               {
+                       T const r = sqrt(T(1) + x[1].y - x[0].x - x[2].z);
+                       T const invr = static_cast<T>(0.5) / r;
+                       real.x = (x[1].x + x[0].y) * invr;
+                       real.y = static_cast<T>(0.5) * r;
+                       real.z = (x[2].y + x[1].z) * invr;
+                       real.w = (x[0].z - x[2].x) * invr;
+               }
+               else
+               {
+                       T const r = sqrt(T(1) + x[2].z - x[0].x - x[1].y);
+                       T const invr = static_cast<T>(0.5) / r;
+                       real.x = (x[0].z + x[2].x) * invr;
+                       real.y = (x[2].y + x[1].z) * invr;
+                       real.z = static_cast<T>(0.5) * r;
+                       real.w = (x[1].x - x[0].y) * invr;
+               }
+               
+               tquat<T, P> dual(uninitialize);
+               dual.x =  static_cast<T>(0.5) * ( x[0].w * real.w + x[1].w * real.z - x[2].w * real.y);
+               dual.y =  static_cast<T>(0.5) * (-x[0].w * real.z + x[1].w * real.w + x[2].w * real.x);
+               dual.z =  static_cast<T>(0.5) * ( x[0].w * real.y - x[1].w * real.x + x[2].w * real.w);
+               dual.w = -static_cast<T>(0.5) * ( x[0].w * real.x + x[1].w * real.y + x[2].w * real.z);
+               return tdualquat<T, P>(real, dual);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/euler_angles.hpp b/core/deps/glm/glm/gtx/euler_angles.hpp
new file mode 100755 (executable)
index 0000000..fdc4f26
--- /dev/null
@@ -0,0 +1,143 @@
+/// @ref gtx_euler_angles
+/// @file glm/gtx/euler_angles.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+///
+/// @defgroup gtx_euler_angles GLM_GTX_euler_angles
+/// @ingroup gtx
+///
+/// @brief Build matrices from Euler angles.
+///
+/// <glm/gtx/euler_angles.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_euler_angles extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_euler_angles
+       /// @{
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle X.
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleX(
+               T const & angleX);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Y.
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleY(
+               T const & angleY);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from an euler angle Z.
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleZ(
+               T const & angleZ);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleXY(
+               T const & angleX,
+               T const & angleY);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleYX(
+               T const & angleY,
+               T const & angleX);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Z).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleXZ(
+               T const & angleX,
+               T const & angleZ);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * X).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleZX(
+               T const & angle,
+               T const & angleX);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * Z).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleYZ(
+               T const & angleY,
+               T const & angleZ);
+
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Z * Y).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleZY(
+               T const & angleZ,
+               T const & angleY);
+
+    /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (X * Y * Z).
+    /// @see gtx_euler_angles
+    template <typename T>
+    GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleXYZ(
+        T const & t1,
+        T const & t2,
+        T const & t3);
+    
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> eulerAngleYXZ(
+               T const & yaw,
+               T const & pitch,
+               T const & roll);
+    
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat4x4<T, defaultp> yawPitchRoll(
+               T const & yaw,
+               T const & pitch,
+               T const & roll);
+
+       /// Creates a 2D 2 * 2 rotation matrix from an euler angle.
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat2x2<T, defaultp> orientate2(T const & angle);
+
+       /// Creates a 2D 4 * 4 homogeneous rotation matrix from an euler angle.
+       /// @see gtx_euler_angles
+       template <typename T>
+       GLM_FUNC_DECL tmat3x3<T, defaultp> orientate3(T const & angle);
+
+       /// Creates a 3D 3 * 3 rotation matrix from euler angles (Y * X * Z). 
+       /// @see gtx_euler_angles
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> orientate3(tvec3<T, P> const & angles);
+               
+       /// Creates a 3D 4 * 4 homogeneous rotation matrix from euler angles (Y * X * Z).
+       /// @see gtx_euler_angles
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> orientate4(tvec3<T, P> const & angles);
+
+    /// Extracts the (X * Y * Z) Euler angles from the rotation matrix M
+    /// @see gtx_euler_angles
+    template <typename T>
+    GLM_FUNC_DECL void extractEulerAngleXYZ(tmat4x4<T, defaultp> const & M,
+                                            T & t1,
+                                            T & t2,
+                                            T & t3);
+    
+       /// @}
+}//namespace glm
+
+#include "euler_angles.inl"
diff --git a/core/deps/glm/glm/gtx/euler_angles.inl b/core/deps/glm/glm/gtx/euler_angles.inl
new file mode 100755 (executable)
index 0000000..dbe0a48
--- /dev/null
@@ -0,0 +1,312 @@
+/// @ref gtx_euler_angles
+/// @file glm/gtx/euler_angles.inl
+
+#include "compatibility.hpp" // glm::atan2
+
+namespace glm
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleX
+       (
+               T const & angleX
+       )
+       {
+               T cosX = glm::cos(angleX);
+               T sinX = glm::sin(angleX);
+       
+               return tmat4x4<T, defaultp>(
+                       T(1), T(0), T(0), T(0),
+                       T(0), cosX, sinX, T(0),
+                       T(0),-sinX, cosX, T(0),
+                       T(0), T(0), T(0), T(1));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleY
+       (
+               T const & angleY
+       )
+       {
+               T cosY = glm::cos(angleY);
+               T sinY = glm::sin(angleY);
+
+               return tmat4x4<T, defaultp>(
+                       cosY,   T(0),   -sinY,  T(0),
+                       T(0),   T(1),   T(0),   T(0),
+                       sinY,   T(0),   cosY,   T(0),
+                       T(0),   T(0),   T(0),   T(1));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleZ
+       (
+               T const & angleZ
+       )
+       {
+               T cosZ = glm::cos(angleZ);
+               T sinZ = glm::sin(angleZ);
+
+               return tmat4x4<T, defaultp>(
+                       cosZ,   sinZ,   T(0), T(0),
+                       -sinZ,  cosZ,   T(0), T(0),
+                       T(0),   T(0),   T(1), T(0),
+                       T(0),   T(0),   T(0), T(1));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleXY
+       (
+               T const & angleX,
+               T const & angleY
+       )
+       {
+               T cosX = glm::cos(angleX);
+               T sinX = glm::sin(angleX);
+               T cosY = glm::cos(angleY);
+               T sinY = glm::sin(angleY);
+
+               return tmat4x4<T, defaultp>(
+                       cosY,   -sinX * -sinY,  cosX * -sinY,   T(0),
+                       T(0),   cosX,           sinX,           T(0),
+                       sinY,   -sinX * cosY,   cosX * cosY,    T(0),
+                       T(0),   T(0),           T(0),           T(1));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleYX
+       (
+               T const & angleY,
+               T const & angleX
+       )
+       {
+               T cosX = glm::cos(angleX);
+               T sinX = glm::sin(angleX);
+               T cosY = glm::cos(angleY);
+               T sinY = glm::sin(angleY);
+
+               return tmat4x4<T, defaultp>(
+                       cosY,          0,      -sinY,    T(0),
+                       sinY * sinX,  cosX, cosY * sinX, T(0),
+                       sinY * cosX, -sinX, cosY * cosX, T(0),
+                       T(0),         T(0),     T(0),    T(1));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleXZ
+       (
+               T const & angleX,
+               T const & angleZ
+       )
+       {
+               return eulerAngleX(angleX) * eulerAngleZ(angleZ);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleZX
+       (
+               T const & angleZ,
+               T const & angleX
+       )
+       {
+               return eulerAngleZ(angleZ) * eulerAngleX(angleX);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleYZ
+       (
+               T const & angleY,
+               T const & angleZ
+       )
+       {
+               return eulerAngleY(angleY) * eulerAngleZ(angleZ);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleZY
+       (
+               T const & angleZ,
+               T const & angleY
+       )
+       {
+               return eulerAngleZ(angleZ) * eulerAngleY(angleY);
+       }
+    
+    template <typename T>
+    GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleXYZ
+    (
+     T const & t1,
+     T const & t2,
+     T const & t3
+     )
+    {
+        T c1 = glm::cos(-t1);
+        T c2 = glm::cos(-t2);
+        T c3 = glm::cos(-t3);
+        T s1 = glm::sin(-t1);
+        T s2 = glm::sin(-t2);
+        T s3 = glm::sin(-t3);
+        
+        tmat4x4<T, defaultp> Result;
+        Result[0][0] = c2 * c3;
+        Result[0][1] =-c1 * s3 + s1 * s2 * c3;
+        Result[0][2] = s1 * s3 + c1 * s2 * c3;
+        Result[0][3] = static_cast<T>(0);
+        Result[1][0] = c2 * s3;
+        Result[1][1] = c1 * c3 + s1 * s2 * s3;
+        Result[1][2] =-s1 * c3 + c1 * s2 * s3;
+        Result[1][3] = static_cast<T>(0);
+        Result[2][0] =-s2;
+        Result[2][1] = s1 * c2;
+        Result[2][2] = c1 * c2;
+        Result[2][3] = static_cast<T>(0);
+        Result[3][0] = static_cast<T>(0);
+        Result[3][1] = static_cast<T>(0);
+        Result[3][2] = static_cast<T>(0);
+        Result[3][3] = static_cast<T>(1);
+        return Result;
+    }
+    
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> eulerAngleYXZ
+       (
+               T const & yaw,
+               T const & pitch,
+               T const & roll
+       )
+       {
+               T tmp_ch = glm::cos(yaw);
+               T tmp_sh = glm::sin(yaw);
+               T tmp_cp = glm::cos(pitch);
+               T tmp_sp = glm::sin(pitch);
+               T tmp_cb = glm::cos(roll);
+               T tmp_sb = glm::sin(roll);
+
+               tmat4x4<T, defaultp> Result;
+               Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb;
+               Result[0][1] = tmp_sb * tmp_cp;
+               Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb;
+               Result[0][3] = static_cast<T>(0);
+               Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb;
+               Result[1][1] = tmp_cb * tmp_cp;
+               Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb;
+               Result[1][3] = static_cast<T>(0);
+               Result[2][0] = tmp_sh * tmp_cp;
+               Result[2][1] = -tmp_sp;
+               Result[2][2] = tmp_ch * tmp_cp;
+               Result[2][3] = static_cast<T>(0);
+               Result[3][0] = static_cast<T>(0);
+               Result[3][1] = static_cast<T>(0);
+               Result[3][2] = static_cast<T>(0);
+               Result[3][3] = static_cast<T>(1);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat4x4<T, defaultp> yawPitchRoll
+       (
+               T const & yaw,
+               T const & pitch,
+               T const & roll
+       )
+       {
+               T tmp_ch = glm::cos(yaw);
+               T tmp_sh = glm::sin(yaw);
+               T tmp_cp = glm::cos(pitch);
+               T tmp_sp = glm::sin(pitch);
+               T tmp_cb = glm::cos(roll);
+               T tmp_sb = glm::sin(roll);
+
+               tmat4x4<T, defaultp> Result;
+               Result[0][0] = tmp_ch * tmp_cb + tmp_sh * tmp_sp * tmp_sb;
+               Result[0][1] = tmp_sb * tmp_cp;
+               Result[0][2] = -tmp_sh * tmp_cb + tmp_ch * tmp_sp * tmp_sb;
+               Result[0][3] = static_cast<T>(0);
+               Result[1][0] = -tmp_ch * tmp_sb + tmp_sh * tmp_sp * tmp_cb;
+               Result[1][1] = tmp_cb * tmp_cp;
+               Result[1][2] = tmp_sb * tmp_sh + tmp_ch * tmp_sp * tmp_cb;
+               Result[1][3] = static_cast<T>(0);
+               Result[2][0] = tmp_sh * tmp_cp;
+               Result[2][1] = -tmp_sp;
+               Result[2][2] = tmp_ch * tmp_cp;
+               Result[2][3] = static_cast<T>(0);
+               Result[3][0] = static_cast<T>(0);
+               Result[3][1] = static_cast<T>(0);
+               Result[3][2] = static_cast<T>(0);
+               Result[3][3] = static_cast<T>(1);
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat2x2<T, defaultp> orientate2
+       (
+               T const & angle
+       )
+       {
+               T c = glm::cos(angle);
+               T s = glm::sin(angle);
+
+               tmat2x2<T, defaultp> Result;
+               Result[0][0] = c;
+               Result[0][1] = s;
+               Result[1][0] = -s;
+               Result[1][1] = c;
+               return Result;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER tmat3x3<T, defaultp> orientate3
+       (
+               T const & angle
+       )
+       {
+               T c = glm::cos(angle);
+               T s = glm::sin(angle);
+
+               tmat3x3<T, defaultp> Result;
+               Result[0][0] = c;
+               Result[0][1] = s;
+               Result[0][2] = 0.0f;
+               Result[1][0] = -s;
+               Result[1][1] = c;
+               Result[1][2] = 0.0f;
+               Result[2][0] = 0.0f;
+               Result[2][1] = 0.0f;
+               Result[2][2] = 1.0f;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> orientate3
+       (
+               tvec3<T, P> const & angles
+       )
+       {
+               return tmat3x3<T, P>(yawPitchRoll(angles.z, angles.x, angles.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> orientate4
+       (
+               tvec3<T, P> const & angles
+       )
+       {
+               return yawPitchRoll(angles.z, angles.x, angles.y);
+       }
+    
+    template <typename T>
+    GLM_FUNC_DECL void extractEulerAngleXYZ(tmat4x4<T, defaultp> const & M,
+                                            T & t1,
+                                            T & t2,
+                                            T & t3)
+    {
+        float T1 = glm::atan2<T, defaultp>(M[2][1], M[2][2]);
+        float C2 = glm::sqrt(M[0][0]*M[0][0] + M[1][0]*M[1][0]);
+        float T2 = glm::atan2<T, defaultp>(-M[2][0], C2);
+        float S1 = glm::sin(T1);
+        float C1 = glm::cos(T1);
+        float T3 = glm::atan2<T, defaultp>(S1*M[0][2] - C1*M[0][1], C1*M[1][1] - S1*M[1][2  ]);
+        t1 = -T1;
+        t2 = -T2;
+        t3 = -T3;
+    }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/extend.hpp b/core/deps/glm/glm/gtx/extend.hpp
new file mode 100755 (executable)
index 0000000..26837a8
--- /dev/null
@@ -0,0 +1,38 @@
+/// @ref gtx_extend
+/// @file glm/gtx/extend.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_extend GLM_GTX_extend
+/// @ingroup gtx
+///
+/// @brief Extend a position from a source to a position at a defined length.
+///
+/// <glm/gtx/extend.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_extend extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_extend
+       /// @{
+
+       /// Extends of Length the Origin position using the (Source - Origin) direction.
+       /// @see gtx_extend
+       template <typename genType> 
+       GLM_FUNC_DECL genType extend(
+               genType const & Origin, 
+               genType const & Source, 
+               typename genType::value_type const Length);
+
+       /// @}
+}//namespace glm
+
+#include "extend.inl"
diff --git a/core/deps/glm/glm/gtx/extend.inl b/core/deps/glm/glm/gtx/extend.inl
new file mode 100755 (executable)
index 0000000..3155583
--- /dev/null
@@ -0,0 +1,49 @@
+/// @ref gtx_extend
+/// @file glm/gtx/extend.inl
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType extend
+       (
+               genType const & Origin, 
+               genType const & Source, 
+               genType const & Distance
+       )
+       {
+               return Origin + (Source - Origin) * Distance;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> extend
+       (
+               tvec2<T, P> const & Origin,
+               tvec2<T, P> const & Source,
+               T const & Distance
+       )
+       {
+               return Origin + (Source - Origin) * Distance;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> extend
+       (
+               tvec3<T, P> const & Origin,
+               tvec3<T, P> const & Source,
+               T const & Distance
+       )
+       {
+               return Origin + (Source - Origin) * Distance;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> extend
+       (
+               tvec4<T, P> const & Origin,
+               tvec4<T, P> const & Source,
+               T const & Distance
+       )
+       {
+               return Origin + (Source - Origin) * Distance;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/extended_min_max.hpp b/core/deps/glm/glm/gtx/extended_min_max.hpp
new file mode 100755 (executable)
index 0000000..f4d8859
--- /dev/null
@@ -0,0 +1,133 @@
+/// @ref gtx_extended_min_max
+/// @file glm/gtx/extended_min_max.hpp
+///
+/// @see core (dependence)
+/// @see gtx_half_float (dependence)
+///
+/// @defgroup gtx_extented_min_max GLM_GTX_extented_min_max
+/// @ingroup gtx
+///
+/// Min and max functions for 3 to 4 parameters.
+///
+/// <glm/gtx/extented_min_max.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_extented_min_max extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_extented_min_max
+       /// @{
+
+       /// Return the minimum component-wise values of 3 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T>
+       GLM_FUNC_DECL T min(
+               T const & x, 
+               T const & y, 
+               T const & z);
+
+       /// Return the minimum component-wise values of 3 inputs
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> min(
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z);
+
+       /// Return the minimum component-wise values of 3 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> min(
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z);
+
+       /// Return the minimum component-wise values of 4 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T>
+       GLM_FUNC_DECL T min(
+               T const & x, 
+               T const & y, 
+               T const & z, 
+               T const & w);
+
+       /// Return the minimum component-wise values of 4 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> min(
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z, 
+               typename C<T>::T const & w);
+
+       /// Return the minimum component-wise values of 4 inputs
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> min(
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z,
+               C<T> const & w);
+
+       /// Return the maximum component-wise values of 3 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T>
+       GLM_FUNC_DECL T max(
+               T const & x, 
+               T const & y, 
+               T const & z);
+
+       /// Return the maximum component-wise values of 3 inputs
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> max(
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z);
+
+       /// Return the maximum component-wise values of 3 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> max(
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z);
+
+       /// Return the maximum component-wise values of 4 inputs
+       /// @see gtx_extented_min_max
+       template <typename T>
+       GLM_FUNC_DECL T max(
+               T const & x, 
+               T const & y, 
+               T const & z, 
+               T const & w);
+
+       /// Return the maximum component-wise values of 4 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> max(
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z, 
+               typename C<T>::T const & w);
+
+       /// Return the maximum component-wise values of 4 inputs 
+       /// @see gtx_extented_min_max
+       template <typename T, template <typename> class C>
+       GLM_FUNC_DECL C<T> max(
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z, 
+               C<T> const & w);
+
+       /// @}
+}//namespace glm
+
+#include "extended_min_max.inl"
diff --git a/core/deps/glm/glm/gtx/extended_min_max.inl b/core/deps/glm/glm/gtx/extended_min_max.inl
new file mode 100755 (executable)
index 0000000..64ea445
--- /dev/null
@@ -0,0 +1,140 @@
+/// @ref gtx_extended_min_max
+/// @file glm/gtx/extended_min_max.inl
+
+namespace glm
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER T min(
+               T const & x, 
+               T const & y, 
+               T const & z)
+       {
+               return glm::min(glm::min(x, y), z);
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> min
+       (
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z
+       )
+       {
+               return glm::min(glm::min(x, y), z);
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> min
+       (
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z
+       )
+       {
+               return glm::min(glm::min(x, y), z);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T min
+       (
+               T const & x, 
+               T const & y, 
+               T const & z, 
+               T const & w
+       )
+       {
+               return glm::min(glm::min(x, y), glm::min(z, w));
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> min
+       (
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z, 
+               typename C<T>::T const & w
+       )
+       {
+               return glm::min(glm::min(x, y), glm::min(z, w));
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> min
+       (
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z, 
+               C<T> const & w
+       )
+       {
+               return glm::min(glm::min(x, y), glm::min(z, w));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T max(
+               T const & x, 
+               T const & y, 
+               T const & z)
+       {
+               return glm::max(glm::max(x, y), z);
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> max
+       (
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z
+       )
+       {
+               return glm::max(glm::max(x, y), z);
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> max
+       (
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z
+       )
+       {
+               return glm::max(glm::max(x, y), z);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T max
+       (
+               T const & x, 
+               T const & y, 
+               T const & z, 
+               T const & w
+       )
+       {
+               return glm::max(glm::max(x, y), glm::max(z, w));
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> max
+       (
+               C<T> const & x, 
+               typename C<T>::T const & y, 
+               typename C<T>::T const & z, 
+               typename C<T>::T const & w
+       )
+       {
+               return glm::max(glm::max(x, y), glm::max(z, w));
+       }
+
+       template <typename T, template <typename> class C>
+       GLM_FUNC_QUALIFIER C<T> max
+       (
+               C<T> const & x, 
+               C<T> const & y, 
+               C<T> const & z, 
+               C<T> const & w
+       )
+       {
+               return glm::max(glm::max(x, y), glm::max(z, w));
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/fast_exponential.hpp b/core/deps/glm/glm/gtx/fast_exponential.hpp
new file mode 100755 (executable)
index 0000000..ed64a27
--- /dev/null
@@ -0,0 +1,91 @@
+/// @ref gtx_fast_exponential
+/// @file glm/gtx/fast_exponential.hpp
+///
+/// @see core (dependence)
+/// @see gtx_half_float (dependence)
+///
+/// @defgroup gtx_fast_exponential GLM_GTX_fast_exponential
+/// @ingroup gtx
+///
+/// @brief Fast but less accurate implementations of exponential based functions.
+///
+/// <glm/gtx/fast_exponential.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_fast_exponential extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_fast_exponential
+       /// @{
+
+       /// Faster than the common pow function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename genType>
+       GLM_FUNC_DECL genType fastPow(genType x, genType y);
+
+       /// Faster than the common pow function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastPow(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Faster than the common pow function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename genTypeT, typename genTypeU>
+       GLM_FUNC_DECL genTypeT fastPow(genTypeT x, genTypeU y);
+
+       /// Faster than the common pow function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastPow(vecType<T, P> const & x);
+
+       /// Faster than the common exp function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T>
+       GLM_FUNC_DECL T fastExp(T x);
+
+       /// Faster than the common exp function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastExp(vecType<T, P> const & x);
+
+       /// Faster than the common log function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T>
+       GLM_FUNC_DECL T fastLog(T x);
+
+       /// Faster than the common exp2 function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastLog(vecType<T, P> const & x);
+
+       /// Faster than the common exp2 function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T>
+       GLM_FUNC_DECL T fastExp2(T x);
+
+       /// Faster than the common exp2 function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastExp2(vecType<T, P> const & x);
+
+       /// Faster than the common log2 function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T>
+       GLM_FUNC_DECL T fastLog2(T x);
+
+       /// Faster than the common log2 function but less accurate.
+       /// @see gtx_fast_exponential
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastLog2(vecType<T, P> const & x);
+
+       /// @}
+}//namespace glm
+
+#include "fast_exponential.inl"
diff --git a/core/deps/glm/glm/gtx/fast_exponential.inl b/core/deps/glm/glm/gtx/fast_exponential.inl
new file mode 100755 (executable)
index 0000000..72f9f8f
--- /dev/null
@@ -0,0 +1,137 @@
+/// @ref gtx_fast_exponential
+/// @file glm/gtx/fast_exponential.inl
+
+namespace glm
+{
+       // fastPow:
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastPow(genType x, genType y)
+       {
+               return exp(y * log(x));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastPow(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return exp(y * log(x));
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T fastPow(T x, int y)
+       {
+               T f = static_cast<T>(1);
+               for(int i = 0; i < y; ++i)
+                       f *= x;
+               return f;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastPow(vecType<T, P> const & x, vecType<int, P> const & y)
+       {
+               vecType<T, P> Result(uninitialize);
+               for(length_t i = 0, n = x.length(); i < n; ++i)
+                       Result[i] = fastPow(x[i], y[i]);
+               return Result;
+       }
+
+       // fastExp
+       // Note: This function provides accurate results only for value between -1 and 1, else avoid it.
+       template <typename T>
+       GLM_FUNC_QUALIFIER T fastExp(T x)
+       {
+               // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower.
+               // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f))));
+               T x2 = x * x;
+               T x3 = x2 * x;
+               T x4 = x3 * x;
+               T x5 = x4 * x;
+               return T(1) + x + (x2 * T(0.5)) + (x3 * T(0.1666666667)) + (x4 * T(0.041666667)) + (x5 * T(0.008333333333));
+       }
+       /*  // Try to handle all values of float... but often shower than std::exp, glm::floor and the loop kill the performance
+       GLM_FUNC_QUALIFIER float fastExp(float x)
+       {
+               const float e = 2.718281828f;
+               const float IntegerPart = floor(x);
+               const float FloatPart = x - IntegerPart;
+               float z = 1.f;
+
+               for(int i = 0; i < int(IntegerPart); ++i)
+                       z *= e;
+
+               const float x2 = FloatPart * FloatPart;
+               const float x3 = x2 * FloatPart;
+               const float x4 = x3 * FloatPart;
+               const float x5 = x4 * FloatPart;
+               return z * (1.0f + FloatPart + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f));
+       }
+
+       // Increase accuracy on number bigger that 1 and smaller than -1 but it's not enough for high and negative numbers
+       GLM_FUNC_QUALIFIER float fastExp(float x)
+       {
+               // This has a better looking and same performance in release mode than the following code. However, in debug mode it's slower.
+               // return 1.0f + x * (1.0f + x * 0.5f * (1.0f + x * 0.3333333333f * (1.0f + x * 0.25 * (1.0f + x * 0.2f))));
+               float x2 = x * x;
+               float x3 = x2 * x;
+               float x4 = x3 * x;
+               float x5 = x4 * x;
+               float x6 = x5 * x;
+               float x7 = x6 * x;
+               float x8 = x7 * x;
+               return 1.0f + x + (x2 * 0.5f) + (x3 * 0.1666666667f) + (x4 * 0.041666667f) + (x5 * 0.008333333333f)+ (x6 * 0.00138888888888f) + (x7 * 0.000198412698f) + (x8 * 0.0000248015873f);;
+       }
+       */
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastExp(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastExp, x);
+       }
+
+       // fastLog
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastLog(genType x)
+       {
+               return std::log(x);
+       }
+
+       /* Slower than the VC7.1 function...
+       GLM_FUNC_QUALIFIER float fastLog(float x)
+       {
+               float y1 = (x - 1.0f) / (x + 1.0f);
+               float y2 = y1 * y1;
+               return 2.0f * y1 * (1.0f + y2 * (0.3333333333f + y2 * (0.2f + y2 * 0.1428571429f)));
+       }
+       */
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastLog(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastLog, x);
+       }
+
+       //fastExp2, ln2 = 0.69314718055994530941723212145818f
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastExp2(genType x)
+       {
+               return fastExp(0.69314718055994530941723212145818f * x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastExp2(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastExp2, x);
+       }
+
+       // fastLog2, ln2 = 0.69314718055994530941723212145818f
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastLog2(genType x)
+       {
+               return fastLog(x) / 0.69314718055994530941723212145818f;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastLog2(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastLog2, x);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/fast_square_root.hpp b/core/deps/glm/glm/gtx/fast_square_root.hpp
new file mode 100755 (executable)
index 0000000..35aa7f3
--- /dev/null
@@ -0,0 +1,88 @@
+/// @ref gtx_fast_square_root
+/// @file glm/gtx/fast_square_root.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_fast_square_root GLM_GTX_fast_square_root
+/// @ingroup gtx
+///
+/// @brief Fast but less accurate implementations of square root based functions.
+/// - Sqrt optimisation based on Newton's method, 
+/// www.gamedev.net/community/forums/topic.asp?topic id=139956
+///
+/// <glm/gtx/fast_square_root.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../common.hpp"
+#include "../exponential.hpp"
+#include "../geometric.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_fast_square_root extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_fast_square_root
+       /// @{
+
+       /// Faster than the common sqrt function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType fastSqrt(genType x);
+
+       /// Faster than the common sqrt function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastSqrt(vecType<T, P> const & x);
+
+       /// Faster than the common inversesqrt function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType fastInverseSqrt(genType x);
+
+       /// Faster than the common inversesqrt function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> fastInverseSqrt(vecType<T, P> const & x);
+
+       /// Faster than the common length function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType fastLength(genType x);
+
+       /// Faster than the common length function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T fastLength(vecType<T, P> const & x);
+
+       /// Faster than the common distance function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType fastDistance(genType x, genType y);
+
+       /// Faster than the common distance function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T fastDistance(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Faster than the common normalize function but less accurate.
+       ///
+       /// @see gtx_fast_square_root extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType fastNormalize(genType const & x);
+
+       /// @}
+}// namespace glm
+
+#include "fast_square_root.inl"
diff --git a/core/deps/glm/glm/gtx/fast_square_root.inl b/core/deps/glm/glm/gtx/fast_square_root.inl
new file mode 100755 (executable)
index 0000000..73950ae
--- /dev/null
@@ -0,0 +1,81 @@
+/// @ref gtx_fast_square_root
+/// @file glm/gtx/fast_square_root.inl
+
+namespace glm
+{
+       // fastSqrt
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastSqrt(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'fastSqrt' only accept floating-point input");
+
+               return genType(1) / fastInverseSqrt(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastSqrt(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastSqrt, x);
+       }
+
+       // fastInversesqrt
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastInverseSqrt(genType x)
+       {
+#              ifdef __CUDACC__ // Wordaround for a CUDA compiler bug up to CUDA6
+                       tvec1<T, P> tmp(detail::compute_inversesqrt<tvec1, genType, lowp, detail::is_aligned<lowp>::value>::call(tvec1<genType, lowp>(x)));
+                       return tmp.x;
+#              else
+                       return detail::compute_inversesqrt<tvec1, genType, highp, detail::is_aligned<highp>::value>::call(tvec1<genType, lowp>(x)).x;
+#              endif
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastInverseSqrt(vecType<T, P> const & x)
+       {
+               return detail::compute_inversesqrt<vecType, T, P, detail::is_aligned<P>::value>::call(x);
+       }
+
+       // fastLength
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastLength(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'fastLength' only accept floating-point inputs");
+
+               return abs(x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T fastLength(vecType<T, P> const & x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'fastLength' only accept floating-point inputs");
+
+               return fastSqrt(dot(x, x));
+       }
+
+       // fastDistance
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastDistance(genType x, genType y)
+       {
+               return fastLength(y - x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T fastDistance(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return fastLength(y - x);
+       }
+
+       // fastNormalize
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType fastNormalize(genType x)
+       {
+               return x > genType(0) ? genType(1) : -genType(1);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastNormalize(vecType<T, P> const & x)
+       {
+               return x * fastInverseSqrt(dot(x, x));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/fast_trigonometry.hpp b/core/deps/glm/glm/gtx/fast_trigonometry.hpp
new file mode 100755 (executable)
index 0000000..ccb1d22
--- /dev/null
@@ -0,0 +1,75 @@
+/// @ref gtx_fast_trigonometry
+/// @file glm/gtx/fast_trigonometry.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_fast_trigonometry GLM_GTX_fast_trigonometry
+/// @ingroup gtx
+///
+/// @brief Fast but less accurate implementations of trigonometric functions.
+///
+/// <glm/gtx/fast_trigonometry.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../gtc/constants.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_fast_trigonometry extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_fast_trigonometry
+       /// @{
+
+       /// Wrap an angle to [0 2pi[
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T wrapAngle(T angle);
+
+       /// Faster than the common sin function but less accurate.
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T>
+       GLM_FUNC_DECL T fastSin(T angle);
+
+       /// Faster than the common cos function but less accurate.
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastCos(T angle);
+
+       /// Faster than the common tan function but less accurate. 
+       /// Defined between -2pi and 2pi. 
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastTan(T angle);
+
+       /// Faster than the common asin function but less accurate. 
+       /// Defined between -2pi and 2pi.
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastAsin(T angle);
+
+       /// Faster than the common acos function but less accurate. 
+       /// Defined between -2pi and 2pi. 
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastAcos(T angle);
+
+       /// Faster than the common atan function but less accurate.
+       /// Defined between -2pi and 2pi. 
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastAtan(T y, T x);
+
+       /// Faster than the common atan function but less accurate. 
+       /// Defined between -2pi and 2pi.
+       /// From GLM_GTX_fast_trigonometry extension.
+       template <typename T> 
+       GLM_FUNC_DECL T fastAtan(T angle);
+
+       /// @}
+}//namespace glm
+
+#include "fast_trigonometry.inl"
diff --git a/core/deps/glm/glm/gtx/fast_trigonometry.inl b/core/deps/glm/glm/gtx/fast_trigonometry.inl
new file mode 100755 (executable)
index 0000000..f576c17
--- /dev/null
@@ -0,0 +1,143 @@
+/// @ref gtx_fast_trigonometry
+/// @file glm/gtx/fast_trigonometry.inl
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> taylorCos(vecType<T, P> const & x)
+       {
+               return static_cast<T>(1)
+                       - (x * x) / 2.f
+                       + (x * x * x * x) / 24.f
+                       - (x * x * x * x * x * x) / 720.f
+                       + (x * x * x * x * x * x * x * x) / 40320.f;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T cos_52s(T x)
+       {
+               T const xx(x * x);
+               return (T(0.9999932946) + xx * (T(-0.4999124376) + xx * (T(0.0414877472) + xx * T(-0.0012712095))));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> cos_52s(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(cos_52s, x);
+       }
+}//namespace detail
+
+       // wrapAngle
+       template <typename T>
+       GLM_FUNC_QUALIFIER T wrapAngle(T angle)
+       {
+               return abs<T>(mod<T>(angle, two_pi<T>()));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> wrapAngle(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(wrapAngle, x);
+       }
+
+       // cos
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastCos(T x)
+       {
+               T const angle(wrapAngle<T>(x));
+
+               if(angle < half_pi<T>())
+                       return detail::cos_52s(angle);
+               if(angle < pi<T>())
+                       return -detail::cos_52s(pi<T>() - angle);
+               if(angle < (T(3) * half_pi<T>()))
+                       return -detail::cos_52s(angle - pi<T>());
+
+               return detail::cos_52s(two_pi<T>() - angle);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastCos(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastCos, x);
+       }
+
+       // sin
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastSin(T x)
+       {
+               return fastCos<T>(half_pi<T>() - x);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastSin(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastSin, x);
+       }
+
+       // tan
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastTan(T x)
+       {
+               return x + (x * x * x * T(0.3333333333)) + (x * x * x * x * x * T(0.1333333333333)) + (x * x * x * x * x * x * x * T(0.0539682539));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastTan(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastTan, x);
+       }
+
+       // asin
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastAsin(T x)
+       {
+               return x + (x * x * x * T(0.166666667)) + (x * x * x * x * x * T(0.075)) + (x * x * x * x * x * x * x * T(0.0446428571)) + (x * x * x * x * x * x * x * x * x * T(0.0303819444));// + (x * x * x * x * x * x * x * x * x * x * x * T(0.022372159));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastAsin(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastAsin, x);
+       }
+
+       // acos
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastAcos(T x)
+       {
+               return T(1.5707963267948966192313216916398) - fastAsin(x); //(PI / 2)
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastAcos(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastAcos, x);
+       }
+
+       // atan
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastAtan(T y, T x)
+       {
+               T sgn = sign(y) * sign(x);
+               return abs(fastAtan(y / x)) * sgn;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastAtan(vecType<T, P> const & y, vecType<T, P> const & x)
+       {
+               return detail::functor2<T, P, vecType>::call(fastAtan, y, x);
+       }
+
+       template <typename T> 
+       GLM_FUNC_QUALIFIER T fastAtan(T x)
+       {
+               return x - (x * x * x * T(0.333333333333)) + (x * x * x * x * x * T(0.2)) - (x * x * x * x * x * x * x * T(0.1428571429)) + (x * x * x * x * x * x * x * x * x * T(0.111111111111)) - (x * x * x * x * x * x * x * x * x * x * x * T(0.0909090909));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> fastAtan(vecType<T, P> const & x)
+       {
+               return detail::functor1<T, T, P, vecType>::call(fastAtan, x);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/float_notmalize.inl b/core/deps/glm/glm/gtx/float_notmalize.inl
new file mode 100755 (executable)
index 0000000..4dde025
--- /dev/null
@@ -0,0 +1,14 @@
+/// @ref gtx_float_normalize
+/// @file glm/gtx/float_normalize.inl
+
+#include <limits>
+
+namespace glm
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<float, P> floatNormalize(vecType<T, P> const & v)
+       {
+               return vecType<float, P>(v) / static_cast<float>(std::numeric_limits<T>::max());
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/gradient_paint.hpp b/core/deps/glm/glm/gtx/gradient_paint.hpp
new file mode 100755 (executable)
index 0000000..de1f18d
--- /dev/null
@@ -0,0 +1,48 @@
+/// @ref gtx_gradient_paint
+/// @file glm/gtx/gradient_paint.hpp
+///
+/// @see core (dependence)
+/// @see gtx_optimum_pow (dependence)
+///
+/// @defgroup gtx_gradient_paint GLM_GTX_gradient_paint
+/// @ingroup gtx
+///
+/// @brief Functions that return the color of procedural gradient for specific coordinates.
+/// <glm/gtx/gradient_paint.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/optimum_pow.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_gradient_paint extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_gradient_paint
+       /// @{
+
+       /// Return a color from a radial gradient.
+       /// @see - gtx_gradient_paint
+       template <typename T, precision P>
+       GLM_FUNC_DECL T radialGradient(
+               tvec2<T, P> const & Center,
+               T const & Radius,
+               tvec2<T, P> const & Focal,
+               tvec2<T, P> const & Position);
+
+       /// Return a color from a linear gradient.
+       /// @see - gtx_gradient_paint
+       template <typename T, precision P>
+       GLM_FUNC_DECL T linearGradient(
+               tvec2<T, P> const & Point0,
+               tvec2<T, P> const & Point1,
+               tvec2<T, P> const & Position);
+
+       /// @}
+}// namespace glm
+
+#include "gradient_paint.inl"
diff --git a/core/deps/glm/glm/gtx/gradient_paint.inl b/core/deps/glm/glm/gtx/gradient_paint.inl
new file mode 100755 (executable)
index 0000000..aaa5ce1
--- /dev/null
@@ -0,0 +1,37 @@
+/// @ref gtx_gradient_paint
+/// @file glm/gtx/gradient_paint.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T radialGradient
+       (
+               tvec2<T, P> const & Center,
+               T const & Radius,
+               tvec2<T, P> const & Focal,
+               tvec2<T, P> const & Position
+       )
+       {
+               tvec2<T, P> F = Focal - Center;
+               tvec2<T, P> D = Position - Focal;
+               T Radius2 = pow2(Radius);
+               T Fx2 = pow2(F.x);
+               T Fy2 = pow2(F.y);
+
+               T Numerator = (D.x * F.x + D.y * F.y) + sqrt(Radius2 * (pow2(D.x) + pow2(D.y)) - pow2(D.x * F.y - D.y * F.x));
+               T Denominator = Radius2 - (Fx2 + Fy2);
+               return Numerator / Denominator;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T linearGradient
+       (
+               tvec2<T, P> const & Point0,
+               tvec2<T, P> const & Point1,
+               tvec2<T, P> const & Position
+       )
+       {
+               tvec2<T, P> Dist = Point1 - Point0;
+               return (Dist.x * (Position.x - Point0.x) + Dist.y * (Position.y - Point0.y)) / glm::dot(Dist, Dist);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/handed_coordinate_space.hpp b/core/deps/glm/glm/gtx/handed_coordinate_space.hpp
new file mode 100755 (executable)
index 0000000..2ee5175
--- /dev/null
@@ -0,0 +1,46 @@
+/// @ref gtx_handed_coordinate_space
+/// @file glm/gtx/handed_coordinate_space.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_handed_coordinate_space GLM_GTX_handed_coordinate_space
+/// @ingroup gtx
+///
+/// @brief To know if a set of three basis vectors defines a right or left-handed coordinate system.
+///
+/// <glm/gtx/handed_coordinate_system.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_handed_coordinate_space extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_handed_coordinate_space
+       /// @{
+
+       //! Return if a trihedron right handed or not.
+       //! From GLM_GTX_handed_coordinate_space extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool rightHanded(
+               tvec3<T, P> const & tangent,
+               tvec3<T, P> const & binormal,
+               tvec3<T, P> const & normal);
+
+       //! Return if a trihedron left handed or not.
+       //! From GLM_GTX_handed_coordinate_space extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool leftHanded(
+               tvec3<T, P> const & tangent,
+               tvec3<T, P> const & binormal,
+               tvec3<T, P> const & normal);
+
+       /// @}
+}// namespace glm
+
+#include "handed_coordinate_space.inl"
diff --git a/core/deps/glm/glm/gtx/handed_coordinate_space.inl b/core/deps/glm/glm/gtx/handed_coordinate_space.inl
new file mode 100755 (executable)
index 0000000..2e55653
--- /dev/null
@@ -0,0 +1,27 @@
+/// @ref gtx_handed_coordinate_space
+/// @file glm/gtx/handed_coordinate_space.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool rightHanded
+       (
+               tvec3<T, P> const & tangent,
+               tvec3<T, P> const & binormal,
+               tvec3<T, P> const & normal
+       )
+       {
+               return dot(cross(normal, tangent), binormal) > T(0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool leftHanded
+       (
+               tvec3<T, P> const & tangent,
+               tvec3<T, P> const & binormal,
+               tvec3<T, P> const & normal
+       )
+       {
+               return dot(cross(normal, tangent), binormal) < T(0);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/hash.hpp b/core/deps/glm/glm/gtx/hash.hpp
new file mode 100755 (executable)
index 0000000..2262618
--- /dev/null
@@ -0,0 +1,134 @@
+/// @ref gtx_hash
+/// @file glm/gtx/hash.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_hash GLM_GTX_hash
+/// @ingroup gtx
+/// 
+/// @brief Add std::hash support for glm types
+/// 
+/// <glm/gtx/hash.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+#include <functional>
+
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../gtc/vec1.hpp"
+
+#include "../gtc/quaternion.hpp"
+#include "../gtx/dual_quaternion.hpp"
+
+#include "../mat2x2.hpp"
+#include "../mat2x3.hpp"
+#include "../mat2x4.hpp"
+
+#include "../mat3x2.hpp"
+#include "../mat3x3.hpp"
+#include "../mat3x4.hpp"
+
+#include "../mat4x2.hpp"
+#include "../mat4x3.hpp"
+#include "../mat4x4.hpp"
+
+#if !GLM_HAS_CXX11_STL
+#      error "GLM_GTX_hash requires C++11 standard library support"
+#endif
+
+namespace std
+{
+       template <typename T, glm::precision P>
+       struct hash<glm::tvec1<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tvec1<T, P> const & v) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tvec2<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tvec2<T, P> const & v) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tvec3<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tvec3<T, P> const & v) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tvec4<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tvec4<T, P> const & v) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tquat<T,P>>
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tquat<T, P> const & q) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tdualquat<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tdualquat<T,P> const & q) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat2x2<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat2x2<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat2x3<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat2x3<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat2x4<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat2x4<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat3x2<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat3x2<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat3x3<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat3x3<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat3x4<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat3x4<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat4x2<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat4x2<T,P> const & m) const;
+       };
+       
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat4x3<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat4x3<T,P> const & m) const;
+       };
+
+       template <typename T, glm::precision P>
+       struct hash<glm::tmat4x4<T,P> >
+       {
+               GLM_FUNC_DECL size_t operator()(glm::tmat4x4<T,P> const & m) const;
+       };
+} // namespace std
+
+#include "hash.inl"
diff --git a/core/deps/glm/glm/gtx/hash.inl b/core/deps/glm/glm/gtx/hash.inl
new file mode 100755 (executable)
index 0000000..c42f4f0
--- /dev/null
@@ -0,0 +1,185 @@
+/// @ref gtx_hash
+/// @file glm/gtx/hash.inl
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_hash GLM_GTX_hash
+/// @ingroup gtx
+///
+/// @brief Add std::hash support for glm types
+///
+/// <glm/gtx/hash.inl> need to be included to use these functionalities.
+
+namespace glm {
+namespace detail
+{
+       GLM_INLINE void hash_combine(size_t &seed, size_t hash)
+       {
+               hash += 0x9e3779b9 + (seed << 6) + (seed >> 2);
+               seed ^= hash;
+       }
+}}
+
+namespace std
+{
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tvec1<T, P>>::operator()(glm::tvec1<T, P> const & v) const
+       {
+               hash<T> hasher;
+               return hasher(v.x);
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tvec2<T, P>>::operator()(glm::tvec2<T, P> const & v) const
+       {
+               size_t seed = 0;
+               hash<T> hasher;
+               glm::detail::hash_combine(seed, hasher(v.x));
+               glm::detail::hash_combine(seed, hasher(v.y));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tvec3<T, P>>::operator()(glm::tvec3<T, P> const & v) const
+       {
+               size_t seed = 0;
+               hash<T> hasher;
+               glm::detail::hash_combine(seed, hasher(v.x));
+               glm::detail::hash_combine(seed, hasher(v.y));
+               glm::detail::hash_combine(seed, hasher(v.z));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tvec4<T, P>>::operator()(glm::tvec4<T, P> const & v) const
+       {
+               size_t seed = 0;
+               hash<T> hasher;
+               glm::detail::hash_combine(seed, hasher(v.x));
+               glm::detail::hash_combine(seed, hasher(v.y));
+               glm::detail::hash_combine(seed, hasher(v.z));
+               glm::detail::hash_combine(seed, hasher(v.w));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tquat<T, P>>::operator()(glm::tquat<T,P> const & q) const
+       {
+               size_t seed = 0;
+               hash<T> hasher;
+               glm::detail::hash_combine(seed, hasher(q.x));
+               glm::detail::hash_combine(seed, hasher(q.y));
+               glm::detail::hash_combine(seed, hasher(q.z));
+               glm::detail::hash_combine(seed, hasher(q.w));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tdualquat<T, P>>::operator()(glm::tdualquat<T, P> const & q) const
+       {
+               size_t seed = 0;
+               hash<glm::tquat<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(q.real));
+               glm::detail::hash_combine(seed, hasher(q.dual));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat2x2<T, P>>::operator()(glm::tmat2x2<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec2<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat2x3<T, P>>::operator()(glm::tmat2x3<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec3<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat2x4<T, P>>::operator()(glm::tmat2x4<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec4<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat3x2<T, P>>::operator()(glm::tmat3x2<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec2<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat3x3<T, P>>::operator()(glm::tmat3x3<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec3<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat3x4<T, P>>::operator()(glm::tmat3x4<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec4<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat4x2<T,P>>::operator()(glm::tmat4x2<T,P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec2<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               glm::detail::hash_combine(seed, hasher(m[3]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat4x3<T,P>>::operator()(glm::tmat4x3<T,P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec3<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               glm::detail::hash_combine(seed, hasher(m[3]));
+               return seed;
+       }
+
+       template <typename T, glm::precision P>
+       GLM_FUNC_QUALIFIER size_t hash<glm::tmat4x4<T,P>>::operator()(glm::tmat4x4<T, P> const & m) const
+       {
+               size_t seed = 0;
+               hash<glm::tvec4<T, P>> hasher;
+               glm::detail::hash_combine(seed, hasher(m[0]));
+               glm::detail::hash_combine(seed, hasher(m[1]));
+               glm::detail::hash_combine(seed, hasher(m[2]));
+               glm::detail::hash_combine(seed, hasher(m[3]));
+               return seed;
+       }
+}
diff --git a/core/deps/glm/glm/gtx/integer.hpp b/core/deps/glm/glm/gtx/integer.hpp
new file mode 100755 (executable)
index 0000000..1173a58
--- /dev/null
@@ -0,0 +1,72 @@
+/// @ref gtx_integer
+/// @file glm/gtx/integer.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_integer GLM_GTX_integer
+/// @ingroup gtx
+///
+/// @brief Add support for integer for core functions
+///
+/// <glm/gtx/integer.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/integer.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_integer extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_integer
+       /// @{
+
+       //! Returns x raised to the y power. 
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL int pow(int x, int y);
+
+       //! Returns the positive square root of x.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL int sqrt(int x);
+
+       //! Returns the floor log2 of x.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL unsigned int floor_log2(unsigned int x);
+
+       //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL int mod(int x, int y);
+
+       //! Return the factorial value of a number (!12 max, integer only)
+       //! From GLM_GTX_integer extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType factorial(genType const & x);
+
+       //! 32bit signed integer. 
+       //! From GLM_GTX_integer extension.
+       typedef signed int                                      sint;
+
+       //! Returns x raised to the y power.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL uint pow(uint x, uint y);
+
+       //! Returns the positive square root of x. 
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL uint sqrt(uint x);
+
+       //! Modulus. Returns x - y * floor(x / y) for each component in x using the floating point value y.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL uint mod(uint x, uint y);
+
+       //! Returns the number of leading zeros.
+       //! From GLM_GTX_integer extension.
+       GLM_FUNC_DECL uint nlz(uint x);
+
+       /// @}
+}//namespace glm
+
+#include "integer.inl"
diff --git a/core/deps/glm/glm/gtx/integer.inl b/core/deps/glm/glm/gtx/integer.inl
new file mode 100755 (executable)
index 0000000..3a479e6
--- /dev/null
@@ -0,0 +1,182 @@
+/// @ref gtx_integer
+/// @file glm/gtx/integer.inl
+
+namespace glm
+{
+       // pow
+       GLM_FUNC_QUALIFIER int pow(int x, int y)
+       {
+               if(y == 0)
+                       return 1;
+               int result = x;
+               for(int i = 1; i < y; ++i)
+                       result *= x;
+               return result;
+       }
+
+       // sqrt: From Christopher J. Musial, An integer square root, Graphics Gems, 1990, page 387
+       GLM_FUNC_QUALIFIER int sqrt(int x)
+       {
+               if(x <= 1) return x;
+
+               int NextTrial = x >> 1;
+               int CurrentAnswer;
+
+               do
+               {
+                       CurrentAnswer = NextTrial;
+                       NextTrial = (NextTrial + x / NextTrial) >> 1;
+               } while(NextTrial < CurrentAnswer);
+
+               return CurrentAnswer;
+       }
+
+// Henry Gordon Dietz: http://aggregate.org/MAGIC/
+namespace detail
+{
+       GLM_FUNC_QUALIFIER unsigned int ones32(unsigned int x)
+       {
+               /* 32-bit recursive reduction using SWAR...
+               but first step is mapping 2-bit values
+               into sum of 2 1-bit values in sneaky way
+               */
+               x -= ((x >> 1) & 0x55555555);
+               x = (((x >> 2) & 0x33333333) + (x & 0x33333333));
+               x = (((x >> 4) + x) & 0x0f0f0f0f);
+               x += (x >> 8);
+               x += (x >> 16);
+               return(x & 0x0000003f);
+       }
+}//namespace detail
+
+       // Henry Gordon Dietz: http://aggregate.org/MAGIC/
+/*
+       GLM_FUNC_QUALIFIER unsigned int floor_log2(unsigned int x)
+       {
+               x |= (x >> 1);
+               x |= (x >> 2);
+               x |= (x >> 4);
+               x |= (x >> 8);
+               x |= (x >> 16);
+
+               return _detail::ones32(x) >> 1;
+       }
+*/
+       // mod
+       GLM_FUNC_QUALIFIER int mod(int x, int y)
+       {
+               return x - y * (x / y);
+       }
+
+       // factorial (!12 max, integer only)
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType factorial(genType const & x)
+       {
+               genType Temp = x;
+               genType Result;
+               for(Result = 1; Temp > 1; --Temp)
+                       Result *= Temp;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> factorial(
+               tvec2<T, P> const & x)
+       {
+               return tvec2<T, P>(
+                       factorial(x.x),
+                       factorial(x.y));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> factorial(
+               tvec3<T, P> const & x)
+       {
+               return tvec3<T, P>(
+                       factorial(x.x),
+                       factorial(x.y),
+                       factorial(x.z));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> factorial(
+               tvec4<T, P> const & x)
+       {
+               return tvec4<T, P>(
+                       factorial(x.x),
+                       factorial(x.y),
+                       factorial(x.z),
+                       factorial(x.w));
+       }
+
+       GLM_FUNC_QUALIFIER uint pow(uint x, uint y)
+       {
+               uint result = x;
+               for(uint i = 1; i < y; ++i)
+                       result *= x;
+               return result;
+       }
+
+       GLM_FUNC_QUALIFIER uint sqrt(uint x)
+       {
+               if(x <= 1) return x;
+
+               uint NextTrial = x >> 1;
+               uint CurrentAnswer;
+
+               do
+               {
+                       CurrentAnswer = NextTrial;
+                       NextTrial = (NextTrial + x / NextTrial) >> 1;
+               } while(NextTrial < CurrentAnswer);
+
+               return CurrentAnswer;
+       }
+
+       GLM_FUNC_QUALIFIER uint mod(uint x, uint y)
+       {
+               return x - y * (x / y);
+       }
+
+#if(GLM_COMPILER & (GLM_COMPILER_VC | GLM_COMPILER_GCC))
+
+       GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) 
+       {
+               return 31u - findMSB(x);
+       }
+
+#else
+
+       // Hackers Delight: http://www.hackersdelight.org/HDcode/nlz.c.txt
+       GLM_FUNC_QUALIFIER unsigned int nlz(unsigned int x) 
+       {
+               int y, m, n;
+
+               y = -int(x >> 16);      // If left half of x is 0,
+               m = (y >> 16) & 16;  // set n = 16.  If left half
+               n = 16 - m;          // is nonzero, set n = 0 and
+               x = x >> m;          // shift x right 16.
+                                                       // Now x is of the form 0000xxxx.
+               y = x - 0x100;       // If positions 8-15 are 0,
+               m = (y >> 16) & 8;   // add 8 to n and shift x left 8.
+               n = n + m;
+               x = x << m;
+
+               y = x - 0x1000;      // If positions 12-15 are 0,
+               m = (y >> 16) & 4;   // add 4 to n and shift x left 4.
+               n = n + m;
+               x = x << m;
+
+               y = x - 0x4000;      // If positions 14-15 are 0,
+               m = (y >> 16) & 2;   // add 2 to n and shift x left 2.
+               n = n + m;
+               x = x << m;
+
+               y = x >> 14;         // Set y = 0, 1, 2, or 3.
+               m = y & ~(y >> 1);   // Set m = 0, 1, 2, or 2 resp.
+               return unsigned(n + 2 - m);
+       }
+
+#endif//(GLM_COMPILER)
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/intersect.hpp b/core/deps/glm/glm/gtx/intersect.hpp
new file mode 100755 (executable)
index 0000000..33b6e99
--- /dev/null
@@ -0,0 +1,87 @@
+/// @ref gtx_intersect
+/// @file glm/gtx/intersect.hpp
+///
+/// @see core (dependence)
+/// @see gtx_closest_point (dependence)
+///
+/// @defgroup gtx_intersect GLM_GTX_intersect
+/// @ingroup gtx
+///
+/// @brief Add intersection functions
+///
+/// <glm/gtx/intersect.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include <cfloat>
+#include <limits>
+#include "../glm.hpp"
+#include "../geometric.hpp"
+#include "../gtx/closest_point.hpp"
+#include "../gtx/vector_query.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_closest_point extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_intersect
+       /// @{
+
+       //! Compute the intersection of a ray and a plane.
+       //! Ray direction and plane normal must be unit length.
+       //! From GLM_GTX_intersect extension.
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectRayPlane(
+               genType const & orig, genType const & dir,
+               genType const & planeOrig, genType const & planeNormal,
+               typename genType::value_type & intersectionDistance);
+
+       //! Compute the intersection of a ray and a triangle.
+       //! From GLM_GTX_intersect extension.
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectRayTriangle(
+               genType const & orig, genType const & dir,
+               genType const & vert0, genType const & vert1, genType const & vert2,
+               genType & baryPosition);
+
+       //! Compute the intersection of a line and a triangle.
+       //! From GLM_GTX_intersect extension.
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectLineTriangle(
+               genType const & orig, genType const & dir,
+               genType const & vert0, genType const & vert1, genType const & vert2,
+               genType & position);
+
+       //! Compute the intersection distance of a ray and a sphere. 
+       //! The ray direction vector is unit length.
+       //! From GLM_GTX_intersect extension.
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectRaySphere(
+               genType const & rayStarting, genType const & rayNormalizedDirection,
+               genType const & sphereCenter, typename genType::value_type const sphereRadiusSquered,
+               typename genType::value_type & intersectionDistance);
+
+       //! Compute the intersection of a ray and a sphere.
+       //! From GLM_GTX_intersect extension.
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectRaySphere(
+               genType const & rayStarting, genType const & rayNormalizedDirection,
+               genType const & sphereCenter, const typename genType::value_type sphereRadius,
+               genType & intersectionPosition, genType & intersectionNormal);
+
+       //! Compute the intersection of a line and a sphere.
+       //! From GLM_GTX_intersect extension
+       template <typename genType>
+       GLM_FUNC_DECL bool intersectLineSphere(
+               genType const & point0, genType const & point1,
+               genType const & sphereCenter, typename genType::value_type sphereRadius,
+               genType & intersectionPosition1, genType & intersectionNormal1, 
+               genType & intersectionPosition2 = genType(), genType & intersectionNormal2 = genType());
+
+       /// @}
+}//namespace glm
+
+#include "intersect.inl"
diff --git a/core/deps/glm/glm/gtx/intersect.inl b/core/deps/glm/glm/gtx/intersect.inl
new file mode 100755 (executable)
index 0000000..904d6cc
--- /dev/null
@@ -0,0 +1,170 @@
+/// @ref gtx_intersect
+/// @file glm/gtx/intersect.inl
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectRayPlane
+       (
+               genType const & orig, genType const & dir,
+               genType const & planeOrig, genType const & planeNormal,
+               typename genType::value_type & intersectionDistance
+       )
+       {
+               typename genType::value_type d = glm::dot(dir, planeNormal);
+               typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
+
+               if(d < -Epsilon)
+               {
+                       intersectionDistance = glm::dot(planeOrig - orig, planeNormal) / d;
+                       return true;
+               }
+
+               return false;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectRayTriangle
+       (
+               genType const & orig, genType const & dir,
+               genType const & v0, genType const & v1, genType const & v2,
+               genType & baryPosition
+       )
+       {
+               genType e1 = v1 - v0;
+               genType e2 = v2 - v0;
+
+               genType p = glm::cross(dir, e2);
+
+               typename genType::value_type a = glm::dot(e1, p);
+
+               typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
+               if(a < Epsilon && a > -Epsilon)
+                       return false;
+
+               typename genType::value_type f = typename genType::value_type(1.0f) / a;
+
+               genType s = orig - v0;
+               baryPosition.x = f * glm::dot(s, p);
+               if(baryPosition.x < typename genType::value_type(0.0f))
+                       return false;
+               if(baryPosition.x > typename genType::value_type(1.0f))
+                       return false;
+
+               genType q = glm::cross(s, e1);
+               baryPosition.y = f * glm::dot(dir, q);
+               if(baryPosition.y < typename genType::value_type(0.0f))
+                       return false;
+               if(baryPosition.y + baryPosition.x > typename genType::value_type(1.0f))
+                       return false;
+
+               baryPosition.z = f * glm::dot(e2, q);
+
+               return baryPosition.z >= typename genType::value_type(0.0f);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectLineTriangle
+       (
+               genType const & orig, genType const & dir,
+               genType const & vert0, genType const & vert1, genType const & vert2,
+               genType & position
+       )
+       {
+               typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
+
+               genType edge1 = vert1 - vert0;
+               genType edge2 = vert2 - vert0;
+
+               genType pvec = cross(dir, edge2);
+
+               float det = dot(edge1, pvec);
+
+               if (det > -Epsilon && det < Epsilon)
+                       return false;
+               float inv_det = typename genType::value_type(1) / det;
+
+               genType tvec = orig - vert0;
+
+               position.y = dot(tvec, pvec) * inv_det;
+               if (position.y < typename genType::value_type(0) || position.y > typename genType::value_type(1))
+                       return false;
+
+               genType qvec = cross(tvec, edge1);
+
+               position.z = dot(dir, qvec) * inv_det;
+               if (position.z < typename genType::value_type(0) || position.y + position.z > typename genType::value_type(1))
+                       return false;
+
+               position.x = dot(edge2, qvec) * inv_det;
+
+               return true;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectRaySphere
+       (
+               genType const & rayStarting, genType const & rayNormalizedDirection,
+               genType const & sphereCenter, const typename genType::value_type sphereRadiusSquered,
+               typename genType::value_type & intersectionDistance
+       )
+       {
+               typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
+               genType diff = sphereCenter - rayStarting;
+               typename genType::value_type t0 = dot(diff, rayNormalizedDirection);
+               typename genType::value_type dSquared = dot(diff, diff) - t0 * t0;
+               if( dSquared > sphereRadiusSquered )
+               {
+                       return false;
+               }
+               typename genType::value_type t1 = sqrt( sphereRadiusSquered - dSquared );
+               intersectionDistance = t0 > t1 + Epsilon ? t0 - t1 : t0 + t1;
+               return intersectionDistance > Epsilon;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectRaySphere
+       (
+               genType const & rayStarting, genType const & rayNormalizedDirection,
+               genType const & sphereCenter, const typename genType::value_type sphereRadius,
+               genType & intersectionPosition, genType & intersectionNormal
+       )
+       {
+               typename genType::value_type distance;
+               if( intersectRaySphere( rayStarting, rayNormalizedDirection, sphereCenter, sphereRadius * sphereRadius, distance ) )
+               {
+                       intersectionPosition = rayStarting + rayNormalizedDirection * distance;
+                       intersectionNormal = (intersectionPosition - sphereCenter) / sphereRadius;
+                       return true;
+               }
+               return false;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER bool intersectLineSphere
+       (
+               genType const & point0, genType const & point1,
+               genType const & sphereCenter, typename genType::value_type sphereRadius,
+               genType & intersectionPoint1, genType & intersectionNormal1, 
+               genType & intersectionPoint2, genType & intersectionNormal2
+       )
+       {
+               typename genType::value_type Epsilon = std::numeric_limits<typename genType::value_type>::epsilon();
+               genType dir = normalize(point1 - point0);
+               genType diff = sphereCenter - point0;
+               typename genType::value_type t0 = dot(diff, dir);
+               typename genType::value_type dSquared = dot(diff, diff) - t0 * t0;
+               if( dSquared > sphereRadius * sphereRadius )
+               {
+                       return false;
+               }
+               typename genType::value_type t1 = sqrt( sphereRadius * sphereRadius - dSquared );
+               if( t0 < t1 + Epsilon )
+                       t1 = -t1;
+               intersectionPoint1 = point0 + dir * (t0 - t1);
+               intersectionNormal1 = (intersectionPoint1 - sphereCenter) / sphereRadius;
+               intersectionPoint2 = point0 + dir * (t0 + t1);
+               intersectionNormal2 = (intersectionPoint2 - sphereCenter) / sphereRadius;
+               return true;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/io.hpp b/core/deps/glm/glm/gtx/io.hpp
new file mode 100755 (executable)
index 0000000..6aa8415
--- /dev/null
@@ -0,0 +1,197 @@
+/// @ref gtx_io
+/// @file glm/gtx/io.hpp
+/// @author Jan P Springer (regnirpsj@gmail.com)
+///
+/// @see core (dependence)
+/// @see gtc_matrix_access (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtx_io GLM_GTX_io
+/// @ingroup gtx
+/// 
+/// @brief std::[w]ostream support for glm types
+///
+/// std::[w]ostream support for glm types + precision/width/etc. manipulators
+/// based on howard hinnant's std::chrono io proposal
+/// [http://home.roadrunner.com/~hinnant/bloomington/chrono_io.html]
+///
+/// <glm/gtx/io.hpp> needs to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+# pragma message("GLM: GLM_GTX_io extension included")
+#endif
+
+#include <iosfwd>  // std::basic_ostream<> (fwd)
+#include <locale>  // std::locale, std::locale::facet, std::locale::id
+#include <utility> // std::pair<>
+
+namespace glm
+{
+       /// @addtogroup gtx_io
+       /// @{
+
+       namespace io
+       {
+               enum order_type { column_major, row_major};
+
+               template <typename CTy>
+               class format_punct : public std::locale::facet
+               {
+                       typedef CTy char_type;
+
+               public:
+
+                       static std::locale::id id;
+
+                       bool       formatted;
+                       unsigned   precision;
+                       unsigned   width;
+                       char_type  separator;
+                       char_type  delim_left;
+                       char_type  delim_right;
+                       char_type  space;
+                       char_type  newline;
+                       order_type order;
+
+                       GLM_FUNC_DECL explicit format_punct(size_t a = 0);
+                       GLM_FUNC_DECL explicit format_punct(format_punct const&);
+               };
+
+               template <typename CTy, typename CTr = std::char_traits<CTy> >
+               class basic_state_saver {
+
+               public:
+
+                       GLM_FUNC_DECL explicit basic_state_saver(std::basic_ios<CTy,CTr>&);
+                       GLM_FUNC_DECL ~basic_state_saver();
+
+               private:
+
+                       typedef ::std::basic_ios<CTy,CTr>      state_type;
+                       typedef typename state_type::char_type char_type;
+                       typedef ::std::ios_base::fmtflags      flags_type;
+                       typedef ::std::streamsize              streamsize_type;
+                       typedef ::std::locale const            locale_type;
+
+                       state_type&     state_;
+                       flags_type      flags_;
+                       streamsize_type precision_;
+                       streamsize_type width_;
+                       char_type       fill_;
+                       locale_type     locale_;
+
+                       GLM_FUNC_DECL basic_state_saver& operator=(basic_state_saver const&);
+               };
+
+               typedef basic_state_saver<char>     state_saver;
+               typedef basic_state_saver<wchar_t> wstate_saver;
+
+               template <typename CTy, typename CTr = std::char_traits<CTy> >
+               class basic_format_saver
+               {
+               public:
+
+                       GLM_FUNC_DECL explicit basic_format_saver(std::basic_ios<CTy,CTr>&);
+                       GLM_FUNC_DECL ~basic_format_saver();
+
+               private:
+
+                       basic_state_saver<CTy> const bss_;
+
+                       GLM_FUNC_DECL basic_format_saver& operator=(basic_format_saver const&);
+               };
+
+               typedef basic_format_saver<char>     format_saver;
+               typedef basic_format_saver<wchar_t> wformat_saver;
+
+               struct precision
+               {
+                       unsigned value;
+
+                       GLM_FUNC_DECL explicit precision(unsigned);
+               };
+
+               struct width
+               {
+                       unsigned value;
+
+                       GLM_FUNC_DECL explicit width(unsigned);
+               };
+
+               template <typename CTy>
+               struct delimeter
+               {
+                       CTy value[3];
+
+                       GLM_FUNC_DECL explicit delimeter(CTy /* left */, CTy /* right */, CTy /* separator */ = ',');
+               };
+
+               struct order
+               {
+                       order_type value;
+
+                       GLM_FUNC_DECL explicit order(order_type);
+               };
+
+               // functions, inlined (inline)
+
+               template <typename FTy, typename CTy, typename CTr>
+               FTy const& get_facet(std::basic_ios<CTy,CTr>&);
+               template <typename FTy, typename CTy, typename CTr>
+               std::basic_ios<CTy,CTr>& formatted(std::basic_ios<CTy,CTr>&);
+               template <typename FTy, typename CTy, typename CTr>
+               std::basic_ios<CTy,CTr>& unformattet(std::basic_ios<CTy,CTr>&);
+
+               template <typename CTy, typename CTr>
+               std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, precision const&);
+               template <typename CTy, typename CTr>
+               std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, width const&);
+               template <typename CTy, typename CTr>
+               std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, delimeter<CTy> const&);
+               template <typename CTy, typename CTr>
+               std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>&, order const&);
+       }//namespace io
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tquat<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tvec1<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tvec2<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tvec3<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tvec4<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat2x2<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat2x3<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat2x4<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat3x2<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat3x3<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat3x4<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat4x2<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat4x3<T,P> const&);
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>&, tmat4x4<T,P> const&);
+
+  template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_DECL std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr> &,
+                                                         std::pair<tmat4x4<T,P> const, tmat4x4<T,P> const> const &);
+
+       /// @}
+}//namespace glm
+
+#include "io.inl"
diff --git a/core/deps/glm/glm/gtx/io.inl b/core/deps/glm/glm/gtx/io.inl
new file mode 100755 (executable)
index 0000000..9b70a5f
--- /dev/null
@@ -0,0 +1,441 @@
+/// @ref gtx_io
+/// @file glm/gtx/io.inl
+/// @author Jan P Springer (regnirpsj@gmail.com)
+
+#include <iomanip>                  // std::fixed, std::setfill<>, std::setprecision, std::right, std::setw
+#include <ostream>                  // std::basic_ostream<>
+#include "../gtc/matrix_access.hpp" // glm::col, glm::row
+#include "../gtx/type_trait.hpp"    // glm::type<>
+
+namespace glm{
+namespace io
+{
+       template <typename CTy>
+       GLM_FUNC_QUALIFIER format_punct<CTy>::format_punct(size_t a)
+               : std::locale::facet(a)
+               , formatted(true)
+               , precision(3)
+               , width(1 + 4 + 1 + precision)
+               , separator(',')
+               , delim_left('[')
+               , delim_right(']')
+               , space(' ')
+               , newline('\n')
+               , order(column_major)
+       {}
+
+       template <typename CTy>
+       GLM_FUNC_QUALIFIER format_punct<CTy>::format_punct(format_punct const& a)
+               : std::locale::facet(0)
+               , formatted(a.formatted)
+               , precision(a.precision)
+               , width(a.width)
+               , separator(a.separator)
+               , delim_left(a.delim_left)
+               , delim_right(a.delim_right)
+               , space(a.space)
+               , newline(a.newline)
+               , order(a.order)
+       {}
+
+       template <typename CTy> std::locale::id format_punct<CTy>::id;
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER basic_state_saver<CTy, CTr>::basic_state_saver(std::basic_ios<CTy, CTr>& a)
+               : state_(a)
+               , flags_(a.flags())
+               , precision_(a.precision())
+               , width_(a.width())
+               , fill_(a.fill())
+               , locale_(a.getloc())
+       {}
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER basic_state_saver<CTy, CTr>::~basic_state_saver()
+       {
+               state_.imbue(locale_);
+               state_.fill(fill_);
+               state_.width(width_);
+               state_.precision(precision_);
+               state_.flags(flags_);
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER basic_format_saver<CTy, CTr>::basic_format_saver(std::basic_ios<CTy, CTr>& a)
+               : bss_(a)
+       {
+               a.imbue(std::locale(a.getloc(), new format_punct<CTy>(get_facet<format_punct<CTy> >(a))));
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER
+       basic_format_saver<CTy, CTr>::~basic_format_saver()
+       {}
+
+       GLM_FUNC_QUALIFIER precision::precision(unsigned a)
+               : value(a)
+       {}
+
+       GLM_FUNC_QUALIFIER width::width(unsigned a)
+               : value(a)
+       {}
+
+       template <typename CTy>
+       GLM_FUNC_QUALIFIER delimeter<CTy>::delimeter(CTy a, CTy b, CTy c)
+               : value()
+       {
+               value[0] = a;
+               value[1] = b;
+               value[2] = c;
+       }
+
+       GLM_FUNC_QUALIFIER order::order(order_type a)
+               : value(a)
+       {}
+
+       template <typename FTy, typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER FTy const& get_facet(std::basic_ios<CTy, CTr>& ios)
+       {
+               if(!std::has_facet<FTy>(ios.getloc()))
+                       ios.imbue(std::locale(ios.getloc(), new FTy));
+
+               return std::use_facet<FTy>(ios.getloc());
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER std::basic_ios<CTy, CTr>& formatted(std::basic_ios<CTy, CTr>& ios)
+       {
+               const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(ios)).formatted = true;
+               return ios;
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER std::basic_ios<CTy, CTr>& unformatted(std::basic_ios<CTy, CTr>& ios)
+       {
+               const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(ios)).formatted = false;
+               return ios;
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, precision const& a)
+       {
+               const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).precision = a.value;
+               return os;
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, width const& a)
+       {
+               const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).width = a.value;
+               return os;
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER  std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, delimeter<CTy> const& a)
+       {
+               format_punct<CTy> & fmt(const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)));
+
+               fmt.delim_left  = a.value[0];
+               fmt.delim_right = a.value[1];
+               fmt.separator   = a.value[2];
+
+               return os;
+       }
+
+       template <typename CTy, typename CTr>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(std::basic_ostream<CTy, CTr>& os, order const& a)
+       {
+               const_cast<format_punct<CTy>&>(get_facet<format_punct<CTy> >(os)).order = a.value;
+               return os;
+       }
+} // namespace io
+
+namespace detail
+{
+       template <typename CTy, typename CTr, template <typename, precision> class V, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>&
+       print_vector_on(std::basic_ostream<CTy, CTr>& os, V<T,P> const& a)
+       {
+               typename std::basic_ostream<CTy, CTr>::sentry const cerberus(os);
+
+               if(cerberus)
+               {
+                       io::format_punct<CTy> const & fmt(io::get_facet<io::format_punct<CTy> >(os));
+
+                       length_t const& components(type<V, T, P>::components);
+
+                       if(fmt.formatted)
+                       {
+                               io::basic_state_saver<CTy> const bss(os);
+
+                               os << std::fixed << std::right << std::setprecision(fmt.precision) << std::setfill(fmt.space) << fmt.delim_left;
+
+                               for(length_t i(0); i < components; ++i)
+                               {
+                                       os << std::setw(fmt.width) << a[i];
+                                       if(components-1 != i)
+                                               os << fmt.separator;
+                               }
+
+                               os << fmt.delim_right;
+                       }
+                       else
+                       {
+                               for(length_t i(0); i < components; ++i)
+                               {
+                                       os << a[i];
+
+                                       if(components-1 != i)
+                                               os << fmt.space;
+                               }
+                       }
+               }
+
+               return os;
+       }
+}//namespace detail
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tquat<T,P> const& a)
+       {
+               return detail::print_vector_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tvec1<T,P> const& a)
+       {
+               return detail::print_vector_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tvec2<T,P> const& a)
+       {
+               return detail::print_vector_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tvec3<T,P> const& a)
+       {
+               return detail::print_vector_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tvec4<T,P> const& a)
+       {
+               return detail::print_vector_on(os, a);
+       }
+
+namespace detail
+{
+       template <typename CTy, typename CTr, template <typename, precision> class M, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& print_matrix_on(std::basic_ostream<CTy, CTr>& os, M<T,P> const& a)
+       {
+               typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
+
+               if(cerberus)
+               {
+                       io::format_punct<CTy> const & fmt(io::get_facet<io::format_punct<CTy> >(os));
+
+                       length_t const& cols(type<M, T, P>::cols);
+                       length_t const& rows(type<M, T, P>::rows);
+
+                       if(fmt.formatted)
+                       {
+                               os << fmt.newline << fmt.delim_left;
+
+                               switch(fmt.order)
+                               {
+                                       case io::column_major:
+                                       {
+                                               for(length_t i(0); i < rows; ++i)
+                                               {
+                                                       if (0 != i)
+                                                               os << fmt.space;
+
+                                                       os << row(a, i);
+
+                                                       if(rows-1 != i)
+                                                               os << fmt.newline;
+                                               }
+                                       }
+                                       break;
+
+                                       case io::row_major:
+                                       {
+                                               for(length_t i(0); i < cols; ++i)
+                                               {
+                                                       if(0 != i)
+                                                               os << fmt.space;
+
+                                                       os << column(a, i);
+
+                                                       if(cols-1 != i)
+                                                               os << fmt.newline;
+                                               }
+                                       }
+                                       break;
+                               }
+
+                               os << fmt.delim_right;
+                       }
+                       else
+                       {
+                               switch (fmt.order)
+                               {
+                                       case io::column_major:
+                                       {
+                                               for(length_t i(0); i < cols; ++i)
+                                               {
+                                                       os << column(a, i);
+
+                                                       if(cols - 1 != i)
+                                                               os << fmt.space;
+                                               }
+                                       }
+                                       break;
+
+                                       case io::row_major:
+                                       {
+                                               for (length_t i(0); i < rows; ++i)
+                                               {
+                                                       os << row(a, i);
+
+                                                       if (rows-1 != i)
+                                                               os << fmt.space;
+                                               }
+                                       }
+                                       break;
+                               }
+                       }
+               }
+
+               return os;
+       }
+}//namespace detail
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tmat2x2<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tmat2x3<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tmat2x4<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tmat3x2<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr>& operator<<(std::basic_ostream<CTy,CTr>& os, tmat3x3<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, tmat3x4<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, tmat4x2<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, tmat4x3<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy,CTr> & operator<<(std::basic_ostream<CTy,CTr>& os, tmat4x4<T,P> const& a)
+       {
+               return detail::print_matrix_on(os, a);
+       }
+
+namespace detail
+{
+       template <typename CTy, typename CTr, template <typename, precision> class M, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& print_matrix_pair_on(std::basic_ostream<CTy, CTr>& os, std::pair<M<T, P> const, M<T, P> const> const& a)
+       {
+               typename std::basic_ostream<CTy,CTr>::sentry const cerberus(os);
+
+               if(cerberus)
+               {
+                       io::format_punct<CTy> const& fmt(io::get_facet<io::format_punct<CTy> >(os));
+                       M<T,P> const& ml(a.first);
+                       M<T,P> const& mr(a.second);
+                       length_t const& cols(type<M, T, P>::cols);
+                       length_t const& rows(type<M, T, P>::rows);
+
+                       if(fmt.formatted)
+                       {
+                               os << fmt.newline << fmt.delim_left;
+
+                               switch(fmt.order)
+                               {
+                                       case io::column_major:
+                                       {
+                                               for(length_t i(0); i < rows; ++i)
+                                               {
+                                                       if(0 != i)
+                                                               os << fmt.space;
+
+                                                       os << row(ml, i) << ((rows-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << row(mr, i);
+
+                                                       if(rows-1 != i)
+                                                               os << fmt.newline;
+                                               }
+                                       }
+                                       break;
+                                       case io::row_major:
+                                       {
+                                               for(length_t i(0); i < cols; ++i)
+                                               {
+                                                       if(0 != i)
+                                                               os << fmt.space;
+
+                                                               os << column(ml, i) << ((cols-1 != i) ? fmt.space : fmt.delim_right) << fmt.space << ((0 != i) ? fmt.space : fmt.delim_left) << column(mr, i);
+
+                                                       if(cols-1 != i)
+                                                               os << fmt.newline;
+                                               }
+                                       }
+                                       break;
+                               }
+
+                               os << fmt.delim_right;
+                       }
+                       else
+                       {
+                               os << ml << fmt.space << mr;
+                       }
+               }
+
+               return os;
+       }
+}//namespace detail
+
+       template <typename CTy, typename CTr, typename T, precision P>
+       GLM_FUNC_QUALIFIER std::basic_ostream<CTy, CTr>& operator<<(
+               std::basic_ostream<CTy, CTr> & os,
+               std::pair<tmat4x4<T, P> const,
+               tmat4x4<T, P> const> const& a)
+       {
+               return detail::print_matrix_pair_on(os, a);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/log_base.hpp b/core/deps/glm/glm/gtx/log_base.hpp
new file mode 100755 (executable)
index 0000000..7958fc3
--- /dev/null
@@ -0,0 +1,44 @@
+/// @ref gtx_log_base
+/// @file glm/gtx/log_base.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_log_base GLM_GTX_log_base
+/// @ingroup gtx
+///
+/// @brief Logarithm for any base. base can be a vector or a scalar.
+///
+/// <glm/gtx/log_base.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_log_base extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_log_base
+       /// @{
+
+       /// Logarithm for any base.
+       /// From GLM_GTX_log_base.
+       template <typename genType>
+       GLM_FUNC_DECL genType log(
+               genType const & x,
+               genType const & base);
+
+       /// Logarithm for any base.
+       /// From GLM_GTX_log_base.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<T, P> sign(
+               vecType<T, P> const & x,
+               vecType<T, P> const & base);
+
+       /// @}
+}//namespace glm
+
+#include "log_base.inl"
diff --git a/core/deps/glm/glm/gtx/log_base.inl b/core/deps/glm/glm/gtx/log_base.inl
new file mode 100755 (executable)
index 0000000..8005d1b
--- /dev/null
@@ -0,0 +1,18 @@
+/// @ref gtx_log_base
+/// @file glm/gtx/log_base.inl
+
+namespace glm
+{
+       template <typename genType> 
+       GLM_FUNC_QUALIFIER genType log(genType const & x, genType const & base)
+       {
+               assert(x != genType(0));
+               return glm::log(x) / glm::log(base);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> log(vecType<T, P> const & x, vecType<T, P> const & base)
+       {
+               return glm::log(x) / glm::log(base);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_cross_product.hpp b/core/deps/glm/glm/gtx/matrix_cross_product.hpp
new file mode 100755 (executable)
index 0000000..d920f4e
--- /dev/null
@@ -0,0 +1,43 @@
+/// @ref gtx_matrix_cross_product
+/// @file glm/gtx/matrix_cross_product.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_matrix_cross_product GLM_GTX_matrix_cross_product
+/// @ingroup gtx
+///
+/// @brief Build cross product matrices
+///
+/// <glm/gtx/matrix_cross_product.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_cross_product extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_cross_product
+       /// @{
+
+       //! Build a cross product matrix.
+       //! From GLM_GTX_matrix_cross_product extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> matrixCross3(
+               tvec3<T, P> const & x);
+               
+       //! Build a cross product matrix.
+       //! From GLM_GTX_matrix_cross_product extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> matrixCross4(
+               tvec3<T, P> const & x);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_cross_product.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_cross_product.inl b/core/deps/glm/glm/gtx/matrix_cross_product.inl
new file mode 100755 (executable)
index 0000000..16f07e9
--- /dev/null
@@ -0,0 +1,38 @@
+/// @ref gtx_matrix_cross_product
+/// @file glm/gtx/matrix_cross_product.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> matrixCross3
+       (
+               tvec3<T, P> const & x
+       )
+       {
+               tmat3x3<T, P> Result(T(0));
+               Result[0][1] = x.z;
+               Result[1][0] = -x.z;
+               Result[0][2] = -x.y;
+               Result[2][0] = x.y;
+               Result[1][2] = x.x;
+               Result[2][1] = -x.x;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> matrixCross4
+       (
+               tvec3<T, P> const & x
+       )
+       {
+               tmat4x4<T, P> Result(T(0));
+               Result[0][1] = x.z;
+               Result[1][0] = -x.z;
+               Result[0][2] = -x.y;
+               Result[2][0] = x.y;
+               Result[1][2] = x.x;
+               Result[2][1] = -x.x;
+               return Result;
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_decompose.hpp b/core/deps/glm/glm/gtx/matrix_decompose.hpp
new file mode 100755 (executable)
index 0000000..e163f5a
--- /dev/null
@@ -0,0 +1,42 @@
+/// @ref gtx_matrix_decompose
+/// @file glm/gtx/matrix_decompose.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_matrix_decompose GLM_GTX_matrix_decompose
+/// @ingroup gtx
+///
+/// @brief Decomposes a model matrix to translations, rotation and scale components
+///
+/// <glm/gtx/matrix_decompose.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../mat4x4.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../geometric.hpp"
+#include "../gtc/quaternion.hpp"
+#include "../gtc/matrix_transform.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_decompose extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_decompose
+       /// @{
+
+       /// Decomposes a model matrix to translations, rotation and scale components 
+       /// @see gtx_matrix_decompose
+       template <typename T, precision P>
+       GLM_FUNC_DECL bool decompose(
+               tmat4x4<T, P> const & modelMatrix,
+               tvec3<T, P> & scale, tquat<T, P> & orientation, tvec3<T, P> & translation, tvec3<T, P> & skew, tvec4<T, P> & perspective);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_decompose.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_decompose.inl b/core/deps/glm/glm/gtx/matrix_decompose.inl
new file mode 100755 (executable)
index 0000000..7194e9d
--- /dev/null
@@ -0,0 +1,194 @@
+/// @ref gtx_matrix_decompose
+/// @file glm/gtx/matrix_decompose.inl
+
+namespace glm{
+namespace detail
+{
+       /// Make a linear combination of two vectors and return the result.
+       // result = (a * ascl) + (b * bscl)
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> combine(
+               tvec3<T, P> const & a, 
+               tvec3<T, P> const & b,
+               T ascl, T bscl)
+       {
+               return (a * ascl) + (b * bscl);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> scale(tvec3<T, P> const& v, T desiredLength)
+       {
+               return v * desiredLength / length(v);
+       }
+}//namespace detail
+
+       // Matrix decompose
+       // http://www.opensource.apple.com/source/WebCore/WebCore-514/platform/graphics/transforms/TransformationMatrix.cpp
+       // Decomposes the mode matrix to translations,rotation scale components
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER bool decompose(tmat4x4<T, P> const & ModelMatrix, tvec3<T, P> & Scale, tquat<T, P> & Orientation, tvec3<T, P> & Translation, tvec3<T, P> & Skew, tvec4<T, P> & Perspective)
+       {
+               tmat4x4<T, P> LocalMatrix(ModelMatrix);
+
+               // Normalize the matrix.
+               if(LocalMatrix[3][3] == static_cast<T>(0))
+                       return false;
+
+               for(length_t i = 0; i < 4; ++i)
+               for(length_t j = 0; j < 4; ++j)
+                       LocalMatrix[i][j] /= LocalMatrix[3][3];
+
+               // perspectiveMatrix is used to solve for perspective, but it also provides
+               // an easy way to test for singularity of the upper 3x3 component.
+               tmat4x4<T, P> PerspectiveMatrix(LocalMatrix);
+
+               for(length_t i = 0; i < 3; i++)
+                       PerspectiveMatrix[i][3] = static_cast<T>(0);
+               PerspectiveMatrix[3][3] = static_cast<T>(1);
+
+               /// TODO: Fixme!
+               if(determinant(PerspectiveMatrix) == static_cast<T>(0))
+                       return false;
+
+               // First, isolate perspective.  This is the messiest.
+               if(LocalMatrix[0][3] != static_cast<T>(0) || LocalMatrix[1][3] != static_cast<T>(0) || LocalMatrix[2][3] != static_cast<T>(0))
+               {
+                       // rightHandSide is the right hand side of the equation.
+                       tvec4<T, P> RightHandSide;
+                       RightHandSide[0] = LocalMatrix[0][3];
+                       RightHandSide[1] = LocalMatrix[1][3];
+                       RightHandSide[2] = LocalMatrix[2][3];
+                       RightHandSide[3] = LocalMatrix[3][3];
+
+                       // Solve the equation by inverting PerspectiveMatrix and multiplying
+                       // rightHandSide by the inverse.  (This is the easiest way, not
+                       // necessarily the best.)
+                       tmat4x4<T, P> InversePerspectiveMatrix = glm::inverse(PerspectiveMatrix);//   inverse(PerspectiveMatrix, inversePerspectiveMatrix);
+                       tmat4x4<T, P> TransposedInversePerspectiveMatrix = glm::transpose(InversePerspectiveMatrix);//   transposeMatrix4(inversePerspectiveMatrix, transposedInversePerspectiveMatrix);
+
+                       Perspective = TransposedInversePerspectiveMatrix * RightHandSide;
+                       //  v4MulPointByMatrix(rightHandSide, transposedInversePerspectiveMatrix, perspectivePoint);
+
+                       // Clear the perspective partition
+                       LocalMatrix[0][3] = LocalMatrix[1][3] = LocalMatrix[2][3] = static_cast<T>(0);
+                       LocalMatrix[3][3] = static_cast<T>(1);
+               }
+               else
+               {
+                       // No perspective.
+                       Perspective = tvec4<T, P>(0, 0, 0, 1);
+               }
+
+               // Next take care of translation (easy).
+               Translation = tvec3<T, P>(LocalMatrix[3]);
+               LocalMatrix[3] = tvec4<T, P>(0, 0, 0, LocalMatrix[3].w);
+
+               tvec3<T, P> Row[3], Pdum3;
+
+               // Now get scale and shear.
+               for(length_t i = 0; i < 3; ++i)
+                       for(int j = 0; j < 3; ++j)
+                               Row[i][j] = LocalMatrix[i][j];
+
+               // Compute X scale factor and normalize first row.
+               Scale.x = length(Row[0]);// v3Length(Row[0]);
+
+               Row[0] = detail::scale(Row[0], static_cast<T>(1));
+
+               // Compute XY shear factor and make 2nd row orthogonal to 1st.
+               Skew.z = dot(Row[0], Row[1]);
+               Row[1] = detail::combine(Row[1], Row[0], static_cast<T>(1), -Skew.z);
+
+               // Now, compute Y scale and normalize 2nd row.
+               Scale.y = length(Row[1]);
+               Row[1] = detail::scale(Row[1], static_cast<T>(1));
+               Skew.z /= Scale.y;
+
+               // Compute XZ and YZ shears, orthogonalize 3rd row.
+               Skew.y = glm::dot(Row[0], Row[2]);
+               Row[2] = detail::combine(Row[2], Row[0], static_cast<T>(1), -Skew.y);
+               Skew.x = glm::dot(Row[1], Row[2]);
+               Row[2] = detail::combine(Row[2], Row[1], static_cast<T>(1), -Skew.x);
+
+               // Next, get Z scale and normalize 3rd row.
+               Scale.z = length(Row[2]);
+               Row[2] = detail::scale(Row[2], static_cast<T>(1));
+               Skew.y /= Scale.z;
+               Skew.x /= Scale.z;
+
+               // At this point, the matrix (in rows[]) is orthonormal.
+               // Check for a coordinate system flip.  If the determinant
+               // is -1, then negate the matrix and the scaling factors.
+               Pdum3 = cross(Row[1], Row[2]); // v3Cross(row[1], row[2], Pdum3);
+               if(dot(Row[0], Pdum3) < 0)
+               {
+                       for(length_t i = 0; i < 3; i++)
+                       {
+                               Scale[i] *= static_cast<T>(-1);
+                               Row[i] *= static_cast<T>(-1);
+                       }
+               }
+
+               // Now, get the rotations out, as described in the gem.
+
+               // FIXME - Add the ability to return either quaternions (which are
+               // easier to recompose with) or Euler angles (rx, ry, rz), which
+               // are easier for authors to deal with. The latter will only be useful
+               // when we fix https://bugs.webkit.org/show_bug.cgi?id=23799, so I
+               // will leave the Euler angle code here for now.
+
+               // ret.rotateY = asin(-Row[0][2]);
+               // if (cos(ret.rotateY) != 0) {
+               //     ret.rotateX = atan2(Row[1][2], Row[2][2]);
+               //     ret.rotateZ = atan2(Row[0][1], Row[0][0]);
+               // } else {
+               //     ret.rotateX = atan2(-Row[2][0], Row[1][1]);
+               //     ret.rotateZ = 0;
+               // }
+
+               T s, t, x, y, z, w;
+
+               t = Row[0][0] + Row[1][1] + Row[2][2] + static_cast<T>(1);
+
+               if(t > static_cast<T>(1e-4))
+               {
+                       s = static_cast<T>(0.5) / sqrt(t);
+                       w = static_cast<T>(0.25) / s;
+                       x = (Row[2][1] - Row[1][2]) * s;
+                       y = (Row[0][2] - Row[2][0]) * s;
+                       z = (Row[1][0] - Row[0][1]) * s;
+               }
+               else if(Row[0][0] > Row[1][1] && Row[0][0] > Row[2][2])
+               { 
+                       s = sqrt (static_cast<T>(1) + Row[0][0] - Row[1][1] - Row[2][2]) * static_cast<T>(2); // S=4*qx 
+                       x = static_cast<T>(0.25) * s;
+                       y = (Row[0][1] + Row[1][0]) / s; 
+                       z = (Row[0][2] + Row[2][0]) / s; 
+                       w = (Row[2][1] - Row[1][2]) / s;
+               }
+               else if(Row[1][1] > Row[2][2])
+               { 
+                       s = sqrt (static_cast<T>(1) + Row[1][1] - Row[0][0] - Row[2][2]) * static_cast<T>(2); // S=4*qy
+                       x = (Row[0][1] + Row[1][0]) / s; 
+                       y = static_cast<T>(0.25) * s;
+                       z = (Row[1][2] + Row[2][1]) / s; 
+                       w = (Row[0][2] - Row[2][0]) / s;
+               }
+               else
+               { 
+                       s = sqrt(static_cast<T>(1) + Row[2][2] - Row[0][0] - Row[1][1]) * static_cast<T>(2); // S=4*qz
+                       x = (Row[0][2] + Row[2][0]) / s;
+                       y = (Row[1][2] + Row[2][1]) / s; 
+                       z = static_cast<T>(0.25) * s;
+                       w = (Row[1][0] - Row[0][1]) / s;
+               }
+
+               Orientation.x = x;
+               Orientation.y = y;
+               Orientation.z = z;
+               Orientation.w = w;
+
+               return true;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_interpolation.hpp b/core/deps/glm/glm/gtx/matrix_interpolation.hpp
new file mode 100755 (executable)
index 0000000..77a69ea
--- /dev/null
@@ -0,0 +1,61 @@
+/// @ref gtx_matrix_interpolation
+/// @file glm/gtx/matrix_interpolation.hpp
+/// @author Ghenadii Ursachi (the.asteroth@gmail.com)
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_matrix_interpolation GLM_GTX_matrix_interpolation
+/// @ingroup gtx
+///
+/// @brief Allows to directly interpolate two exiciting matrices.
+///
+/// <glm/gtx/matrix_interpolation.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_interpolation extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_interpolation
+       /// @{
+
+       /// Get the axis and angle of the rotation from a matrix.
+       /// From GLM_GTX_matrix_interpolation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL void axisAngle(
+               tmat4x4<T, P> const & mat,
+               tvec3<T, P> & axis,
+               T & angle);
+
+       /// Build a matrix from axis and angle.
+       /// From GLM_GTX_matrix_interpolation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> axisAngleMatrix(
+               tvec3<T, P> const & axis,
+               T const angle);
+
+       /// Extracts the rotation part of a matrix.
+       /// From GLM_GTX_matrix_interpolation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> extractMatrixRotation(
+               tmat4x4<T, P> const & mat);
+
+       /// Build a interpolation of 4 * 4 matrixes.
+       /// From GLM_GTX_matrix_interpolation extension.
+       /// Warning! works only with rotation and/or translation matrixes, scale will generate unexpected results.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> interpolate(
+               tmat4x4<T, P> const & m1,
+               tmat4x4<T, P> const & m2,
+               T const delta);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_interpolation.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_interpolation.inl b/core/deps/glm/glm/gtx/matrix_interpolation.inl
new file mode 100755 (executable)
index 0000000..8645f96
--- /dev/null
@@ -0,0 +1,134 @@
+/// @ref gtx_matrix_interpolation
+/// @file glm/gtx/matrix_interpolation.hpp
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER void axisAngle
+       (
+               tmat4x4<T, P> const & mat,
+               tvec3<T, P> & axis,
+               T & angle
+       )
+       {
+               T epsilon = (T)0.01;
+               T epsilon2 = (T)0.1;
+
+               if((abs(mat[1][0] - mat[0][1]) < epsilon) && (abs(mat[2][0] - mat[0][2]) < epsilon) && (abs(mat[2][1] - mat[1][2]) < epsilon))
+               {
+                       if ((abs(mat[1][0] + mat[0][1]) < epsilon2) && (abs(mat[2][0] + mat[0][2]) < epsilon2) && (abs(mat[2][1] + mat[1][2]) < epsilon2) && (abs(mat[0][0] + mat[1][1] + mat[2][2] - (T)3.0) < epsilon2))
+                       {
+                               angle = (T)0.0;
+                               axis.x = (T)1.0;
+                               axis.y = (T)0.0;
+                               axis.z = (T)0.0;
+                               return;
+                       }
+                       angle = static_cast<T>(3.1415926535897932384626433832795);
+                       T xx = (mat[0][0] + (T)1.0) / (T)2.0;
+                       T yy = (mat[1][1] + (T)1.0) / (T)2.0;
+                       T zz = (mat[2][2] + (T)1.0) / (T)2.0;
+                       T xy = (mat[1][0] + mat[0][1]) / (T)4.0;
+                       T xz = (mat[2][0] + mat[0][2]) / (T)4.0;
+                       T yz = (mat[2][1] + mat[1][2]) / (T)4.0;
+                       if((xx > yy) && (xx > zz))
+                       {
+                               if (xx < epsilon) {
+                                       axis.x = (T)0.0;
+                                       axis.y = (T)0.7071;
+                                       axis.z = (T)0.7071;
+                               } else {
+                                       axis.x = sqrt(xx);
+                                       axis.y = xy / axis.x;
+                                       axis.z = xz / axis.x;
+                               }
+                       }
+                       else if (yy > zz)
+                       {
+                               if (yy < epsilon) {
+                                       axis.x = (T)0.7071;
+                                       axis.y = (T)0.0;
+                                       axis.z = (T)0.7071;
+                               } else {
+                                       axis.y = sqrt(yy);
+                                       axis.x = xy / axis.y;
+                                       axis.z = yz / axis.y;
+                               }
+                       }
+                       else
+                       {
+                               if (zz < epsilon) {
+                                       axis.x = (T)0.7071;
+                                       axis.y = (T)0.7071;
+                                       axis.z = (T)0.0;
+                               } else {
+                                       axis.z = sqrt(zz);
+                                       axis.x = xz / axis.z;
+                                       axis.y = yz / axis.z;
+                               }
+                       }
+                       return;
+               }
+               T s = sqrt((mat[2][1] - mat[1][2]) * (mat[2][1] - mat[1][2]) + (mat[2][0] - mat[0][2]) * (mat[2][0] - mat[0][2]) + (mat[1][0] - mat[0][1]) * (mat[1][0] - mat[0][1]));
+               if (glm::abs(s) < T(0.001))
+                       s = (T)1.0;
+               angle = acos((mat[0][0] + mat[1][1] + mat[2][2] - (T)1.0) / (T)2.0);
+               axis.x = (mat[1][2] - mat[2][1]) / s;
+               axis.y = (mat[2][0] - mat[0][2]) / s;
+               axis.z = (mat[0][1] - mat[1][0]) / s;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> axisAngleMatrix
+       (
+               tvec3<T, P> const & axis,
+               T const angle
+       )
+       {
+               T c = cos(angle);
+               T s = sin(angle);
+               T t = static_cast<T>(1) - c;
+               tvec3<T, P> n = normalize(axis);
+
+               return tmat4x4<T, P>(
+                       t * n.x * n.x + c,          t * n.x * n.y + n.z * s,    t * n.x * n.z - n.y * s,    T(0),
+                       t * n.x * n.y - n.z * s,    t * n.y * n.y + c,          t * n.y * n.z + n.x * s,    T(0),
+                       t * n.x * n.z + n.y * s,    t * n.y * n.z - n.x * s,    t * n.z * n.z + c,          T(0),
+                       T(0),                        T(0),                        T(0),                     T(1)
+               );
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> extractMatrixRotation
+       (
+               tmat4x4<T, P> const & mat
+       )
+       {
+               return tmat4x4<T, P>(
+                       mat[0][0], mat[0][1], mat[0][2], 0.0,
+                       mat[1][0], mat[1][1], mat[1][2], 0.0,
+                       mat[2][0], mat[2][1], mat[2][2], 0.0,
+                       0.0,       0.0,       0.0,       1.0
+               );
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> interpolate
+       (
+               tmat4x4<T, P> const & m1,
+               tmat4x4<T, P> const & m2,
+               T const delta
+       )
+       {
+               tmat4x4<T, P> m1rot = extractMatrixRotation(m1);
+               tmat4x4<T, P> dltRotation = m2 * transpose(m1rot);
+               tvec3<T, P> dltAxis;
+               T dltAngle;
+               axisAngle(dltRotation, dltAxis, dltAngle);
+               tmat4x4<T, P> out = axisAngleMatrix(dltAxis, dltAngle * delta) * m1rot;
+               out[3][0] = m1[3][0] + delta * (m2[3][0] - m1[3][0]);
+               out[3][1] = m1[3][1] + delta * (m2[3][1] - m1[3][1]);
+               out[3][2] = m1[3][2] + delta * (m2[3][2] - m1[3][2]);
+               return out;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_major_storage.hpp b/core/deps/glm/glm/gtx/matrix_major_storage.hpp
new file mode 100755 (executable)
index 0000000..9402abe
--- /dev/null
@@ -0,0 +1,115 @@
+/// @ref gtx_matrix_major_storage
+/// @file glm/gtx/matrix_major_storage.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_matrix_major_storage GLM_GTX_matrix_major_storage
+/// @ingroup gtx
+///
+/// @brief Build matrices with specific matrix order, row or column
+///
+/// <glm/gtx/matrix_major_storage.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_major_storage extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_major_storage
+       /// @{
+
+       //! Build a row major matrix from row vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> rowMajor2(
+               tvec2<T, P> const & v1, 
+               tvec2<T, P> const & v2);
+               
+       //! Build a row major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> rowMajor2(
+               tmat2x2<T, P> const & m);
+
+       //! Build a row major matrix from row vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> rowMajor3(
+               tvec3<T, P> const & v1, 
+               tvec3<T, P> const & v2, 
+               tvec3<T, P> const & v3);
+
+       //! Build a row major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> rowMajor3(
+               tmat3x3<T, P> const & m);
+
+       //! Build a row major matrix from row vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> rowMajor4(
+               tvec4<T, P> const & v1, 
+               tvec4<T, P> const & v2,
+               tvec4<T, P> const & v3, 
+               tvec4<T, P> const & v4);
+
+       //! Build a row major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> rowMajor4(
+               tmat4x4<T, P> const & m);
+
+       //! Build a column major matrix from column vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> colMajor2(
+               tvec2<T, P> const & v1, 
+               tvec2<T, P> const & v2);
+               
+       //! Build a column major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> colMajor2(
+               tmat2x2<T, P> const & m);
+
+       //! Build a column major matrix from column vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> colMajor3(
+               tvec3<T, P> const & v1, 
+               tvec3<T, P> const & v2, 
+               tvec3<T, P> const & v3);
+               
+       //! Build a column major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> colMajor3(
+               tmat3x3<T, P> const & m);
+               
+       //! Build a column major matrix from column vectors.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> colMajor4(
+               tvec4<T, P> const & v1, 
+               tvec4<T, P> const & v2, 
+               tvec4<T, P> const & v3, 
+               tvec4<T, P> const & v4);
+                               
+       //! Build a column major matrix from other matrix.
+       //! From GLM_GTX_matrix_major_storage extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat4x4<T, P> colMajor4(
+               tmat4x4<T, P> const & m);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_major_storage.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_major_storage.inl b/core/deps/glm/glm/gtx/matrix_major_storage.inl
new file mode 100755 (executable)
index 0000000..7097739
--- /dev/null
@@ -0,0 +1,167 @@
+/// @ref gtx_matrix_major_storage
+/// @file glm/gtx/matrix_major_storage.hpp
+
+namespace glm
+{
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> rowMajor2
+       (
+               tvec2<T, P> const & v1, 
+               tvec2<T, P> const & v2
+       )
+       {
+               tmat2x2<T, P> Result;
+               Result[0][0] = v1.x;
+               Result[1][0] = v1.y;
+               Result[0][1] = v2.x;
+               Result[1][1] = v2.y;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> rowMajor2(
+               const tmat2x2<T, P>& m)
+       {
+               tmat2x2<T, P> Result;
+               Result[0][0] = m[0][0];
+               Result[0][1] = m[1][0];
+               Result[1][0] = m[0][1];
+               Result[1][1] = m[1][1];
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> rowMajor3(
+               const tvec3<T, P>& v1, 
+               const tvec3<T, P>& v2, 
+               const tvec3<T, P>& v3)
+       {
+               tmat3x3<T, P> Result;
+               Result[0][0] = v1.x;
+               Result[1][0] = v1.y;
+               Result[2][0] = v1.z;
+               Result[0][1] = v2.x;
+               Result[1][1] = v2.y;
+               Result[2][1] = v2.z;
+               Result[0][2] = v3.x;
+               Result[1][2] = v3.y;
+               Result[2][2] = v3.z;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> rowMajor3(
+               const tmat3x3<T, P>& m)
+       {
+               tmat3x3<T, P> Result;
+               Result[0][0] = m[0][0];
+               Result[0][1] = m[1][0];
+               Result[0][2] = m[2][0];
+               Result[1][0] = m[0][1];
+               Result[1][1] = m[1][1];
+               Result[1][2] = m[2][1];
+               Result[2][0] = m[0][2];
+               Result[2][1] = m[1][2];
+               Result[2][2] = m[2][2];
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rowMajor4(
+               const tvec4<T, P>& v1, 
+               const tvec4<T, P>& v2, 
+               const tvec4<T, P>& v3, 
+               const tvec4<T, P>& v4)
+       {
+               tmat4x4<T, P> Result;
+               Result[0][0] = v1.x;
+               Result[1][0] = v1.y;
+               Result[2][0] = v1.z;
+               Result[3][0] = v1.w;
+               Result[0][1] = v2.x;
+               Result[1][1] = v2.y;
+               Result[2][1] = v2.z;
+               Result[3][1] = v2.w;
+               Result[0][2] = v3.x;
+               Result[1][2] = v3.y;
+               Result[2][2] = v3.z;
+               Result[3][2] = v3.w;
+               Result[0][3] = v4.x;
+               Result[1][3] = v4.y;
+               Result[2][3] = v4.z;
+               Result[3][3] = v4.w;
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rowMajor4(
+               const tmat4x4<T, P>& m)
+       {
+               tmat4x4<T, P> Result;
+               Result[0][0] = m[0][0];
+               Result[0][1] = m[1][0];
+               Result[0][2] = m[2][0];
+               Result[0][3] = m[3][0];
+               Result[1][0] = m[0][1];
+               Result[1][1] = m[1][1];
+               Result[1][2] = m[2][1];
+               Result[1][3] = m[3][1];
+               Result[2][0] = m[0][2];
+               Result[2][1] = m[1][2];
+               Result[2][2] = m[2][2];
+               Result[2][3] = m[3][2];
+               Result[3][0] = m[0][3];
+               Result[3][1] = m[1][3];
+               Result[3][2] = m[2][3];
+               Result[3][3] = m[3][3];
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> colMajor2(
+               const tvec2<T, P>& v1, 
+               const tvec2<T, P>& v2)
+       {
+               return tmat2x2<T, P>(v1, v2);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> colMajor2(
+               const tmat2x2<T, P>& m)
+       {
+               return tmat2x2<T, P>(m);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> colMajor3(
+               const tvec3<T, P>& v1, 
+               const tvec3<T, P>& v2, 
+               const tvec3<T, P>& v3)
+       {
+               return tmat3x3<T, P>(v1, v2, v3);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> colMajor3(
+               const tmat3x3<T, P>& m)
+       {
+               return tmat3x3<T, P>(m);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> colMajor4(
+               const tvec4<T, P>& v1, 
+               const tvec4<T, P>& v2, 
+               const tvec4<T, P>& v3, 
+               const tvec4<T, P>& v4)
+       {
+               return tmat4x4<T, P>(v1, v2, v3, v4);
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> colMajor4(
+               const tmat4x4<T, P>& m)
+       {
+               return tmat4x4<T, P>(m);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_operation.hpp b/core/deps/glm/glm/gtx/matrix_operation.hpp
new file mode 100755 (executable)
index 0000000..3192ae5
--- /dev/null
@@ -0,0 +1,84 @@
+/// @ref gtx_matrix_operation
+/// @file glm/gtx/matrix_operation.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_matrix_operation GLM_GTX_matrix_operation
+/// @ingroup gtx
+///
+/// @brief Build diagonal matrices from vectors.
+///
+/// <glm/gtx/matrix_operation.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_operation extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_operation
+       /// @{
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x2<T, P> diagonal2x2(
+               tvec2<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x3<T, P> diagonal2x3(
+               tvec2<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat2x4<T, P> diagonal2x4(
+               tvec2<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x2<T, P> diagonal3x2(
+               tvec2<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> diagonal3x3(
+               tvec3<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x4<T, P> diagonal3x4(
+               tvec3<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x2<T, P> diagonal4x2(
+               tvec2<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x3<T, P> diagonal4x3(
+               tvec3<T, P> const & v);
+
+       //! Build a diagonal matrix.
+       //! From GLM_GTX_matrix_operation extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> diagonal4x4(
+               tvec4<T, P> const & v);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_operation.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_operation.inl b/core/deps/glm/glm/gtx/matrix_operation.inl
new file mode 100755 (executable)
index 0000000..1553215
--- /dev/null
@@ -0,0 +1,118 @@
+/// @ref gtx_matrix_operation
+/// @file glm/gtx/matrix_operation.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x2<T, P> diagonal2x2
+       (
+               tvec2<T, P> const & v
+       )
+       {
+               tmat2x2<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x3<T, P> diagonal2x3
+       (
+               tvec2<T, P> const & v
+       )
+       {
+               tmat2x3<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat2x4<T, P> diagonal2x4
+       (
+               tvec2<T, P> const & v
+       )
+       {
+               tmat2x4<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x2<T, P> diagonal3x2
+       (
+               tvec2<T, P> const & v
+       )
+       {
+               tmat3x2<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> diagonal3x3
+       (
+               tvec3<T, P> const & v
+       )
+       {
+               tmat3x3<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               Result[2][2] = v[2];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x4<T, P> diagonal3x4
+       (
+               tvec3<T, P> const & v
+       )
+       {
+               tmat3x4<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               Result[2][2] = v[2];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> diagonal4x4
+       (
+               tvec4<T, P> const & v
+       )
+       {
+               tmat4x4<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               Result[2][2] = v[2];
+               Result[3][3] = v[3];
+               return Result;          
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x3<T, P> diagonal4x3
+       (
+               tvec3<T, P> const & v
+       )
+       {
+               tmat4x3<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               Result[2][2] = v[2];
+               return Result;          
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x2<T, P> diagonal4x2
+       (
+               tvec2<T, P> const & v
+       )
+       {
+               tmat4x2<T, P> Result(static_cast<T>(1));
+               Result[0][0] = v[0];
+               Result[1][1] = v[1];
+               return Result;          
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_query.hpp b/core/deps/glm/glm/gtx/matrix_query.hpp
new file mode 100755 (executable)
index 0000000..2518274
--- /dev/null
@@ -0,0 +1,73 @@
+/// @ref gtx_matrix_query
+/// @file glm/gtx/matrix_query.hpp
+///
+/// @see core (dependence)
+/// @see gtx_vector_query (dependence)
+///
+/// @defgroup gtx_matrix_query GLM_GTX_matrix_query
+/// @ingroup gtx
+///
+/// @brief Query to evaluate matrix properties
+///
+/// <glm/gtx/matrix_query.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/vector_query.hpp"
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_query extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_query
+       /// @{
+
+       /// Return whether a matrix a null matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNull(tmat2x2<T, P> const & m, T const & epsilon);
+               
+       /// Return whether a matrix a null matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNull(tmat3x3<T, P> const & m, T const & epsilon);
+               
+       /// Return whether a matrix is a null matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNull(tmat4x4<T, P> const & m, T const & epsilon);
+                       
+       /// Return whether a matrix is an identity matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL bool isIdentity(matType<T, P> const & m, T const & epsilon);
+
+       /// Return whether a matrix is a normalized matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNormalized(tmat2x2<T, P> const & m, T const & epsilon);
+
+       /// Return whether a matrix is a normalized matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNormalized(tmat3x3<T, P> const & m, T const & epsilon);
+
+       /// Return whether a matrix is a normalized matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P>
+       GLM_FUNC_DECL bool isNormalized(tmat4x4<T, P> const & m, T const & epsilon);
+
+       /// Return whether a matrix is an orthonormalized matrix.
+       /// From GLM_GTX_matrix_query extension.
+       template<typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_DECL bool isOrthogonal(matType<T, P> const & m, T const & epsilon);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_query.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_query.inl b/core/deps/glm/glm/gtx/matrix_query.inl
new file mode 100755 (executable)
index 0000000..491b774
--- /dev/null
@@ -0,0 +1,114 @@
+/// @ref gtx_matrix_query
+/// @file glm/gtx/matrix_query.inl
+
+namespace glm
+{
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNull(tmat2x2<T, P> const & m, T const & epsilon)
+       {
+               bool result = true;
+               for(length_t i = 0; result && i < m.length() ; ++i)
+                       result = isNull(m[i], epsilon);
+               return result;
+       }
+
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNull(tmat3x3<T, P> const & m, T const & epsilon)
+       {
+               bool result = true;
+               for(length_t i = 0; result && i < m.length() ; ++i)
+                       result = isNull(m[i], epsilon);
+               return result;
+       }
+
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNull(tmat4x4<T, P> const & m, T const & epsilon)
+       {
+               bool result = true;
+               for(length_t i = 0; result && i < m.length() ; ++i)
+                       result = isNull(m[i], epsilon);
+               return result;
+       }
+
+       template<typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER bool isIdentity(matType<T, P> const & m, T const & epsilon)
+       {
+               bool result = true;
+               for(length_t i = 0; result && i < m[0].length() ; ++i)
+               {
+                       for(length_t j = 0; result && j < i ; ++j)
+                               result = abs(m[i][j]) <= epsilon;
+                       if(result)
+                               result = abs(m[i][i] - 1) <= epsilon;
+                       for(length_t j = i + 1; result && j < m.length(); ++j)
+                               result = abs(m[i][j]) <= epsilon;
+               }
+               return result;
+       }
+
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNormalized(tmat2x2<T, P> const & m, T const & epsilon)
+       {
+               bool result(true);
+               for(length_t i = 0; result && i < m.length(); ++i)
+                       result = isNormalized(m[i], epsilon);
+               for(length_t i = 0; result && i < m.length(); ++i)
+               {
+                       typename tmat2x2<T, P>::col_type v;
+                       for(length_t j = 0; j < m.length(); ++j)
+                               v[j] = m[j][i];
+                       result = isNormalized(v, epsilon);
+               }
+               return result;
+       }
+
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNormalized(tmat3x3<T, P> const & m, T const & epsilon)
+       {
+               bool result(true);
+               for(length_t i = 0; result && i < m.length(); ++i)
+                       result = isNormalized(m[i], epsilon);
+               for(length_t i = 0; result && i < m.length(); ++i)
+               {
+                       typename tmat3x3<T, P>::col_type v;
+                       for(length_t j = 0; j < m.length(); ++j)
+                               v[j] = m[j][i];
+                       result = isNormalized(v, epsilon);
+               }
+               return result;
+       }
+
+       template<typename T, precision P>
+       GLM_FUNC_QUALIFIER bool isNormalized(tmat4x4<T, P> const & m, T const & epsilon)
+       {
+               bool result(true);
+               for(length_t i = 0; result && i < m.length(); ++i)
+                       result = isNormalized(m[i], epsilon);
+               for(length_t i = 0; result && i < m.length(); ++i)
+               {
+                       typename tmat4x4<T, P>::col_type v;
+                       for(length_t j = 0; j < m.length(); ++j)
+                               v[j] = m[j][i];
+                       result = isNormalized(v, epsilon);
+               }
+               return result;
+       }
+
+       template<typename T, precision P, template <typename, precision> class matType>
+       GLM_FUNC_QUALIFIER bool isOrthogonal(matType<T, P> const & m, T const & epsilon)
+       {
+               bool result(true);
+               for(length_t i(0); result && i < m.length() - 1; ++i)
+               for(length_t j(i + 1); result && j < m.length(); ++j)
+                       result = areOrthogonal(m[i], m[j], epsilon);
+
+               if(result)
+               {
+                       matType<T, P> tmp = transpose(m);
+                       for(length_t i(0); result && i < m.length() - 1 ; ++i)
+                       for(length_t j(i + 1); result && j < m.length(); ++j)
+                               result = areOrthogonal(tmp[i], tmp[j], epsilon);
+               }
+               return result;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/matrix_transform_2d.hpp b/core/deps/glm/glm/gtx/matrix_transform_2d.hpp
new file mode 100755 (executable)
index 0000000..91f4834
--- /dev/null
@@ -0,0 +1,78 @@
+/// @ref gtx_matrix_transform_2d
+/// @file glm/gtx/matrix_transform_2d.hpp
+/// @author Miguel Ángel Pérez Martínez
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_matrix_transform_2d GLM_GTX_matrix_transform_2d
+/// @ingroup gtx
+///
+/// @brief Defines functions that generate common 2d transformation matrices.
+///
+/// <glm/gtx/matrix_transform_2d.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../mat3x3.hpp"
+#include "../vec2.hpp"
+
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_matrix_transform_2d extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_matrix_transform_2d
+       /// @{
+       
+       /// Builds a translation 3 * 3 matrix created from a vector of 2 components.
+       ///
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param v Coordinates of a translation vector.               
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> translate(
+               tmat3x3<T, P> const & m,
+               tvec2<T, P> const & v);
+
+       /// Builds a rotation 3 * 3 matrix created from an angle. 
+       ///
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param angle Rotation angle expressed in radians if GLM_FORCE_RADIANS is defined or degrees otherwise.
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> rotate(
+               tmat3x3<T, P> const & m,
+               T angle);
+
+       /// Builds a scale 3 * 3 matrix created from a vector of 2 components.
+       ///
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param v Coordinates of a scale vector.             
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> scale(
+               tmat3x3<T, P> const & m,
+               tvec2<T, P> const & v);
+
+       /// Builds an horizontal (parallel to the x axis) shear 3 * 3 matrix. 
+       ///
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param y Shear factor.
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearX(
+               tmat3x3<T, P> const & m,
+               T y);
+
+       /// Builds a vertical (parallel to the y axis) shear 3 * 3 matrix. 
+       ///
+       /// @param m Input matrix multiplied by this translation matrix.
+       /// @param x Shear factor.
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearY(
+               tmat3x3<T, P> const & m,
+               T x);
+
+       /// @}
+}//namespace glm
+
+#include "matrix_transform_2d.inl"
diff --git a/core/deps/glm/glm/gtx/matrix_transform_2d.inl b/core/deps/glm/glm/gtx/matrix_transform_2d.inl
new file mode 100755 (executable)
index 0000000..bea5670
--- /dev/null
@@ -0,0 +1,69 @@
+/// @ref gtx_matrix_transform_2d
+/// @file glm/gtc/matrix_transform_2d.inl
+/// @author Miguel Ángel Pérez Martínez
+
+#include "../trigonometric.hpp"
+
+namespace glm
+{
+       
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> translate(
+               tmat3x3<T, P> const & m,
+               tvec2<T, P> const & v)
+       {
+               tmat3x3<T, P> Result(m);
+               Result[2] = m[0] * v[0] + m[1] * v[1] + m[2];
+               return Result;
+       }
+
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> rotate(
+               tmat3x3<T, P> const & m,
+               T angle)
+       {
+               T const a = angle;
+               T const c = cos(a);
+               T const s = sin(a);
+
+               tmat3x3<T, P> Result(uninitialize);
+               Result[0] = m[0] * c + m[1] * s;
+               Result[1] = m[0] * -s + m[1] * c;
+               Result[2] = m[2];
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> scale(
+               tmat3x3<T, P> const & m,
+               tvec2<T, P> const & v)
+       {
+               tmat3x3<T, P> Result(uninitialize);
+               Result[0] = m[0] * v[0];
+               Result[1] = m[1] * v[1];
+               Result[2] = m[2];
+               return Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearX(
+               tmat3x3<T, P> const & m,
+               T y)
+       {
+               tmat3x3<T, P> Result(1);
+               Result[0][1] = y;
+               return m * Result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearY(
+               tmat3x3<T, P> const & m,
+               T x)
+       {
+               tmat3x3<T, P> Result(1);
+               Result[1][0] = x;
+               return m * Result;
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/mixed_product.hpp b/core/deps/glm/glm/gtx/mixed_product.hpp
new file mode 100755 (executable)
index 0000000..65861f7
--- /dev/null
@@ -0,0 +1,37 @@
+/// @ref gtx_mixed_product
+/// @file glm/gtx/mixed_product.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_mixed_product GLM_GTX_mixed_producte
+/// @ingroup gtx
+///
+/// @brief Mixed product of 3 vectors.
+///
+/// <glm/gtx/mixed_product.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_mixed_product extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_mixed_product
+       /// @{
+
+       /// @brief Mixed product of 3 vectors (from GLM_GTX_mixed_product extension)
+       template <typename T, precision P> 
+       GLM_FUNC_DECL T mixedProduct(
+               tvec3<T, P> const & v1, 
+               tvec3<T, P> const & v2, 
+               tvec3<T, P> const & v3);
+
+       /// @}
+}// namespace glm
+
+#include "mixed_product.inl"
diff --git a/core/deps/glm/glm/gtx/mixed_product.inl b/core/deps/glm/glm/gtx/mixed_product.inl
new file mode 100755 (executable)
index 0000000..a6ede59
--- /dev/null
@@ -0,0 +1,16 @@
+/// @ref gtx_mixed_product
+/// @file glm/gtx/mixed_product.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T mixedProduct
+       (
+               tvec3<T, P> const & v1,
+               tvec3<T, P> const & v2,
+               tvec3<T, P> const & v3
+       )
+       {
+               return dot(cross(v1, v2), v3);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/norm.hpp b/core/deps/glm/glm/gtx/norm.hpp
new file mode 100755 (executable)
index 0000000..b3cb528
--- /dev/null
@@ -0,0 +1,86 @@
+/// @ref gtx_norm
+/// @file glm/gtx/norm.hpp
+///
+/// @see core (dependence)
+/// @see gtx_quaternion (dependence)
+///
+/// @defgroup gtx_norm GLM_GTX_norm
+/// @ingroup gtx
+///
+/// @brief Various ways to compute vector norms.
+/// 
+/// <glm/gtx/norm.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../detail/func_geometric.hpp"
+#include "../gtx/quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_norm extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_norm
+       /// @{
+
+       /// Returns the squared length of x.
+       /// From GLM_GTX_norm extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T length2(
+               vecType<T, P> const & x);
+
+       /// Returns the squared distance between p0 and p1, i.e., length2(p0 - p1).
+       /// From GLM_GTX_norm extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T distance2(
+               vecType<T, P> const & p0,
+               vecType<T, P> const & p1);
+
+       //! Returns the L1 norm between x and y.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T l1Norm(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y);
+               
+       //! Returns the L1 norm of v.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T l1Norm(
+               tvec3<T, P> const & v);
+               
+       //! Returns the L2 norm between x and y.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T l2Norm(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y);
+               
+       //! Returns the L2 norm of v.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T l2Norm(
+               tvec3<T, P> const & x);
+               
+       //! Returns the L norm between x and y.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T lxNorm(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               unsigned int Depth);
+
+       //! Returns the L norm of v.
+       //! From GLM_GTX_norm extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T lxNorm(
+               tvec3<T, P> const & x,
+               unsigned int Depth);
+
+       /// @}
+}//namespace glm
+
+#include "norm.inl"
diff --git a/core/deps/glm/glm/gtx/norm.inl b/core/deps/glm/glm/gtx/norm.inl
new file mode 100755 (executable)
index 0000000..20954ec
--- /dev/null
@@ -0,0 +1,106 @@
+/// @ref gtx_norm
+/// @file glm/gtx/norm.inl
+
+#include "../detail/precision.hpp"
+
+namespace glm{
+namespace detail
+{
+       template <template <typename, precision> class vecType, typename T, precision P, bool Aligned>
+       struct compute_length2
+       {
+               GLM_FUNC_QUALIFIER static T call(vecType<T, P> const & v)
+               {
+                       return dot(v, v);
+               }
+       };
+}//namespace detail
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType length2(genType x)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'length2' accepts only floating-point inputs");
+               return x * x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T length2(vecType<T, P> const & v)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'length2' accepts only floating-point inputs");
+               return detail::compute_length2<vecType, T, P, detail::is_aligned<P>::value>::call(v);
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER T distance2(T p0, T p1)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'distance2' accepts only floating-point inputs");
+               return length2(p1 - p0);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T distance2(vecType<T, P> const & p0, vecType<T, P> const & p1)
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'distance2' accepts only floating-point inputs");
+               return length2(p1 - p0);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T l1Norm
+       (
+               tvec3<T, P> const & a,
+               tvec3<T, P> const & b
+       )
+       {
+               return abs(b.x - a.x) + abs(b.y - a.y) + abs(b.z - a.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T l1Norm
+       (
+               tvec3<T, P> const & v
+       )
+       {
+               return abs(v.x) + abs(v.y) + abs(v.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T l2Norm
+       (
+               tvec3<T, P> const & a,
+               tvec3<T, P> const & b
+       )
+       {
+               return length(b - a);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T l2Norm
+       (
+               tvec3<T, P> const & v
+       )
+       {
+               return length(v);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T lxNorm
+       (
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               unsigned int Depth
+       )
+       {
+               return pow(pow(y.x - x.x, T(Depth)) + pow(y.y - x.y, T(Depth)) + pow(y.z - x.z, T(Depth)), T(1) / T(Depth));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T lxNorm
+       (
+               tvec3<T, P> const & v,
+               unsigned int Depth
+       )
+       {
+               return pow(pow(v.x, T(Depth)) + pow(v.y, T(Depth)) + pow(v.z, T(Depth)), T(1) / T(Depth));
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/normal.hpp b/core/deps/glm/glm/gtx/normal.hpp
new file mode 100755 (executable)
index 0000000..2e0044e
--- /dev/null
@@ -0,0 +1,39 @@
+/// @ref gtx_normal
+/// @file glm/gtx/normal.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_normal GLM_GTX_normal
+/// @ingroup gtx
+///
+/// @brief Compute the normal of a triangle.
+///
+/// <glm/gtx/normal.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_normal extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_normal
+       /// @{
+
+       //! Computes triangle normal from triangle points. 
+       //! From GLM_GTX_normal extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tvec3<T, P> triangleNormal(
+               tvec3<T, P> const & p1, 
+               tvec3<T, P> const & p2, 
+               tvec3<T, P> const & p3);
+
+       /// @}
+}//namespace glm
+
+#include "normal.inl"
diff --git a/core/deps/glm/glm/gtx/normal.inl b/core/deps/glm/glm/gtx/normal.inl
new file mode 100755 (executable)
index 0000000..e442317
--- /dev/null
@@ -0,0 +1,16 @@
+/// @ref gtx_normal
+/// @file glm/gtx/normal.inl
+
+namespace glm
+{
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> triangleNormal
+       (
+               tvec3<T, P> const & p1, 
+               tvec3<T, P> const & p2, 
+               tvec3<T, P> const & p3
+       )
+       {
+               return normalize(cross(p1 - p2, p1 - p3));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/normalize_dot.hpp b/core/deps/glm/glm/gtx/normalize_dot.hpp
new file mode 100755 (executable)
index 0000000..de650d3
--- /dev/null
@@ -0,0 +1,45 @@
+/// @ref gtx_normalize_dot
+/// @file glm/gtx/normalize_dot.hpp
+///
+/// @see core (dependence)
+/// @see gtx_fast_square_root (dependence)
+///
+/// @defgroup gtx_normalize_dot GLM_GTX_normalize_dot
+/// @ingroup gtx
+///
+/// @brief Dot product of vectors that need to be normalize with a single square root.
+///
+/// <glm/gtx/normalized_dot.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../gtx/fast_square_root.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_normalize_dot extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_normalize_dot
+       /// @{
+
+       /// Normalize parameters and returns the dot product of x and y.
+       /// It's faster that dot(normalize(x), normalize(y)).
+       ///
+       /// @see gtx_normalize_dot extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T normalizeDot(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// Normalize parameters and returns the dot product of x and y.
+       /// Faster that dot(fastNormalize(x), fastNormalize(y)).
+       ///
+       /// @see gtx_normalize_dot extension.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL T fastNormalizeDot(vecType<T, P> const & x, vecType<T, P> const & y);
+
+       /// @}
+}//namespace glm
+
+#include "normalize_dot.inl"
diff --git a/core/deps/glm/glm/gtx/normalize_dot.inl b/core/deps/glm/glm/gtx/normalize_dot.inl
new file mode 100755 (executable)
index 0000000..0d01ffe
--- /dev/null
@@ -0,0 +1,17 @@
+/// @ref gtx_normalize_dot
+/// @file glm/gtx/normalize_dot.inl
+
+namespace glm
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T normalizeDot(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return glm::dot(x, y) * glm::inversesqrt(glm::dot(x, x) * glm::dot(y, y));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER T fastNormalizeDot(vecType<T, P> const & x, vecType<T, P> const & y)
+       {
+               return glm::dot(x, y) * glm::fastInverseSqrt(glm::dot(x, x) * glm::dot(y, y));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/number_precision.hpp b/core/deps/glm/glm/gtx/number_precision.hpp
new file mode 100755 (executable)
index 0000000..736d035
--- /dev/null
@@ -0,0 +1,57 @@
+/// @ref gtx_number_precision
+/// @file glm/gtx/number_precision.hpp
+///
+/// @see core (dependence)
+/// @see gtc_type_precision (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtx_number_precision GLM_GTX_number_precision
+/// @ingroup gtx
+///
+/// @brief Defined size types.
+///
+/// <glm/gtx/number_precision.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/type_precision.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_number_precision extension included")
+#endif
+
+namespace glm{
+namespace gtx
+{
+       /////////////////////////////
+       // Unsigned int vector types 
+
+       /// @addtogroup gtx_number_precision
+       /// @{
+
+       typedef u8                      u8vec1;         //!< \brief 8bit unsigned integer scalar. (from GLM_GTX_number_precision extension)
+       typedef u16                     u16vec1;    //!< \brief 16bit unsigned integer scalar. (from GLM_GTX_number_precision extension)
+       typedef u32                     u32vec1;    //!< \brief 32bit unsigned integer scalar. (from GLM_GTX_number_precision extension)
+       typedef u64                     u64vec1;    //!< \brief 64bit unsigned integer scalar. (from GLM_GTX_number_precision extension)
+
+       //////////////////////
+       // Float vector types 
+
+       typedef f32                     f32vec1;    //!< \brief Single-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+       typedef f64                     f64vec1;    //!< \brief Single-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+
+       //////////////////////
+       // Float matrix types 
+
+       typedef f32                     f32mat1;        //!< \brief Single-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+       typedef f32                     f32mat1x1;      //!< \brief Single-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+       typedef f64                     f64mat1;        //!< \brief Double-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+       typedef f64                     f64mat1x1;      //!< \brief Double-precision floating-point scalar. (from GLM_GTX_number_precision extension)
+
+       /// @}
+}//namespace gtx
+}//namespace glm
+
+#include "number_precision.inl"
diff --git a/core/deps/glm/glm/gtx/number_precision.inl b/core/deps/glm/glm/gtx/number_precision.inl
new file mode 100755 (executable)
index 0000000..b54cf66
--- /dev/null
@@ -0,0 +1,7 @@
+/// @ref gtx_number_precision
+/// @file glm/gtx/number_precision.inl
+
+namespace glm
+{
+
+}
diff --git a/core/deps/glm/glm/gtx/optimum_pow.hpp b/core/deps/glm/glm/gtx/optimum_pow.hpp
new file mode 100755 (executable)
index 0000000..e9510c4
--- /dev/null
@@ -0,0 +1,50 @@
+/// @ref gtx_optimum_pow
+/// @file glm/gtx/optimum_pow.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_optimum_pow GLM_GTX_optimum_pow
+/// @ingroup gtx
+///
+/// @brief Integer exponentiation of power functions.
+///
+/// <glm/gtx/optimum_pow.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_optimum_pow extension included")
+#endif
+
+namespace glm{
+namespace gtx
+{
+       /// @addtogroup gtx_optimum_pow
+       /// @{
+
+       /// Returns x raised to the power of 2.
+       ///
+       /// @see gtx_optimum_pow
+       template <typename genType>
+       GLM_FUNC_DECL genType pow2(genType const & x);
+
+       /// Returns x raised to the power of 3.
+       ///
+       /// @see gtx_optimum_pow
+       template <typename genType>
+       GLM_FUNC_DECL genType pow3(genType const & x);
+
+       /// Returns x raised to the power of 4.
+       ///
+       /// @see gtx_optimum_pow
+       template <typename genType>
+       GLM_FUNC_DECL genType pow4(genType const & x);
+
+       /// @}
+}//namespace gtx
+}//namespace glm
+
+#include "optimum_pow.inl"
diff --git a/core/deps/glm/glm/gtx/optimum_pow.inl b/core/deps/glm/glm/gtx/optimum_pow.inl
new file mode 100755 (executable)
index 0000000..2216a74
--- /dev/null
@@ -0,0 +1,23 @@
+/// @ref gtx_optimum_pow
+/// @file glm/gtx/optimum_pow.inl
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType pow2(genType const & x)
+       {
+               return x * x;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType pow3(genType const & x)
+       {
+               return x * x * x;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType pow4(genType const & x)
+       {
+               return (x * x) * (x * x);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/orthonormalize.hpp b/core/deps/glm/glm/gtx/orthonormalize.hpp
new file mode 100755 (executable)
index 0000000..4bea449
--- /dev/null
@@ -0,0 +1,45 @@
+/// @ref gtx_orthonormalize
+/// @file glm/gtx/orthonormalize.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_orthonormalize GLM_GTX_orthonormalize
+/// @ingroup gtx
+///
+/// @brief Orthonormalize matrices.
+///
+/// <glm/gtx/orthonormalize.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../vec3.hpp"
+#include "../mat3x3.hpp"
+#include "../geometric.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_orthonormalize extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_orthonormalize
+       /// @{
+
+       /// Returns the orthonormalized matrix of m.
+       ///
+       /// @see gtx_orthonormalize
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat3x3<T, P> orthonormalize(tmat3x3<T, P> const & m);
+               
+       /// Orthonormalizes x according y.
+       ///
+       /// @see gtx_orthonormalize
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tvec3<T, P> orthonormalize(tvec3<T, P> const & x, tvec3<T, P> const & y);
+
+       /// @}
+}//namespace glm
+
+#include "orthonormalize.inl"
diff --git a/core/deps/glm/glm/gtx/orthonormalize.inl b/core/deps/glm/glm/gtx/orthonormalize.inl
new file mode 100755 (executable)
index 0000000..4796384
--- /dev/null
@@ -0,0 +1,30 @@
+/// @ref gtx_orthonormalize
+/// @file glm/gtx/orthonormalize.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> orthonormalize(tmat3x3<T, P> const & m)
+       {
+               tmat3x3<T, P> r = m;
+
+               r[0] = normalize(r[0]);
+
+               T d0 = dot(r[0], r[1]);
+               r[1] -= r[0] * d0;
+               r[1] = normalize(r[1]);
+
+               T d1 = dot(r[1], r[2]);
+               d0 = dot(r[0], r[2]);
+               r[2] -= r[0] * d0 + r[1] * d1;
+               r[2] = normalize(r[2]);
+
+               return r;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tvec3<T, P> orthonormalize(tvec3<T, P> const & x, tvec3<T, P> const & y)
+       {
+               return normalize(x - y * dot(y, x));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/perpendicular.hpp b/core/deps/glm/glm/gtx/perpendicular.hpp
new file mode 100755 (executable)
index 0000000..8b6260a
--- /dev/null
@@ -0,0 +1,39 @@
+/// @ref gtx_perpendicular
+/// @file glm/gtx/perpendicular.hpp
+///
+/// @see core (dependence)
+/// @see gtx_projection (dependence)
+///
+/// @defgroup gtx_perpendicular GLM_GTX_perpendicular
+/// @ingroup gtx
+///
+/// @brief Perpendicular of a vector from other one
+///
+/// <glm/gtx/perpendicular.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/projection.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_perpendicular extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_perpendicular
+       /// @{
+
+       //! Projects x a perpendicular axis of Normal.
+       //! From GLM_GTX_perpendicular extension.
+       template <typename vecType> 
+       GLM_FUNC_DECL vecType perp(
+               vecType const & x, 
+               vecType const & Normal);
+
+       /// @}
+}//namespace glm
+
+#include "perpendicular.inl"
diff --git a/core/deps/glm/glm/gtx/perpendicular.inl b/core/deps/glm/glm/gtx/perpendicular.inl
new file mode 100755 (executable)
index 0000000..08a7a81
--- /dev/null
@@ -0,0 +1,15 @@
+/// @ref gtx_perpendicular
+/// @file glm/gtx/perpendicular.inl
+
+namespace glm
+{
+       template <typename vecType> 
+       GLM_FUNC_QUALIFIER vecType perp
+       (
+               vecType const & x, 
+               vecType const & Normal
+       )
+       {
+               return x - proj(x, Normal);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/polar_coordinates.hpp b/core/deps/glm/glm/gtx/polar_coordinates.hpp
new file mode 100755 (executable)
index 0000000..c647c0f
--- /dev/null
@@ -0,0 +1,44 @@
+/// @ref gtx_polar_coordinates
+/// @file glm/gtx/polar_coordinates.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_polar_coordinates GLM_GTX_polar_coordinates
+/// @ingroup gtx
+///
+/// @brief Conversion from Euclidean space to polar space and revert.
+///
+/// <glm/gtx/polar_coordinates.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_polar_coordinates extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_polar_coordinates
+       /// @{
+
+       /// Convert Euclidean to Polar coordinates, x is the xz distance, y, the latitude and z the longitude.
+       ///
+       /// @see gtx_polar_coordinates
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> polar(
+               tvec3<T, P> const & euclidean);
+
+       /// Convert Polar to Euclidean coordinates.
+       ///
+       /// @see gtx_polar_coordinates
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> euclidean(
+               tvec2<T, P> const & polar);
+
+       /// @}
+}//namespace glm
+
+#include "polar_coordinates.inl"
diff --git a/core/deps/glm/glm/gtx/polar_coordinates.inl b/core/deps/glm/glm/gtx/polar_coordinates.inl
new file mode 100755 (executable)
index 0000000..afc9d2b
--- /dev/null
@@ -0,0 +1,37 @@
+/// @ref gtx_polar_coordinates
+/// @file glm/gtx/polar_coordinates.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> polar
+       (
+               tvec3<T, P> const & euclidean
+       )
+       {
+               T const Length(length(euclidean));
+               tvec3<T, P> const tmp(euclidean / Length);
+               T const xz_dist(sqrt(tmp.x * tmp.x + tmp.z * tmp.z));
+
+               return tvec3<T, P>(
+                       asin(tmp.y),    // latitude
+                       atan(tmp.x, tmp.z),             // longitude
+                       xz_dist);                               // xz distance
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> euclidean
+       (
+               tvec2<T, P> const & polar
+       )
+       {
+               T const latitude(polar.x);
+               T const longitude(polar.y);
+
+               return tvec3<T, P>(
+                       cos(latitude) * sin(longitude),
+                       sin(latitude),
+                       cos(latitude) * cos(longitude));
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/projection.hpp b/core/deps/glm/glm/gtx/projection.hpp
new file mode 100755 (executable)
index 0000000..fcddae8
--- /dev/null
@@ -0,0 +1,36 @@
+/// @ref gtx_projection
+/// @file glm/gtx/projection.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_projection GLM_GTX_projection
+/// @ingroup gtx
+///
+/// @brief Projection of a vector to other one
+///
+/// <glm/gtx/projection.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../geometric.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_projection extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_projection
+       /// @{
+
+       /// Projects x on Normal.
+       ///
+       /// @see gtx_projection
+       template <typename vecType>
+       GLM_FUNC_DECL vecType proj(vecType const & x, vecType const & Normal);
+
+       /// @}
+}//namespace glm
+
+#include "projection.inl"
diff --git a/core/deps/glm/glm/gtx/projection.inl b/core/deps/glm/glm/gtx/projection.inl
new file mode 100755 (executable)
index 0000000..d21fe83
--- /dev/null
@@ -0,0 +1,11 @@
+/// @ref gtx_projection
+/// @file glm/gtx/projection.inl
+
+namespace glm
+{
+       template <typename vecType>
+       GLM_FUNC_QUALIFIER vecType proj(vecType const & x, vecType const & Normal)
+       {
+               return glm::dot(x, Normal) / glm::dot(Normal, Normal) * Normal;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/quaternion.hpp b/core/deps/glm/glm/gtx/quaternion.hpp
new file mode 100755 (executable)
index 0000000..674d7e7
--- /dev/null
@@ -0,0 +1,185 @@
+/// @ref gtx_quaternion
+/// @file glm/gtx/quaternion.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_quaternion GLM_GTX_quaternion
+/// @ingroup gtx
+///
+/// @brief Extented quaternion types and functions
+///
+/// <glm/gtx/quaternion.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/constants.hpp"
+#include "../gtc/quaternion.hpp"
+#include "../gtx/norm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_quaternion extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_quaternion
+       /// @{
+
+       /// Compute a cross product between a quaternion and a vector.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> cross(
+               tquat<T, P> const & q,
+               tvec3<T, P> const & v);
+
+       //! Compute a cross product between a vector and a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> cross(
+               tvec3<T, P> const & v,
+               tquat<T, P> const & q);
+
+       //! Compute a point on a path according squad equation. 
+       //! q1 and q2 are control points; s1 and s2 are intermediate control points.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> squad(
+               tquat<T, P> const & q1,
+               tquat<T, P> const & q2,
+               tquat<T, P> const & s1,
+               tquat<T, P> const & s2,
+               T const & h);
+
+       //! Returns an intermediate control point for squad interpolation.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> intermediate(
+               tquat<T, P> const & prev,
+               tquat<T, P> const & curr,
+               tquat<T, P> const & next);
+
+       //! Returns a exp of a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> exp(
+               tquat<T, P> const & q);
+
+       //! Returns a log of a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> log(
+               tquat<T, P> const & q);
+
+       /// Returns x raised to the y power.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> pow(
+               tquat<T, P> const & x,
+               T const & y);
+
+       //! Returns quarternion square root.
+       ///
+       /// @see gtx_quaternion
+       //template<typename T, precision P>
+       //tquat<T, P> sqrt(
+       //      tquat<T, P> const & q);
+
+       //! Rotates a 3 components vector by a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rotate(
+               tquat<T, P> const & q,
+               tvec3<T, P> const & v);
+
+       /// Rotates a 4 components vector by a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> rotate(
+               tquat<T, P> const & q,
+               tvec4<T, P> const & v);
+
+       /// Extract the real component of a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL T extractRealComponent(
+               tquat<T, P> const & q);
+
+       /// Converts a quaternion to a 3 * 3 matrix.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> toMat3(
+               tquat<T, P> const & x){return mat3_cast(x);}
+
+       /// Converts a quaternion to a 4 * 4 matrix.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> toMat4(
+               tquat<T, P> const & x){return mat4_cast(x);}
+
+       /// Converts a 3 * 3 matrix to a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> toQuat(
+               tmat3x3<T, P> const & x){return quat_cast(x);}
+
+       /// Converts a 4 * 4 matrix to a quaternion.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> toQuat(
+               tmat4x4<T, P> const & x){return quat_cast(x);}
+
+       /// Quaternion interpolation using the rotation short path.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> shortMix(
+               tquat<T, P> const & x,
+               tquat<T, P> const & y,
+               T const & a);
+
+       /// Quaternion normalized linear interpolation.
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> fastMix(
+               tquat<T, P> const & x,
+               tquat<T, P> const & y,
+               T const & a);
+
+       /// Compute the rotation between two vectors.
+       /// param orig vector, needs to be normalized
+       /// param dest vector, needs to be normalized
+       ///
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> rotation(
+               tvec3<T, P> const & orig, 
+               tvec3<T, P> const & dest);
+
+       /// Returns the squared length of x.
+       /// 
+       /// @see gtx_quaternion
+       template<typename T, precision P>
+       GLM_FUNC_DECL T length2(tquat<T, P> const & q);
+
+       /// @}
+}//namespace glm
+
+#include "quaternion.inl"
diff --git a/core/deps/glm/glm/gtx/quaternion.inl b/core/deps/glm/glm/gtx/quaternion.inl
new file mode 100755 (executable)
index 0000000..c86ec18
--- /dev/null
@@ -0,0 +1,212 @@
+/// @ref gtx_quaternion
+/// @file glm/gtx/quaternion.inl
+
+#include <limits>
+#include "../gtc/constants.hpp"
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> cross(tvec3<T, P> const& v, tquat<T, P> const& q)
+       {
+               return inverse(q) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> cross(tquat<T, P> const& q, tvec3<T, P> const& v)
+       {
+               return q * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> squad
+       (
+               tquat<T, P> const & q1,
+               tquat<T, P> const & q2,
+               tquat<T, P> const & s1,
+               tquat<T, P> const & s2,
+               T const & h)
+       {
+               return mix(mix(q1, q2, h), mix(s1, s2, h), static_cast<T>(2) * (static_cast<T>(1) - h) * h);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> intermediate
+       (
+               tquat<T, P> const & prev,
+               tquat<T, P> const & curr,
+               tquat<T, P> const & next
+       )
+       {
+               tquat<T, P> invQuat = inverse(curr);
+               return exp((log(next + invQuat) + log(prev + invQuat)) / static_cast<T>(-4)) * curr;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> exp(tquat<T, P> const& q)
+       {
+               tvec3<T, P> u(q.x, q.y, q.z);
+               T const Angle = glm::length(u);
+               if (Angle < epsilon<T>())
+                       return tquat<T, P>();
+
+               tvec3<T, P> const v(u / Angle);
+               return tquat<T, P>(cos(Angle), sin(Angle) * v);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> log(tquat<T, P> const& q)
+       {
+               tvec3<T, P> u(q.x, q.y, q.z);
+               T Vec3Len = length(u);
+
+               if (Vec3Len < epsilon<T>())
+               {
+                       if(q.w > static_cast<T>(0))
+                               return tquat<T, P>(log(q.w), static_cast<T>(0), static_cast<T>(0), static_cast<T>(0));
+                       else if(q.w < static_cast<T>(0))
+                               return tquat<T, P>(log(-q.w), pi<T>(), static_cast<T>(0), static_cast<T>(0));
+                       else
+                               return tquat<T, P>(std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity(), std::numeric_limits<T>::infinity());
+               }
+               else
+               {
+                       T t = atan(Vec3Len, T(q.w)) / Vec3Len;
+                       T QuatLen2 = Vec3Len * Vec3Len + q.w * q.w;
+                       return tquat<T, P>(static_cast<T>(0.5) * log(QuatLen2), t * q.x, t * q.y, t * q.z);
+               }
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> pow(tquat<T, P> const & x, T const & y)
+       {
+               //Raising to the power of 0 should yield 1
+               //Needed to prevent a division by 0 error later on
+               if(y > -epsilon<T>() && y < epsilon<T>())
+                       return tquat<T, P>(1,0,0,0);
+
+               //To deal with non-unit quaternions
+               T magnitude = sqrt(x.x * x.x + x.y * x.y + x.z * x.z + x.w *x.w);
+
+               //Equivalent to raising a real number to a power
+               //Needed to prevent a division by 0 error later on
+               if(abs(x.w / magnitude) > static_cast<T>(1) - epsilon<T>() && abs(x.w / magnitude) < static_cast<T>(1) + epsilon<T>())
+                       return tquat<T, P>(pow(x.w, y),0,0,0);
+
+               T Angle = acos(x.w / magnitude);
+               T NewAngle = Angle * y;
+               T Div = sin(NewAngle) / sin(Angle);
+               T Mag = pow(magnitude, y - static_cast<T>(1));
+
+               return tquat<T, P>(cos(NewAngle) * magnitude * Mag, x.x * Div * Mag, x.y * Div * Mag, x.z * Div * Mag);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotate(tquat<T, P> const& q, tvec3<T, P> const& v)
+       {
+               return q * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> rotate(tquat<T, P> const& q, tvec4<T, P> const& v)
+       {
+               return q * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T extractRealComponent(tquat<T, P> const& q)
+       {
+               T w = static_cast<T>(1) - q.x * q.x - q.y * q.y - q.z * q.z;
+               if(w < T(0))
+                       return T(0);
+               else
+                       return -sqrt(w);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T length2(tquat<T, P> const& q)
+       {
+               return q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> shortMix(tquat<T, P> const& x, tquat<T, P> const& y, T const& a)
+       {
+               if(a <= static_cast<T>(0)) return x;
+               if(a >= static_cast<T>(1)) return y;
+
+               T fCos = dot(x, y);
+               tquat<T, P> y2(y); //BUG!!! tquat<T> y2;
+               if(fCos < static_cast<T>(0))
+               {
+                       y2 = -y;
+                       fCos = -fCos;
+               }
+
+               //if(fCos > 1.0f) // problem
+               T k0, k1;
+               if(fCos > (static_cast<T>(1) - epsilon<T>()))
+               {
+                       k0 = static_cast<T>(1) - a;
+                       k1 = static_cast<T>(0) + a; //BUG!!! 1.0f + a;
+               }
+               else
+               {
+                       T fSin = sqrt(T(1) - fCos * fCos);
+                       T fAngle = atan(fSin, fCos);
+                       T fOneOverSin = static_cast<T>(1) / fSin;
+                       k0 = sin((static_cast<T>(1) - a) * fAngle) * fOneOverSin;
+                       k1 = sin((static_cast<T>(0) + a) * fAngle) * fOneOverSin;
+               }
+
+               return tquat<T, P>(
+                       k0 * x.w + k1 * y2.w,
+                       k0 * x.x + k1 * y2.x,
+                       k0 * x.y + k1 * y2.y,
+                       k0 * x.z + k1 * y2.z);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> fastMix(tquat<T, P> const& x, tquat<T, P> const& y, T const & a)
+       {
+               return glm::normalize(x * (static_cast<T>(1) - a) + (y * a));
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> rotation(tvec3<T, P> const& orig, tvec3<T, P> const& dest)
+       {
+               T cosTheta = dot(orig, dest);
+               tvec3<T, P> rotationAxis;
+
+               if(cosTheta >= static_cast<T>(1) - epsilon<T>())
+                       return quat();
+
+               if(cosTheta < static_cast<T>(-1) + epsilon<T>())
+               {
+                       // special case when vectors in opposite directions :
+                       // there is no "ideal" rotation axis
+                       // So guess one; any will do as long as it's perpendicular to start
+                       // This implementation favors a rotation around the Up axis (Y),
+                       // since it's often what you want to do.
+                       rotationAxis = cross(tvec3<T, P>(0, 0, 1), orig);
+                       if(length2(rotationAxis) < epsilon<T>()) // bad luck, they were parallel, try again!
+                               rotationAxis = cross(tvec3<T, P>(1, 0, 0), orig);
+
+                       rotationAxis = normalize(rotationAxis);
+                       return angleAxis(pi<T>(), rotationAxis);
+               }
+
+               // Implementation from Stan Melax's Game Programming Gems 1 article
+               rotationAxis = cross(orig, dest);
+
+               T s = sqrt((T(1) + cosTheta) * static_cast<T>(2));
+               T invs = static_cast<T>(1) / s;
+
+               return tquat<T, P>(
+                       s * static_cast<T>(0.5f), 
+                       rotationAxis.x * invs,
+                       rotationAxis.y * invs,
+                       rotationAxis.z * invs);
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/range.hpp b/core/deps/glm/glm/gtx/range.hpp
new file mode 100755 (executable)
index 0000000..00d78b4
--- /dev/null
@@ -0,0 +1,85 @@
+/// @ref gtx_range
+/// @file glm/gtx/range.hpp
+/// @author Joshua Moerman
+///
+/// @defgroup gtx_range GLM_GTX_range
+/// @ingroup gtx
+///
+/// @brief Defines begin and end for vectors and matrices. Useful for range-based for loop.
+/// The range is defined over the elements, not over columns or rows (e.g. mat4 has 16 elements).
+///
+/// <glm/gtx/range.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+
+#if !GLM_HAS_RANGE_FOR
+#      error "GLM_GTX_range requires C++11 suppport or 'range for'"
+#endif
+
+#include "../gtc/type_ptr.hpp"
+#include "../gtc/vec1.hpp"
+
+namespace glm
+{
+       /// @addtogroup gtx_range
+       /// @{
+
+       template <typename T, precision P>
+       inline length_t components(tvec1<T, P> const & v)
+       {
+               return v.length();
+       }
+       
+       template <typename T, precision P>
+       inline length_t components(tvec2<T, P> const & v)
+       {
+               return v.length();
+       }
+       
+       template <typename T, precision P>
+       inline length_t components(tvec3<T, P> const & v)
+       {
+               return v.length();
+       }
+       
+       template <typename T, precision P>
+       inline length_t components(tvec4<T, P> const & v)
+       {
+               return v.length();
+       }
+       
+       template <typename genType>
+       inline length_t components(genType const & m)
+       {
+               return m.length() * m[0].length();
+       }
+       
+       template <typename genType>
+       inline typename genType::value_type const * begin(genType const & v)
+       {
+               return value_ptr(v);
+       }
+
+       template <typename genType>
+       inline typename genType::value_type const * end(genType const & v)
+       {
+               return begin(v) + components(v);
+       }
+
+       template <typename genType>
+       inline typename genType::value_type * begin(genType& v)
+       {
+               return value_ptr(v);
+       }
+
+       template <typename genType>
+       inline typename genType::value_type * end(genType& v)
+       {
+               return begin(v) + components(v);
+       }
+
+       /// @}
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/raw_data.hpp b/core/deps/glm/glm/gtx/raw_data.hpp
new file mode 100755 (executable)
index 0000000..2625fd1
--- /dev/null
@@ -0,0 +1,47 @@
+/// @ref gtx_raw_data
+/// @file glm/gtx/raw_data.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_raw_data GLM_GTX_raw_data
+/// @ingroup gtx
+///
+/// @brief Projection of a vector to other one
+///
+/// <glm/gtx/raw_data.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+#include "../detail/type_int.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_raw_data extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_raw_data
+       /// @{
+
+       //! Type for byte numbers. 
+       //! From GLM_GTX_raw_data extension.
+       typedef detail::uint8           byte;
+
+       //! Type for word numbers. 
+       //! From GLM_GTX_raw_data extension.
+       typedef detail::uint16          word;
+
+       //! Type for dword numbers. 
+       //! From GLM_GTX_raw_data extension.
+       typedef detail::uint32          dword;
+
+       //! Type for qword numbers. 
+       //! From GLM_GTX_raw_data extension.
+       typedef detail::uint64          qword;
+
+       /// @}
+}// namespace glm
+
+#include "raw_data.inl"
diff --git a/core/deps/glm/glm/gtx/raw_data.inl b/core/deps/glm/glm/gtx/raw_data.inl
new file mode 100755 (executable)
index 0000000..29af148
--- /dev/null
@@ -0,0 +1,2 @@
+/// @ref gtx_raw_data
+/// @file glm/gtx/raw_data.inl
diff --git a/core/deps/glm/glm/gtx/rotate_normalized_axis.hpp b/core/deps/glm/glm/gtx/rotate_normalized_axis.hpp
new file mode 100755 (executable)
index 0000000..f1dfa7b
--- /dev/null
@@ -0,0 +1,64 @@
+/// @ref gtx_rotate_normalized_axis
+/// @file glm/gtx/rotate_normalized_axis.hpp
+///
+/// @see core (dependence)
+/// @see gtc_matrix_transform
+/// @see gtc_quaternion
+///
+/// @defgroup gtx_rotate_normalized_axis GLM_GTX_rotate_normalized_axis
+/// @ingroup gtx
+///
+/// @brief Quaternions and matrices rotations around normalized axis.
+///
+/// <glm/gtx/rotate_normalized_axis.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/epsilon.hpp"
+#include "../gtc/quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_rotate_normalized_axis extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_rotate_normalized_axis
+       /// @{
+
+       /// Builds a rotation 4 * 4 matrix created from a normalized axis and an angle. 
+       /// 
+       /// @param m Input matrix multiplied by this rotation matrix.
+       /// @param angle Rotation angle expressed in radians if GLM_FORCE_RADIANS is define or degrees otherwise.
+       /// @param axis Rotation axis, must be normalized.
+       /// @tparam T Value type used to build the matrix. Currently supported: half (not recommanded), float or double.
+       /// 
+       /// @see gtx_rotate_normalized_axis
+       /// @see - rotate(T angle, T x, T y, T z) 
+       /// @see - rotate(tmat4x4<T, P> const & m, T angle, T x, T y, T z) 
+       /// @see - rotate(T angle, tvec3<T, P> const & v) 
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> rotateNormalizedAxis(
+               tmat4x4<T, P> const & m,
+               T const & angle,
+               tvec3<T, P> const & axis);
+
+       /// Rotates a quaternion from a vector of 3 components normalized axis and an angle.
+       /// 
+       /// @param q Source orientation
+       /// @param angle Angle expressed in radians if GLM_FORCE_RADIANS is define or degrees otherwise.
+       /// @param axis Normalized axis of the rotation, must be normalized.
+       /// 
+       /// @see gtx_rotate_normalized_axis
+       template <typename T, precision P>
+       GLM_FUNC_DECL tquat<T, P> rotateNormalizedAxis(
+               tquat<T, P> const & q,
+               T const & angle,
+               tvec3<T, P> const & axis);
+
+       /// @}
+}//namespace glm
+
+#include "rotate_normalized_axis.inl"
diff --git a/core/deps/glm/glm/gtx/rotate_normalized_axis.inl b/core/deps/glm/glm/gtx/rotate_normalized_axis.inl
new file mode 100755 (executable)
index 0000000..dc1b1a8
--- /dev/null
@@ -0,0 +1,59 @@
+/// @ref gtx_rotate_normalized_axis
+/// @file glm/gtx/rotate_normalized_axis.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rotateNormalizedAxis
+       (
+               tmat4x4<T, P> const & m,
+               T const & angle,
+               tvec3<T, P> const & v
+       )
+       {
+               T const a = angle;
+               T const c = cos(a);
+               T const s = sin(a);
+
+               tvec3<T, P> const axis(v);
+
+               tvec3<T, P> const temp((static_cast<T>(1) - c) * axis);
+
+               tmat4x4<T, P> Rotate(uninitialize);
+               Rotate[0][0] = c + temp[0] * axis[0];
+               Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];
+               Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];
+
+               Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];
+               Rotate[1][1] = c + temp[1] * axis[1];
+               Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];
+
+               Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];
+               Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];
+               Rotate[2][2] = c + temp[2] * axis[2];
+
+               tmat4x4<T, P> Result(uninitialize);
+               Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
+               Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
+               Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
+               Result[3] = m[3];
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tquat<T, P> rotateNormalizedAxis
+       (
+               tquat<T, P> const & q, 
+               T const & angle,
+               tvec3<T, P> const & v
+       )
+       {
+               tvec3<T, P> const Tmp(v);
+
+               T const AngleRad(angle);
+               T const Sin = sin(AngleRad * T(0.5));
+
+               return q * tquat<T, P>(cos(AngleRad * static_cast<T>(0.5)), Tmp.x * Sin, Tmp.y * Sin, Tmp.z * Sin);
+               //return gtc::quaternion::cross(q, tquat<T, P>(cos(AngleRad * T(0.5)), Tmp.x * fSin, Tmp.y * fSin, Tmp.z * fSin));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/rotate_vector.hpp b/core/deps/glm/glm/gtx/rotate_vector.hpp
new file mode 100755 (executable)
index 0000000..91d1784
--- /dev/null
@@ -0,0 +1,117 @@
+/// @ref gtx_rotate_vector
+/// @file glm/gtx/rotate_vector.hpp
+///
+/// @see core (dependence)
+/// @see gtx_transform (dependence)
+///
+/// @defgroup gtx_rotate_vector GLM_GTX_rotate_vector
+/// @ingroup gtx
+///
+/// @brief Function to directly rotate a vector
+///
+/// <glm/gtx/rotate_vector.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/transform.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_rotate_vector extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_rotate_vector
+       /// @{
+
+       /// Returns Spherical interpolation between two vectors
+       /// 
+       /// @param x A first vector
+       /// @param y A second vector
+       /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].
+       /// 
+       /// @see gtx_rotate_vector
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> slerp(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               T const & a);
+
+       //! Rotate a two dimensional vector.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec2<T, P> rotate(
+               tvec2<T, P> const & v,
+               T const & angle);
+               
+       //! Rotate a three dimensional vector around an axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rotate(
+               tvec3<T, P> const & v,
+               T const & angle,
+               tvec3<T, P> const & normal);
+               
+       //! Rotate a four dimensional vector around an axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> rotate(
+               tvec4<T, P> const & v,
+               T const & angle,
+               tvec3<T, P> const & normal);
+               
+       //! Rotate a three dimensional vector around the X axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rotateX(
+               tvec3<T, P> const & v,
+               T const & angle);
+
+       //! Rotate a three dimensional vector around the Y axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rotateY(
+               tvec3<T, P> const & v,
+               T const & angle);
+               
+       //! Rotate a three dimensional vector around the Z axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec3<T, P> rotateZ(
+               tvec3<T, P> const & v,
+               T const & angle);
+               
+       //! Rotate a four dimentionnals vector around the X axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> rotateX(
+               tvec4<T, P> const & v,
+               T const & angle);
+               
+       //! Rotate a four dimensional vector around the X axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> rotateY(
+               tvec4<T, P> const & v,
+               T const & angle);
+               
+       //! Rotate a four dimensional vector around the X axis.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tvec4<T, P> rotateZ(
+               tvec4<T, P> const & v,
+               T const & angle);
+               
+       //! Build a rotation matrix from a normal and a up vector.
+       //! From GLM_GTX_rotate_vector extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> orientation(
+               tvec3<T, P> const & Normal,
+               tvec3<T, P> const & Up);
+
+       /// @}
+}//namespace glm
+
+#include "rotate_vector.inl"
diff --git a/core/deps/glm/glm/gtx/rotate_vector.inl b/core/deps/glm/glm/gtx/rotate_vector.inl
new file mode 100755 (executable)
index 0000000..5620e96
--- /dev/null
@@ -0,0 +1,188 @@
+/// @ref gtx_rotate_vector
+/// @file glm/gtx/rotate_vector.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> slerp
+       (
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               T const & a
+       )
+       {
+               // get cosine of angle between vectors (-1 -> 1)
+               T CosAlpha = dot(x, y);
+               // get angle (0 -> pi)
+               T Alpha = acos(CosAlpha);
+               // get sine of angle between vectors (0 -> 1)
+               T SinAlpha = sin(Alpha);
+               // this breaks down when SinAlpha = 0, i.e. Alpha = 0 or pi
+               T t1 = sin((static_cast<T>(1) - a) * Alpha) / SinAlpha;
+               T t2 = sin(a * Alpha) / SinAlpha;
+
+               // interpolate src vectors
+               return x * t1 + y * t2;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<T, P> rotate
+       (
+               tvec2<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec2<T, P> Result;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.x = v.x * Cos - v.y * Sin;
+               Result.y = v.x * Sin + v.y * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotate
+       (
+               tvec3<T, P> const & v,
+               T const & angle,
+               tvec3<T, P> const & normal
+       )
+       {
+               return tmat3x3<T, P>(glm::rotate(angle, normal)) * v;
+       }
+       /*
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotateGTX(
+               const tvec3<T, P>& x,
+               T angle,
+               const tvec3<T, P>& normal)
+       {
+               const T Cos = cos(radians(angle));
+               const T Sin = sin(radians(angle));
+               return x * Cos + ((x * normal) * (T(1) - Cos)) * normal + cross(x, normal) * Sin;
+       }
+       */
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> rotate
+       (
+               tvec4<T, P> const & v,
+               T const & angle,
+               tvec3<T, P> const & normal
+       )
+       {
+               return rotate(angle, normal) * v;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotateX
+       (
+               tvec3<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec3<T, P> Result(v);
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.y = v.y * Cos - v.z * Sin;
+               Result.z = v.y * Sin + v.z * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotateY
+       (
+               tvec3<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec3<T, P> Result = v;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.x =  v.x * Cos + v.z * Sin;
+               Result.z = -v.x * Sin + v.z * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<T, P> rotateZ
+       (
+               tvec3<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec3<T, P> Result = v;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.x = v.x * Cos - v.y * Sin;
+               Result.y = v.x * Sin + v.y * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> rotateX
+       (
+               tvec4<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec4<T, P> Result = v;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.y = v.y * Cos - v.z * Sin;
+               Result.z = v.y * Sin + v.z * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> rotateY
+       (
+               tvec4<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec4<T, P> Result = v;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.x =  v.x * Cos + v.z * Sin;
+               Result.z = -v.x * Sin + v.z * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<T, P> rotateZ
+       (
+               tvec4<T, P> const & v,
+               T const & angle
+       )
+       {
+               tvec4<T, P> Result = v;
+               T const Cos(cos(angle));
+               T const Sin(sin(angle));
+
+               Result.x = v.x * Cos - v.y * Sin;
+               Result.y = v.x * Sin + v.y * Cos;
+               return Result;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> orientation
+       (
+               tvec3<T, P> const & Normal,
+               tvec3<T, P> const & Up
+       )
+       {
+               if(all(equal(Normal, Up)))
+                       return tmat4x4<T, P>(T(1));
+
+               tvec3<T, P> RotationAxis = cross(Up, Normal);
+               T Angle = acos(dot(Normal, Up));
+
+               return rotate(Angle, RotationAxis);
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/scalar_multiplication.hpp b/core/deps/glm/glm/gtx/scalar_multiplication.hpp
new file mode 100755 (executable)
index 0000000..695e841
--- /dev/null
@@ -0,0 +1,69 @@
+/// @ref gtx
+/// @file glm/gtx/scalar_multiplication.hpp
+/// @author Joshua Moerman
+///
+/// @brief Enables scalar multiplication for all types
+///
+/// Since GLSL is very strict about types, the following (often used) combinations do not work:
+///    double * vec4
+///    int * vec4
+///    vec4 / int
+/// So we'll fix that! Of course "float * vec4" should remain the same (hence the enable_if magic)
+
+#pragma once
+
+#include "../detail/setup.hpp"
+
+#if !GLM_HAS_TEMPLATE_ALIASES && !(GLM_COMPILER & GLM_COMPILER_GCC)
+#      error "GLM_GTX_scalar_multiplication requires C++11 support or alias templates and if not support for GCC"
+#endif
+
+#include "../vec2.hpp"
+#include "../vec3.hpp"
+#include "../vec4.hpp"
+#include "../mat2x2.hpp"
+#include <type_traits>
+
+namespace glm
+{
+       template <typename T, typename Vec>
+       using return_type_scalar_multiplication = typename std::enable_if<
+               !std::is_same<T, float>::value       // T may not be a float
+               && std::is_arithmetic<T>::value, Vec // But it may be an int or double (no vec3 or mat3, ...)
+       >::type;
+
+#define GLM_IMPLEMENT_SCAL_MULT(Vec) \
+       template <typename T> \
+       return_type_scalar_multiplication<T, Vec> \
+       operator*(T const & s, Vec rh){ \
+               return rh *= static_cast<float>(s); \
+       } \
+        \
+       template <typename T> \
+       return_type_scalar_multiplication<T, Vec> \
+       operator*(Vec lh, T const & s){ \
+               return lh *= static_cast<float>(s); \
+       } \
+        \
+       template <typename T> \
+       return_type_scalar_multiplication<T, Vec> \
+       operator/(Vec lh, T const & s){ \
+               return lh *= 1.0f / s; \
+       }
+
+GLM_IMPLEMENT_SCAL_MULT(vec2)
+GLM_IMPLEMENT_SCAL_MULT(vec3)
+GLM_IMPLEMENT_SCAL_MULT(vec4)
+
+GLM_IMPLEMENT_SCAL_MULT(mat2)
+GLM_IMPLEMENT_SCAL_MULT(mat2x3)
+GLM_IMPLEMENT_SCAL_MULT(mat2x4)
+GLM_IMPLEMENT_SCAL_MULT(mat3x2)
+GLM_IMPLEMENT_SCAL_MULT(mat3)
+GLM_IMPLEMENT_SCAL_MULT(mat3x4)
+GLM_IMPLEMENT_SCAL_MULT(mat4x2)
+GLM_IMPLEMENT_SCAL_MULT(mat4x3)
+GLM_IMPLEMENT_SCAL_MULT(mat4)
+
+#undef GLM_IMPLEMENT_SCAL_MULT
+} // namespace glm
diff --git a/core/deps/glm/glm/gtx/scalar_relational.hpp b/core/deps/glm/glm/gtx/scalar_relational.hpp
new file mode 100755 (executable)
index 0000000..9695716
--- /dev/null
@@ -0,0 +1,32 @@
+/// @ref gtx_scalar_relational
+/// @file glm/gtx/scalar_relational.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_scalar_relational GLM_GTX_scalar_relational
+/// @ingroup gtx
+///
+/// @brief Extend a position from a source to a position at a defined length.
+///
+/// <glm/gtx/scalar_relational.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_extend extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_scalar_relational
+       /// @{
+
+
+
+       /// @}
+}//namespace glm
+
+#include "scalar_relational.inl"
diff --git a/core/deps/glm/glm/gtx/scalar_relational.inl b/core/deps/glm/glm/gtx/scalar_relational.inl
new file mode 100755 (executable)
index 0000000..709da04
--- /dev/null
@@ -0,0 +1,89 @@
+/// @ref gtx_scalar_relational
+/// @file glm/gtx/scalar_relational.inl
+
+namespace glm
+{
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool lessThan
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x < y;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool lessThanEqual
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x <= y;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool greaterThan
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x > y;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool greaterThanEqual
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x >= y;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool equal
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x == y;
+       }
+
+       template <typename T>
+       GLM_FUNC_QUALIFIER bool notEqual
+       (
+               T const & x, 
+               T const & y
+       )
+       {
+               return x != y;
+       }
+
+       GLM_FUNC_QUALIFIER bool any
+       (
+               bool const & x
+       )
+       {
+               return x;
+       }
+
+       GLM_FUNC_QUALIFIER bool all
+       (
+               bool const & x
+       )
+       {
+               return x;
+       }
+
+       GLM_FUNC_QUALIFIER bool not_
+       (
+               bool const & x
+       )
+       {
+               return !x;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/simd_mat4.hpp b/core/deps/glm/glm/gtx/simd_mat4.hpp
new file mode 100755 (executable)
index 0000000..a68220c
--- /dev/null
@@ -0,0 +1,182 @@
+/// @ref gtx_simd_mat4
+/// @file glm/gtx/simd_mat4.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_simd_mat4 GLM_GTX_simd_mat4
+/// @ingroup gtx
+///
+/// @brief SIMD implementation of mat4 type.
+///
+/// <glm/gtx/simd_mat4.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependencies
+#include "../detail/setup.hpp"
+
+#if(GLM_ARCH != GLM_ARCH_PURE)
+
+#if(GLM_ARCH & GLM_ARCH_SSE2_BIT)
+#      include "../detail/intrinsic_matrix.hpp"
+#      include "../gtx/simd_vec4.hpp"
+#else
+#      error "GLM: GLM_GTX_simd_mat4 requires compiler support of SSE2 through intrinsics"
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_simd_mat4 extension included")
+#      pragma message("GLM: GLM_GTX_simd_mat4 extension is deprecated and will be removed in GLM 0.9.9. Use mat4 instead and use compiler SIMD arguments.")
+#endif
+
+namespace glm{
+namespace detail
+{
+       /// 4x4 Matrix implemented using SIMD SEE intrinsics.
+       /// \ingroup gtx_simd_mat4
+       GLM_ALIGNED_STRUCT(16) fmat4x4SIMD
+       {
+               typedef float value_type;
+               typedef fvec4SIMD col_type;
+               typedef fvec4SIMD row_type;
+               typedef std::size_t size_type;
+               typedef fmat4x4SIMD type;
+               typedef fmat4x4SIMD transpose_type;
+
+               typedef tmat4x4<float, defaultp> pure_type;
+               typedef tvec4<float, defaultp> pure_row_type;
+               typedef tvec4<float, defaultp> pure_col_type;
+               typedef tmat4x4<float, defaultp> pure_transpose_type;
+
+               GLM_FUNC_DECL length_t length() const;
+
+               fvec4SIMD Data[4];
+
+               //////////////////////////////////////
+               // Constructors
+
+               fmat4x4SIMD() GLM_DEFAULT_CTOR;
+               explicit fmat4x4SIMD(float const & s);
+               explicit fmat4x4SIMD(
+                       float const & x0, float const & y0, float const & z0, float const & w0,
+                       float const & x1, float const & y1, float const & z1, float const & w1,
+                       float const & x2, float const & y2, float const & z2, float const & w2,
+                       float const & x3, float const & y3, float const & z3, float const & w3);
+               explicit fmat4x4SIMD(
+                       fvec4SIMD const & v0,
+                       fvec4SIMD const & v1,
+                       fvec4SIMD const & v2,
+                       fvec4SIMD const & v3);
+               explicit fmat4x4SIMD(
+                       mat4x4 const & m);
+               explicit fmat4x4SIMD(
+                       __m128 const in[4]);
+
+               // Conversions
+               //template <typename U>
+               //explicit tmat4x4(tmat4x4<U> const & m);
+
+               //explicit tmat4x4(tmat2x2<T> const & x);
+               //explicit tmat4x4(tmat3x3<T> const & x);
+               //explicit tmat4x4(tmat2x3<T> const & x);
+               //explicit tmat4x4(tmat3x2<T> const & x);
+               //explicit tmat4x4(tmat2x4<T> const & x);
+               //explicit tmat4x4(tmat4x2<T> const & x);
+               //explicit tmat4x4(tmat3x4<T> const & x);
+               //explicit tmat4x4(tmat4x3<T> const & x);
+
+               // Accesses
+               fvec4SIMD & operator[](length_t i);
+               fvec4SIMD const & operator[](length_t i) const;
+
+               // Unary updatable operators
+               fmat4x4SIMD & operator= (fmat4x4SIMD const & m) GLM_DEFAULT;
+               fmat4x4SIMD & operator+= (float const & s);
+               fmat4x4SIMD & operator+= (fmat4x4SIMD const & m);
+               fmat4x4SIMD & operator-= (float const & s);
+               fmat4x4SIMD & operator-= (fmat4x4SIMD const & m);
+               fmat4x4SIMD & operator*= (float const & s);
+               fmat4x4SIMD & operator*= (fmat4x4SIMD const & m);
+               fmat4x4SIMD & operator/= (float const & s);
+               fmat4x4SIMD & operator/= (fmat4x4SIMD const & m);
+               fmat4x4SIMD & operator++ ();
+               fmat4x4SIMD & operator-- ();
+       };
+
+       // Binary operators
+       fmat4x4SIMD operator+ (fmat4x4SIMD const & m, float const & s);
+       fmat4x4SIMD operator+ (float const & s, fmat4x4SIMD const & m);
+       fmat4x4SIMD operator+ (fmat4x4SIMD const & m1, fmat4x4SIMD const & m2);
+
+       fmat4x4SIMD operator- (fmat4x4SIMD const & m, float const & s);
+       fmat4x4SIMD operator- (float const & s, fmat4x4SIMD const & m);
+       fmat4x4SIMD operator- (fmat4x4SIMD const & m1, fmat4x4SIMD const & m2);
+
+       fmat4x4SIMD operator* (fmat4x4SIMD const & m, float const & s);
+       fmat4x4SIMD operator* (float const & s, fmat4x4SIMD const & m);
+
+       fvec4SIMD operator* (fmat4x4SIMD const & m, fvec4SIMD const & v);
+       fvec4SIMD operator* (fvec4SIMD const & v, fmat4x4SIMD const & m);
+
+       fmat4x4SIMD operator* (fmat4x4SIMD const & m1, fmat4x4SIMD const & m2);
+
+       fmat4x4SIMD operator/ (fmat4x4SIMD const & m, float const & s);
+       fmat4x4SIMD operator/ (float const & s, fmat4x4SIMD const & m);
+
+       fvec4SIMD operator/ (fmat4x4SIMD const & m, fvec4SIMD const & v);
+       fvec4SIMD operator/ (fvec4SIMD const & v, fmat4x4SIMD const & m);
+
+       fmat4x4SIMD operator/ (fmat4x4SIMD const & m1, fmat4x4SIMD const & m2);
+
+       // Unary constant operators
+       fmat4x4SIMD const operator-  (fmat4x4SIMD const & m);
+       fmat4x4SIMD const operator-- (fmat4x4SIMD const & m, int);
+       fmat4x4SIMD const operator++ (fmat4x4SIMD const & m, int);
+}//namespace detail
+
+       typedef detail::fmat4x4SIMD simdMat4;
+
+       /// @addtogroup gtx_simd_mat4
+       /// @{
+
+       //! Convert a simdMat4 to a mat4.
+       //! (From GLM_GTX_simd_mat4 extension)
+       mat4 mat4_cast(
+               detail::fmat4x4SIMD const & x);
+
+       //! Multiply matrix x by matrix y component-wise, i.e.,
+       //! result[i][j] is the scalar product of x[i][j] and y[i][j].
+       //! (From GLM_GTX_simd_mat4 extension).
+       detail::fmat4x4SIMD matrixCompMult(
+               detail::fmat4x4SIMD const & x,
+               detail::fmat4x4SIMD const & y);
+
+       //! Treats the first parameter c as a column vector
+       //! and the second parameter r as a row vector
+       //! and does a linear algebraic matrix multiply c * r.
+       //! (From GLM_GTX_simd_mat4 extension).
+       detail::fmat4x4SIMD outerProduct(
+               detail::fvec4SIMD const & c,
+               detail::fvec4SIMD const & r);
+
+       //! Returns the transposed matrix of x
+       //! (From GLM_GTX_simd_mat4 extension).
+       detail::fmat4x4SIMD transpose(
+               detail::fmat4x4SIMD const & x);
+
+       //! Return the determinant of a mat4 matrix.
+       //! (From GLM_GTX_simd_mat4 extension).
+       float determinant(
+               detail::fmat4x4SIMD const & m);
+
+       //! Return the inverse of a mat4 matrix.
+       //! (From GLM_GTX_simd_mat4 extension).
+       detail::fmat4x4SIMD inverse(
+               detail::fmat4x4SIMD const & m);
+
+       /// @}
+}// namespace glm
+
+#include "simd_mat4.inl"
+
+#endif//(GLM_ARCH != GLM_ARCH_PURE)
diff --git a/core/deps/glm/glm/gtx/simd_mat4.inl b/core/deps/glm/glm/gtx/simd_mat4.inl
new file mode 100755 (executable)
index 0000000..9643255
--- /dev/null
@@ -0,0 +1,577 @@
+/// @ref gtx_simd_mat4
+/// @file glm/gtx/simd_mat4.inl
+
+namespace glm{
+namespace detail{
+
+GLM_FUNC_QUALIFIER length_t fmat4x4SIMD::length() const
+{
+       return 4;
+}
+
+//////////////////////////////////////
+// Accesses
+
+GLM_FUNC_QUALIFIER fvec4SIMD & fmat4x4SIMD::operator[]
+(
+       length_t i
+)
+{
+       assert(i < this->length());
+
+       return this->Data[i];
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD const & fmat4x4SIMD::operator[]
+(
+       length_t i
+) const
+{
+       assert(i < this->length());
+
+       return this->Data[i];
+}
+
+//////////////////////////////////////////////////////////////
+// Constructors
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+       GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD()
+       {
+#              ifndef GLM_FORCE_NO_CTOR_INIT
+                       this->Data[0] = fvec4SIMD(1, 0, 0, 0);
+                       this->Data[1] = fvec4SIMD(0, 1, 0, 0);
+                       this->Data[2] = fvec4SIMD(0, 0, 1, 0);
+                       this->Data[3] = fvec4SIMD(0, 0, 0, 1);
+#              endif
+       }
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD(float const & s)
+{
+       this->Data[0] = fvec4SIMD(s, 0, 0, 0);
+       this->Data[1] = fvec4SIMD(0, s, 0, 0);
+       this->Data[2] = fvec4SIMD(0, 0, s, 0);
+       this->Data[3] = fvec4SIMD(0, 0, 0, s);
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
+(
+       float const & x0, float const & y0, float const & z0, float const & w0,
+       float const & x1, float const & y1, float const & z1, float const & w1,
+       float const & x2, float const & y2, float const & z2, float const & w2,
+       float const & x3, float const & y3, float const & z3, float const & w3
+)
+{
+       this->Data[0] = fvec4SIMD(x0, y0, z0, w0);
+       this->Data[1] = fvec4SIMD(x1, y1, z1, w1);
+       this->Data[2] = fvec4SIMD(x2, y2, z2, w2);
+       this->Data[3] = fvec4SIMD(x3, y3, z3, w3);
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
+(
+       fvec4SIMD const & v0,
+       fvec4SIMD const & v1,
+       fvec4SIMD const & v2,
+       fvec4SIMD const & v3
+)
+{
+       this->Data[0] = v0;
+       this->Data[1] = v1;
+       this->Data[2] = v2;
+       this->Data[3] = v3;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
+(
+       mat4 const & m
+)
+{
+       this->Data[0] = fvec4SIMD(m[0]);
+       this->Data[1] = fvec4SIMD(m[1]);
+       this->Data[2] = fvec4SIMD(m[2]);
+       this->Data[3] = fvec4SIMD(m[3]);
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD::fmat4x4SIMD
+(
+       __m128 const in[4]
+)
+{
+       this->Data[0] = in[0];
+       this->Data[1] = in[1];
+       this->Data[2] = in[2];
+       this->Data[3] = in[3];
+}
+
+//////////////////////////////////////////////////////////////
+// mat4 operators
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS
+       GLM_FUNC_QUALIFIER fmat4x4SIMD& fmat4x4SIMD::operator=
+       (
+               fmat4x4SIMD const & m
+       )
+       {
+               this->Data[0] = m[0];
+               this->Data[1] = m[1];
+               this->Data[2] = m[2];
+               this->Data[3] = m[3];
+               return *this;
+       }
+#endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator+= 
+(
+       fmat4x4SIMD const & m
+)
+{
+       this->Data[0].Data = _mm_add_ps(this->Data[0].Data, m[0].Data);
+       this->Data[1].Data = _mm_add_ps(this->Data[1].Data, m[1].Data);
+       this->Data[2].Data = _mm_add_ps(this->Data[2].Data, m[2].Data);
+       this->Data[3].Data = _mm_add_ps(this->Data[3].Data, m[3].Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-= 
+(
+       fmat4x4SIMD const & m
+)
+{
+       this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, m[0].Data);
+       this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, m[1].Data);
+       this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, m[2].Data);
+       this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, m[3].Data);
+
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator*= 
+(
+       fmat4x4SIMD const & m
+)
+{
+       sse_mul_ps(&this->Data[0].Data, &m.Data[0].Data, &this->Data[0].Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator/= 
+(
+       fmat4x4SIMD const & m
+)
+{
+       __m128 Inv[4];
+       sse_inverse_ps(&m.Data[0].Data, Inv);
+       sse_mul_ps(&this->Data[0].Data, Inv, &this->Data[0].Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator+= 
+(
+       float const & s
+)
+{
+       __m128 Operand = _mm_set_ps1(s);
+       this->Data[0].Data = _mm_add_ps(this->Data[0].Data, Operand);
+       this->Data[1].Data = _mm_add_ps(this->Data[1].Data, Operand);
+       this->Data[2].Data = _mm_add_ps(this->Data[2].Data, Operand);
+       this->Data[3].Data = _mm_add_ps(this->Data[3].Data, Operand);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-= 
+(
+       float const & s
+)
+{
+       __m128 Operand = _mm_set_ps1(s);
+       this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, Operand);
+       this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, Operand);
+       this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, Operand);
+       this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, Operand);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator*= 
+(
+       float const & s
+)
+{
+       __m128 Operand = _mm_set_ps1(s);
+       this->Data[0].Data = _mm_mul_ps(this->Data[0].Data, Operand);
+       this->Data[1].Data = _mm_mul_ps(this->Data[1].Data, Operand);
+       this->Data[2].Data = _mm_mul_ps(this->Data[2].Data, Operand);
+       this->Data[3].Data = _mm_mul_ps(this->Data[3].Data, Operand);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator/= 
+(
+       float const & s
+)
+{
+       __m128 Operand = _mm_div_ps(one, _mm_set_ps1(s));
+       this->Data[0].Data = _mm_mul_ps(this->Data[0].Data, Operand);
+       this->Data[1].Data = _mm_mul_ps(this->Data[1].Data, Operand);
+       this->Data[2].Data = _mm_mul_ps(this->Data[2].Data, Operand);
+       this->Data[3].Data = _mm_mul_ps(this->Data[3].Data, Operand);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator++ ()
+{
+       this->Data[0].Data = _mm_add_ps(this->Data[0].Data, one);
+       this->Data[1].Data = _mm_add_ps(this->Data[1].Data, one);
+       this->Data[2].Data = _mm_add_ps(this->Data[2].Data, one);
+       this->Data[3].Data = _mm_add_ps(this->Data[3].Data, one);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD & fmat4x4SIMD::operator-- ()
+{
+       this->Data[0].Data = _mm_sub_ps(this->Data[0].Data, one);
+       this->Data[1].Data = _mm_sub_ps(this->Data[1].Data, one);
+       this->Data[2].Data = _mm_sub_ps(this->Data[2].Data, one);
+       this->Data[3].Data = _mm_sub_ps(this->Data[3].Data, one);
+       return *this;
+}
+
+
+//////////////////////////////////////////////////////////////
+// Binary operators
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
+(
+       const fmat4x4SIMD &m,
+       float const & s
+)
+{
+       return detail::fmat4x4SIMD
+       (
+               m[0] + s,
+               m[1] + s,
+               m[2] + s,
+               m[3] + s
+       );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
+(
+       float const & s,
+       const fmat4x4SIMD &m
+)
+{
+       return detail::fmat4x4SIMD
+       (
+               m[0] + s,
+               m[1] + s,
+               m[2] + s,
+               m[3] + s
+       );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator+
+(
+    const fmat4x4SIMD &m1,
+    const fmat4x4SIMD &m2
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m1[0] + m2[0],
+        m1[1] + m2[1],
+        m1[2] + m2[2],
+        m1[3] + m2[3]
+    );
+}
+
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
+(
+    const fmat4x4SIMD &m,
+    float const & s
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] - s,
+        m[1] - s,
+        m[2] - s,
+        m[3] - s
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
+(
+    float const & s,
+    const fmat4x4SIMD &m
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        s - m[0],
+        s - m[1],
+        s - m[2],
+        s - m[3]
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator-
+(
+    const fmat4x4SIMD &m1,
+    const fmat4x4SIMD &m2
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m1[0] - m2[0],
+        m1[1] - m2[1],
+        m1[2] - m2[2],
+        m1[3] - m2[3]
+    );
+}
+
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
+(
+    const fmat4x4SIMD &m,
+    float const & s
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] * s,
+        m[1] * s,
+        m[2] * s,
+        m[3] * s
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
+(
+    float const & s,
+    const fmat4x4SIMD &m
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] * s,
+        m[1] * s,
+        m[2] * s,
+        m[3] * s
+    );
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator*
+(
+    const fmat4x4SIMD &m,
+    fvec4SIMD const & v
+)
+{
+    return sse_mul_ps(&m.Data[0].Data, v.Data);
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator*
+(
+    fvec4SIMD const & v,
+    const fmat4x4SIMD &m
+)
+{
+    return sse_mul_ps(v.Data, &m.Data[0].Data);
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator*
+(
+    const fmat4x4SIMD &m1,
+    const fmat4x4SIMD &m2
+)
+{
+    fmat4x4SIMD result;
+    sse_mul_ps(&m1.Data[0].Data, &m2.Data[0].Data, &result.Data[0].Data);
+    
+    return result;
+}
+    
+
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
+(
+    const fmat4x4SIMD &m,
+    float const & s
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] / s,
+        m[1] / s,
+        m[2] / s,
+        m[3] / s
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
+(
+    float const & s,
+    const fmat4x4SIMD &m
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        s / m[0],
+        s / m[1],
+        s / m[2],
+        s / m[3]
+    );
+}
+
+GLM_FUNC_QUALIFIER detail::fmat4x4SIMD inverse(detail::fmat4x4SIMD const & m)
+{
+       detail::fmat4x4SIMD result;
+       detail::sse_inverse_ps(&m[0].Data, &result[0].Data);
+       return result;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator/
+(
+       const fmat4x4SIMD & m,
+       fvec4SIMD const & v
+)
+{
+       return inverse(m) * v;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator/
+(
+       fvec4SIMD const & v,
+       const fmat4x4SIMD &m
+)
+{
+       return v * inverse(m);
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD operator/
+(
+       const fmat4x4SIMD &m1,
+       const fmat4x4SIMD &m2
+)
+{
+       __m128 result[4];
+       __m128 inv[4];
+
+       sse_inverse_ps(&m2.Data[0].Data, inv);
+       sse_mul_ps(&m1.Data[0].Data, inv, result);
+
+       return fmat4x4SIMD(result);
+}
+
+
+//////////////////////////////////////////////////////////////
+// Unary constant operators
+GLM_FUNC_QUALIFIER fmat4x4SIMD const operator-
+(
+    fmat4x4SIMD const & m
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        -m[0],
+        -m[1],
+        -m[2],
+        -m[3]
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD const operator--
+(
+    fmat4x4SIMD const & m,
+    int
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] - 1.0f,
+        m[1] - 1.0f,
+        m[2] - 1.0f,
+        m[3] - 1.0f
+    );
+}
+
+GLM_FUNC_QUALIFIER fmat4x4SIMD const operator++
+(
+    fmat4x4SIMD const & m,
+    int
+)
+{
+    return detail::fmat4x4SIMD
+    (
+        m[0] + 1.0f,
+        m[1] + 1.0f,
+        m[2] + 1.0f,
+        m[3] + 1.0f
+    );
+}
+
+}//namespace detail
+
+GLM_FUNC_QUALIFIER mat4 mat4_cast
+(
+       detail::fmat4x4SIMD const & x
+)
+{
+       GLM_ALIGN(16) mat4 Result;
+       _mm_store_ps(&Result[0][0], x.Data[0].Data);
+       _mm_store_ps(&Result[1][0], x.Data[1].Data);
+       _mm_store_ps(&Result[2][0], x.Data[2].Data);
+       _mm_store_ps(&Result[3][0], x.Data[3].Data);
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER detail::fmat4x4SIMD matrixCompMult
+(
+       detail::fmat4x4SIMD const & x,
+       detail::fmat4x4SIMD const & y
+)
+{
+       detail::fmat4x4SIMD result;
+       result[0] = x[0] * y[0];
+       result[1] = x[1] * y[1];
+       result[2] = x[2] * y[2];
+       result[3] = x[3] * y[3];
+       return result;
+}
+
+GLM_FUNC_QUALIFIER detail::fmat4x4SIMD outerProduct
+(
+       detail::fvec4SIMD const & c,
+       detail::fvec4SIMD const & r
+)
+{
+       __m128 Shu0 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Shu1 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 Shu2 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 Shu3 = _mm_shuffle_ps(r.Data, r.Data, _MM_SHUFFLE(3, 3, 3, 3));
+
+       detail::fmat4x4SIMD result(uninitialize);
+       result[0].Data = _mm_mul_ps(c.Data, Shu0);
+       result[1].Data = _mm_mul_ps(c.Data, Shu1);
+       result[2].Data = _mm_mul_ps(c.Data, Shu2);
+       result[3].Data = _mm_mul_ps(c.Data, Shu3);
+       return result;
+}
+
+GLM_FUNC_QUALIFIER detail::fmat4x4SIMD transpose(detail::fmat4x4SIMD const & m)
+{
+       detail::fmat4x4SIMD result;
+       glm_mat4_transpose(&m[0].Data, &result[0].Data);
+       return result;
+}
+
+GLM_FUNC_QUALIFIER float determinant(detail::fmat4x4SIMD const & m)
+{
+       float Result;
+       _mm_store_ss(&Result, glm_mat4_determinant(&m[0].Data));
+       return Result;
+}
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/simd_quat.hpp b/core/deps/glm/glm/gtx/simd_quat.hpp
new file mode 100755 (executable)
index 0000000..b134019
--- /dev/null
@@ -0,0 +1,307 @@
+/// @ref gtx_simd_quat
+/// @file glm/gtx/simd_quat.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_simd_quat GLM_GTX_simd_quat
+/// @ingroup gtx
+///
+/// @brief SIMD implementation of quat type.
+///
+/// <glm/gtx/simd_quat.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/quaternion.hpp"
+#include "../gtx/fast_trigonometry.hpp"
+
+#if GLM_ARCH != GLM_ARCH_PURE
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+#      include "../gtx/simd_mat4.hpp"
+#else
+#      error "GLM: GLM_GTX_simd_quat requires compiler support of SSE2 through intrinsics"
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_simd_quat extension included")
+#      pragma message("GLM: GLM_GTX_simd_quat extension is deprecated and will be removed in GLM 0.9.9. Use GLM_GTC_quaternion instead and use compiler SIMD arguments.")
+#endif
+
+// Warning silencer for nameless struct/union.
+#if (GLM_COMPILER & GLM_COMPILER_VC)
+#   pragma warning(push)
+#   pragma warning(disable:4201)   // warning C4201: nonstandard extension used : nameless struct/union
+#endif
+
+namespace glm{
+namespace detail
+{
+       GLM_ALIGNED_STRUCT(16) fquatSIMD
+       {
+               typedef float value_type;
+               typedef std::size_t size_type;
+
+               typedef fquatSIMD type;
+               typedef tquat<bool, defaultp> bool_type;
+               typedef tquat<float, defaultp> pure_type;
+
+#ifdef GLM_SIMD_ENABLE_XYZW_UNION
+               union
+               {
+                       __m128 Data;
+                       struct {float x, y, z, w;};
+               };
+#else
+               __m128 Data;
+#endif
+
+               //////////////////////////////////////
+               // Implicit basic constructors
+
+               fquatSIMD() GLM_DEFAULT_CTOR;
+               fquatSIMD(fquatSIMD const & q) GLM_DEFAULT;
+               fquatSIMD(__m128 const & Data);
+
+               //////////////////////////////////////
+               // Explicit basic constructors
+
+               explicit fquatSIMD(
+                       ctor);
+               explicit fquatSIMD(
+                       float const & w,
+                       float const & x,
+                       float const & y,
+                       float const & z);
+               explicit fquatSIMD(
+                       quat const & v);
+               explicit fquatSIMD(
+                       vec3 const & eulerAngles);
+
+
+               //////////////////////////////////////
+               // Unary arithmetic operators
+
+               fquatSIMD& operator= (fquatSIMD const & q) GLM_DEFAULT;
+               fquatSIMD& operator*=(float const & s);
+               fquatSIMD& operator/=(float const & s);
+       };
+
+
+       //////////////////////////////////////
+       // Arithmetic operators
+
+       detail::fquatSIMD operator- (
+               detail::fquatSIMD const & q);
+
+       detail::fquatSIMD operator+ (
+               detail::fquatSIMD const & q,
+               detail::fquatSIMD const & p);
+
+       detail::fquatSIMD operator* (
+               detail::fquatSIMD const & q,
+               detail::fquatSIMD const & p);
+
+       detail::fvec4SIMD operator* (
+               detail::fquatSIMD const & q,
+               detail::fvec4SIMD const & v);
+
+       detail::fvec4SIMD operator* (
+               detail::fvec4SIMD const & v,
+               detail::fquatSIMD const & q);
+
+       detail::fquatSIMD operator* (
+               detail::fquatSIMD const & q,
+               float s);
+
+       detail::fquatSIMD operator* (
+               float s,
+               detail::fquatSIMD const & q);
+
+       detail::fquatSIMD operator/ (
+               detail::fquatSIMD const & q,
+               float s);
+
+}//namespace detail
+
+       /// @addtogroup gtx_simd_quat
+       /// @{
+
+       typedef glm::detail::fquatSIMD simdQuat;
+
+       //! Convert a simdQuat to a quat.
+       /// @see gtx_simd_quat
+       quat quat_cast(
+               detail::fquatSIMD const & x);
+
+       //! Convert a simdMat4 to a simdQuat.
+       /// @see gtx_simd_quat
+       detail::fquatSIMD quatSIMD_cast(
+               detail::fmat4x4SIMD const & m);
+
+       //! Converts a mat4 to a simdQuat.
+       /// @see gtx_simd_quat
+       template <typename T, precision P>
+       detail::fquatSIMD quatSIMD_cast(
+               tmat4x4<T, P> const & m);
+
+       //! Converts a mat3 to a simdQuat.
+       /// @see gtx_simd_quat
+       template <typename T, precision P>
+       detail::fquatSIMD quatSIMD_cast(
+               tmat3x3<T, P> const & m);
+
+       //! Convert a simdQuat to a simdMat4
+       /// @see gtx_simd_quat
+       detail::fmat4x4SIMD mat4SIMD_cast(
+               detail::fquatSIMD const & q);
+
+       //! Converts a simdQuat to a standard mat4.
+       /// @see gtx_simd_quat
+       mat4 mat4_cast(
+               detail::fquatSIMD const & q);
+
+
+       /// Returns the length of the quaternion.
+       ///
+       /// @see gtx_simd_quat
+       float length(
+               detail::fquatSIMD const & x);
+
+       /// Returns the normalized quaternion.
+       ///
+       /// @see gtx_simd_quat
+       detail::fquatSIMD normalize(
+               detail::fquatSIMD const & x);
+
+       /// Returns dot product of q1 and q2, i.e., q1[0] * q2[0] + q1[1] * q2[1] + ...
+       ///
+       /// @see gtx_simd_quat
+       float dot(
+               detail::fquatSIMD const & q1,
+               detail::fquatSIMD const & q2);
+
+       /// Spherical linear interpolation of two quaternions.
+       /// The interpolation is oriented and the rotation is performed at constant speed.
+       /// For short path spherical linear interpolation, use the slerp function.
+       ///
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtx_simd_quat
+       /// @see - slerp(detail::fquatSIMD const & x, detail::fquatSIMD const & y, T const & a)
+       detail::fquatSIMD mix(
+               detail::fquatSIMD const & x,
+               detail::fquatSIMD const & y,
+               float const & a);
+
+       /// Linear interpolation of two quaternions.
+       /// The interpolation is oriented.
+       ///
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined in the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtx_simd_quat
+       detail::fquatSIMD lerp(
+               detail::fquatSIMD const & x,
+               detail::fquatSIMD const & y,
+               float const & a);
+
+       /// Spherical linear interpolation of two quaternions.
+       /// The interpolation always take the short path and the rotation is performed at constant speed.
+       ///
+       /// @param x A quaternion
+       /// @param y A quaternion
+       /// @param a Interpolation factor. The interpolation is defined beyond the range [0, 1].
+       /// @tparam T Value type used to build the quaternion. Supported: half, float or double.
+       /// @see gtx_simd_quat
+       detail::fquatSIMD slerp(
+               detail::fquatSIMD const & x,
+               detail::fquatSIMD const & y,
+               float const & a);
+
+
+       /// Faster spherical linear interpolation of two unit length quaternions.
+       ///
+       /// This is the same as mix(), except for two rules:
+       ///   1) The two quaternions must be unit length.
+       ///   2) The interpolation factor (a) must be in the range [0, 1].
+       ///
+       /// This will use the equivalent to fastAcos() and fastSin().
+       ///
+       /// @see gtx_simd_quat
+       /// @see - mix(detail::fquatSIMD const & x, detail::fquatSIMD const & y, T const & a)
+       detail::fquatSIMD fastMix(
+               detail::fquatSIMD const & x,
+               detail::fquatSIMD const & y,
+               float const & a);
+
+       /// Identical to fastMix() except takes the shortest path.
+       ///
+       /// The same rules apply here as those in fastMix(). Both quaternions must be unit length and 'a' must be
+       /// in the range [0, 1].
+       ///
+       /// @see - fastMix(detail::fquatSIMD const & x, detail::fquatSIMD const & y, T const & a)
+       /// @see - slerp(detail::fquatSIMD const & x, detail::fquatSIMD const & y, T const & a)
+       detail::fquatSIMD fastSlerp(
+               detail::fquatSIMD const & x,
+               detail::fquatSIMD const & y,
+               float const & a);
+
+
+       /// Returns the q conjugate.
+       ///
+       /// @see gtx_simd_quat
+       detail::fquatSIMD conjugate(
+               detail::fquatSIMD const & q);
+
+       /// Returns the q inverse.
+       ///
+       /// @see gtx_simd_quat
+       detail::fquatSIMD inverse(
+               detail::fquatSIMD const & q);
+
+       /// Build a quaternion from an angle and a normalized axis.
+       ///
+       /// @param angle Angle expressed in radians.
+       /// @param axis Axis of the quaternion, must be normalized.
+       ///
+       /// @see gtx_simd_quat
+       detail::fquatSIMD angleAxisSIMD(
+               float const & angle,
+               vec3 const & axis);
+
+       /// Build a quaternion from an angle and a normalized axis.
+       ///
+       /// @param angle Angle expressed in radians.
+       /// @param x x component of the x-axis, x, y, z must be a normalized axis
+       /// @param y y component of the y-axis, x, y, z must be a normalized axis
+       /// @param z z component of the z-axis, x, y, z must be a normalized axis
+       ///
+       /// @see gtx_simd_quat
+       detail::fquatSIMD angleAxisSIMD(
+               float const & angle,
+               float const & x,
+               float const & y,
+               float const & z);
+
+       // TODO: Move this to somewhere more appropriate. Used with fastMix() and fastSlerp().
+       /// Performs the equivalent of glm::fastSin() on each component of the given __m128.
+       __m128 fastSin(__m128 x);
+
+       /// @}
+}//namespace glm
+
+#include "simd_quat.inl"
+
+
+#if (GLM_COMPILER & GLM_COMPILER_VC)
+#   pragma warning(pop)
+#endif
+
+
+#endif//(GLM_ARCH != GLM_ARCH_PURE)
diff --git a/core/deps/glm/glm/gtx/simd_quat.inl b/core/deps/glm/glm/gtx/simd_quat.inl
new file mode 100755 (executable)
index 0000000..b84865c
--- /dev/null
@@ -0,0 +1,620 @@
+/// @ref gtx_simd_quat
+/// @file glm/gtx/simd_quat.inl
+
+namespace glm{
+namespace detail{
+
+
+//////////////////////////////////////
+// Debugging
+#if 0
+void print(__m128 v)
+{
+    GLM_ALIGN(16) float result[4];
+    _mm_store_ps(result, v);
+
+    printf("__m128:    %f %f %f %f\n", result[0], result[1], result[2], result[3]);
+}
+
+void print(const fvec4SIMD &v)
+{
+    printf("fvec4SIMD: %f %f %f %f\n", v.x, v.y, v.z, v.w);
+}
+#endif
+
+//////////////////////////////////////
+// Implicit basic constructors
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+       GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD()
+#              ifdef GLM_FORCE_NO_CTOR_INIT
+                       : Data(_mm_set_ps(1.0f, 0.0f, 0.0f, 0.0f))
+#              endif
+       {}
+#      endif
+
+#      if !GLM_HAS_DEFAULTED_FUNCTIONS
+       GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD(fquatSIMD const & q) :
+               Data(q.Data)
+       {}
+#      endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD(__m128 const & Data) :
+       Data(Data)
+{}
+
+//////////////////////////////////////
+// Explicit basic constructors
+
+GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD(float const & w, float const & x, float const & y, float const & z) :
+       Data(_mm_set_ps(w, z, y, x))
+{}
+
+GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD(quat const & q) :
+       Data(_mm_set_ps(q.w, q.z, q.y, q.x))
+{}
+
+GLM_FUNC_QUALIFIER fquatSIMD::fquatSIMD(vec3 const & eulerAngles)
+{
+       vec3 c = glm::cos(eulerAngles * 0.5f);
+       vec3 s = glm::sin(eulerAngles * 0.5f);
+
+       Data = _mm_set_ps(
+               (c.x * c.y * c.z) + (s.x * s.y * s.z),
+               (c.x * c.y * s.z) - (s.x * s.y * c.z),
+               (c.x * s.y * c.z) + (s.x * c.y * s.z),
+               (s.x * c.y * c.z) - (c.x * s.y * s.z));
+}
+
+
+//////////////////////////////////////
+// Unary arithmetic operators
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS
+       GLM_FUNC_QUALIFIER fquatSIMD& fquatSIMD::operator=(fquatSIMD const & q)
+       {
+               this->Data = q.Data;
+               return *this;
+       }
+#endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fquatSIMD& fquatSIMD::operator*=(float const & s)
+{
+       this->Data = _mm_mul_ps(this->Data, _mm_set_ps1(s));
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fquatSIMD& fquatSIMD::operator/=(float const & s)
+{
+       this->Data = _mm_div_ps(Data, _mm_set1_ps(s));
+       return *this;
+}
+
+
+
+// negate operator
+GLM_FUNC_QUALIFIER fquatSIMD operator- (fquatSIMD const & q)
+{
+    return fquatSIMD(_mm_mul_ps(q.Data, _mm_set_ps(-1.0f, -1.0f, -1.0f, -1.0f)));
+}
+
+// operator+
+GLM_FUNC_QUALIFIER fquatSIMD operator+ (fquatSIMD const & q1, fquatSIMD const & q2)
+{
+       return fquatSIMD(_mm_add_ps(q1.Data, q2.Data));
+}
+
+//operator*
+GLM_FUNC_QUALIFIER fquatSIMD operator* (fquatSIMD const & q1, fquatSIMD const & q2)
+{
+    // SSE2 STATS:
+    //    11 shuffle
+    //    8  mul
+    //    8  add
+    
+    // SSE4 STATS:
+    //    3 shuffle
+    //    4 mul
+    //    4 dpps
+
+    __m128 mul0 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(0, 1, 2, 3)));
+    __m128 mul1 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(1, 0, 3, 2)));
+    __m128 mul2 = _mm_mul_ps(q1.Data, _mm_shuffle_ps(q2.Data, q2.Data, _MM_SHUFFLE(2, 3, 0, 1)));
+    __m128 mul3 = _mm_mul_ps(q1.Data, q2.Data);
+
+#   if(GLM_ARCH & GLM_ARCH_SSE41_BIT)
+    __m128 add0 = _mm_dp_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f), 0xff);
+    __m128 add1 = _mm_dp_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f), 0xff);
+    __m128 add2 = _mm_dp_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f), 0xff);
+    __m128 add3 = _mm_dp_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f), 0xff);
+#   else
+           mul0 = _mm_mul_ps(mul0, _mm_set_ps(1.0f, -1.0f,  1.0f,  1.0f));
+    __m128 add0 = _mm_add_ps(mul0, _mm_movehl_ps(mul0, mul0));
+           add0 = _mm_add_ss(add0, _mm_shuffle_ps(add0, add0, 1));
+
+           mul1 = _mm_mul_ps(mul1, _mm_set_ps(1.0f,  1.0f,  1.0f, -1.0f));
+    __m128 add1 = _mm_add_ps(mul1, _mm_movehl_ps(mul1, mul1));
+           add1 = _mm_add_ss(add1, _mm_shuffle_ps(add1, add1, 1));
+
+           mul2 = _mm_mul_ps(mul2, _mm_set_ps(1.0f,  1.0f, -1.0f,  1.0f));
+    __m128 add2 = _mm_add_ps(mul2, _mm_movehl_ps(mul2, mul2));
+           add2 = _mm_add_ss(add2, _mm_shuffle_ps(add2, add2, 1));
+
+           mul3 = _mm_mul_ps(mul3, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f));
+    __m128 add3 = _mm_add_ps(mul3, _mm_movehl_ps(mul3, mul3));
+           add3 = _mm_add_ss(add3, _mm_shuffle_ps(add3, add3, 1));
+#endif
+
+
+    // This SIMD code is a politically correct way of doing this, but in every test I've tried it has been slower than
+    // the final code below. I'll keep this here for reference - maybe somebody else can do something better...
+    //
+    //__m128 xxyy = _mm_shuffle_ps(add0, add1, _MM_SHUFFLE(0, 0, 0, 0));
+    //__m128 zzww = _mm_shuffle_ps(add2, add3, _MM_SHUFFLE(0, 0, 0, 0));
+    //
+    //return _mm_shuffle_ps(xxyy, zzww, _MM_SHUFFLE(2, 0, 2, 0));
+    
+    float x;
+    float y;
+    float z;
+    float w;
+
+    _mm_store_ss(&x, add0);
+    _mm_store_ss(&y, add1);
+    _mm_store_ss(&z, add2);
+    _mm_store_ss(&w, add3);
+
+    return detail::fquatSIMD(w, x, y, z);
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator* (fquatSIMD const & q, fvec4SIMD const & v)
+{
+    static const __m128 two = _mm_set1_ps(2.0f);
+
+    __m128 q_wwww  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 3, 3, 3));
+    __m128 q_swp0  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 0, 2, 1));
+       __m128 q_swp1  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 1, 0, 2));
+       __m128 v_swp0  = _mm_shuffle_ps(v.Data, v.Data, _MM_SHUFFLE(3, 0, 2, 1));
+       __m128 v_swp1  = _mm_shuffle_ps(v.Data, v.Data, _MM_SHUFFLE(3, 1, 0, 2));
+       
+       __m128 uv      = _mm_sub_ps(_mm_mul_ps(q_swp0, v_swp1), _mm_mul_ps(q_swp1, v_swp0));
+    __m128 uv_swp0 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 0, 2, 1));
+    __m128 uv_swp1 = _mm_shuffle_ps(uv, uv, _MM_SHUFFLE(3, 1, 0, 2));
+    __m128 uuv     = _mm_sub_ps(_mm_mul_ps(q_swp0, uv_swp1), _mm_mul_ps(q_swp1, uv_swp0));
+
+    
+    uv  = _mm_mul_ps(uv,  _mm_mul_ps(q_wwww, two));
+    uuv = _mm_mul_ps(uuv, two);
+
+    return _mm_add_ps(v.Data, _mm_add_ps(uv, uuv));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator* (fvec4SIMD const & v, fquatSIMD const & q)
+{
+       return glm::inverse(q) * v;
+}
+
+GLM_FUNC_QUALIFIER fquatSIMD operator* (fquatSIMD const & q, float s)
+{
+       return fquatSIMD(_mm_mul_ps(q.Data, _mm_set1_ps(s)));
+}
+
+GLM_FUNC_QUALIFIER fquatSIMD operator* (float s, fquatSIMD const & q)
+{
+       return fquatSIMD(_mm_mul_ps(_mm_set1_ps(s), q.Data));
+}
+
+
+//operator/
+GLM_FUNC_QUALIFIER fquatSIMD operator/ (fquatSIMD const & q, float s)
+{
+       return fquatSIMD(_mm_div_ps(q.Data, _mm_set1_ps(s)));
+}
+
+
+}//namespace detail
+
+
+GLM_FUNC_QUALIFIER quat quat_cast
+(
+       detail::fquatSIMD const & x
+)
+{
+       GLM_ALIGN(16) quat Result;
+       _mm_store_ps(&Result[0], x.Data);
+
+       return Result;
+}
+
+template <typename T>
+GLM_FUNC_QUALIFIER detail::fquatSIMD quatSIMD_cast_impl(const T m0[], const T m1[], const T m2[])
+{
+    T trace = m0[0] + m1[1] + m2[2] + T(1.0);
+    if (trace > T(0))
+    {
+        T s = static_cast<T>(0.5) / sqrt(trace);
+
+        return _mm_set_ps(
+            static_cast<float>(T(0.25) / s),
+            static_cast<float>((m0[1] - m1[0]) * s),
+            static_cast<float>((m2[0] - m0[2]) * s),
+            static_cast<float>((m1[2] - m2[1]) * s));
+    }
+    else
+    {
+        if (m0[0] > m1[1])
+        {
+            if (m0[0] > m2[2])
+            {
+                // X is biggest.
+                T s = sqrt(m0[0] - m1[1] - m2[2] + T(1.0)) * T(0.5);
+
+                return _mm_set_ps(
+                    static_cast<float>((m1[2] - m2[1]) * s),
+                    static_cast<float>((m2[0] + m0[2]) * s),
+                    static_cast<float>((m0[1] + m1[0]) * s),
+                    static_cast<float>(T(0.5)          * s));
+            }
+        }
+        else
+        {
+            if (m1[1] > m2[2])
+            {
+                // Y is biggest.
+                T s = sqrt(m1[1] - m0[0] - m2[2] + T(1.0)) * T(0.5);
+
+                return _mm_set_ps(
+                    static_cast<float>((m2[0] - m0[2]) * s),
+                    static_cast<float>((m1[2] + m2[1]) * s),
+                    static_cast<float>(T(0.5)          * s),
+                    static_cast<float>((m0[1] + m1[0]) * s));
+            }
+        }
+
+        // Z is biggest.
+        T s = sqrt(m2[2] - m0[0] - m1[1] + T(1.0)) * T(0.5);
+
+        return _mm_set_ps(
+            static_cast<float>((m0[1] - m1[0]) * s),
+            static_cast<float>(T(0.5)          * s),
+            static_cast<float>((m1[2] + m2[1]) * s),
+            static_cast<float>((m2[0] + m0[2]) * s));
+    }
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD quatSIMD_cast
+(
+       detail::fmat4x4SIMD const & m
+)
+{
+    // Scalar implementation for now.
+    GLM_ALIGN(16) float m0[4];
+    GLM_ALIGN(16) float m1[4];
+    GLM_ALIGN(16) float m2[4];
+
+    _mm_store_ps(m0, m[0].Data);
+    _mm_store_ps(m1, m[1].Data);
+    _mm_store_ps(m2, m[2].Data);
+
+    return quatSIMD_cast_impl(m0, m1, m2);
+}
+
+template <typename T, precision P>
+GLM_FUNC_QUALIFIER detail::fquatSIMD quatSIMD_cast
+(
+    tmat4x4<T, P> const & m
+)
+{
+    return quatSIMD_cast_impl(&m[0][0], &m[1][0], &m[2][0]);
+}
+
+template <typename T, precision P>
+GLM_FUNC_QUALIFIER detail::fquatSIMD quatSIMD_cast
+(
+    tmat3x3<T, P> const & m
+)
+{
+    return quatSIMD_cast_impl(&m[0][0], &m[1][0], &m[2][0]);
+}
+
+
+GLM_FUNC_QUALIFIER detail::fmat4x4SIMD mat4SIMD_cast
+(
+       detail::fquatSIMD const & q
+)
+{
+    detail::fmat4x4SIMD result;
+
+    __m128 _wwww  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 3, 3, 3));
+    __m128 _xyzw  = q.Data;
+    __m128 _zxyw  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 1, 0, 2));
+    __m128 _yzxw  = _mm_shuffle_ps(q.Data, q.Data, _MM_SHUFFLE(3, 0, 2, 1));
+
+    __m128 _xyzw2 = _mm_add_ps(_xyzw, _xyzw);
+    __m128 _zxyw2 = _mm_shuffle_ps(_xyzw2, _xyzw2, _MM_SHUFFLE(3, 1, 0, 2));
+    __m128 _yzxw2 = _mm_shuffle_ps(_xyzw2, _xyzw2, _MM_SHUFFLE(3, 0, 2, 1));
+    
+    __m128 _tmp0  = _mm_sub_ps(_mm_set1_ps(1.0f), _mm_mul_ps(_yzxw2, _yzxw));
+           _tmp0  = _mm_sub_ps(_tmp0, _mm_mul_ps(_zxyw2, _zxyw));
+
+    __m128 _tmp1  = _mm_mul_ps(_yzxw2, _xyzw);
+           _tmp1  = _mm_add_ps(_tmp1, _mm_mul_ps(_zxyw2, _wwww));
+
+    __m128 _tmp2  = _mm_mul_ps(_zxyw2, _xyzw);
+           _tmp2  = _mm_sub_ps(_tmp2, _mm_mul_ps(_yzxw2, _wwww));
+
+
+    // There's probably a better, more politically correct way of doing this...
+    result[0].Data = _mm_set_ps(
+        0.0f,
+        reinterpret_cast<float*>(&_tmp2)[0],
+        reinterpret_cast<float*>(&_tmp1)[0],
+        reinterpret_cast<float*>(&_tmp0)[0]);
+
+    result[1].Data = _mm_set_ps(
+        0.0f,
+        reinterpret_cast<float*>(&_tmp1)[1],
+        reinterpret_cast<float*>(&_tmp0)[1],
+        reinterpret_cast<float*>(&_tmp2)[1]);
+
+    result[2].Data = _mm_set_ps(
+        0.0f,
+        reinterpret_cast<float*>(&_tmp0)[2],
+        reinterpret_cast<float*>(&_tmp2)[2],
+        reinterpret_cast<float*>(&_tmp1)[2]);
+
+   result[3].Data = _mm_set_ps(
+        1.0f,
+        0.0f,
+        0.0f,
+        0.0f);
+
+
+    return result;
+}
+
+GLM_FUNC_QUALIFIER mat4 mat4_cast
+(
+       detail::fquatSIMD const & q
+)
+{
+    return mat4_cast(mat4SIMD_cast(q));
+}
+
+
+
+GLM_FUNC_QUALIFIER float length
+(
+       detail::fquatSIMD const & q
+)
+{
+    return glm::sqrt(dot(q, q));
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD normalize
+(
+       detail::fquatSIMD const & q
+)
+{
+    return _mm_mul_ps(q.Data, _mm_set1_ps(1.0f / length(q)));
+}
+
+GLM_FUNC_QUALIFIER float dot
+(
+       detail::fquatSIMD const & q1,
+       detail::fquatSIMD const & q2
+)
+{
+    float result;
+    _mm_store_ss(&result, detail::sse_dot_ps(q1.Data, q2.Data));
+
+    return result;
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD mix
+(
+       detail::fquatSIMD const & x, 
+       detail::fquatSIMD const & y, 
+       float const & a
+)
+{
+       float cosTheta = dot(x, y);
+
+    if (cosTheta > 1.0f - glm::epsilon<float>())
+    {
+           return _mm_add_ps(x.Data, _mm_mul_ps(_mm_set1_ps(a), _mm_sub_ps(y.Data, x.Data)));
+    }
+    else
+    {
+        float angle = glm::acos(cosTheta);
+        
+        
+        float s0 = glm::sin((1.0f - a) * angle);
+        float s1 = glm::sin(a * angle);
+        float d  = 1.0f / glm::sin(angle);
+
+        return (s0 * x + s1 * y) * d;
+    }
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD lerp
+(
+       detail::fquatSIMD const & x, 
+       detail::fquatSIMD const & y, 
+       float const & a
+)
+{
+       // Lerp is only defined in [0, 1]
+       assert(a >= 0.0f);
+       assert(a <= 1.0f);
+
+    return _mm_add_ps(x.Data, _mm_mul_ps(_mm_set1_ps(a), _mm_sub_ps(y.Data, x.Data)));
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD slerp
+(
+       detail::fquatSIMD const & x, 
+       detail::fquatSIMD const & y, 
+       float const & a
+)
+{
+       detail::fquatSIMD z = y;
+
+       float cosTheta = dot(x, y);
+
+       // If cosTheta < 0, the interpolation will take the long way around the sphere. 
+       // To fix this, one quat must be negated.
+       if (cosTheta < 0.0f)
+       {
+               z        = -y;
+               cosTheta = -cosTheta;
+       }
+
+       // Perform a linear interpolation when cosTheta is close to 1 to avoid side effect of sin(angle) becoming a zero denominator
+       if(cosTheta > 1.0f - epsilon<float>())
+       {
+               return _mm_add_ps(x.Data, _mm_mul_ps(_mm_set1_ps(a), _mm_sub_ps(y.Data, x.Data)));
+       }
+       else
+       {
+        float angle = glm::acos(cosTheta);
+
+
+               float s0 = glm::sin((1.0f - a) * angle);
+        float s1 = glm::sin(a * angle);
+        float d  = 1.0f / glm::sin(angle);
+
+        return (s0 * x + s1 * y) * d;
+       }
+}
+
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD fastMix
+(
+       detail::fquatSIMD const & x, 
+       detail::fquatSIMD const & y, 
+       float const & a
+)
+{
+       float cosTheta = dot(x, y);
+
+    if (cosTheta > 1.0f - glm::epsilon<float>())
+    {
+           return _mm_add_ps(x.Data, _mm_mul_ps(_mm_set1_ps(a), _mm_sub_ps(y.Data, x.Data)));
+    }
+    else
+    {
+        float angle = glm::fastAcos(cosTheta);
+
+
+        __m128 s  = glm::fastSin(_mm_set_ps((1.0f - a) * angle, a * angle, angle, 0.0f));
+
+        __m128 s0 =                               _mm_shuffle_ps(s, s, _MM_SHUFFLE(3, 3, 3, 3));
+        __m128 s1 =                               _mm_shuffle_ps(s, s, _MM_SHUFFLE(2, 2, 2, 2));
+        __m128 d  = _mm_div_ps(_mm_set1_ps(1.0f), _mm_shuffle_ps(s, s, _MM_SHUFFLE(1, 1, 1, 1)));
+        
+        return _mm_mul_ps(_mm_add_ps(_mm_mul_ps(s0, x.Data), _mm_mul_ps(s1, y.Data)), d);
+    }
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD fastSlerp
+(
+       detail::fquatSIMD const & x, 
+       detail::fquatSIMD const & y, 
+       float const & a
+)
+{
+       detail::fquatSIMD z = y;
+
+       float cosTheta = dot(x, y);
+       if (cosTheta < 0.0f)
+       {
+               z        = -y;
+               cosTheta = -cosTheta;
+       }
+
+
+       if(cosTheta > 1.0f - epsilon<float>())
+       {
+               return _mm_add_ps(x.Data, _mm_mul_ps(_mm_set1_ps(a), _mm_sub_ps(y.Data, x.Data)));
+       }
+       else
+       {
+        float angle = glm::fastAcos(cosTheta);
+
+
+        __m128 s  = glm::fastSin(_mm_set_ps((1.0f - a) * angle, a * angle, angle, 0.0f));
+
+        __m128 s0 =                               _mm_shuffle_ps(s, s, _MM_SHUFFLE(3, 3, 3, 3));
+        __m128 s1 =                               _mm_shuffle_ps(s, s, _MM_SHUFFLE(2, 2, 2, 2));
+        __m128 d  = _mm_div_ps(_mm_set1_ps(1.0f), _mm_shuffle_ps(s, s, _MM_SHUFFLE(1, 1, 1, 1)));
+        
+        return _mm_mul_ps(_mm_add_ps(_mm_mul_ps(s0, x.Data), _mm_mul_ps(s1, y.Data)), d);
+       }
+}
+
+
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD conjugate
+(
+       detail::fquatSIMD const & q
+)
+{
+       return detail::fquatSIMD(_mm_mul_ps(q.Data, _mm_set_ps(1.0f, -1.0f, -1.0f, -1.0f)));
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD inverse
+(
+       detail::fquatSIMD const & q
+)
+{
+       return conjugate(q) / dot(q, q);
+}
+
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD angleAxisSIMD
+(
+       float const & angle,
+       vec3 const & v
+)
+{
+       float s = glm::sin(angle * 0.5f);
+
+       return _mm_set_ps(
+               glm::cos(angle * 0.5f),
+               v.z * s,
+               v.y * s,
+               v.x * s);
+}
+
+GLM_FUNC_QUALIFIER detail::fquatSIMD angleAxisSIMD
+(
+       float const & angle, 
+       float const & x, 
+       float const & y, 
+       float const & z
+)
+{
+       return angleAxisSIMD(angle, vec3(x, y, z));
+}
+
+
+GLM_FUNC_QUALIFIER __m128 fastSin(__m128 x)
+{
+       static const __m128 c0 = _mm_set1_ps(0.16666666666666666666666666666667f);
+       static const __m128 c1 = _mm_set1_ps(0.00833333333333333333333333333333f);
+       static const __m128 c2 = _mm_set1_ps(0.00019841269841269841269841269841f);
+
+       __m128 x3 = _mm_mul_ps(x,  _mm_mul_ps(x, x));
+       __m128 x5 = _mm_mul_ps(x3, _mm_mul_ps(x, x));
+       __m128 x7 = _mm_mul_ps(x5, _mm_mul_ps(x, x));
+
+       __m128 y0 = _mm_mul_ps(x3, c0);
+       __m128 y1 = _mm_mul_ps(x5, c1);
+       __m128 y2 = _mm_mul_ps(x7, c2);
+
+       return _mm_sub_ps(_mm_add_ps(_mm_sub_ps(x, y0), y1), y2);
+}
+
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/simd_vec4.hpp b/core/deps/glm/glm/gtx/simd_vec4.hpp
new file mode 100755 (executable)
index 0000000..cde540b
--- /dev/null
@@ -0,0 +1,546 @@
+/// @ref gtx_simd_vec4
+/// @file glm/gtx/simd_vec4.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_simd_vec4 GLM_GTX_simd_vec4
+/// @ingroup gtx
+///
+/// @brief SIMD implementation of vec4 type.
+///
+/// <glm/gtx/simd_vec4.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+
+#if(GLM_ARCH != GLM_ARCH_PURE)
+
+#if(GLM_ARCH & GLM_ARCH_SSE2_BIT)
+#      include "../detail/intrinsic_common.hpp"
+#      include "../detail/intrinsic_geometric.hpp"
+#      include "../detail/intrinsic_integer.hpp"
+#else
+#      error "GLM: GLM_GTX_simd_vec4 requires compiler support of SSE2 through intrinsics"
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_simd_vec4 extension included")
+#      pragma message("GLM: GLM_GTX_simd_vec4 extension is deprecated and will be removed in GLM 0.9.9. Use *vec4 types instead and use compiler SIMD arguments.")
+#endif
+
+
+// Warning silencer for nameless struct/union.
+#if (GLM_COMPILER & GLM_COMPILER_VC)
+#      pragma warning(push)
+#      pragma warning(disable:4201)   // warning C4201: nonstandard extension used : nameless struct/union
+#endif
+
+namespace glm
+{
+       enum comp
+       {
+               X = 0,
+               R = 0,
+               S = 0,
+               Y = 1,
+               G = 1,
+               T = 1,
+               Z = 2,
+               B = 2,
+               P = 2,
+               W = 3,
+               A = 3,
+               Q = 3
+       };
+
+}//namespace glm
+
+namespace glm{
+namespace detail
+{
+       /// 4-dimensional vector implemented using SIMD SEE intrinsics.
+       /// \ingroup gtx_simd_vec4
+       GLM_ALIGNED_STRUCT(16) fvec4SIMD
+       {
+               typedef float value_type;
+               typedef std::size_t size_type;
+
+               typedef fvec4SIMD type;
+               typedef tvec4<float, defaultp> pure_type;
+               typedef tvec4<bool, highp> bool_type;
+
+#ifdef GLM_SIMD_ENABLE_XYZW_UNION
+               union
+               {
+                       __m128 Data;
+                       struct {float x, y, z, w;};
+               };
+#else
+               __m128 Data;
+#endif
+
+               //////////////////////////////////////
+               // Implicit basic constructors
+
+               fvec4SIMD() GLM_DEFAULT_CTOR;
+               fvec4SIMD(fvec4SIMD const & v) GLM_DEFAULT;
+               fvec4SIMD(__m128 const & Data);
+
+               //////////////////////////////////////
+               // Explicit basic constructors
+
+               explicit fvec4SIMD(
+                       ctor);
+               explicit fvec4SIMD(
+                       float const & s);
+               explicit fvec4SIMD(
+                       float const & x,
+                       float const & y,
+                       float const & z,
+                       float const & w);
+               explicit fvec4SIMD(
+                       vec4 const & v);
+
+               ////////////////////////////////////////
+               //// Conversion vector constructors
+
+               fvec4SIMD(vec2 const & v, float const & s1, float const & s2);
+               fvec4SIMD(float const & s1, vec2 const & v, float const & s2);
+               fvec4SIMD(float const & s1, float const & s2, vec2 const & v);
+               fvec4SIMD(vec3 const & v, float const & s);
+               fvec4SIMD(float const & s, vec3 const & v);
+               fvec4SIMD(vec2 const & v1, vec2 const & v2);
+               //fvec4SIMD(ivec4SIMD const & v);
+
+               //////////////////////////////////////
+               // Unary arithmetic operators
+
+               fvec4SIMD& operator= (fvec4SIMD const & v) GLM_DEFAULT;
+               fvec4SIMD& operator+=(fvec4SIMD const & v);
+               fvec4SIMD& operator-=(fvec4SIMD const & v);
+               fvec4SIMD& operator*=(fvec4SIMD const & v);
+               fvec4SIMD& operator/=(fvec4SIMD const & v);
+
+               fvec4SIMD& operator+=(float const & s);
+               fvec4SIMD& operator-=(float const & s);
+               fvec4SIMD& operator*=(float const & s);
+               fvec4SIMD& operator/=(float const & s);
+
+               fvec4SIMD& operator++();
+               fvec4SIMD& operator--();
+
+               //////////////////////////////////////
+               // Swizzle operators
+
+               template <comp X_, comp Y_, comp Z_, comp W_>
+               fvec4SIMD& swizzle();
+               template <comp X_, comp Y_, comp Z_, comp W_>
+               fvec4SIMD swizzle() const;
+               template <comp X_, comp Y_, comp Z_>
+               fvec4SIMD swizzle() const;
+               template <comp X_, comp Y_>
+               fvec4SIMD swizzle() const;
+               template <comp X_>
+               fvec4SIMD swizzle() const;
+       };
+}//namespace detail
+
+       typedef glm::detail::fvec4SIMD simdVec4;
+
+       /// @addtogroup gtx_simd_vec4
+       /// @{
+
+       //! Convert a simdVec4 to a vec4.
+       /// @see gtx_simd_vec4
+       vec4 vec4_cast(
+               detail::fvec4SIMD const & x);
+
+       //! Returns x if x >= 0; otherwise, it returns -x.
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD abs(detail::fvec4SIMD const & x);
+
+       //! Returns 1.0 if x > 0, 0.0 if x = 0, or -1.0 if x < 0.
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD sign(detail::fvec4SIMD const & x);
+
+       //! Returns a value equal to the nearest integer that is less then or equal to x.
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD floor(detail::fvec4SIMD const & x);
+
+       //! Returns a value equal to the nearest integer to x
+       //! whose absolute value is not larger than the absolute value of x.
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD trunc(detail::fvec4SIMD const & x);
+
+       //! Returns a value equal to the nearest integer to x.
+       //! The fraction 0.5 will round in a direction chosen by the
+       //! implementation, presumably the direction that is fastest.
+       //! This includes the possibility that round(x) returns the
+       //! same value as roundEven(x) for all values of x.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD round(detail::fvec4SIMD const & x);
+
+       //! Returns a value equal to the nearest integer to x.
+       //! A fractional part of 0.5 will round toward the nearest even
+       //! integer. (Both 3.5 and 4.5 for x will return 4.0.)
+       ///
+       /// @see gtx_simd_vec4
+       //detail::fvec4SIMD roundEven(detail::fvec4SIMD const & x);
+
+       //! Returns a value equal to the nearest integer
+       //! that is greater than or equal to x.
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD ceil(detail::fvec4SIMD const & x);
+
+       //! Return x - floor(x).
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fract(detail::fvec4SIMD const & x);
+
+       //! Modulus. Returns x - y * floor(x / y)
+       //! for each component in x using the floating point value y.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD mod(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       //! Modulus. Returns x - y * floor(x / y)
+       //! for each component in x using the floating point value y.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD mod(
+               detail::fvec4SIMD const & x,
+               float const & y);
+
+       //! Returns the fractional part of x and sets i to the integer
+       //! part (as a whole number floating point value). Both the
+       //! return value and the output parameter will have the same
+       //! sign as x.
+       //! (From GLM_GTX_simd_vec4 extension, common function)
+       //detail::fvec4SIMD modf(
+       //      detail::fvec4SIMD const & x,
+       //      detail::fvec4SIMD & i);
+
+       //! Returns y if y < x; otherwise, it returns x.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD min(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       detail::fvec4SIMD min(
+               detail::fvec4SIMD const & x,
+               float const & y);
+
+       //! Returns y if x < y; otherwise, it returns x.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD max(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       detail::fvec4SIMD max(
+               detail::fvec4SIMD const & x,
+               float const & y);
+
+       //! Returns min(max(x, minVal), maxVal) for each component in x
+       //! using the floating-point values minVal and maxVal.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD clamp(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & minVal,
+               detail::fvec4SIMD const & maxVal);
+
+       detail::fvec4SIMD clamp(
+               detail::fvec4SIMD const & x,
+               float const & minVal,
+               float const & maxVal);
+
+       //! \return If genTypeU is a floating scalar or vector:
+       //! Returns x * (1.0 - a) + y * a, i.e., the linear blend of
+       //! x and y using the floating-point value a.
+       //! The value for a is not restricted to the range [0, 1].
+       //!
+       //! \return If genTypeU is a boolean scalar or vector:
+       //! Selects which vector each returned component comes
+       //! from. For a component of a that is false, the
+       //! corresponding component of x is returned. For a
+       //! component of a that is true, the corresponding
+       //! component of y is returned. Components of x and y that
+       //! are not selected are allowed to be invalid floating point
+       //! values and will have no effect on the results. Thus, this
+       //! provides different functionality than
+       //! genType mix(genType x, genType y, genType(a))
+       //! where a is a Boolean vector.
+       //!
+       //! From GLSL 1.30.08 specification, section 8.3
+       //!
+       //! \param[in]  x Floating point scalar or vector.
+       //! \param[in]  y Floating point scalar or vector.
+       //! \param[in]  a Floating point or boolean scalar or vector.
+       //!
+       /// \todo Test when 'a' is a boolean.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD mix(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y,
+               detail::fvec4SIMD const & a);
+
+       //! Returns 0.0 if x < edge, otherwise it returns 1.0.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD step(
+               detail::fvec4SIMD const & edge,
+               detail::fvec4SIMD const & x);
+
+       detail::fvec4SIMD step(
+               float const & edge,
+               detail::fvec4SIMD const & x);
+
+       //! Returns 0.0 if x <= edge0 and 1.0 if x >= edge1 and
+       //! performs smooth Hermite interpolation between 0 and 1
+       //! when edge0 < x < edge1. This is useful in cases where
+       //! you would want a threshold function with a smooth
+       //! transition. This is equivalent to:
+       //! genType t;
+       //! t = clamp ((x - edge0) / (edge1 - edge0), 0, 1);
+       //! return t * t * (3 - 2 * t);
+       //! Results are undefined if edge0 >= edge1.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD smoothstep(
+               detail::fvec4SIMD const & edge0,
+               detail::fvec4SIMD const & edge1,
+               detail::fvec4SIMD const & x);
+
+       detail::fvec4SIMD smoothstep(
+               float const & edge0,
+               float const & edge1,
+               detail::fvec4SIMD const & x);
+
+       //! Returns true if x holds a NaN (not a number)
+       //! representation in the underlying implementation's set of
+       //! floating point representations. Returns false otherwise,
+       //! including for implementations with no NaN
+       //! representations.
+       ///
+       /// @see gtx_simd_vec4
+       //bvec4 isnan(detail::fvec4SIMD const & x);
+
+       //! Returns true if x holds a positive infinity or negative
+       //! infinity representation in the underlying implementation's
+       //! set of floating point representations. Returns false
+       //! otherwise, including for implementations with no infinity
+       //! representations.
+       ///
+       /// @see gtx_simd_vec4
+       //bvec4 isinf(detail::fvec4SIMD const & x);
+
+       //! Returns a signed or unsigned integer value representing
+       //! the encoding of a floating-point value. The floatingpoint
+       //! value's bit-level representation is preserved.
+       ///
+       /// @see gtx_simd_vec4
+       //detail::ivec4SIMD floatBitsToInt(detail::fvec4SIMD const & value);
+
+       //! Returns a floating-point value corresponding to a signed
+       //! or unsigned integer encoding of a floating-point value.
+       //! If an inf or NaN is passed in, it will not signal, and the
+       //! resulting floating point value is unspecified. Otherwise,
+       //! the bit-level representation is preserved.
+       ///
+       /// @see gtx_simd_vec4
+       //detail::fvec4SIMD intBitsToFloat(detail::ivec4SIMD const & value);
+
+       //! Computes and returns a * b + c.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fma(
+               detail::fvec4SIMD const & a,
+               detail::fvec4SIMD const & b,
+               detail::fvec4SIMD const & c);
+
+       //! Splits x into a floating-point significand in the range
+       //! [0.5, 1.0) and an integral exponent of two, such that:
+       //! x = significand * exp(2, exponent)
+       //! The significand is returned by the function and the
+       //! exponent is returned in the parameter exp. For a
+       //! floating-point value of zero, the significant and exponent
+       //! are both zero. For a floating-point value that is an
+       //! infinity or is not a number, the results are undefined.
+       ///
+       /// @see gtx_simd_vec4
+       //detail::fvec4SIMD frexp(detail::fvec4SIMD const & x, detail::ivec4SIMD & exp);
+
+       //! Builds a floating-point number from x and the
+       //! corresponding integral exponent of two in exp, returning:
+       //! significand * exp(2, exponent)
+       //! If this product is too large to be represented in the
+       //! floating-point type, the result is undefined.
+       ///
+       /// @see gtx_simd_vec4
+       //detail::fvec4SIMD ldexp(detail::fvec4SIMD const & x, detail::ivec4SIMD const & exp);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       ///
+       /// @see gtx_simd_vec4
+       float length(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       //! Less accurate but much faster than simdLength.
+       ///
+       /// @see gtx_simd_vec4
+       float fastLength(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       //! Slightly more accurate but much slower than simdLength.
+       ///
+       /// @see gtx_simd_vec4
+       float niceLength(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD length4(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       //! Less accurate but much faster than simdLength4.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fastLength4(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the length of x, i.e., sqrt(x * x).
+       //! Slightly more accurate but much slower than simdLength4.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD niceLength4(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the distance betwwen p0 and p1, i.e., length(p0 - p1).
+       ///
+       /// @see gtx_simd_vec4
+       float distance(
+               detail::fvec4SIMD const & p0,
+               detail::fvec4SIMD const & p1);
+
+       //! Returns the distance betwwen p0 and p1, i.e., length(p0 - p1).
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD distance4(
+               detail::fvec4SIMD const & p0,
+               detail::fvec4SIMD const & p1);
+
+       //! Returns the dot product of x and y, i.e., result = x * y.
+       ///
+       /// @see gtx_simd_vec4
+       float simdDot(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       //! Returns the dot product of x and y, i.e., result = x * y.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD dot4(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       //! Returns the cross product of x and y.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD cross(
+               detail::fvec4SIMD const & x,
+               detail::fvec4SIMD const & y);
+
+       //! Returns a vector in the same direction as x but with length of 1.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD normalize(
+               detail::fvec4SIMD const & x);
+
+       //! Returns a vector in the same direction as x but with length of 1.
+       //! Less accurate but much faster than simdNormalize.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fastNormalize(
+               detail::fvec4SIMD const & x);
+
+       //! If dot(Nref, I) < 0.0, return N, otherwise, return -N.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD simdFaceforward(
+               detail::fvec4SIMD const & N,
+               detail::fvec4SIMD const & I,
+               detail::fvec4SIMD const & Nref);
+
+       //! For the incident vector I and surface orientation N,
+       //! returns the reflection direction : result = I - 2.0 * dot(N, I) * N.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD reflect(
+               detail::fvec4SIMD const & I,
+               detail::fvec4SIMD const & N);
+
+       //! For the incident vector I and surface normal N,
+       //! and the ratio of indices of refraction eta,
+       //! return the refraction vector.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD refract(
+               detail::fvec4SIMD const & I,
+               detail::fvec4SIMD const & N,
+               float const & eta);
+
+       //! Returns the positive square root of x.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD sqrt(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the positive square root of x with the nicest quality but very slow.
+       //! Slightly more accurate but much slower than simdSqrt.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD niceSqrt(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the positive square root of x
+       //! Less accurate but much faster than sqrt.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fastSqrt(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the reciprocal of the positive square root of x.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD inversesqrt(
+               detail::fvec4SIMD const & x);
+
+       //! Returns the reciprocal of the positive square root of x.
+       //! Faster than inversesqrt but less accurate.
+       ///
+       /// @see gtx_simd_vec4
+       detail::fvec4SIMD fastInversesqrt(
+               detail::fvec4SIMD const & x);
+
+       /// @}
+}//namespace glm
+
+#include "simd_vec4.inl"
+
+#if (GLM_COMPILER & GLM_COMPILER_VC)
+#      pragma warning(pop)
+#endif
+
+#endif//(GLM_ARCH != GLM_ARCH_PURE)
diff --git a/core/deps/glm/glm/gtx/simd_vec4.inl b/core/deps/glm/glm/gtx/simd_vec4.inl
new file mode 100755 (executable)
index 0000000..efc87c6
--- /dev/null
@@ -0,0 +1,721 @@
+/// @ref gtx_simd_vec4
+/// @file glm/gtx/simd_vec4.inl
+
+namespace glm{
+namespace detail{
+
+//////////////////////////////////////
+// Implicit basic constructors
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS || !defined(GLM_FORCE_NO_CTOR_INIT)
+       GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD()
+#              ifdef GLM_FORCE_NO_CTOR_INIT
+                       : Data(_mm_set_ps(0.0f, 0.0f, 0.0f, 0.0f))
+#              endif
+       {}
+#endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS
+       GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(fvec4SIMD const & v) :
+               Data(v.Data)
+       {}
+#endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(__m128 const & Data) :
+       Data(Data)
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(vec4 const & v) :
+       Data(_mm_set_ps(v.w, v.z, v.y, v.x))
+{}
+
+//////////////////////////////////////
+// Explicit basic constructors
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const & s) :
+       Data(_mm_set1_ps(s))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const & x, float const & y, float const & z, float const & w) :
+//             Data(_mm_setr_ps(x, y, z, w))
+       Data(_mm_set_ps(w, z, y, x))
+{}
+/*
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const v[4]) :
+       Data(_mm_load_ps(v))
+{}
+*/
+//////////////////////////////////////
+// Swizzle constructors
+
+//fvec4SIMD(ref4<float> const & r);
+
+//////////////////////////////////////
+// Conversion vector constructors
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(vec2 const & v, float const & s1, float const & s2) :
+       Data(_mm_set_ps(s2, s1, v.y, v.x))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const & s1, vec2 const & v, float const & s2) :
+       Data(_mm_set_ps(s2, v.y, v.x, s1))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const & s1, float const & s2, vec2 const & v) :
+       Data(_mm_set_ps(v.y, v.x, s2, s1))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(vec3 const & v, float const & s) :
+       Data(_mm_set_ps(s, v.z, v.y, v.x))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(float const & s, vec3 const & v) :
+       Data(_mm_set_ps(v.z, v.y, v.x, s))
+{}
+
+GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(vec2 const & v1, vec2 const & v2) :
+       Data(_mm_set_ps(v2.y, v2.x, v1.y, v1.x))
+{}
+
+//GLM_FUNC_QUALIFIER fvec4SIMD::fvec4SIMD(ivec4SIMD const & v) :
+//     Data(_mm_cvtepi32_ps(v.Data))
+//{}
+
+//////////////////////////////////////
+// Unary arithmetic operators
+
+#if !GLM_HAS_DEFAULTED_FUNCTIONS
+       GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator=(fvec4SIMD const & v)
+       {
+               this->Data = v.Data;
+               return *this;
+       }
+#endif//!GLM_HAS_DEFAULTED_FUNCTIONS
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator+=(float const & s)
+{
+       this->Data = _mm_add_ps(Data, _mm_set_ps1(s));
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator+=(fvec4SIMD const & v)
+{
+       this->Data = _mm_add_ps(this->Data , v.Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator-=(float const & s)
+{
+       this->Data = _mm_sub_ps(Data, _mm_set_ps1(s));
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator-=(fvec4SIMD const & v)
+{
+       this->Data = _mm_sub_ps(this->Data , v.Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator*=(float const & s)
+{
+       this->Data = _mm_mul_ps(this->Data, _mm_set_ps1(s));
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator*=(fvec4SIMD const & v)
+{
+       this->Data = _mm_mul_ps(this->Data , v.Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator/=(float const & s)
+{
+       this->Data = _mm_div_ps(Data, _mm_set1_ps(s));
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator/=(fvec4SIMD const & v)
+{
+       this->Data = _mm_div_ps(this->Data , v.Data);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator++()
+{
+       this->Data = _mm_add_ps(this->Data , glm::detail::one);
+       return *this;
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::operator--()
+{
+       this->Data = _mm_sub_ps(this->Data, glm::detail::one);
+       return *this;
+}
+
+//////////////////////////////////////
+// Swizzle operators
+
+template <comp X_, comp Y_, comp Z_, comp W_>
+GLM_FUNC_QUALIFIER fvec4SIMD fvec4SIMD::swizzle() const
+{
+       __m128 Data = _mm_shuffle_ps(
+               this->Data, this->Data, 
+               shuffle_mask<(W_ << 6) | (Z_ << 4) | (Y_ << 2) | (X_ << 0)>::value);
+       return fvec4SIMD(Data);
+}
+
+template <comp X_, comp Y_, comp Z_, comp W_>
+GLM_FUNC_QUALIFIER fvec4SIMD& fvec4SIMD::swizzle()
+{
+       this->Data = _mm_shuffle_ps(
+               this->Data, this->Data, 
+               shuffle_mask<(W_ << 6) | (Z_ << 4) | (Y_ << 2) | (X_ << 0)>::value);
+       return *this;
+}
+
+// operator+
+GLM_FUNC_QUALIFIER fvec4SIMD operator+ (fvec4SIMD const & v, float s)
+{
+       return fvec4SIMD(_mm_add_ps(v.Data, _mm_set1_ps(s)));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator+ (float s, fvec4SIMD const & v)
+{
+       return fvec4SIMD(_mm_add_ps(_mm_set1_ps(s), v.Data));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator+ (fvec4SIMD const & v1, fvec4SIMD const & v2)
+{
+       return fvec4SIMD(_mm_add_ps(v1.Data, v2.Data));
+}
+
+//operator-
+GLM_FUNC_QUALIFIER fvec4SIMD operator- (fvec4SIMD const & v, float s)
+{
+       return fvec4SIMD(_mm_sub_ps(v.Data, _mm_set1_ps(s)));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator- (float s, fvec4SIMD const & v)
+{
+       return fvec4SIMD(_mm_sub_ps(_mm_set1_ps(s), v.Data));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator- (fvec4SIMD const & v1, fvec4SIMD const & v2)
+{
+       return fvec4SIMD(_mm_sub_ps(v1.Data, v2.Data));
+}
+
+//operator*
+GLM_FUNC_QUALIFIER fvec4SIMD operator* (fvec4SIMD const & v, float s)
+{
+       __m128 par0 = v.Data;
+       __m128 par1 = _mm_set1_ps(s);
+       return fvec4SIMD(_mm_mul_ps(par0, par1));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator* (float s, fvec4SIMD const & v)
+{
+       __m128 par0 = _mm_set1_ps(s);
+       __m128 par1 = v.Data;
+       return fvec4SIMD(_mm_mul_ps(par0, par1));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator* (fvec4SIMD const & v1, fvec4SIMD const & v2)
+{
+       return fvec4SIMD(_mm_mul_ps(v1.Data, v2.Data));
+}
+
+//operator/
+GLM_FUNC_QUALIFIER fvec4SIMD operator/ (fvec4SIMD const & v, float s)
+{
+       __m128 par0 = v.Data;
+       __m128 par1 = _mm_set1_ps(s);
+       return fvec4SIMD(_mm_div_ps(par0, par1));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator/ (float s, fvec4SIMD const & v)
+{
+       __m128 par0 = _mm_set1_ps(s);
+       __m128 par1 = v.Data;
+       return fvec4SIMD(_mm_div_ps(par0, par1));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator/ (fvec4SIMD const & v1, fvec4SIMD const & v2)
+{
+       return fvec4SIMD(_mm_div_ps(v1.Data, v2.Data));
+}
+
+// Unary constant operators
+GLM_FUNC_QUALIFIER fvec4SIMD operator- (fvec4SIMD const & v)
+{
+       return fvec4SIMD(_mm_sub_ps(_mm_setzero_ps(), v.Data));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator++ (fvec4SIMD const & v, int)
+{
+       return fvec4SIMD(_mm_add_ps(v.Data, glm::detail::one));
+}
+
+GLM_FUNC_QUALIFIER fvec4SIMD operator-- (fvec4SIMD const & v, int)
+{
+       return fvec4SIMD(_mm_sub_ps(v.Data, glm::detail::one));
+}
+
+}//namespace detail
+
+GLM_FUNC_QUALIFIER vec4 vec4_cast
+(
+       detail::fvec4SIMD const & x
+)
+{
+       GLM_ALIGN(16) vec4 Result;
+       _mm_store_ps(&Result[0], x.Data);
+       return Result;
+}
+
+// Other possible implementation
+//float abs(float a)
+//{
+//  return max(-a, a);
+//}
+GLM_FUNC_QUALIFIER detail::fvec4SIMD abs
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_abs_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD sign
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_sgn_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD floor
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_flr_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD trunc
+(
+       detail::fvec4SIMD const & x
+)
+{
+    //return x < 0 ? -floor(-x) : floor(x);
+
+       __m128 Flr0 = detail::sse_flr_ps(_mm_sub_ps(_mm_setzero_ps(), x.Data));
+       __m128 Sub0 = _mm_sub_ps(Flr0, x.Data);
+       __m128 Flr1 = detail::sse_flr_ps(x.Data);
+
+       __m128 Cmp0 = _mm_cmplt_ps(x.Data, glm::detail::zero);
+       __m128 Cmp1 = _mm_cmpnlt_ps(x.Data, glm::detail::zero);
+
+       __m128 And0 = _mm_and_ps(Sub0, Cmp0);
+       __m128 And1 = _mm_and_ps(Flr1, Cmp1);
+
+       return _mm_or_ps(And0, And1);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD round
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_rnd_ps(x.Data);
+}
+
+//GLM_FUNC_QUALIFIER detail::fvec4SIMD roundEven
+//(
+//     detail::fvec4SIMD const & x
+//)
+//{
+
+//}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD ceil
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_ceil_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fract
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_frc_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD mod
+(
+       detail::fvec4SIMD const & x, 
+       detail::fvec4SIMD const & y
+)
+{
+       return detail::sse_mod_ps(x.Data, y.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD mod
+(
+       detail::fvec4SIMD const & x, 
+       float const & y
+)
+{
+       return detail::sse_mod_ps(x.Data, _mm_set1_ps(y));
+}
+
+//GLM_FUNC_QUALIFIER detail::fvec4SIMD modf
+//(
+//     detail::fvec4SIMD const & x, 
+//     detail::fvec4SIMD & i
+//)
+//{
+
+//}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD min
+(
+       detail::fvec4SIMD const & x, 
+       detail::fvec4SIMD const & y
+)
+{
+       return _mm_min_ps(x.Data, y.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD min
+(
+       detail::fvec4SIMD const & x, 
+       float const & y
+)
+{
+       return _mm_min_ps(x.Data, _mm_set1_ps(y));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD max
+(
+       detail::fvec4SIMD const & x, 
+       detail::fvec4SIMD const & y
+)
+{
+       return _mm_max_ps(x.Data, y.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD max
+(
+       detail::fvec4SIMD const & x, 
+       float const & y
+)
+{
+       return _mm_max_ps(x.Data, _mm_set1_ps(y));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD clamp
+(
+       detail::fvec4SIMD const & x, 
+       detail::fvec4SIMD const & minVal, 
+       detail::fvec4SIMD const & maxVal
+)
+{
+       return detail::sse_clp_ps(x.Data, minVal.Data, maxVal.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD clamp
+(
+       detail::fvec4SIMD const & x, 
+       float const & minVal, 
+       float const & maxVal
+) 
+{
+       return detail::sse_clp_ps(x.Data, _mm_set1_ps(minVal), _mm_set1_ps(maxVal));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD mix
+(
+       detail::fvec4SIMD const & x, 
+       detail::fvec4SIMD const & y, 
+       detail::fvec4SIMD const & a
+)
+{
+       __m128 Sub0 = _mm_sub_ps(y.Data, x.Data);
+       __m128 Mul0 = _mm_mul_ps(a.Data, Sub0);
+       return _mm_add_ps(x.Data, Mul0);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD step
+(
+       detail::fvec4SIMD const & edge, 
+       detail::fvec4SIMD const & x
+)
+{
+       __m128 cmp0 = _mm_cmpngt_ps(x.Data, edge.Data);
+       return _mm_max_ps(_mm_min_ps(cmp0, _mm_setzero_ps()), detail::one);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD step
+(
+       float const & edge, 
+       detail::fvec4SIMD const & x
+)
+{
+       __m128 cmp0 = _mm_cmpngt_ps(x.Data, _mm_set1_ps(edge));
+       return _mm_max_ps(_mm_min_ps(cmp0, _mm_setzero_ps()), detail::one);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD smoothstep
+(
+       detail::fvec4SIMD const & edge0, 
+       detail::fvec4SIMD const & edge1, 
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_ssp_ps(edge0.Data, edge1.Data, x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD smoothstep
+(
+       float const & edge0, 
+       float const & edge1, 
+       detail::fvec4SIMD const & x
+)
+{
+       return detail::sse_ssp_ps(_mm_set1_ps(edge0), _mm_set1_ps(edge1), x.Data);
+}
+
+//GLM_FUNC_QUALIFIER bvec4 isnan(detail::fvec4SIMD const & x)
+//{
+
+//}
+
+//GLM_FUNC_QUALIFIER bvec4 isinf(detail::fvec4SIMD const & x)
+//{
+
+//}
+
+//GLM_FUNC_QUALIFIER detail::ivec4SIMD floatBitsToInt
+//(
+//     detail::fvec4SIMD const & value
+//)
+//{
+
+//}
+
+//GLM_FUNC_QUALIFIER detail::fvec4SIMD intBitsToFloat
+//(
+//     detail::ivec4SIMD const & value
+//)
+//{
+
+//}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fma
+(
+       detail::fvec4SIMD const & a, 
+       detail::fvec4SIMD const & b, 
+       detail::fvec4SIMD const & c
+)
+{
+       return _mm_add_ps(_mm_mul_ps(a.Data, b.Data), c.Data);
+}
+
+GLM_FUNC_QUALIFIER float length
+(
+       detail::fvec4SIMD const & x
+)
+{
+       detail::fvec4SIMD dot0 = detail::sse_dot_ss(x.Data, x.Data);
+       detail::fvec4SIMD sqt0 = sqrt(dot0);
+       float Result = 0;
+       _mm_store_ss(&Result, sqt0.Data);
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER float fastLength
+(
+       detail::fvec4SIMD const & x
+)
+{
+       detail::fvec4SIMD dot0 = detail::sse_dot_ss(x.Data, x.Data);
+       detail::fvec4SIMD sqt0 = fastSqrt(dot0);
+       float Result = 0;
+       _mm_store_ss(&Result, sqt0.Data);
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER float niceLength
+(
+       detail::fvec4SIMD const & x
+)
+{
+       detail::fvec4SIMD dot0 = detail::sse_dot_ss(x.Data, x.Data);
+       detail::fvec4SIMD sqt0 = niceSqrt(dot0);
+       float Result = 0;
+       _mm_store_ss(&Result, sqt0.Data);
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD length4
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return sqrt(dot4(x, x));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fastLength4
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return fastSqrt(dot4(x, x));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD niceLength4
+(
+       detail::fvec4SIMD const & x
+)
+{
+       return niceSqrt(dot4(x, x));
+}
+
+GLM_FUNC_QUALIFIER float distance
+(
+       detail::fvec4SIMD const & p0,
+       detail::fvec4SIMD const & p1
+)
+{
+       float Result = 0;
+       _mm_store_ss(&Result, detail::sse_dst_ps(p0.Data, p1.Data));
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD distance4
+(
+       detail::fvec4SIMD const & p0,
+       detail::fvec4SIMD const & p1
+)
+{
+       return detail::sse_dst_ps(p0.Data, p1.Data);
+}
+
+GLM_FUNC_QUALIFIER float dot
+(
+       detail::fvec4SIMD const & x,
+       detail::fvec4SIMD const & y
+)
+{
+       float Result = 0;
+       _mm_store_ss(&Result, detail::sse_dot_ss(x.Data, y.Data));
+       return Result;
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD dot4
+(
+       detail::fvec4SIMD const & x,
+       detail::fvec4SIMD const & y
+)
+{
+       return detail::sse_dot_ps(x.Data, y.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD cross
+(
+       detail::fvec4SIMD const & x,
+       detail::fvec4SIMD const & y
+)
+{
+       return detail::sse_xpd_ps(x.Data, y.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD normalize
+(
+       detail::fvec4SIMD const & x
+)
+{
+       __m128 dot0 = detail::sse_dot_ps(x.Data, x.Data);
+       __m128 isr0 = inversesqrt(detail::fvec4SIMD(dot0)).Data;
+       __m128 mul0 = _mm_mul_ps(x.Data, isr0);
+       return mul0;
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fastNormalize
+(
+       detail::fvec4SIMD const & x
+)
+{
+       __m128 dot0 = detail::sse_dot_ps(x.Data, x.Data);
+       __m128 isr0 = fastInversesqrt(dot0).Data;
+       __m128 mul0 = _mm_mul_ps(x.Data, isr0);
+       return mul0;
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD faceforward
+(
+       detail::fvec4SIMD const & N,
+       detail::fvec4SIMD const & I,
+       detail::fvec4SIMD const & Nref
+)
+{
+       return detail::sse_ffd_ps(N.Data, I.Data, Nref.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD reflect
+(
+       detail::fvec4SIMD const & I,
+       detail::fvec4SIMD const & N
+)
+{
+       return detail::sse_rfe_ps(I.Data, N.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD refract
+(
+       detail::fvec4SIMD const & I,
+       detail::fvec4SIMD const & N,
+       float const & eta
+)
+{
+       return detail::sse_rfa_ps(I.Data, N.Data, _mm_set1_ps(eta));
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD sqrt(detail::fvec4SIMD const & x)
+{
+       return _mm_mul_ps(inversesqrt(x).Data, x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD niceSqrt(detail::fvec4SIMD const & x)
+{
+       return _mm_sqrt_ps(x.Data);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fastSqrt(detail::fvec4SIMD const & x)
+{
+       return _mm_mul_ps(fastInversesqrt(x.Data).Data, x.Data);
+}
+
+// SSE scalar reciprocal sqrt using rsqrt op, plus one Newton-Rhaphson iteration
+// By Elan Ruskin, http://assemblyrequired.crashworks.org/
+GLM_FUNC_QUALIFIER detail::fvec4SIMD inversesqrt(detail::fvec4SIMD const & x)
+{
+       GLM_ALIGN(4) static const __m128 three = {3, 3, 3, 3}; // aligned consts for fast load
+       GLM_ALIGN(4) static const __m128 half = {0.5,0.5,0.5,0.5};
+
+       __m128 recip = _mm_rsqrt_ps(x.Data);  // "estimate" opcode
+       __m128 halfrecip = _mm_mul_ps(half, recip);
+       __m128 threeminus_xrr = _mm_sub_ps(three, _mm_mul_ps(x.Data, _mm_mul_ps(recip, recip)));
+       return _mm_mul_ps(halfrecip, threeminus_xrr);
+}
+
+GLM_FUNC_QUALIFIER detail::fvec4SIMD fastInversesqrt(detail::fvec4SIMD const & x)
+{
+       return _mm_rsqrt_ps(x.Data);
+}
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/spline.hpp b/core/deps/glm/glm/gtx/spline.hpp
new file mode 100755 (executable)
index 0000000..333a5bc
--- /dev/null
@@ -0,0 +1,61 @@
+/// @ref gtx_spline
+/// @file glm/gtx/spline.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_spline GLM_GTX_spline
+/// @ingroup gtx
+///
+/// @brief Spline functions
+///
+/// <glm/gtx/spline.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/optimum_pow.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_spline extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_spline
+       /// @{
+
+       /// Return a point from a catmull rom curve.
+       /// @see gtx_spline extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType catmullRom(
+               genType const & v1, 
+               genType const & v2, 
+               genType const & v3, 
+               genType const & v4, 
+               typename genType::value_type const & s);
+               
+       /// Return a point from a hermite curve.
+       /// @see gtx_spline extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType hermite(
+               genType const & v1, 
+               genType const & t1, 
+               genType const & v2, 
+               genType const & t2, 
+               typename genType::value_type const & s);
+               
+       /// Return a point from a cubic curve. 
+       /// @see gtx_spline extension.
+       template <typename genType> 
+       GLM_FUNC_DECL genType cubic(
+               genType const & v1, 
+               genType const & v2, 
+               genType const & v3, 
+               genType const & v4, 
+               typename genType::value_type const & s);
+
+       /// @}
+}//namespace glm
+
+#include "spline.inl"
diff --git a/core/deps/glm/glm/gtx/spline.inl b/core/deps/glm/glm/gtx/spline.inl
new file mode 100755 (executable)
index 0000000..fcd3382
--- /dev/null
@@ -0,0 +1,63 @@
+/// @ref gtx_spline
+/// @file glm/gtx/spline.inl
+
+namespace glm
+{
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType catmullRom
+       (
+               genType const & v1, 
+               genType const & v2, 
+               genType const & v3, 
+               genType const & v4, 
+               typename genType::value_type const & s
+       )
+       {
+               typename genType::value_type s1 = s;
+               typename genType::value_type s2 = pow2(s);
+               typename genType::value_type s3 = pow3(s);
+
+               typename genType::value_type f1 = -s3 + typename genType::value_type(2) * s2 - s;
+               typename genType::value_type f2 = typename genType::value_type(3) * s3 - typename genType::value_type(5) * s2 + typename genType::value_type(2);
+               typename genType::value_type f3 = typename genType::value_type(-3) * s3 + typename genType::value_type(4) * s2 + s;
+               typename genType::value_type f4 = s3 - s2;
+
+               return (f1 * v1 + f2 * v2 + f3 * v3 + f4 * v4) / typename genType::value_type(2);
+
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType hermite
+       (
+               genType const & v1, 
+               genType const & t1, 
+               genType const & v2, 
+               genType const & t2, 
+               typename genType::value_type const & s
+       )
+       {
+               typename genType::value_type s1 = s;
+               typename genType::value_type s2 = pow2(s);
+               typename genType::value_type s3 = pow3(s);
+
+               typename genType::value_type f1 = typename genType::value_type(2) * s3 - typename genType::value_type(3) * s2 + typename genType::value_type(1);
+               typename genType::value_type f2 = typename genType::value_type(-2) * s3 + typename genType::value_type(3) * s2;
+               typename genType::value_type f3 = s3 - typename genType::value_type(2) * s2 + s;
+               typename genType::value_type f4 = s3 - s2;
+
+               return f1 * v1 + f2 * v2 + f3 * t1 + f4 * t2;
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType cubic
+       (
+               genType const & v1, 
+               genType const & v2, 
+               genType const & v3, 
+               genType const & v4, 
+               typename genType::value_type const & s
+       )
+       {
+               return ((v1 * s + v2) * s + v3) * s + v4;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/std_based_type.hpp b/core/deps/glm/glm/gtx/std_based_type.hpp
new file mode 100755 (executable)
index 0000000..ea1791b
--- /dev/null
@@ -0,0 +1,63 @@
+/// @ref gtx_std_based_type
+/// @file glm/gtx/std_based_type.hpp
+///
+/// @see core (dependence)
+/// @see gtx_extented_min_max (dependence)
+///
+/// @defgroup gtx_std_based_type GLM_GTX_std_based_type
+/// @ingroup gtx
+///
+/// @brief Adds vector types based on STL value types.
+/// <glm/gtx/std_based_type.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include <cstdlib>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_std_based_type extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_std_based_type
+       /// @{
+
+       /// Vector type based of one std::size_t component.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec1<std::size_t, defaultp>            size1;
+
+       /// Vector type based of two std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec2<std::size_t, defaultp>            size2;
+
+       /// Vector type based of three std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec3<std::size_t, defaultp>            size3;
+
+       /// Vector type based of four std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec4<std::size_t, defaultp>            size4;
+
+       /// Vector type based of one std::size_t component.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec1<std::size_t, defaultp>            size1_t;
+
+       /// Vector type based of two std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec2<std::size_t, defaultp>            size2_t;
+
+       /// Vector type based of three std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec3<std::size_t, defaultp>            size3_t;
+
+       /// Vector type based of four std::size_t components.
+       /// @see GLM_GTX_std_based_type
+       typedef tvec4<std::size_t, defaultp>            size4_t;
+
+       /// @}
+}//namespace glm
+
+#include "std_based_type.inl"
diff --git a/core/deps/glm/glm/gtx/std_based_type.inl b/core/deps/glm/glm/gtx/std_based_type.inl
new file mode 100755 (executable)
index 0000000..ca431a3
--- /dev/null
@@ -0,0 +1,7 @@
+/// @ref gtx_std_based_type
+/// @file glm/gtx/std_based_type.inl
+
+namespace glm
+{
+
+}
diff --git a/core/deps/glm/glm/gtx/string_cast.hpp b/core/deps/glm/glm/gtx/string_cast.hpp
new file mode 100755 (executable)
index 0000000..d2b9fc6
--- /dev/null
@@ -0,0 +1,47 @@
+/// @ref gtx_string_cast
+/// @file glm/gtx/string_cast.hpp
+///
+/// @see core (dependence)
+/// @see gtc_half_float (dependence)
+/// @see gtx_integer (dependence)
+/// @see gtx_quaternion (dependence)
+///
+/// @defgroup gtx_string_cast GLM_GTX_string_cast
+/// @ingroup gtx
+///
+/// @brief Setup strings for GLM type values
+///
+/// <glm/gtx/string_cast.hpp> need to be included to use these functionalities.
+/// This extension is not supported with CUDA
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/type_precision.hpp"
+#include "../gtc/quaternion.hpp"
+#include "../gtx/dual_quaternion.hpp"
+#include <string>
+
+#if(GLM_COMPILER & GLM_COMPILER_CUDA)
+#      error "GLM_GTX_string_cast is not supported on CUDA compiler"
+#endif
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_string_cast extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_string_cast
+       /// @{
+
+       /// Create a string from a GLM vector or matrix typed variable.
+       /// @see gtx_string_cast extension.
+       template <template <typename, precision> class matType, typename T, precision P>
+       GLM_FUNC_DECL std::string to_string(matType<T, P> const & x);
+
+       /// @}
+}//namespace glm
+
+#include "string_cast.inl"
diff --git a/core/deps/glm/glm/gtx/string_cast.inl b/core/deps/glm/glm/gtx/string_cast.inl
new file mode 100755 (executable)
index 0000000..19f136b
--- /dev/null
@@ -0,0 +1,458 @@
+/// @ref gtx_string_cast
+/// @file glm/gtx/string_cast.inl
+
+#include <cstdarg>
+#include <cstdio>
+
+namespace glm{
+namespace detail
+{
+       GLM_FUNC_QUALIFIER std::string format(const char* msg, ...)
+       {
+               std::size_t const STRING_BUFFER(4096);
+               char text[STRING_BUFFER];
+               va_list list;
+
+               if(msg == 0)
+                       return std::string();
+
+               va_start(list, msg);
+#              if(GLM_COMPILER & GLM_COMPILER_VC)
+                       vsprintf_s(text, STRING_BUFFER, msg, list);
+#              else//
+                       vsprintf(text, msg, list);
+#              endif//
+               va_end(list);
+
+               return std::string(text);
+       }
+
+       static const char* LabelTrue = "true";
+       static const char* LabelFalse = "false";
+
+       template <typename T, bool isFloat = false>
+       struct literal
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "%d";};
+       };
+
+       template <typename T>
+       struct literal<T, true>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "%f";};
+       };
+
+#      if GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC
+       template <>
+       struct literal<uint64_t, false>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "%lld";};
+       };
+
+       template <>
+       struct literal<int64_t, false>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "%lld";};
+       };
+#      endif//GLM_MODEL == GLM_MODEL_32 && GLM_COMPILER && GLM_COMPILER_VC
+
+       template <typename T>
+       struct prefix{};
+
+       template <>
+       struct prefix<float>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "";};
+       };
+
+       template <>
+       struct prefix<double>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "d";};
+       };
+
+       template <>
+       struct prefix<bool>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "b";};
+       };
+
+       template <>
+       struct prefix<uint8_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "u8";};
+       };
+
+       template <>
+       struct prefix<int8_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "i8";};
+       };
+
+       template <>
+       struct prefix<uint16_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "u16";};
+       };
+
+       template <>
+       struct prefix<int16_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "i16";};
+       };
+
+       template <>
+       struct prefix<uint32_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "u";};
+       };
+
+       template <>
+       struct prefix<int32_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "i";};
+       };
+
+       template <>
+       struct prefix<uint64_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "u64";};
+       };
+
+       template <>
+       struct prefix<int64_t>
+       {
+               GLM_FUNC_QUALIFIER static char const * value() {return "i64";};
+       };
+
+       template <template <typename, precision> class matType, typename T, precision P>
+       struct compute_to_string
+       {};
+
+       template <precision P>
+       struct compute_to_string<tvec1, bool, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec1<bool, P> const & x)
+               {
+                       return detail::format("bvec1(%s)",
+                               x[0] ? detail::LabelTrue : detail::LabelFalse);
+               }
+       };
+
+       template <precision P>
+       struct compute_to_string<tvec2, bool, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec2<bool, P> const & x)
+               {
+                       return detail::format("bvec2(%s, %s)",
+                               x[0] ? detail::LabelTrue : detail::LabelFalse,
+                               x[1] ? detail::LabelTrue : detail::LabelFalse);
+               }
+       };
+
+       template <precision P>
+       struct compute_to_string<tvec3, bool, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec3<bool, P> const & x)
+               {
+                       return detail::format("bvec3(%s, %s, %s)",
+                               x[0] ? detail::LabelTrue : detail::LabelFalse,
+                               x[1] ? detail::LabelTrue : detail::LabelFalse,
+                               x[2] ? detail::LabelTrue : detail::LabelFalse);
+               }
+       };
+
+       template <precision P>
+       struct compute_to_string<tvec4, bool, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec4<bool, P> const & x)
+               {
+                       return detail::format("bvec4(%s, %s, %s, %s)",
+                               x[0] ? detail::LabelTrue : detail::LabelFalse,
+                               x[1] ? detail::LabelTrue : detail::LabelFalse,
+                               x[2] ? detail::LabelTrue : detail::LabelFalse,
+                               x[3] ? detail::LabelTrue : detail::LabelFalse);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tvec1, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec1<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%svec1(%s)",
+                               PrefixStr,
+                               LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x[0]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tvec2, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec2<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%svec2(%s, %s)",
+                               PrefixStr,
+                               LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x[0], x[1]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tvec3, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec3<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%svec3(%s, %s, %s)",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x[0], x[1], x[2]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tvec4, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tvec4<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%svec4(%s, %s, %s, %s)",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x[0], x[1], x[2], x[3]);
+               }
+       };
+
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat2x2, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat2x2<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat2x2((%s, %s), (%s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1],
+                               x[1][0], x[1][1]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat2x3, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat2x3<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat2x3((%s, %s, %s), (%s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2],
+                               x[1][0], x[1][1], x[1][2]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat2x4, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat2x4<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat2x4((%s, %s, %s, %s), (%s, %s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2], x[0][3],
+                               x[1][0], x[1][1], x[1][2], x[1][3]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat3x2, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat3x2<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat3x2((%s, %s), (%s, %s), (%s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1],
+                               x[1][0], x[1][1],
+                               x[2][0], x[2][1]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat3x3, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat3x3<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat3x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2],
+                               x[1][0], x[1][1], x[1][2],
+                               x[2][0], x[2][1], x[2][2]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat3x4, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat3x4<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat3x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2], x[0][3],
+                               x[1][0], x[1][1], x[1][2], x[1][3],
+                               x[2][0], x[2][1], x[2][2], x[2][3]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat4x2, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat4x2<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat4x2((%s, %s), (%s, %s), (%s, %s), (%s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1],
+                               x[1][0], x[1][1],
+                               x[2][0], x[2][1],
+                               x[3][0], x[3][1]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat4x3, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat4x3<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat4x3((%s, %s, %s), (%s, %s, %s), (%s, %s, %s), (%s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2],
+                               x[1][0], x[1][1], x[1][2],
+                               x[2][0], x[2][1], x[2][2],
+                               x[3][0], x[3][1], x[3][2]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tmat4x4, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tmat4x4<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%smat4x4((%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s), (%s, %s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(),
+                               x[0][0], x[0][1], x[0][2], x[0][3],
+                               x[1][0], x[1][1], x[1][2], x[1][3],
+                               x[2][0], x[2][1], x[2][2], x[2][3],
+                               x[3][0], x[3][1], x[3][2], x[3][3]);
+               }
+       };
+
+
+       template <typename T, precision P>
+       struct compute_to_string<tquat, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tquat<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%squat(%s, %s, %s, %s)",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x[0], x[1], x[2], x[3]);
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_to_string<tdualquat, T, P>
+       {
+               GLM_FUNC_QUALIFIER static std::string call(tdualquat<T, P> const & x)
+               {
+                       char const * PrefixStr = prefix<T>::value();
+                       char const * LiteralStr = literal<T, std::numeric_limits<T>::is_iec559>::value();
+                       std::string FormatStr(detail::format("%sdualquat((%s, %s, %s, %s), (%s, %s, %s, %s))",
+                               PrefixStr,
+                               LiteralStr, LiteralStr, LiteralStr, LiteralStr));
+
+                       return detail::format(FormatStr.c_str(), x.real[0], x.real[1], x.real[2], x.real[3], x.dual[0], x.dual[1], x.dual[2], x.dual[3]);
+               }
+       };
+
+}//namespace detail
+
+template <template <typename, precision> class matType, typename T, precision P>
+GLM_FUNC_QUALIFIER std::string to_string(matType<T, P> const & x)
+{
+       return detail::compute_to_string<matType, T, P>::call(x);
+}
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/transform.hpp b/core/deps/glm/glm/gtx/transform.hpp
new file mode 100755 (executable)
index 0000000..365748b
--- /dev/null
@@ -0,0 +1,56 @@
+/// @ref gtx_transform
+/// @file glm/gtx/transform.hpp
+///
+/// @see core (dependence)
+/// @see gtc_matrix_transform (dependence)
+/// @see gtx_transform
+/// @see gtx_transform2
+///
+/// @defgroup gtx_transform GLM_GTX_transform
+/// @ingroup gtx
+///
+/// @brief Add transformation matrices
+///
+/// <glm/gtx/transform.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/matrix_transform.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_transform extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_transform
+       /// @{
+
+       /// Transforms a matrix with a translation 4 * 4 matrix created from 3 scalars.
+       /// @see gtc_matrix_transform
+       /// @see gtx_transform
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> translate(
+               tvec3<T, P> const & v);
+
+       /// Builds a rotation 4 * 4 matrix created from an axis of 3 scalars and an angle expressed in radians. 
+       /// @see gtc_matrix_transform
+       /// @see gtx_transform
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> rotate(
+               T angle, 
+               tvec3<T, P> const & v);
+
+       /// Transforms a matrix with a scale 4 * 4 matrix created from a vector of 3 components.
+       /// @see gtc_matrix_transform
+       /// @see gtx_transform
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat4x4<T, P> scale(
+               tvec3<T, P> const & v);
+
+       /// @}
+}// namespace glm
+
+#include "transform.inl"
diff --git a/core/deps/glm/glm/gtx/transform.inl b/core/deps/glm/glm/gtx/transform.inl
new file mode 100755 (executable)
index 0000000..516d866
--- /dev/null
@@ -0,0 +1,24 @@
+/// @ref gtx_transform
+/// @file glm/gtx/transform.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> translate(tvec3<T, P> const & v)
+       {
+               return translate(tmat4x4<T, P>(static_cast<T>(1)), v);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> rotate(T angle, tvec3<T, P> const & v)
+       {
+               return rotate(tmat4x4<T, P>(static_cast<T>(1)), angle, v);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> scale(tvec3<T, P> const & v)
+       {
+               return scale(tmat4x4<T, P>(static_cast<T>(1)), v);
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/transform2.hpp b/core/deps/glm/glm/gtx/transform2.hpp
new file mode 100755 (executable)
index 0000000..bf5fbc9
--- /dev/null
@@ -0,0 +1,107 @@
+/// @ref gtx_transform2
+/// @file glm/gtx/transform2.hpp
+///
+/// @see core (dependence)
+/// @see gtx_transform (dependence)
+///
+/// @defgroup gtx_transform2 GLM_GTX_transform2
+/// @ingroup gtx
+///
+/// @brief Add extra transformation matrices
+///
+/// <glm/gtx/transform2.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtx/transform.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_transform2 extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_transform2
+       /// @{
+
+       //! Transforms a matrix with a shearing on X axis.
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL tmat3x3<T, P> shearX2D(
+               tmat3x3<T, P> const & m, 
+               T y);
+
+       //! Transforms a matrix with a shearing on Y axis.
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat3x3<T, P> shearY2D(
+               tmat3x3<T, P> const & m, 
+               T x);
+
+       //! Transforms a matrix with a shearing on X axis
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat4x4<T, P> shearX3D(
+               const tmat4x4<T, P> & m,
+               T y, 
+               T z);
+
+       //! Transforms a matrix with a shearing on Y axis.
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat4x4<T, P> shearY3D(
+               const tmat4x4<T, P> & m, 
+               T x, 
+               T z);
+
+       //! Transforms a matrix with a shearing on Z axis. 
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat4x4<T, P> shearZ3D(
+               const tmat4x4<T, P> & m, 
+               T x, 
+               T y);
+
+       //template <typename T> GLM_FUNC_QUALIFIER tmat4x4<T, P> shear(const tmat4x4<T, P> & m, shearPlane, planePoint, angle)
+       // Identity + tan(angle) * cross(Normal, OnPlaneVector)     0
+       // - dot(PointOnPlane, normal) * OnPlaneVector              1
+
+       // Reflect functions seem to don't work
+       //template <typename T> tmat3x3<T, P> reflect2D(const tmat3x3<T, P> & m, const tvec3<T, P>& normal){return reflect2DGTX(m, normal);}                                                                    //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension)
+       //template <typename T> tmat4x4<T, P> reflect3D(const tmat4x4<T, P> & m, const tvec3<T, P>& normal){return reflect3DGTX(m, normal);}                                                                    //!< \brief Build a reflection matrix (from GLM_GTX_transform2 extension)
+               
+       //! Build planar projection matrix along normal axis.
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat3x3<T, P> proj2D(
+               const tmat3x3<T, P> & m, 
+               const tvec3<T, P>& normal);
+
+       //! Build planar projection matrix along normal axis.
+       //! From GLM_GTX_transform2 extension.
+       template <typename T, precision P> 
+       GLM_FUNC_DECL tmat4x4<T, P> proj3D(
+               const tmat4x4<T, P> & m, 
+               const tvec3<T, P>& normal);
+
+       //! Build a scale bias matrix. 
+       //! From GLM_GTX_transform2 extension.
+       template <typename valType, precision P> 
+       GLM_FUNC_DECL tmat4x4<valType, P> scaleBias(
+               valType scale, 
+               valType bias);
+
+       //! Build a scale bias matrix.
+       //! From GLM_GTX_transform2 extension.
+       template <typename valType, precision P> 
+       GLM_FUNC_DECL tmat4x4<valType, P> scaleBias(
+               tmat4x4<valType, P> const & m, 
+               valType scale, 
+               valType bias);
+
+       /// @}
+}// namespace glm
+
+#include "transform2.inl"
diff --git a/core/deps/glm/glm/gtx/transform2.inl b/core/deps/glm/glm/gtx/transform2.inl
new file mode 100755 (executable)
index 0000000..6e0ab31
--- /dev/null
@@ -0,0 +1,126 @@
+/// @ref gtx_transform2
+/// @file glm/gtx/transform2.inl
+
+namespace glm
+{
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearX2D(tmat3x3<T, P> const& m, T s)
+       {
+               tmat3x3<T, P> r(1);
+               r[1][0] = s;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> shearY2D(tmat3x3<T, P> const& m, T s)
+       {
+               tmat3x3<T, P> r(1);
+               r[0][1] = s;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> shearX3D(tmat4x4<T, P> const& m, T s, T t)
+       {
+               tmat4x4<T, P> r(1);
+               r[0][1] = s;
+               r[0][2] = t;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> shearY3D(tmat4x4<T, P> const& m, T s, T t)
+       {
+               tmat4x4<T, P> r(1);
+               r[1][0] = s;
+               r[1][2] = t;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> shearZ3D(tmat4x4<T, P> const& m, T s, T t)
+       {
+               tmat4x4<T, P> r(1);
+               r[2][0] = s;
+               r[2][1] = t;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> reflect2D(tmat3x3<T, P> const& m, tvec3<T, P> const& normal)
+       {
+               tmat3x3<T, P> r(static_cast<T>(1));
+               r[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
+               r[0][1] = -static_cast<T>(2) * normal.x * normal.y;
+               r[1][0] = -static_cast<T>(2) * normal.x * normal.y;
+               r[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> reflect3D(tmat4x4<T, P> const& m, tvec3<T, P> const& normal)
+       {
+               tmat4x4<T, P> r(static_cast<T>(1));
+               r[0][0] = static_cast<T>(1) - static_cast<T>(2) * normal.x * normal.x;
+               r[0][1] = -static_cast<T>(2) * normal.x * normal.y;
+               r[0][2] = -static_cast<T>(2) * normal.x * normal.z;
+
+               r[1][0] = -static_cast<T>(2) * normal.x * normal.y;
+               r[1][1] = static_cast<T>(1) - static_cast<T>(2) * normal.y * normal.y;
+               r[1][2] = -static_cast<T>(2) * normal.y * normal.z;
+
+               r[2][0] = -static_cast<T>(2) * normal.x * normal.z;
+               r[2][1] = -static_cast<T>(2) * normal.y * normal.z;
+               r[2][2] = static_cast<T>(1) - static_cast<T>(2) * normal.z * normal.z;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat3x3<T, P> proj2D(
+               const tmat3x3<T, P>& m, 
+               const tvec3<T, P>& normal)
+       {
+               tmat3x3<T, P> r(static_cast<T>(1));
+               r[0][0] = static_cast<T>(1) - normal.x * normal.x;
+               r[0][1] = - normal.x * normal.y;
+               r[1][0] = - normal.x * normal.y;
+               r[1][1] = static_cast<T>(1) - normal.y * normal.y;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> proj3D(
+               const tmat4x4<T, P>& m, 
+               const tvec3<T, P>& normal)
+       {
+               tmat4x4<T, P> r(static_cast<T>(1));
+               r[0][0] = static_cast<T>(1) - normal.x * normal.x;
+               r[0][1] = - normal.x * normal.y;
+               r[0][2] = - normal.x * normal.z;
+               r[1][0] = - normal.x * normal.y;
+               r[1][1] = static_cast<T>(1) - normal.y * normal.y;
+               r[1][2] = - normal.y * normal.z;
+               r[2][0] = - normal.x * normal.z;
+               r[2][1] = - normal.y * normal.z;
+               r[2][2] = static_cast<T>(1) - normal.z * normal.z;
+               return m * r;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> scaleBias(T scale, T bias)
+       {
+               tmat4x4<T, P> result;
+               result[3] = tvec4<T, P>(tvec3<T, P>(bias), static_cast<T>(1));
+               result[0][0] = scale;
+               result[1][1] = scale;
+               result[2][2] = scale;
+               return result;
+       }
+
+       template <typename T, precision P> 
+       GLM_FUNC_QUALIFIER tmat4x4<T, P> scaleBias(tmat4x4<T, P> const& m, T scale, T bias)
+       {
+               return m * scaleBias(scale, bias);
+       }
+}//namespace glm
+
diff --git a/core/deps/glm/glm/gtx/type_aligned.hpp b/core/deps/glm/glm/gtx/type_aligned.hpp
new file mode 100755 (executable)
index 0000000..8962a6f
--- /dev/null
@@ -0,0 +1,966 @@
+/// @ref gtx_type_aligned
+/// @file glm/gtx/type_aligned.hpp
+///
+/// @see core (dependence)
+/// @see gtc_quaternion (dependence)
+///
+/// @defgroup gtx_type_aligned GLM_GTX_type_aligned
+/// @ingroup gtx
+///
+/// @brief Defines aligned types.
+///
+/// @ref core_precision defines aligned types.
+///
+/// <glm/gtx/type_aligned.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../gtc/type_precision.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_type_aligned extension included")
+#endif
+
+namespace glm
+{
+       ///////////////////////////
+       // Signed int vector types 
+
+       /// @addtogroup gtx_type_aligned
+       /// @{
+
+       /// Low precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int8, aligned_lowp_int8, 1);
+
+       /// Low precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int16, aligned_lowp_int16, 2);
+
+       /// Low precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int32, aligned_lowp_int32, 4);
+
+       /// Low precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int64, aligned_lowp_int64, 8);
+
+
+       /// Low precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int8_t, aligned_lowp_int8_t, 1);
+
+       /// Low precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int16_t, aligned_lowp_int16_t, 2);
+
+       /// Low precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int32_t, aligned_lowp_int32_t, 4);
+
+       /// Low precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_int64_t, aligned_lowp_int64_t, 8);
+
+
+       /// Low precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_i8, aligned_lowp_i8, 1);
+
+       /// Low precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_i16, aligned_lowp_i16, 2);
+
+       /// Low precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_i32, aligned_lowp_i32, 4);
+
+       /// Low precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_i64, aligned_lowp_i64, 8);
+
+
+       /// Medium precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int8, aligned_mediump_int8, 1);
+
+       /// Medium precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int16, aligned_mediump_int16, 2);
+
+       /// Medium precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int32, aligned_mediump_int32, 4);
+
+       /// Medium precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int64, aligned_mediump_int64, 8);
+
+
+       /// Medium precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int8_t, aligned_mediump_int8_t, 1);
+
+       /// Medium precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int16_t, aligned_mediump_int16_t, 2);
+
+       /// Medium precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int32_t, aligned_mediump_int32_t, 4);
+
+       /// Medium precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_int64_t, aligned_mediump_int64_t, 8);
+
+
+       /// Medium precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_i8, aligned_mediump_i8, 1);
+
+       /// Medium precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_i16, aligned_mediump_i16, 2);
+
+       /// Medium precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_i32, aligned_mediump_i32, 4);
+
+       /// Medium precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_i64, aligned_mediump_i64, 8);
+
+
+       /// High precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int8, aligned_highp_int8, 1);
+
+       /// High precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int16, aligned_highp_int16, 2);
+
+       /// High precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int32, aligned_highp_int32, 4);
+
+       /// High precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int64, aligned_highp_int64, 8);
+
+
+       /// High precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int8_t, aligned_highp_int8_t, 1);
+
+       /// High precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int16_t, aligned_highp_int16_t, 2);
+
+       /// High precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int32_t, aligned_highp_int32_t, 4);
+
+       /// High precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_int64_t, aligned_highp_int64_t, 8);
+
+
+       /// High precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_i8, aligned_highp_i8, 1);
+
+       /// High precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_i16, aligned_highp_i16, 2);
+
+       /// High precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_i32, aligned_highp_i32, 4);
+
+       /// High precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_i64, aligned_highp_i64, 8);
+
+
+       /// Default precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int8, aligned_int8, 1);
+
+       /// Default precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int16, aligned_int16, 2);
+
+       /// Default precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int32, aligned_int32, 4);
+
+       /// Default precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int64, aligned_int64, 8);
+
+
+       /// Default precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int8_t, aligned_int8_t, 1);
+
+       /// Default precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int16_t, aligned_int16_t, 2);
+
+       /// Default precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int32_t, aligned_int32_t, 4);
+
+       /// Default precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(int64_t, aligned_int64_t, 8);
+
+
+       /// Default precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i8, aligned_i8, 1);
+
+       /// Default precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i16, aligned_i16, 2);
+
+       /// Default precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i32, aligned_i32, 4);
+
+       /// Default precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i64, aligned_i64, 8);
+
+
+       /// Default precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(ivec1, aligned_ivec1, 4);
+       
+       /// Default precision 32 bit signed integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(ivec2, aligned_ivec2, 8);
+
+       /// Default precision 32 bit signed integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(ivec3, aligned_ivec3, 16);
+
+       /// Default precision 32 bit signed integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(ivec4, aligned_ivec4, 16);
+
+
+       /// Default precision 8 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i8vec1, aligned_i8vec1, 1);
+
+       /// Default precision 8 bit signed integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i8vec2, aligned_i8vec2, 2);
+
+       /// Default precision 8 bit signed integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i8vec3, aligned_i8vec3, 4);
+
+       /// Default precision 8 bit signed integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i8vec4, aligned_i8vec4, 4);
+
+
+       /// Default precision 16 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i16vec1, aligned_i16vec1, 2);
+       
+       /// Default precision 16 bit signed integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i16vec2, aligned_i16vec2, 4);
+
+       /// Default precision 16 bit signed integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i16vec3, aligned_i16vec3, 8);
+
+       /// Default precision 16 bit signed integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i16vec4, aligned_i16vec4, 8);
+
+
+       /// Default precision 32 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i32vec1, aligned_i32vec1, 4);
+       
+       /// Default precision 32 bit signed integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i32vec2, aligned_i32vec2, 8);
+
+       /// Default precision 32 bit signed integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i32vec3, aligned_i32vec3, 16);
+
+       /// Default precision 32 bit signed integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i32vec4, aligned_i32vec4, 16);
+
+
+       /// Default precision 64 bit signed integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i64vec1, aligned_i64vec1, 8);
+       
+       /// Default precision 64 bit signed integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i64vec2, aligned_i64vec2, 16);
+
+       /// Default precision 64 bit signed integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i64vec3, aligned_i64vec3, 32);
+
+       /// Default precision 64 bit signed integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(i64vec4, aligned_i64vec4, 32);
+
+
+       /////////////////////////////
+       // Unsigned int vector types
+
+       /// Low precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint8, aligned_lowp_uint8, 1);
+
+       /// Low precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint16, aligned_lowp_uint16, 2);
+
+       /// Low precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint32, aligned_lowp_uint32, 4);
+
+       /// Low precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint64, aligned_lowp_uint64, 8);
+
+
+       /// Low precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint8_t, aligned_lowp_uint8_t, 1);
+
+       /// Low precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint16_t, aligned_lowp_uint16_t, 2);
+
+       /// Low precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint32_t, aligned_lowp_uint32_t, 4);
+
+       /// Low precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_uint64_t, aligned_lowp_uint64_t, 8);
+
+
+       /// Low precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_u8, aligned_lowp_u8, 1);
+
+       /// Low precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_u16, aligned_lowp_u16, 2);
+
+       /// Low precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_u32, aligned_lowp_u32, 4);
+
+       /// Low precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(lowp_u64, aligned_lowp_u64, 8);
+
+
+       /// Medium precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint8, aligned_mediump_uint8, 1);
+
+       /// Medium precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint16, aligned_mediump_uint16, 2);
+
+       /// Medium precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint32, aligned_mediump_uint32, 4);
+
+       /// Medium precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint64, aligned_mediump_uint64, 8);
+
+
+       /// Medium precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint8_t, aligned_mediump_uint8_t, 1);
+
+       /// Medium precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint16_t, aligned_mediump_uint16_t, 2);
+
+       /// Medium precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint32_t, aligned_mediump_uint32_t, 4);
+
+       /// Medium precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_uint64_t, aligned_mediump_uint64_t, 8);
+
+
+       /// Medium precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_u8, aligned_mediump_u8, 1);
+
+       /// Medium precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_u16, aligned_mediump_u16, 2);
+
+       /// Medium precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_u32, aligned_mediump_u32, 4);
+
+       /// Medium precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mediump_u64, aligned_mediump_u64, 8);
+
+
+       /// High precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint8, aligned_highp_uint8, 1);
+
+       /// High precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint16, aligned_highp_uint16, 2);
+
+       /// High precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint32, aligned_highp_uint32, 4);
+
+       /// High precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint64, aligned_highp_uint64, 8);
+
+
+       /// High precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint8_t, aligned_highp_uint8_t, 1);
+
+       /// High precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint16_t, aligned_highp_uint16_t, 2);
+
+       /// High precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint32_t, aligned_highp_uint32_t, 4);
+
+       /// High precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_uint64_t, aligned_highp_uint64_t, 8);
+
+
+       /// High precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_u8, aligned_highp_u8, 1);
+
+       /// High precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_u16, aligned_highp_u16, 2);
+
+       /// High precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_u32, aligned_highp_u32, 4);
+
+       /// High precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(highp_u64, aligned_highp_u64, 8);
+
+
+       /// Default precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint8, aligned_uint8, 1);
+
+       /// Default precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint16, aligned_uint16, 2);
+
+       /// Default precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint32, aligned_uint32, 4);
+
+       /// Default precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint64, aligned_uint64, 8);
+
+
+       /// Default precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint8_t, aligned_uint8_t, 1);
+
+       /// Default precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint16_t, aligned_uint16_t, 2);
+
+       /// Default precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint32_t, aligned_uint32_t, 4);
+
+       /// Default precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uint64_t, aligned_uint64_t, 8);
+
+
+       /// Default precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u8, aligned_u8, 1);
+
+       /// Default precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u16, aligned_u16, 2);
+
+       /// Default precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u32, aligned_u32, 4);
+
+       /// Default precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u64, aligned_u64, 8);
+
+
+       /// Default precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uvec1, aligned_uvec1, 4);
+       
+       /// Default precision 32 bit unsigned integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uvec2, aligned_uvec2, 8);
+
+       /// Default precision 32 bit unsigned integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uvec3, aligned_uvec3, 16);
+
+       /// Default precision 32 bit unsigned integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(uvec4, aligned_uvec4, 16);
+
+
+       /// Default precision 8 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u8vec1, aligned_u8vec1, 1);
+
+       /// Default precision 8 bit unsigned integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u8vec2, aligned_u8vec2, 2);
+
+       /// Default precision 8 bit unsigned integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u8vec3, aligned_u8vec3, 4);
+
+       /// Default precision 8 bit unsigned integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u8vec4, aligned_u8vec4, 4);
+
+
+       /// Default precision 16 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u16vec1, aligned_u16vec1, 2);
+       
+       /// Default precision 16 bit unsigned integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u16vec2, aligned_u16vec2, 4);
+
+       /// Default precision 16 bit unsigned integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u16vec3, aligned_u16vec3, 8);
+
+       /// Default precision 16 bit unsigned integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u16vec4, aligned_u16vec4, 8);
+
+
+       /// Default precision 32 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u32vec1, aligned_u32vec1, 4);
+       
+       /// Default precision 32 bit unsigned integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u32vec2, aligned_u32vec2, 8);
+
+       /// Default precision 32 bit unsigned integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u32vec3, aligned_u32vec3, 16);
+
+       /// Default precision 32 bit unsigned integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u32vec4, aligned_u32vec4, 16);
+
+
+       /// Default precision 64 bit unsigned integer aligned scalar type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u64vec1, aligned_u64vec1, 8);
+       
+       /// Default precision 64 bit unsigned integer aligned vector of 2 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u64vec2, aligned_u64vec2, 16);
+
+       /// Default precision 64 bit unsigned integer aligned vector of 3 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u64vec3, aligned_u64vec3, 32);
+
+       /// Default precision 64 bit unsigned integer aligned vector of 4 components type.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(u64vec4, aligned_u64vec4, 32);
+
+
+       //////////////////////
+       // Float vector types
+
+       /// 32 bit single-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float32, aligned_float32, 4);
+
+       /// 64 bit double-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float64, aligned_float64, 8);
+
+
+       /// 32 bit single-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float32_t, aligned_float32_t, 4);
+
+       /// 64 bit double-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float64_t, aligned_float64_t, 8);
+
+
+       /// 32 bit single-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float32, aligned_f32, 4);
+
+       /// 64 bit double-precision floating-point aligned scalar.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(float64, aligned_f64, 8);
+
+
+       /// Single-precision floating-point aligned vector of 1 component.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(vec1, aligned_vec1, 4);
+
+       /// Single-precision floating-point aligned vector of 2 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(vec2, aligned_vec2, 8);
+
+       /// Single-precision floating-point aligned vector of 3 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(vec3, aligned_vec3, 16);
+
+       /// Single-precision floating-point aligned vector of 4 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(vec4, aligned_vec4, 16);
+
+
+       /// Single-precision floating-point aligned vector of 1 component.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fvec1, aligned_fvec1, 4);
+
+       /// Single-precision floating-point aligned vector of 2 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fvec2, aligned_fvec2, 8);
+
+       /// Single-precision floating-point aligned vector of 3 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fvec3, aligned_fvec3, 16);
+
+       /// Single-precision floating-point aligned vector of 4 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fvec4, aligned_fvec4, 16);
+
+       
+       /// Single-precision floating-point aligned vector of 1 component.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32vec1, aligned_f32vec1, 4);
+
+       /// Single-precision floating-point aligned vector of 2 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32vec2, aligned_f32vec2, 8);
+
+       /// Single-precision floating-point aligned vector of 3 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32vec3, aligned_f32vec3, 16);
+
+       /// Single-precision floating-point aligned vector of 4 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32vec4, aligned_f32vec4, 16);
+
+
+       /// Double-precision floating-point aligned vector of 1 component.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(dvec1, aligned_dvec1, 8);
+
+       /// Double-precision floating-point aligned vector of 2 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(dvec2, aligned_dvec2, 16);
+
+       /// Double-precision floating-point aligned vector of 3 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(dvec3, aligned_dvec3, 32);
+
+       /// Double-precision floating-point aligned vector of 4 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(dvec4, aligned_dvec4, 32);
+
+
+       /// Double-precision floating-point aligned vector of 1 component.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64vec1, aligned_f64vec1, 8);
+
+       /// Double-precision floating-point aligned vector of 2 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64vec2, aligned_f64vec2, 16);
+
+       /// Double-precision floating-point aligned vector of 3 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64vec3, aligned_f64vec3, 32);
+
+       /// Double-precision floating-point aligned vector of 4 components.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64vec4, aligned_f64vec4, 32);
+
+
+       //////////////////////
+       // Float matrix types 
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef detail::tmat1<f32> mat1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat2, aligned_mat2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat3, aligned_mat3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat4, aligned_mat4, 16);
+
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef detail::tmat1x1<f32> mat1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat2x2, aligned_mat2x2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat3x3, aligned_mat3x3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(mat4x4, aligned_mat4x4, 16);
+
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef detail::tmat1x1<f32> fmat1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4, 16);
+
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef f32 fmat1x1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat2x2, aligned_fmat2x2, 16);
+
+       /// Single-precision floating-point aligned 2x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat2x3, aligned_fmat2x3, 16);
+
+       /// Single-precision floating-point aligned 2x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat2x4, aligned_fmat2x4, 16);
+
+       /// Single-precision floating-point aligned 3x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat3x2, aligned_fmat3x2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat3x3, aligned_fmat3x3, 16);
+
+       /// Single-precision floating-point aligned 3x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat3x4, aligned_fmat3x4, 16);
+
+       /// Single-precision floating-point aligned 4x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat4x2, aligned_fmat4x2, 16);
+
+       /// Single-precision floating-point aligned 4x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat4x3, aligned_fmat4x3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fmat4x4, aligned_fmat4x4, 16);
+
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef detail::tmat1x1<f32, defaultp> f32mat1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4, 16);
+
+
+       /// Single-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef f32 f32mat1x1;
+
+       /// Single-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat2x2, aligned_f32mat2x2, 16);
+
+       /// Single-precision floating-point aligned 2x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat2x3, aligned_f32mat2x3, 16);
+
+       /// Single-precision floating-point aligned 2x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat2x4, aligned_f32mat2x4, 16);
+
+       /// Single-precision floating-point aligned 3x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat3x2, aligned_f32mat3x2, 16);
+
+       /// Single-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat3x3, aligned_f32mat3x3, 16);
+
+       /// Single-precision floating-point aligned 3x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat3x4, aligned_f32mat3x4, 16);
+
+       /// Single-precision floating-point aligned 4x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat4x2, aligned_f32mat4x2, 16);
+
+       /// Single-precision floating-point aligned 4x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat4x3, aligned_f32mat4x3, 16);
+
+       /// Single-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32mat4x4, aligned_f32mat4x4, 16);
+
+
+       /// Double-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef detail::tmat1x1<f64, defaultp> f64mat1;
+
+       /// Double-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2, 32);
+
+       /// Double-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3, 32);
+
+       /// Double-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4, 32);
+
+
+       /// Double-precision floating-point aligned 1x1 matrix.
+       /// @see gtx_type_aligned
+       //typedef f64 f64mat1x1;
+
+       /// Double-precision floating-point aligned 2x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat2x2, aligned_f64mat2x2, 32);
+
+       /// Double-precision floating-point aligned 2x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat2x3, aligned_f64mat2x3, 32);
+
+       /// Double-precision floating-point aligned 2x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat2x4, aligned_f64mat2x4, 32);
+
+       /// Double-precision floating-point aligned 3x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat3x2, aligned_f64mat3x2, 32);
+
+       /// Double-precision floating-point aligned 3x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat3x3, aligned_f64mat3x3, 32);
+
+       /// Double-precision floating-point aligned 3x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat3x4, aligned_f64mat3x4, 32);
+
+       /// Double-precision floating-point aligned 4x2 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat4x2, aligned_f64mat4x2, 32);
+
+       /// Double-precision floating-point aligned 4x3 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat4x3, aligned_f64mat4x3, 32);
+
+       /// Double-precision floating-point aligned 4x4 matrix.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64mat4x4, aligned_f64mat4x4, 32);
+
+
+       //////////////////////////
+       // Quaternion types
+
+       /// Single-precision floating-point aligned quaternion.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(quat, aligned_quat, 16);
+
+       /// Single-precision floating-point aligned quaternion.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(fquat, aligned_fquat, 16);
+
+       /// Double-precision floating-point aligned quaternion.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(dquat, aligned_dquat, 32);
+
+       /// Single-precision floating-point aligned quaternion.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f32quat, aligned_f32quat, 16);
+
+       /// Double-precision floating-point aligned quaternion.
+       /// @see gtx_type_aligned
+       GLM_ALIGNED_TYPEDEF(f64quat, aligned_f64quat, 32);
+
+       /// @}
+}//namespace glm
+
+#include "type_aligned.inl"
diff --git a/core/deps/glm/glm/gtx/type_aligned.inl b/core/deps/glm/glm/gtx/type_aligned.inl
new file mode 100755 (executable)
index 0000000..83202df
--- /dev/null
@@ -0,0 +1,7 @@
+/// @ref gtc_type_aligned
+/// @file glm/gtc/type_aligned.inl
+
+namespace glm
+{
+
+}
diff --git a/core/deps/glm/glm/gtx/type_trait.hpp b/core/deps/glm/glm/gtx/type_trait.hpp
new file mode 100755 (executable)
index 0000000..0207a06
--- /dev/null
@@ -0,0 +1,252 @@
+/// @ref gtx_type_trait
+/// @file glm/gtx/type_trait.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_type_trait GLM_GTX_type_trait
+/// @ingroup gtx
+///
+/// @brief Defines traits for each type.
+///
+/// <glm/gtx/type_trait.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../detail/type_vec2.hpp"
+#include "../detail/type_vec3.hpp"
+#include "../detail/type_vec4.hpp"
+#include "../detail/type_mat2x2.hpp"
+#include "../detail/type_mat2x3.hpp"
+#include "../detail/type_mat2x4.hpp"
+#include "../detail/type_mat3x2.hpp"
+#include "../detail/type_mat3x3.hpp"
+#include "../detail/type_mat3x4.hpp"
+#include "../detail/type_mat4x2.hpp"
+#include "../detail/type_mat4x3.hpp"
+#include "../detail/type_mat4x4.hpp"
+#include "../gtc/quaternion.hpp"
+#include "../gtx/dual_quaternion.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_type_trait extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_type_trait
+       /// @{
+
+       template <template <typename, precision> class genType, typename T, precision P>
+       struct type
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = false;
+               static bool const is_quat = false;
+               static length_t const components = 0;
+               static length_t const cols = 0;
+               static length_t const rows = 0;
+       };
+
+       template <typename T, precision P>
+       struct type<tvec1, T, P>
+       {
+               static bool const is_vec = true;
+               static bool const is_mat = false;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 1
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tvec2, T, P>
+       {
+               static bool const is_vec = true;
+               static bool const is_mat = false;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 2
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tvec3, T, P>
+       {
+               static bool const is_vec = true;
+               static bool const is_mat = false;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 3
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tvec4, T, P>
+       {
+               static bool const is_vec = true;
+               static bool const is_mat = false;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 4
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat2x2, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 2,
+                       cols = 2,
+                       rows = 2
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat2x3, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 2,
+                       cols = 2,
+                       rows = 3
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat2x4, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 2,
+                       cols = 2,
+                       rows = 4
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat3x2, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 3,
+                       cols = 3,
+                       rows = 2
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat3x3, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 3,
+                       cols = 3,
+                       rows = 3
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat3x4, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 3,
+                       cols = 3,
+                       rows = 4
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat4x2, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 4,
+                       cols = 4,
+                       rows = 2
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat4x3, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 4,
+                       cols = 4,
+                       rows = 3
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tmat4x4, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = true;
+               static bool const is_quat = false;
+               enum
+               {
+                       components = 4,
+                       cols = 4,
+                       rows = 4
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tquat, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = false;
+               static bool const is_quat = true;
+               enum
+               {
+                       components = 4
+               };
+       };
+
+       template <typename T, precision P>
+       struct type<tdualquat, T, P>
+       {
+               static bool const is_vec = false;
+               static bool const is_mat = false;
+               static bool const is_quat = true;
+               enum
+               {
+                       components = 8
+               };
+       };
+
+       /// @}
+}//namespace glm
+
+#include "type_trait.inl"
diff --git a/core/deps/glm/glm/gtx/type_trait.inl b/core/deps/glm/glm/gtx/type_trait.inl
new file mode 100755 (executable)
index 0000000..e69de29
diff --git a/core/deps/glm/glm/gtx/vector_angle.hpp b/core/deps/glm/glm/gtx/vector_angle.hpp
new file mode 100755 (executable)
index 0000000..d52d3f8
--- /dev/null
@@ -0,0 +1,60 @@
+/// @ref gtx_vector_angle
+/// @file glm/gtx/vector_angle.hpp
+///
+/// @see core (dependence)
+/// @see gtx_quaternion (dependence)
+/// @see gtx_epsilon (dependence)
+///
+/// @defgroup gtx_vector_angle GLM_GTX_vector_angle
+/// @ingroup gtx
+///
+/// @brief Compute angle between vectors
+///
+/// <glm/gtx/vector_angle.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/epsilon.hpp"
+#include "../gtx/quaternion.hpp"
+#include "../gtx/rotate_vector.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_vector_angle extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_vector_angle
+       /// @{
+
+       //! Returns the absolute angle between two vectors.
+       //! Parameters need to be normalized.
+       /// @see gtx_vector_angle extension.
+       template <typename vecType>
+       GLM_FUNC_DECL typename vecType::value_type angle(
+               vecType const & x, 
+               vecType const & y);
+
+       //! Returns the oriented angle between two 2d vectors.
+       //! Parameters need to be normalized.
+       /// @see gtx_vector_angle extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T orientedAngle(
+               tvec2<T, P> const & x,
+               tvec2<T, P> const & y);
+
+       //! Returns the oriented angle between two 3d vectors based from a reference axis.
+       //! Parameters need to be normalized.
+       /// @see gtx_vector_angle extension.
+       template <typename T, precision P>
+       GLM_FUNC_DECL T orientedAngle(
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               tvec3<T, P> const & ref);
+
+       /// @}
+}// namespace glm
+
+#include "vector_angle.inl"
diff --git a/core/deps/glm/glm/gtx/vector_angle.inl b/core/deps/glm/glm/gtx/vector_angle.inl
new file mode 100755 (executable)
index 0000000..05c3028
--- /dev/null
@@ -0,0 +1,58 @@
+/// @ref gtx_vector_angle
+/// @file glm/gtx/vector_angle.inl
+
+namespace glm
+{
+       template <typename genType> 
+       GLM_FUNC_QUALIFIER genType angle
+       (
+               genType const & x,
+               genType const & y
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<genType>::is_iec559, "'angle' only accept floating-point inputs");
+               return acos(clamp(dot(x, y), genType(-1), genType(1)));
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType> 
+       GLM_FUNC_QUALIFIER T angle
+       (
+               vecType<T, P> const & x,
+               vecType<T, P> const & y
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'angle' only accept floating-point inputs");
+               return acos(clamp(dot(x, y), T(-1), T(1)));
+       }
+
+       //! \todo epsilon is hard coded to 0.01
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T orientedAngle
+       (
+               tvec2<T, P> const & x,
+               tvec2<T, P> const & y
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'orientedAngle' only accept floating-point inputs");
+               T const Angle(acos(clamp(dot(x, y), T(-1), T(1))));
+
+               if(all(epsilonEqual(y, glm::rotate(x, Angle), T(0.0001))))
+                       return Angle;
+               else
+                       return -Angle;
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER T orientedAngle
+       (
+               tvec3<T, P> const & x,
+               tvec3<T, P> const & y,
+               tvec3<T, P> const & ref
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'orientedAngle' only accept floating-point inputs");
+
+               T const Angle(acos(clamp(dot(x, y), T(-1), T(1))));
+               return mix(Angle, -Angle, dot(ref, cross(x, y)) < T(0));
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/vector_query.hpp b/core/deps/glm/glm/gtx/vector_query.hpp
new file mode 100755 (executable)
index 0000000..2c0d022
--- /dev/null
@@ -0,0 +1,62 @@
+/// @ref gtx_vector_query
+/// @file glm/gtx/vector_query.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_vector_query GLM_GTX_vector_query
+/// @ingroup gtx
+///
+/// @brief Query informations of vector types
+///
+/// <glm/gtx/vector_query.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include <cfloat>
+#include <limits>
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_vector_query extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_vector_query
+       /// @{
+
+       //! Check whether two vectors are collinears.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool areCollinear(vecType<T, P> const & v0, vecType<T, P> const & v1, T const & epsilon);
+               
+       //! Check whether two vectors are orthogonals.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool areOrthogonal(vecType<T, P> const & v0, vecType<T, P> const & v1, T const & epsilon);
+
+       //! Check whether a vector is normalized.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool isNormalized(vecType<T, P> const & v, T const & epsilon);
+               
+       //! Check whether a vector is null.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool isNull(vecType<T, P> const & v, T const & epsilon);
+
+       //! Check whether a each component of a vector is null.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL vecType<bool, P> isCompNull(vecType<T, P> const & v, T const & epsilon);
+
+       //! Check whether two vectors are orthonormal.
+       /// @see gtx_vector_query extensions.
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_DECL bool areOrthonormal(vecType<T, P> const & v0, vecType<T, P> const & v1, T const & epsilon);
+
+       /// @}
+}// namespace glm
+
+#include "vector_query.inl"
diff --git a/core/deps/glm/glm/gtx/vector_query.inl b/core/deps/glm/glm/gtx/vector_query.inl
new file mode 100755 (executable)
index 0000000..85ea5e5
--- /dev/null
@@ -0,0 +1,193 @@
+/// @ref gtx_vector_query
+/// @file glm/gtx/vector_query.inl
+
+#include <cassert>
+
+namespace glm{
+namespace detail
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_areCollinear{};
+
+       template <typename T, precision P>
+       struct compute_areCollinear<T, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static bool call(tvec2<T, P> const & v0, tvec2<T, P> const & v1, T const & epsilon)
+               {
+                       return length(cross(tvec3<T, P>(v0, static_cast<T>(0)), tvec3<T, P>(v1, static_cast<T>(0)))) < epsilon;
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_areCollinear<T, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static bool call(tvec3<T, P> const & v0, tvec3<T, P> const & v1, T const & epsilon)
+               {
+                       return length(cross(v0, v1)) < epsilon;
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_areCollinear<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static bool call(tvec4<T, P> const & v0, tvec4<T, P> const & v1, T const & epsilon)
+               {
+                       return length(cross(tvec3<T, P>(v0), tvec3<T, P>(v1))) < epsilon;
+               }
+       };
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       struct compute_isCompNull{};
+
+       template <typename T, precision P>
+       struct compute_isCompNull<T, P, tvec2>
+       {
+               GLM_FUNC_QUALIFIER static tvec2<bool, P> call(tvec2<T, P> const & v, T const & epsilon)
+               {
+                       return tvec2<bool, P>(
+                               (abs(v.x) < epsilon),
+                               (abs(v.y) < epsilon));
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_isCompNull<T, P, tvec3>
+       {
+               GLM_FUNC_QUALIFIER static tvec3<bool, P> call(tvec3<T, P> const & v, T const & epsilon)
+               {
+                       return tvec3<bool, P>(
+                               (abs(v.x) < epsilon),
+                               (abs(v.y) < epsilon),
+                               (abs(v.z) < epsilon));
+               }
+       };
+
+       template <typename T, precision P>
+       struct compute_isCompNull<T, P, tvec4>
+       {
+               GLM_FUNC_QUALIFIER static tvec4<bool, P> call(tvec4<T, P> const & v, T const & epsilon)
+               {
+                       return tvec4<bool, P>(
+                               (abs(v.x) < epsilon),
+                               (abs(v.y) < epsilon),
+                               (abs(v.z) < epsilon),
+                               (abs(v.w) < epsilon));
+               }
+       };
+
+}//namespace detail
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool areCollinear
+       (
+               vecType<T, P> const & v0,
+               vecType<T, P> const & v1,
+               T const & epsilon
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'areCollinear' only accept floating-point inputs");
+
+               return detail::compute_areCollinear<T, P, vecType>::call(v0, v1, epsilon);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool areOrthogonal
+       (
+               vecType<T, P> const & v0,
+               vecType<T, P> const & v1,
+               T const & epsilon
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'areOrthogonal' only accept floating-point inputs");
+
+               return abs(dot(v0, v1)) <= max(
+                       static_cast<T>(1),
+                       length(v0)) * max(static_cast<T>(1), length(v1)) * epsilon;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool isNormalized
+       (
+               vecType<T, P> const & v,
+               T const & epsilon
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isNormalized' only accept floating-point inputs");
+
+               return abs(length(v) - static_cast<T>(1)) <= static_cast<T>(2) * epsilon;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool isNull
+       (
+               vecType<T, P> const & v,
+               T const & epsilon
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isNull' only accept floating-point inputs");
+
+               return length(v) <= epsilon;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<bool, P> isCompNull
+       (
+               vecType<T, P> const & v,
+               T const & epsilon
+       )
+       {
+               GLM_STATIC_ASSERT(std::numeric_limits<T>::is_iec559, "'isCompNull' only accept floating-point inputs");
+
+               return detail::compute_isCompNull<T, P, vecType>::call(v, epsilon);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec2<bool, P> isCompNull
+       (
+               tvec2<T, P> const & v,
+               T const & epsilon)
+       {
+               return tvec2<bool, P>(
+                       abs(v.x) < epsilon,
+                       abs(v.y) < epsilon);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec3<bool, P> isCompNull
+       (
+               tvec3<T, P> const & v,
+               T const & epsilon
+       )
+       {
+               return tvec3<bool, P>(
+                       abs(v.x) < epsilon,
+                       abs(v.y) < epsilon,
+                       abs(v.z) < epsilon);
+       }
+
+       template <typename T, precision P>
+       GLM_FUNC_QUALIFIER tvec4<bool, P> isCompNull
+       (
+               tvec4<T, P> const & v,
+               T const & epsilon
+       )
+       {
+               return tvec4<bool, P>(
+                       abs(v.x) < epsilon,
+                       abs(v.y) < epsilon,
+                       abs(v.z) < epsilon,
+                       abs(v.w) < epsilon);
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER bool areOrthonormal
+       (
+               vecType<T, P> const & v0,
+               vecType<T, P> const & v1,
+               T const & epsilon
+       )
+       {
+               return isNormalized(v0, epsilon) && isNormalized(v1, epsilon) && (abs(dot(v0, v1)) <= epsilon);
+       }
+
+}//namespace glm
diff --git a/core/deps/glm/glm/gtx/wrap.hpp b/core/deps/glm/glm/gtx/wrap.hpp
new file mode 100755 (executable)
index 0000000..0060073
--- /dev/null
@@ -0,0 +1,51 @@
+/// @ref gtx_wrap
+/// @file glm/gtx/wrap.hpp
+///
+/// @see core (dependence)
+///
+/// @defgroup gtx_wrap GLM_GTX_wrap
+/// @ingroup gtx
+///
+/// @brief Wrapping mode of texture coordinates.
+///
+/// <glm/gtx/wrap.hpp> need to be included to use these functionalities.
+
+#pragma once
+
+// Dependency:
+#include "../glm.hpp"
+#include "../gtc/vec1.hpp"
+
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_EXT_INCLUDED)
+#      pragma message("GLM: GLM_GTX_wrap extension included")
+#endif
+
+namespace glm
+{
+       /// @addtogroup gtx_wrap
+       /// @{
+
+       /// Simulate GL_CLAMP OpenGL wrap mode
+       /// @see gtx_wrap extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType clamp(genType const& Texcoord);
+
+       /// Simulate GL_REPEAT OpenGL wrap mode
+       /// @see gtx_wrap extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType repeat(genType const& Texcoord);
+
+       /// Simulate GL_MIRRORED_REPEAT OpenGL wrap mode
+       /// @see gtx_wrap extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType mirrorClamp(genType const& Texcoord);
+
+       /// Simulate GL_MIRROR_REPEAT OpenGL wrap mode
+       /// @see gtx_wrap extension.
+       template <typename genType>
+       GLM_FUNC_DECL genType mirrorRepeat(genType const& Texcoord);
+
+       /// @}
+}// namespace glm
+
+#include "wrap.inl"
diff --git a/core/deps/glm/glm/gtx/wrap.inl b/core/deps/glm/glm/gtx/wrap.inl
new file mode 100755 (executable)
index 0000000..941a803
--- /dev/null
@@ -0,0 +1,58 @@
+/// @ref gtx_wrap
+/// @file glm/gtx/wrap.inl
+
+namespace glm
+{
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> clamp(vecType<T, P> const& Texcoord)
+       {
+               return glm::clamp(Texcoord, vecType<T, P>(0), vecType<T, P>(1));
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType clamp(genType const & Texcoord)
+       {
+               return clamp(tvec1<genType, defaultp>(Texcoord)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> repeat(vecType<T, P> const& Texcoord)
+       {
+               return glm::fract(Texcoord);
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType repeat(genType const & Texcoord)
+       {
+               return repeat(tvec1<genType, defaultp>(Texcoord)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mirrorClamp(vecType<T, P> const& Texcoord)
+       {
+               return glm::fract(glm::abs(Texcoord));
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType mirrorClamp(genType const & Texcoord)
+       {
+               return mirrorClamp(tvec1<genType, defaultp>(Texcoord)).x;
+       }
+
+       template <typename T, precision P, template <typename, precision> class vecType>
+       GLM_FUNC_QUALIFIER vecType<T, P> mirrorRepeat(vecType<T, P> const& Texcoord)
+       {
+               vecType<T, P> const Abs = glm::abs(Texcoord);
+               vecType<T, P> const Clamp = glm::mod(glm::floor(Abs), vecType<T, P>(2));
+               vecType<T, P> const Floor = glm::floor(Abs);
+               vecType<T, P> const Rest = Abs - Floor;
+               vecType<T, P> const Mirror = Clamp + Rest;
+               return mix(Rest, vecType<T, P>(1) - Rest, glm::greaterThanEqual(Mirror, vecType<T, P>(1)));
+       }
+
+       template <typename genType>
+       GLM_FUNC_QUALIFIER genType mirrorRepeat(genType const& Texcoord)
+       {
+               return mirrorRepeat(tvec1<genType, defaultp>(Texcoord)).x;
+       }
+}//namespace glm
diff --git a/core/deps/glm/glm/integer.hpp b/core/deps/glm/glm/integer.hpp
new file mode 100755 (executable)
index 0000000..178e10e
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/integer.hpp
+
+#pragma once
+
+#include "detail/func_integer.hpp"
diff --git a/core/deps/glm/glm/mat2x2.hpp b/core/deps/glm/glm/mat2x2.hpp
new file mode 100755 (executable)
index 0000000..420fe9d
--- /dev/null
@@ -0,0 +1,52 @@
+/// @ref core
+/// @file glm/mat2x2.hpp
+
+#pragma once
+
+#include "detail/type_mat2x2.hpp"
+
+namespace glm
+{
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, lowp>            lowp_mat2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, mediump>         mediump_mat2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, highp>           highp_mat2;
+       
+       /// 2 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, lowp>            lowp_mat2x2;
+       
+       /// 2 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, mediump>         mediump_mat2x2;
+       
+       /// 2 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x2<float, highp>           highp_mat2x2;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat2x3.hpp b/core/deps/glm/glm/mat2x3.hpp
new file mode 100755 (executable)
index 0000000..5c1cc70
--- /dev/null
@@ -0,0 +1,32 @@
+/// @ref core
+/// @file glm/mat2x3.hpp
+
+#pragma once
+
+#include "detail/type_mat2x3.hpp"
+
+namespace glm
+{
+       /// 2 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, lowp>            lowp_mat2x3;
+
+       /// 2 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, mediump>         mediump_mat2x3;
+
+       /// 2 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x3<float, highp>           highp_mat2x3;
+
+}//namespace glm
+
diff --git a/core/deps/glm/glm/mat2x4.hpp b/core/deps/glm/glm/mat2x4.hpp
new file mode 100755 (executable)
index 0000000..a82f136
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref core
+/// @file glm/mat2x4.hpp
+
+#pragma once
+
+#include "detail/type_mat2x4.hpp"
+
+namespace glm
+{
+       /// 2 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, lowp>            lowp_mat2x4;
+       
+       /// 2 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, mediump>         mediump_mat2x4;
+       
+       /// 2 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat2x4<float, highp>           highp_mat2x4;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat3x2.hpp b/core/deps/glm/glm/mat3x2.hpp
new file mode 100755 (executable)
index 0000000..40a56de
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref core
+/// @file glm/mat3x2.hpp
+
+#pragma once
+
+#include "detail/type_mat3x2.hpp"
+
+namespace glm
+{
+       /// 3 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, lowp>            lowp_mat3x2;
+       
+       /// 3 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, mediump>         mediump_mat3x2;
+       
+       /// 3 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x2<float, highp>           highp_mat3x2;
+
+}//namespace
diff --git a/core/deps/glm/glm/mat3x3.hpp b/core/deps/glm/glm/mat3x3.hpp
new file mode 100755 (executable)
index 0000000..66bfdfa
--- /dev/null
@@ -0,0 +1,52 @@
+/// @ref core
+/// @file glm/mat3x3.hpp
+
+#pragma once
+
+#include "detail/type_mat3x3.hpp"
+
+namespace glm
+{
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, lowp>            lowp_mat3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, mediump>         mediump_mat3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, highp>           highp_mat3;
+       
+       /// 3 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, lowp>            lowp_mat3x3;
+       
+       /// 3 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, mediump>         mediump_mat3x3;
+       
+       /// 3 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x3<float, highp>           highp_mat3x3;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat3x4.hpp b/core/deps/glm/glm/mat3x4.hpp
new file mode 100755 (executable)
index 0000000..5f83407
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref core
+/// @file glm/mat3x4.hpp
+
+#pragma once
+
+#include "detail/type_mat3x4.hpp"
+
+namespace glm
+{
+       /// 3 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, lowp>            lowp_mat3x4;
+       
+       /// 3 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, mediump>         mediump_mat3x4;
+       
+       /// 3 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat3x4<float, highp>           highp_mat3x4;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat4x2.hpp b/core/deps/glm/glm/mat4x2.hpp
new file mode 100755 (executable)
index 0000000..fe67c4f
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref core
+/// @file glm/mat4x2.hpp
+
+#pragma once
+
+#include "detail/type_mat4x2.hpp"
+
+namespace glm
+{
+       /// 4 columns of 2 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, lowp>            lowp_mat4x2;
+       
+       /// 4 columns of 2 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, mediump>         mediump_mat4x2;
+       
+       /// 4 columns of 2 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x2<float, highp>           highp_mat4x2;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat4x3.hpp b/core/deps/glm/glm/mat4x3.hpp
new file mode 100755 (executable)
index 0000000..ea1cf88
--- /dev/null
@@ -0,0 +1,31 @@
+/// @ref core
+/// @file glm/mat4x3.hpp
+
+#pragma once
+
+#include "detail/type_mat4x3.hpp"
+
+namespace glm
+{
+       /// 4 columns of 3 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, lowp>            lowp_mat4x3;
+       
+       /// 4 columns of 3 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, mediump>         mediump_mat4x3;
+       
+       /// 4 columns of 3 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x3<float, highp>           highp_mat4x3;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/mat4x4.hpp b/core/deps/glm/glm/mat4x4.hpp
new file mode 100755 (executable)
index 0000000..d6c44e8
--- /dev/null
@@ -0,0 +1,52 @@
+/// @ref core
+/// @file glm/mat4x4.hpp
+
+#pragma once
+
+#include "detail/type_mat4x4.hpp"
+
+namespace glm
+{
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, lowp>            lowp_mat4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, mediump>         mediump_mat4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, highp>           highp_mat4;
+       
+       /// 4 columns of 4 components matrix of low precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, lowp>            lowp_mat4x4;
+       
+       /// 4 columns of 4 components matrix of medium precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, mediump>         mediump_mat4x4;
+       
+       /// 4 columns of 4 components matrix of high precision floating-point numbers.
+       /// There is no guarantee on the actual precision.
+       ///
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.1.6 Matrices</a>
+       /// @see <a href="http://www.opengl.org/registry/doc/GLSLangSpec.4.20.8.pdf">GLSL 4.20.8 specification, section 4.7.2 Precision Qualifier</a>
+       typedef tmat4x4<float, highp>           highp_mat4x4;
+
+}//namespace glm
diff --git a/core/deps/glm/glm/matrix.hpp b/core/deps/glm/glm/matrix.hpp
new file mode 100755 (executable)
index 0000000..736dd49
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/matrix.hpp
+
+#pragma once
+
+#include "detail/func_matrix.hpp"
diff --git a/core/deps/glm/glm/packing.hpp b/core/deps/glm/glm/packing.hpp
new file mode 100755 (executable)
index 0000000..4545adb
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/packing.hpp
+
+#pragma once
+
+#include "detail/func_packing.hpp"
diff --git a/core/deps/glm/glm/simd/common.h b/core/deps/glm/glm/simd/common.h
new file mode 100755 (executable)
index 0000000..d8c212d
--- /dev/null
@@ -0,0 +1,240 @@
+/// @ref simd
+/// @file glm/simd/common.h
+
+#pragma once
+
+#include "platform.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_add(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_add_ps(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_add(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_add_ss(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sub(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_sub_ps(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_sub(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_sub_ss(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mul(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_mul_ps(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_mul(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_mul_ss(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_div(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_div_ps(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_div(glm_vec4 a, glm_vec4 b)
+{
+       return _mm_div_ss(a, b);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_div_lowp(glm_vec4 a, glm_vec4 b)
+{
+       return glm_vec4_mul(a, _mm_rcp_ps(b));
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_swizzle_xyzw(glm_vec4 a)
+{
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+               return _mm_permute_ps(a, _MM_SHUFFLE(3, 2, 1, 0));
+#      else
+               return _mm_shuffle_ps(a, a, _MM_SHUFFLE(3, 2, 1, 0));
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_fma(glm_vec4 a, glm_vec4 b, glm_vec4 c)
+{
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+               return _mm_fmadd_ss(a, b, c);
+#      else
+               return _mm_add_ss(_mm_mul_ss(a, b), c);
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fma(glm_vec4 a, glm_vec4 b, glm_vec4 c)
+{
+#      if GLM_ARCH & GLM_ARCH_AVX2_BIT
+               return _mm_fmadd_ps(a, b, c);
+#      else
+               return glm_vec4_add(glm_vec4_mul(a, b), c);
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_abs(glm_vec4 x)
+{
+       return _mm_and_ps(x, _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF)));
+}
+
+GLM_FUNC_QUALIFIER glm_ivec4 glm_ivec4_abs(glm_ivec4 x)
+{
+#      if GLM_ARCH & GLM_ARCH_SSSE3_BIT
+               return _mm_sign_epi32(x, x);
+#      else
+               glm_ivec4 const sgn0 = _mm_srai_epi32(x, 31);
+               glm_ivec4 const inv0 = _mm_xor_si128(x, sgn0);
+               glm_ivec4 const sub0 = _mm_sub_epi32(inv0, sgn0);
+               return sub0;
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sign(glm_vec4 x)
+{
+       glm_vec4 const zro0 = _mm_setzero_ps();
+       glm_vec4 const cmp0 = _mm_cmplt_ps(x, zro0);
+       glm_vec4 const cmp1 = _mm_cmpgt_ps(x, zro0);
+       glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(-1.0f));
+       glm_vec4 const and1 = _mm_and_ps(cmp1, _mm_set1_ps(1.0f));
+       glm_vec4 const or0 = _mm_or_ps(and0, and1);;
+       return or0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_round(glm_vec4 x)
+{
+#      if GLM_ARCH & GLM_ARCH_SSE41_BIT
+               return _mm_round_ps(x, _MM_FROUND_TO_NEAREST_INT);
+#      else
+               glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+               glm_vec4 const and0 = _mm_and_ps(sgn0, x);
+               glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f));
+               glm_vec4 const add0 = glm_vec4_add(x, or0);
+               glm_vec4 const sub0 = glm_vec4_sub(add0, or0);
+               return sub0;
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_floor(glm_vec4 x)
+{
+#      if GLM_ARCH & GLM_ARCH_SSE41_BIT
+               return _mm_floor_ps(x);
+#      else
+               glm_vec4 const rnd0 = glm_vec4_round(x);
+               glm_vec4 const cmp0 = _mm_cmplt_ps(x, rnd0);
+               glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f));
+               glm_vec4 const sub0 = glm_vec4_sub(rnd0, and0);
+               return sub0;
+#      endif
+}
+
+/* trunc TODO
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_trunc(glm_vec4 x)
+{
+       return glm_vec4();
+}
+*/
+
+//roundEven
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_roundEven(glm_vec4 x)
+{
+       glm_vec4 const sgn0 = _mm_castsi128_ps(_mm_set1_epi32(0x80000000));
+       glm_vec4 const and0 = _mm_and_ps(sgn0, x);
+       glm_vec4 const or0 = _mm_or_ps(and0, _mm_set_ps1(8388608.0f));
+       glm_vec4 const add0 = glm_vec4_add(x, or0);
+       glm_vec4 const sub0 = glm_vec4_sub(add0, or0);
+       return sub0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_ceil(glm_vec4 x)
+{
+#      if GLM_ARCH & GLM_ARCH_SSE41_BIT
+               return _mm_ceil_ps(x);
+#      else
+               glm_vec4 const rnd0 = glm_vec4_round(x);
+               glm_vec4 const cmp0 = _mm_cmpgt_ps(x, rnd0);
+               glm_vec4 const and0 = _mm_and_ps(cmp0, _mm_set1_ps(1.0f));
+               glm_vec4 const add0 = glm_vec4_add(rnd0, and0);
+               return add0;
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_fract(glm_vec4 x)
+{
+       glm_vec4 const flr0 = glm_vec4_floor(x);
+       glm_vec4 const sub0 = glm_vec4_sub(x, flr0);
+       return sub0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mod(glm_vec4 x, glm_vec4 y)
+{
+       glm_vec4 const div0 = glm_vec4_div(x, y);
+       glm_vec4 const flr0 = glm_vec4_floor(div0);
+       glm_vec4 const mul0 = glm_vec4_mul(y, flr0);
+       glm_vec4 const sub0 = glm_vec4_sub(x, mul0);
+       return sub0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_clamp(glm_vec4 v, glm_vec4 minVal, glm_vec4 maxVal)
+{
+       glm_vec4 const min0 = _mm_min_ps(v, maxVal);
+       glm_vec4 const max0 = _mm_max_ps(min0, minVal);
+       return max0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_mix(glm_vec4 v1, glm_vec4 v2, glm_vec4 a)
+{
+       glm_vec4 const sub0 = glm_vec4_sub(_mm_set1_ps(1.0f), a);
+       glm_vec4 const mul0 = glm_vec4_mul(v1, sub0);
+       glm_vec4 const mad0 = glm_vec4_fma(v2, a, mul0);
+       return mad0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_step(glm_vec4 edge, glm_vec4 x)
+{
+       glm_vec4 const cmp = _mm_cmple_ps(x, edge);
+       return _mm_movemask_ps(cmp) == 0 ? _mm_set1_ps(1.0f) : _mm_setzero_ps();
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_smoothstep(glm_vec4 edge0, glm_vec4 edge1, glm_vec4 x)
+{
+       glm_vec4 const sub0 = glm_vec4_sub(x, edge0);
+       glm_vec4 const sub1 = glm_vec4_sub(edge1, edge0);
+       glm_vec4 const div0 = glm_vec4_sub(sub0, sub1);
+       glm_vec4 const clp0 = glm_vec4_clamp(div0, _mm_setzero_ps(), _mm_set1_ps(1.0f));
+       glm_vec4 const mul0 = glm_vec4_mul(_mm_set1_ps(2.0f), clp0);
+       glm_vec4 const sub2 = glm_vec4_sub(_mm_set1_ps(3.0f), mul0);
+       glm_vec4 const mul1 = glm_vec4_mul(clp0, clp0);
+       glm_vec4 const mul2 = glm_vec4_mul(mul1, sub2);
+       return mul2;
+}
+
+// Agner Fog method
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_nan(glm_vec4 x)
+{
+       glm_ivec4 const t1 = _mm_castps_si128(x);                                               // reinterpret as 32-bit integer
+       glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1));   // shift out sign bit
+       glm_ivec4 const t3 = _mm_set1_epi32(0xFF000000);                                // exponent mask
+       glm_ivec4 const t4 = _mm_and_si128(t2, t3);                                             // exponent
+       glm_ivec4 const t5 = _mm_andnot_si128(t3, t2);                                  // fraction
+       glm_ivec4 const Equal = _mm_cmpeq_epi32(t3, t4);
+       glm_ivec4 const Nequal = _mm_cmpeq_epi32(t5, _mm_setzero_si128());
+       glm_ivec4 const And = _mm_and_si128(Equal, Nequal);
+       return _mm_castsi128_ps(And);                                                                   // exponent = all 1s and fraction != 0
+}
+
+// Agner Fog method
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_inf(glm_vec4 x)
+{
+       glm_ivec4 const t1 = _mm_castps_si128(x);                                                                               // reinterpret as 32-bit integer
+       glm_ivec4 const t2 = _mm_sll_epi32(t1, _mm_cvtsi32_si128(1));                                   // shift out sign bit
+       return _mm_castsi128_ps(_mm_cmpeq_epi32(t2, _mm_set1_epi32(0xFF000000)));               // exponent is all 1s, fraction is 0
+}
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/exponential.h b/core/deps/glm/glm/simd/exponential.h
new file mode 100755 (executable)
index 0000000..4eb0fb7
--- /dev/null
@@ -0,0 +1,20 @@
+/// @ref simd
+/// @file glm/simd/experimental.h
+
+#pragma once
+
+#include "platform.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_sqrt_lowp(glm_vec4 x)
+{
+       return _mm_mul_ss(_mm_rsqrt_ss(x), x);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_sqrt_lowp(glm_vec4 x)
+{
+       return _mm_mul_ps(_mm_rsqrt_ps(x), x);
+}
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/geometric.h b/core/deps/glm/glm/simd/geometric.h
new file mode 100755 (executable)
index 0000000..ca53387
--- /dev/null
@@ -0,0 +1,124 @@
+/// @ref simd
+/// @file glm/simd/geometric.h
+
+#pragma once
+
+#include "common.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+GLM_FUNC_DECL glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2);
+GLM_FUNC_DECL glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2);
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_length(glm_vec4 x)
+{
+       glm_vec4 const dot0 = glm_vec4_dot(x, x);
+       glm_vec4 const sqt0 = _mm_sqrt_ps(dot0);
+       return sqt0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_distance(glm_vec4 p0, glm_vec4 p1)
+{
+       glm_vec4 const sub0 = _mm_sub_ps(p0, p1);
+       glm_vec4 const len0 = glm_vec4_length(sub0);
+       return len0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_dot(glm_vec4 v1, glm_vec4 v2)
+{
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+               return _mm_dp_ps(v1, v2, 0xff);
+#      elif GLM_ARCH & GLM_ARCH_SSE3_BIT
+               glm_vec4 const mul0 = _mm_mul_ps(v1, v2);
+               glm_vec4 const hadd0 = _mm_hadd_ps(mul0, mul0);
+               glm_vec4 const hadd1 = _mm_hadd_ps(hadd0, hadd0);
+               return hadd1;
+#      else
+               glm_vec4 const mul0 = _mm_mul_ps(v1, v2);
+               glm_vec4 const swp0 = _mm_shuffle_ps(mul0, mul0, _MM_SHUFFLE(2, 3, 0, 1));
+               glm_vec4 const add0 = _mm_add_ps(mul0, swp0);
+               glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, _MM_SHUFFLE(0, 1, 2, 3));
+               glm_vec4 const add1 = _mm_add_ps(add0, swp1);
+               return add1;
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec1_dot(glm_vec4 v1, glm_vec4 v2)
+{
+#      if GLM_ARCH & GLM_ARCH_AVX_BIT
+               return _mm_dp_ps(v1, v2, 0xff);
+#      elif GLM_ARCH & GLM_ARCH_SSE3_BIT
+               glm_vec4 const mul0 = _mm_mul_ps(v1, v2);
+               glm_vec4 const had0 = _mm_hadd_ps(mul0, mul0);
+               glm_vec4 const had1 = _mm_hadd_ps(had0, had0);
+               return had1;
+#      else
+               glm_vec4 const mul0 = _mm_mul_ps(v1, v2);
+               glm_vec4 const mov0 = _mm_movehl_ps(mul0, mul0);
+               glm_vec4 const add0 = _mm_add_ps(mov0, mul0);
+               glm_vec4 const swp1 = _mm_shuffle_ps(add0, add0, 1);
+               glm_vec4 const add1 = _mm_add_ss(add0, swp1);
+               return add1;
+#      endif
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_cross(glm_vec4 v1, glm_vec4 v2)
+{
+       glm_vec4 const swp0 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 0, 2, 1));
+       glm_vec4 const swp1 = _mm_shuffle_ps(v1, v1, _MM_SHUFFLE(3, 1, 0, 2));
+       glm_vec4 const swp2 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 0, 2, 1));
+       glm_vec4 const swp3 = _mm_shuffle_ps(v2, v2, _MM_SHUFFLE(3, 1, 0, 2));
+       glm_vec4 const mul0 = _mm_mul_ps(swp0, swp3);
+       glm_vec4 const mul1 = _mm_mul_ps(swp1, swp2);
+       glm_vec4 const sub0 = _mm_sub_ps(mul0, mul1);
+       return sub0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_normalize(glm_vec4 v)
+{
+       glm_vec4 const dot0 = glm_vec4_dot(v, v);
+       glm_vec4 const isr0 = _mm_rsqrt_ps(dot0);
+       glm_vec4 const mul0 = _mm_mul_ps(v, isr0);
+       return mul0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_faceforward(glm_vec4 N, glm_vec4 I, glm_vec4 Nref)
+{
+       glm_vec4 const dot0 = glm_vec4_dot(Nref, I);
+       glm_vec4 const sgn0 = glm_vec4_sign(dot0);
+       glm_vec4 const mul0 = _mm_mul_ps(sgn0, _mm_set1_ps(-1.0f));
+       glm_vec4 const mul1 = _mm_mul_ps(N, mul0);
+       return mul1;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_vec4_reflect(glm_vec4 I, glm_vec4 N)
+{
+       glm_vec4 const dot0 = glm_vec4_dot(N, I);
+       glm_vec4 const mul0 = _mm_mul_ps(N, dot0);
+       glm_vec4 const mul1 = _mm_mul_ps(mul0, _mm_set1_ps(2.0f));
+       glm_vec4 const sub0 = _mm_sub_ps(I, mul1);
+       return sub0;
+}
+
+GLM_FUNC_QUALIFIER __m128 glm_vec4_refract(glm_vec4 I, glm_vec4 N, glm_vec4 eta)
+{
+       glm_vec4 const dot0 = glm_vec4_dot(N, I);
+       glm_vec4 const mul0 = _mm_mul_ps(eta, eta);
+       glm_vec4 const mul1 = _mm_mul_ps(dot0, dot0);
+       glm_vec4 const sub0 = _mm_sub_ps(_mm_set1_ps(1.0f), mul0);
+       glm_vec4 const sub1 = _mm_sub_ps(_mm_set1_ps(1.0f), mul1);
+       glm_vec4 const mul2 = _mm_mul_ps(sub0, sub1);
+       
+       if(_mm_movemask_ps(_mm_cmplt_ss(mul2, _mm_set1_ps(0.0f))) == 0)
+               return _mm_set1_ps(0.0f);
+
+       glm_vec4 const sqt0 = _mm_sqrt_ps(mul2);
+       glm_vec4 const mad0 = glm_vec4_fma(eta, dot0, sqt0);
+       glm_vec4 const mul4 = _mm_mul_ps(mad0, N);
+       glm_vec4 const mul5 = _mm_mul_ps(eta, I);
+       glm_vec4 const sub2 = _mm_sub_ps(mul5, mul4);
+
+       return sub2;
+}
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/integer.h b/core/deps/glm/glm/simd/integer.h
new file mode 100755 (executable)
index 0000000..50fd824
--- /dev/null
@@ -0,0 +1,115 @@
+/// @ref simd
+/// @file glm/simd/integer.h
+
+#pragma once
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave(glm_uvec4 x)
+{
+       glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF);
+       glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF);
+       glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F);
+       glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333);
+       glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555);
+
+       glm_uvec4 Reg1;
+       glm_uvec4 Reg2;
+
+       // REG1 = x;
+       // REG2 = y;
+       //Reg1 = _mm_unpacklo_epi64(x, y);
+       Reg1 = x;
+
+       //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF);
+       //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF);
+       Reg2 = _mm_slli_si128(Reg1, 2);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask4);
+
+       //REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0x00FF00FF00FF00FF);
+       //REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0x00FF00FF00FF00FF);
+       Reg2 = _mm_slli_si128(Reg1, 1);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask3);
+
+       //REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F);
+       //REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F);
+       Reg2 = _mm_slli_epi32(Reg1, 4);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask2);
+
+       //REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x3333333333333333);
+       //REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x3333333333333333);
+       Reg2 = _mm_slli_epi32(Reg1, 2);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask1);
+
+       //REG1 = ((REG1 <<  1) | REG1) & glm::uint64(0x5555555555555555);
+       //REG2 = ((REG2 <<  1) | REG2) & glm::uint64(0x5555555555555555);
+       Reg2 = _mm_slli_epi32(Reg1, 1);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask0);
+
+       //return REG1 | (REG2 << 1);
+       Reg2 = _mm_slli_epi32(Reg1, 1);
+       Reg2 = _mm_srli_si128(Reg2, 8);
+       Reg1 = _mm_or_si128(Reg1, Reg2);
+       
+       return Reg1;
+}
+
+GLM_FUNC_QUALIFIER glm_uvec4 glm_i128_interleave2(glm_uvec4 x, glm_uvec4 y)
+{
+       glm_uvec4 const Mask4 = _mm_set1_epi32(0x0000FFFF);
+       glm_uvec4 const Mask3 = _mm_set1_epi32(0x00FF00FF);
+       glm_uvec4 const Mask2 = _mm_set1_epi32(0x0F0F0F0F);
+       glm_uvec4 const Mask1 = _mm_set1_epi32(0x33333333);
+       glm_uvec4 const Mask0 = _mm_set1_epi32(0x55555555);
+
+       glm_uvec4 Reg1;
+       glm_uvec4 Reg2;
+
+       // REG1 = x;
+       // REG2 = y;
+       Reg1 = _mm_unpacklo_epi64(x, y);
+
+       //REG1 = ((REG1 << 16) | REG1) & glm::uint64(0x0000FFFF0000FFFF);
+       //REG2 = ((REG2 << 16) | REG2) & glm::uint64(0x0000FFFF0000FFFF);
+       Reg2 = _mm_slli_si128(Reg1, 2);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask4);
+
+       //REG1 = ((REG1 <<  8) | REG1) & glm::uint64(0x00FF00FF00FF00FF);
+       //REG2 = ((REG2 <<  8) | REG2) & glm::uint64(0x00FF00FF00FF00FF);
+       Reg2 = _mm_slli_si128(Reg1, 1);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask3);
+
+       //REG1 = ((REG1 <<  4) | REG1) & glm::uint64(0x0F0F0F0F0F0F0F0F);
+       //REG2 = ((REG2 <<  4) | REG2) & glm::uint64(0x0F0F0F0F0F0F0F0F);
+       Reg2 = _mm_slli_epi32(Reg1, 4);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask2);
+
+       //REG1 = ((REG1 <<  2) | REG1) & glm::uint64(0x3333333333333333);
+       //REG2 = ((REG2 <<  2) | REG2) & glm::uint64(0x3333333333333333);
+       Reg2 = _mm_slli_epi32(Reg1, 2);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask1);
+
+       //REG1 = ((REG1 <<  1) | REG1) & glm::uint64(0x5555555555555555);
+       //REG2 = ((REG2 <<  1) | REG2) & glm::uint64(0x5555555555555555);
+       Reg2 = _mm_slli_epi32(Reg1, 1);
+       Reg1 = _mm_or_si128(Reg2, Reg1);
+       Reg1 = _mm_and_si128(Reg1, Mask0);
+
+       //return REG1 | (REG2 << 1);
+       Reg2 = _mm_slli_epi32(Reg1, 1);
+       Reg2 = _mm_srli_si128(Reg2, 8);
+       Reg1 = _mm_or_si128(Reg1, Reg2);
+       
+       return Reg1;
+}
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/matrix.h b/core/deps/glm/glm/simd/matrix.h
new file mode 100755 (executable)
index 0000000..549d40c
--- /dev/null
@@ -0,0 +1,1028 @@
+/// @ref simd
+/// @file glm/simd/matrix.h
+
+#pragma once
+
+#include "geometric.h"
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+GLM_FUNC_QUALIFIER void glm_mat4_matrixCompMult(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])
+{
+       out[0] = _mm_mul_ps(in1[0], in2[0]);
+       out[1] = _mm_mul_ps(in1[1], in2[1]);
+       out[2] = _mm_mul_ps(in1[2], in2[2]);
+       out[3] = _mm_mul_ps(in1[3], in2[3]);
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_add(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])
+{
+       out[0] = _mm_add_ps(in1[0], in2[0]);
+       out[1] = _mm_add_ps(in1[1], in2[1]);
+       out[2] = _mm_add_ps(in1[2], in2[2]);
+       out[3] = _mm_add_ps(in1[3], in2[3]);
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_sub(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])
+{
+       out[0] = _mm_sub_ps(in1[0], in2[0]);
+       out[1] = _mm_sub_ps(in1[1], in2[1]);
+       out[2] = _mm_sub_ps(in1[2], in2[2]);
+       out[3] = _mm_sub_ps(in1[3], in2[3]);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_mul_vec4(glm_vec4 const m[4], glm_vec4 v)
+{
+       __m128 v0 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 v1 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 v2 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 v3 = _mm_shuffle_ps(v, v, _MM_SHUFFLE(3, 3, 3, 3));
+
+       __m128 m0 = _mm_mul_ps(m[0], v0);
+       __m128 m1 = _mm_mul_ps(m[1], v1);
+       __m128 m2 = _mm_mul_ps(m[2], v2);
+       __m128 m3 = _mm_mul_ps(m[3], v3);
+
+       __m128 a0 = _mm_add_ps(m0, m1);
+       __m128 a1 = _mm_add_ps(m2, m3);
+       __m128 a2 = _mm_add_ps(a0, a1);
+
+       return a2;
+}
+
+GLM_FUNC_QUALIFIER __m128 glm_vec4_mul_mat4(glm_vec4 v, glm_vec4 const m[4])
+{
+       __m128 i0 = m[0];
+       __m128 i1 = m[1];
+       __m128 i2 = m[2];
+       __m128 i3 = m[3];
+
+       __m128 m0 = _mm_mul_ps(v, i0);
+       __m128 m1 = _mm_mul_ps(v, i1);
+       __m128 m2 = _mm_mul_ps(v, i2);
+       __m128 m3 = _mm_mul_ps(v, i3);
+
+       __m128 u0 = _mm_unpacklo_ps(m0, m1);
+       __m128 u1 = _mm_unpackhi_ps(m0, m1);
+       __m128 a0 = _mm_add_ps(u0, u1);
+
+       __m128 u2 = _mm_unpacklo_ps(m2, m3);
+       __m128 u3 = _mm_unpackhi_ps(m2, m3);
+       __m128 a1 = _mm_add_ps(u2, u3);
+
+       __m128 f0 = _mm_movelh_ps(a0, a1);
+       __m128 f1 = _mm_movehl_ps(a1, a0);
+       __m128 f2 = _mm_add_ps(f0, f1);
+
+       return f2;
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_mul(glm_vec4 const in1[4], glm_vec4 const in2[4], glm_vec4 out[4])
+{
+       {
+               __m128 e0 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 e1 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 e2 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 e3 = _mm_shuffle_ps(in2[0], in2[0], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 m0 = _mm_mul_ps(in1[0], e0);
+               __m128 m1 = _mm_mul_ps(in1[1], e1);
+               __m128 m2 = _mm_mul_ps(in1[2], e2);
+               __m128 m3 = _mm_mul_ps(in1[3], e3);
+
+               __m128 a0 = _mm_add_ps(m0, m1);
+               __m128 a1 = _mm_add_ps(m2, m3);
+               __m128 a2 = _mm_add_ps(a0, a1);
+
+               out[0] = a2;
+       }
+
+       {
+               __m128 e0 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 e1 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 e2 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 e3 = _mm_shuffle_ps(in2[1], in2[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 m0 = _mm_mul_ps(in1[0], e0);
+               __m128 m1 = _mm_mul_ps(in1[1], e1);
+               __m128 m2 = _mm_mul_ps(in1[2], e2);
+               __m128 m3 = _mm_mul_ps(in1[3], e3);
+
+               __m128 a0 = _mm_add_ps(m0, m1);
+               __m128 a1 = _mm_add_ps(m2, m3);
+               __m128 a2 = _mm_add_ps(a0, a1);
+
+               out[1] = a2;
+       }
+
+       {
+               __m128 e0 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 e1 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 e2 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 e3 = _mm_shuffle_ps(in2[2], in2[2], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 m0 = _mm_mul_ps(in1[0], e0);
+               __m128 m1 = _mm_mul_ps(in1[1], e1);
+               __m128 m2 = _mm_mul_ps(in1[2], e2);
+               __m128 m3 = _mm_mul_ps(in1[3], e3);
+
+               __m128 a0 = _mm_add_ps(m0, m1);
+               __m128 a1 = _mm_add_ps(m2, m3);
+               __m128 a2 = _mm_add_ps(a0, a1);
+
+               out[2] = a2;
+       }
+
+       {
+               //(__m128&)_mm_shuffle_epi32(__m128i&)in2[0], _MM_SHUFFLE(3, 3, 3, 3))
+               __m128 e0 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 e1 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 e2 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 e3 = _mm_shuffle_ps(in2[3], in2[3], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 m0 = _mm_mul_ps(in1[0], e0);
+               __m128 m1 = _mm_mul_ps(in1[1], e1);
+               __m128 m2 = _mm_mul_ps(in1[2], e2);
+               __m128 m3 = _mm_mul_ps(in1[3], e3);
+
+               __m128 a0 = _mm_add_ps(m0, m1);
+               __m128 a1 = _mm_add_ps(m2, m3);
+               __m128 a2 = _mm_add_ps(a0, a1);
+
+               out[3] = a2;
+       }
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_transpose(glm_vec4 const in[4], glm_vec4 out[4])
+{
+       __m128 tmp0 = _mm_shuffle_ps(in[0], in[1], 0x44);
+       __m128 tmp2 = _mm_shuffle_ps(in[0], in[1], 0xEE);
+       __m128 tmp1 = _mm_shuffle_ps(in[2], in[3], 0x44);
+       __m128 tmp3 = _mm_shuffle_ps(in[2], in[3], 0xEE);
+
+       out[0] = _mm_shuffle_ps(tmp0, tmp1, 0x88);
+       out[1] = _mm_shuffle_ps(tmp0, tmp1, 0xDD);
+       out[2] = _mm_shuffle_ps(tmp2, tmp3, 0x88);
+       out[3] = _mm_shuffle_ps(tmp2, tmp3, 0xDD);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_highp(glm_vec4 const in[4])
+{
+       __m128 Fac0;
+       {
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+               //      valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac0 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac1;
+       {
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+               //      valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac1 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+
+       __m128 Fac2;
+       {
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+               //      valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac2 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac3;
+       {
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+               //      valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac3 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac4;
+       {
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+               //      valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac4 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac5;
+       {
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+               //      valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac5 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);
+       __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);
+
+       // m[1][0]
+       // m[0][0]
+       // m[0][0]
+       // m[0][0]
+       __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][1]
+       // m[0][1]
+       // m[0][1]
+       // m[0][1]
+       __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][2]
+       // m[0][2]
+       // m[0][2]
+       // m[0][2]
+       __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][3]
+       // m[0][3]
+       // m[0][3]
+       // m[0][3]
+       __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));
+       __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // col0
+       // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),
+       // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),
+       // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),
+       // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),
+       __m128 Mul00 = _mm_mul_ps(Vec1, Fac0);
+       __m128 Mul01 = _mm_mul_ps(Vec2, Fac1);
+       __m128 Mul02 = _mm_mul_ps(Vec3, Fac2);
+       __m128 Sub00 = _mm_sub_ps(Mul00, Mul01);
+       __m128 Add00 = _mm_add_ps(Sub00, Mul02);
+       __m128 Inv0 = _mm_mul_ps(SignB, Add00);
+
+       // col1
+       // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),
+       // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),
+       // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),
+       // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),
+       __m128 Mul03 = _mm_mul_ps(Vec0, Fac0);
+       __m128 Mul04 = _mm_mul_ps(Vec2, Fac3);
+       __m128 Mul05 = _mm_mul_ps(Vec3, Fac4);
+       __m128 Sub01 = _mm_sub_ps(Mul03, Mul04);
+       __m128 Add01 = _mm_add_ps(Sub01, Mul05);
+       __m128 Inv1 = _mm_mul_ps(SignA, Add01);
+
+       // col2
+       // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),
+       // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),
+       // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),
+       // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),
+       __m128 Mul06 = _mm_mul_ps(Vec0, Fac1);
+       __m128 Mul07 = _mm_mul_ps(Vec1, Fac3);
+       __m128 Mul08 = _mm_mul_ps(Vec3, Fac5);
+       __m128 Sub02 = _mm_sub_ps(Mul06, Mul07);
+       __m128 Add02 = _mm_add_ps(Sub02, Mul08);
+       __m128 Inv2 = _mm_mul_ps(SignB, Add02);
+
+       // col3
+       // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),
+       // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),
+       // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),
+       // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));
+       __m128 Mul09 = _mm_mul_ps(Vec0, Fac2);
+       __m128 Mul10 = _mm_mul_ps(Vec1, Fac4);
+       __m128 Mul11 = _mm_mul_ps(Vec2, Fac5);
+       __m128 Sub03 = _mm_sub_ps(Mul09, Mul10);
+       __m128 Add03 = _mm_add_ps(Sub03, Mul11);
+       __m128 Inv3 = _mm_mul_ps(SignA, Add03);
+
+       __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));
+
+       //      valType Determinant = m[0][0] * Inverse[0][0]
+       //                                              + m[0][1] * Inverse[1][0]
+       //                                              + m[0][2] * Inverse[2][0]
+       //                                              + m[0][3] * Inverse[3][0];
+       __m128 Det0 = glm_vec4_dot(in[0], Row2);
+       return Det0;
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant_lowp(glm_vec4 const m[4])
+{
+       // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(
+
+       //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+       //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+       //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+       //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+       //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+       //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+
+       // First 2 columns
+       __m128 Swp2A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 1, 1, 2)));
+       __m128 Swp3A = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(3, 2, 3, 3)));
+       __m128 MulA = _mm_mul_ps(Swp2A, Swp3A);
+
+       // Second 2 columns
+       __m128 Swp2B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(3, 2, 3, 3)));
+       __m128 Swp3B = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(0, 1, 1, 2)));
+       __m128 MulB = _mm_mul_ps(Swp2B, Swp3B);
+
+       // Columns subtraction
+       __m128 SubE = _mm_sub_ps(MulA, MulB);
+
+       // Last 2 rows
+       __m128 Swp2C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[2]), _MM_SHUFFLE(0, 0, 1, 2)));
+       __m128 Swp3C = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[3]), _MM_SHUFFLE(1, 2, 0, 0)));
+       __m128 MulC = _mm_mul_ps(Swp2C, Swp3C);
+       __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC);
+
+       //tvec4<T, P> DetCof(
+       //      + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),
+       //      - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),
+       //      + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),
+       //      - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));
+
+       __m128 SubFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubE), _MM_SHUFFLE(2, 1, 0, 0)));
+       __m128 SwpFacA = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(0, 0, 0, 1)));
+       __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA);
+
+       __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1));
+       __m128 SubFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpB), _MM_SHUFFLE(3, 1, 1, 0)));//SubF[0], SubE[3], SubE[3], SubE[1];
+       __m128 SwpFacB = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(1, 1, 2, 2)));
+       __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB);
+
+       __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB);
+
+       __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2));
+       __m128 SubFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(SubTmpC), _MM_SHUFFLE(3, 3, 2, 0)));
+       __m128 SwpFacC = _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(m[1]), _MM_SHUFFLE(2, 3, 3, 3)));
+       __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC);
+
+       __m128 AddRes = _mm_add_ps(SubRes, MulFacC);
+       __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f));
+
+       //return m[0][0] * DetCof[0]
+       //       + m[0][1] * DetCof[1]
+       //       + m[0][2] * DetCof[2]
+       //       + m[0][3] * DetCof[3];
+
+       return glm_vec4_dot(m[0], DetCof);
+}
+
+GLM_FUNC_QUALIFIER glm_vec4 glm_mat4_determinant(glm_vec4 const m[4])
+{
+       // _mm_castsi128_ps(_mm_shuffle_epi32(_mm_castps_si128(add)
+
+       //T SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+       //T SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+       //T SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+       //T SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+       //T SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+       //T SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+
+       // First 2 columns
+       __m128 Swp2A = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 1, 1, 2));
+       __m128 Swp3A = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(3, 2, 3, 3));
+       __m128 MulA = _mm_mul_ps(Swp2A, Swp3A);
+
+       // Second 2 columns
+       __m128 Swp2B = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(3, 2, 3, 3));
+       __m128 Swp3B = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(0, 1, 1, 2));
+       __m128 MulB = _mm_mul_ps(Swp2B, Swp3B);
+
+       // Columns subtraction
+       __m128 SubE = _mm_sub_ps(MulA, MulB);
+
+       // Last 2 rows
+       __m128 Swp2C = _mm_shuffle_ps(m[2], m[2], _MM_SHUFFLE(0, 0, 1, 2));
+       __m128 Swp3C = _mm_shuffle_ps(m[3], m[3], _MM_SHUFFLE(1, 2, 0, 0));
+       __m128 MulC = _mm_mul_ps(Swp2C, Swp3C);
+       __m128 SubF = _mm_sub_ps(_mm_movehl_ps(MulC, MulC), MulC);
+
+       //tvec4<T, P> DetCof(
+       //      + (m[1][1] * SubFactor00 - m[1][2] * SubFactor01 + m[1][3] * SubFactor02),
+       //      - (m[1][0] * SubFactor00 - m[1][2] * SubFactor03 + m[1][3] * SubFactor04),
+       //      + (m[1][0] * SubFactor01 - m[1][1] * SubFactor03 + m[1][3] * SubFactor05),
+       //      - (m[1][0] * SubFactor02 - m[1][1] * SubFactor04 + m[1][2] * SubFactor05));
+
+       __m128 SubFacA = _mm_shuffle_ps(SubE, SubE, _MM_SHUFFLE(2, 1, 0, 0));
+       __m128 SwpFacA = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(0, 0, 0, 1));
+       __m128 MulFacA = _mm_mul_ps(SwpFacA, SubFacA);
+
+       __m128 SubTmpB = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(0, 0, 3, 1));
+       __m128 SubFacB = _mm_shuffle_ps(SubTmpB, SubTmpB, _MM_SHUFFLE(3, 1, 1, 0));//SubF[0], SubE[3], SubE[3], SubE[1];
+       __m128 SwpFacB = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(1, 1, 2, 2));
+       __m128 MulFacB = _mm_mul_ps(SwpFacB, SubFacB);
+
+       __m128 SubRes = _mm_sub_ps(MulFacA, MulFacB);
+
+       __m128 SubTmpC = _mm_shuffle_ps(SubE, SubF, _MM_SHUFFLE(1, 0, 2, 2));
+       __m128 SubFacC = _mm_shuffle_ps(SubTmpC, SubTmpC, _MM_SHUFFLE(3, 3, 2, 0));
+       __m128 SwpFacC = _mm_shuffle_ps(m[1], m[1], _MM_SHUFFLE(2, 3, 3, 3));
+       __m128 MulFacC = _mm_mul_ps(SwpFacC, SubFacC);
+
+       __m128 AddRes = _mm_add_ps(SubRes, MulFacC);
+       __m128 DetCof = _mm_mul_ps(AddRes, _mm_setr_ps( 1.0f,-1.0f, 1.0f,-1.0f));
+
+       //return m[0][0] * DetCof[0]
+       //       + m[0][1] * DetCof[1]
+       //       + m[0][2] * DetCof[2]
+       //       + m[0][3] * DetCof[3];
+
+       return glm_vec4_dot(m[0], DetCof);
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_inverse(glm_vec4 const in[4], glm_vec4 out[4])
+{
+       __m128 Fac0;
+       {
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+               //      valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac0 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac1;
+       {
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+               //      valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac1 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+
+       __m128 Fac2;
+       {
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+               //      valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac2 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac3;
+       {
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+               //      valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac3 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac4;
+       {
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+               //      valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac4 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac5;
+       {
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+               //      valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac5 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);
+       __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);
+
+       // m[1][0]
+       // m[0][0]
+       // m[0][0]
+       // m[0][0]
+       __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][1]
+       // m[0][1]
+       // m[0][1]
+       // m[0][1]
+       __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][2]
+       // m[0][2]
+       // m[0][2]
+       // m[0][2]
+       __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][3]
+       // m[0][3]
+       // m[0][3]
+       // m[0][3]
+       __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));
+       __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // col0
+       // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),
+       // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),
+       // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),
+       // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),
+       __m128 Mul00 = _mm_mul_ps(Vec1, Fac0);
+       __m128 Mul01 = _mm_mul_ps(Vec2, Fac1);
+       __m128 Mul02 = _mm_mul_ps(Vec3, Fac2);
+       __m128 Sub00 = _mm_sub_ps(Mul00, Mul01);
+       __m128 Add00 = _mm_add_ps(Sub00, Mul02);
+       __m128 Inv0 = _mm_mul_ps(SignB, Add00);
+
+       // col1
+       // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),
+       // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),
+       // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),
+       // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),
+       __m128 Mul03 = _mm_mul_ps(Vec0, Fac0);
+       __m128 Mul04 = _mm_mul_ps(Vec2, Fac3);
+       __m128 Mul05 = _mm_mul_ps(Vec3, Fac4);
+       __m128 Sub01 = _mm_sub_ps(Mul03, Mul04);
+       __m128 Add01 = _mm_add_ps(Sub01, Mul05);
+       __m128 Inv1 = _mm_mul_ps(SignA, Add01);
+
+       // col2
+       // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),
+       // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),
+       // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),
+       // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),
+       __m128 Mul06 = _mm_mul_ps(Vec0, Fac1);
+       __m128 Mul07 = _mm_mul_ps(Vec1, Fac3);
+       __m128 Mul08 = _mm_mul_ps(Vec3, Fac5);
+       __m128 Sub02 = _mm_sub_ps(Mul06, Mul07);
+       __m128 Add02 = _mm_add_ps(Sub02, Mul08);
+       __m128 Inv2 = _mm_mul_ps(SignB, Add02);
+
+       // col3
+       // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),
+       // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),
+       // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),
+       // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));
+       __m128 Mul09 = _mm_mul_ps(Vec0, Fac2);
+       __m128 Mul10 = _mm_mul_ps(Vec1, Fac4);
+       __m128 Mul11 = _mm_mul_ps(Vec2, Fac5);
+       __m128 Sub03 = _mm_sub_ps(Mul09, Mul10);
+       __m128 Add03 = _mm_add_ps(Sub03, Mul11);
+       __m128 Inv3 = _mm_mul_ps(SignA, Add03);
+
+       __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));
+
+       //      valType Determinant = m[0][0] * Inverse[0][0] 
+       //                                              + m[0][1] * Inverse[1][0] 
+       //                                              + m[0][2] * Inverse[2][0] 
+       //                                              + m[0][3] * Inverse[3][0];
+       __m128 Det0 = glm_vec4_dot(in[0], Row2);
+       __m128 Rcp0 = _mm_div_ps(_mm_set1_ps(1.0f), Det0);
+       //__m128 Rcp0 = _mm_rcp_ps(Det0);
+
+       //      Inverse /= Determinant;
+       out[0] = _mm_mul_ps(Inv0, Rcp0);
+       out[1] = _mm_mul_ps(Inv1, Rcp0);
+       out[2] = _mm_mul_ps(Inv2, Rcp0);
+       out[3] = _mm_mul_ps(Inv3, Rcp0);
+}
+
+GLM_FUNC_QUALIFIER void glm_mat4_inverse_lowp(glm_vec4 const in[4], glm_vec4 out[4])
+{
+       __m128 Fac0;
+       {
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor00 = m[2][2] * m[3][3] - m[3][2] * m[2][3];
+               //      valType SubFactor06 = m[1][2] * m[3][3] - m[3][2] * m[1][3];
+               //      valType SubFactor13 = m[1][2] * m[2][3] - m[2][2] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac0 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac1;
+       {
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor01 = m[2][1] * m[3][3] - m[3][1] * m[2][3];
+               //      valType SubFactor07 = m[1][1] * m[3][3] - m[3][1] * m[1][3];
+               //      valType SubFactor14 = m[1][1] * m[2][3] - m[2][1] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac1 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+
+       __m128 Fac2;
+       {
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor02 = m[2][1] * m[3][2] - m[3][1] * m[2][2];
+               //      valType SubFactor08 = m[1][1] * m[3][2] - m[3][1] * m[1][2];
+               //      valType SubFactor15 = m[1][1] * m[2][2] - m[2][1] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac2 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac3;
+       {
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor03 = m[2][0] * m[3][3] - m[3][0] * m[2][3];
+               //      valType SubFactor09 = m[1][0] * m[3][3] - m[3][0] * m[1][3];
+               //      valType SubFactor16 = m[1][0] * m[2][3] - m[2][0] * m[1][3];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(3, 3, 3, 3));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(3, 3, 3, 3));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac3 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac4;
+       {
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor04 = m[2][0] * m[3][2] - m[3][0] * m[2][2];
+               //      valType SubFactor10 = m[1][0] * m[3][2] - m[3][0] * m[1][2];
+               //      valType SubFactor17 = m[1][0] * m[2][2] - m[2][0] * m[1][2];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(2, 2, 2, 2));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(2, 2, 2, 2));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac4 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 Fac5;
+       {
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor05 = m[2][0] * m[3][1] - m[3][0] * m[2][1];
+               //      valType SubFactor12 = m[1][0] * m[3][1] - m[3][0] * m[1][1];
+               //      valType SubFactor18 = m[1][0] * m[2][1] - m[2][0] * m[1][1];
+
+               __m128 Swp0a = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(1, 1, 1, 1));
+               __m128 Swp0b = _mm_shuffle_ps(in[3], in[2], _MM_SHUFFLE(0, 0, 0, 0));
+
+               __m128 Swp00 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(0, 0, 0, 0));
+               __m128 Swp01 = _mm_shuffle_ps(Swp0a, Swp0a, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp02 = _mm_shuffle_ps(Swp0b, Swp0b, _MM_SHUFFLE(2, 0, 0, 0));
+               __m128 Swp03 = _mm_shuffle_ps(in[2], in[1], _MM_SHUFFLE(1, 1, 1, 1));
+
+               __m128 Mul00 = _mm_mul_ps(Swp00, Swp01);
+               __m128 Mul01 = _mm_mul_ps(Swp02, Swp03);
+               Fac5 = _mm_sub_ps(Mul00, Mul01);
+       }
+
+       __m128 SignA = _mm_set_ps( 1.0f,-1.0f, 1.0f,-1.0f);
+       __m128 SignB = _mm_set_ps(-1.0f, 1.0f,-1.0f, 1.0f);
+
+       // m[1][0]
+       // m[0][0]
+       // m[0][0]
+       // m[0][0]
+       __m128 Temp0 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Vec0 = _mm_shuffle_ps(Temp0, Temp0, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][1]
+       // m[0][1]
+       // m[0][1]
+       // m[0][1]
+       __m128 Temp1 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 Vec1 = _mm_shuffle_ps(Temp1, Temp1, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][2]
+       // m[0][2]
+       // m[0][2]
+       // m[0][2]
+       __m128 Temp2 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 Vec2 = _mm_shuffle_ps(Temp2, Temp2, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // m[1][3]
+       // m[0][3]
+       // m[0][3]
+       // m[0][3]
+       __m128 Temp3 = _mm_shuffle_ps(in[1], in[0], _MM_SHUFFLE(3, 3, 3, 3));
+       __m128 Vec3 = _mm_shuffle_ps(Temp3, Temp3, _MM_SHUFFLE(2, 2, 2, 0));
+
+       // col0
+       // + (Vec1[0] * Fac0[0] - Vec2[0] * Fac1[0] + Vec3[0] * Fac2[0]),
+       // - (Vec1[1] * Fac0[1] - Vec2[1] * Fac1[1] + Vec3[1] * Fac2[1]),
+       // + (Vec1[2] * Fac0[2] - Vec2[2] * Fac1[2] + Vec3[2] * Fac2[2]),
+       // - (Vec1[3] * Fac0[3] - Vec2[3] * Fac1[3] + Vec3[3] * Fac2[3]),
+       __m128 Mul00 = _mm_mul_ps(Vec1, Fac0);
+       __m128 Mul01 = _mm_mul_ps(Vec2, Fac1);
+       __m128 Mul02 = _mm_mul_ps(Vec3, Fac2);
+       __m128 Sub00 = _mm_sub_ps(Mul00, Mul01);
+       __m128 Add00 = _mm_add_ps(Sub00, Mul02);
+       __m128 Inv0 = _mm_mul_ps(SignB, Add00);
+
+       // col1
+       // - (Vec0[0] * Fac0[0] - Vec2[0] * Fac3[0] + Vec3[0] * Fac4[0]),
+       // + (Vec0[0] * Fac0[1] - Vec2[1] * Fac3[1] + Vec3[1] * Fac4[1]),
+       // - (Vec0[0] * Fac0[2] - Vec2[2] * Fac3[2] + Vec3[2] * Fac4[2]),
+       // + (Vec0[0] * Fac0[3] - Vec2[3] * Fac3[3] + Vec3[3] * Fac4[3]),
+       __m128 Mul03 = _mm_mul_ps(Vec0, Fac0);
+       __m128 Mul04 = _mm_mul_ps(Vec2, Fac3);
+       __m128 Mul05 = _mm_mul_ps(Vec3, Fac4);
+       __m128 Sub01 = _mm_sub_ps(Mul03, Mul04);
+       __m128 Add01 = _mm_add_ps(Sub01, Mul05);
+       __m128 Inv1 = _mm_mul_ps(SignA, Add01);
+
+       // col2
+       // + (Vec0[0] * Fac1[0] - Vec1[0] * Fac3[0] + Vec3[0] * Fac5[0]),
+       // - (Vec0[0] * Fac1[1] - Vec1[1] * Fac3[1] + Vec3[1] * Fac5[1]),
+       // + (Vec0[0] * Fac1[2] - Vec1[2] * Fac3[2] + Vec3[2] * Fac5[2]),
+       // - (Vec0[0] * Fac1[3] - Vec1[3] * Fac3[3] + Vec3[3] * Fac5[3]),
+       __m128 Mul06 = _mm_mul_ps(Vec0, Fac1);
+       __m128 Mul07 = _mm_mul_ps(Vec1, Fac3);
+       __m128 Mul08 = _mm_mul_ps(Vec3, Fac5);
+       __m128 Sub02 = _mm_sub_ps(Mul06, Mul07);
+       __m128 Add02 = _mm_add_ps(Sub02, Mul08);
+       __m128 Inv2 = _mm_mul_ps(SignB, Add02);
+
+       // col3
+       // - (Vec1[0] * Fac2[0] - Vec1[0] * Fac4[0] + Vec2[0] * Fac5[0]),
+       // + (Vec1[0] * Fac2[1] - Vec1[1] * Fac4[1] + Vec2[1] * Fac5[1]),
+       // - (Vec1[0] * Fac2[2] - Vec1[2] * Fac4[2] + Vec2[2] * Fac5[2]),
+       // + (Vec1[0] * Fac2[3] - Vec1[3] * Fac4[3] + Vec2[3] * Fac5[3]));
+       __m128 Mul09 = _mm_mul_ps(Vec0, Fac2);
+       __m128 Mul10 = _mm_mul_ps(Vec1, Fac4);
+       __m128 Mul11 = _mm_mul_ps(Vec2, Fac5);
+       __m128 Sub03 = _mm_sub_ps(Mul09, Mul10);
+       __m128 Add03 = _mm_add_ps(Sub03, Mul11);
+       __m128 Inv3 = _mm_mul_ps(SignA, Add03);
+
+       __m128 Row0 = _mm_shuffle_ps(Inv0, Inv1, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row1 = _mm_shuffle_ps(Inv2, Inv3, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Row2 = _mm_shuffle_ps(Row0, Row1, _MM_SHUFFLE(2, 0, 2, 0));
+
+       //      valType Determinant = m[0][0] * Inverse[0][0] 
+       //                                              + m[0][1] * Inverse[1][0] 
+       //                                              + m[0][2] * Inverse[2][0] 
+       //                                              + m[0][3] * Inverse[3][0];
+       __m128 Det0 = glm_vec4_dot(in[0], Row2);
+       __m128 Rcp0 = _mm_rcp_ps(Det0);
+       //__m128 Rcp0 = _mm_div_ps(one, Det0);
+       //      Inverse /= Determinant;
+       out[0] = _mm_mul_ps(Inv0, Rcp0);
+       out[1] = _mm_mul_ps(Inv1, Rcp0);
+       out[2] = _mm_mul_ps(Inv2, Rcp0);
+       out[3] = _mm_mul_ps(Inv3, Rcp0);
+}
+/*
+GLM_FUNC_QUALIFIER void glm_mat4_rotate(__m128 const in[4], float Angle, float const v[3], __m128 out[4])
+{
+       float a = glm::radians(Angle);
+       float c = cos(a);
+       float s = sin(a);
+
+       glm::vec4 AxisA(v[0], v[1], v[2], float(0));
+       __m128 AxisB = _mm_set_ps(AxisA.w, AxisA.z, AxisA.y, AxisA.x);
+       __m128 AxisC = detail::sse_nrm_ps(AxisB);
+
+       __m128 Cos0 = _mm_set_ss(c);
+       __m128 CosA = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 Sin0 = _mm_set_ss(s);
+       __m128 SinA = _mm_shuffle_ps(Sin0, Sin0, _MM_SHUFFLE(0, 0, 0, 0));
+
+       // tvec3<T, P> temp = (valType(1) - c) * axis;
+       __m128 Temp0 = _mm_sub_ps(one, CosA);
+       __m128 Temp1 = _mm_mul_ps(Temp0, AxisC);
+       
+       //Rotate[0][0] = c + temp[0] * axis[0];
+       //Rotate[0][1] = 0 + temp[0] * axis[1] + s * axis[2];
+       //Rotate[0][2] = 0 + temp[0] * axis[2] - s * axis[1];
+       __m128 Axis0 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(0, 0, 0, 0));
+       __m128 TmpA0 = _mm_mul_ps(Axis0, AxisC);
+       __m128 CosA0 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 1, 0));
+       __m128 TmpA1 = _mm_add_ps(CosA0, TmpA0);
+       __m128 SinA0 = SinA;//_mm_set_ps(0.0f, s, -s, 0.0f);
+       __m128 TmpA2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 1, 2, 3));
+       __m128 TmpA3 = _mm_mul_ps(SinA0, TmpA2);
+       __m128 TmpA4 = _mm_add_ps(TmpA1, TmpA3);
+
+       //Rotate[1][0] = 0 + temp[1] * axis[0] - s * axis[2];
+       //Rotate[1][1] = c + temp[1] * axis[1];
+       //Rotate[1][2] = 0 + temp[1] * axis[2] + s * axis[0];
+       __m128 Axis1 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(1, 1, 1, 1));
+       __m128 TmpB0 = _mm_mul_ps(Axis1, AxisC);
+       __m128 CosA1 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 1, 0, 1));
+       __m128 TmpB1 = _mm_add_ps(CosA1, TmpB0);
+       __m128 SinB0 = SinA;//_mm_set_ps(-s, 0.0f, s, 0.0f);
+       __m128 TmpB2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 0, 3, 2));
+       __m128 TmpB3 = _mm_mul_ps(SinA0, TmpB2);
+       __m128 TmpB4 = _mm_add_ps(TmpB1, TmpB3);
+
+       //Rotate[2][0] = 0 + temp[2] * axis[0] + s * axis[1];
+       //Rotate[2][1] = 0 + temp[2] * axis[1] - s * axis[0];
+       //Rotate[2][2] = c + temp[2] * axis[2];
+       __m128 Axis2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(2, 2, 2, 2));
+       __m128 TmpC0 = _mm_mul_ps(Axis2, AxisC);
+       __m128 CosA2 = _mm_shuffle_ps(Cos0, Cos0, _MM_SHUFFLE(1, 0, 1, 1));
+       __m128 TmpC1 = _mm_add_ps(CosA2, TmpC0);
+       __m128 SinC0 = SinA;//_mm_set_ps(s, -s, 0.0f, 0.0f);
+       __m128 TmpC2 = _mm_shuffle_ps(AxisC, AxisC, _MM_SHUFFLE(3, 3, 0, 1));
+       __m128 TmpC3 = _mm_mul_ps(SinA0, TmpC2);
+       __m128 TmpC4 = _mm_add_ps(TmpC1, TmpC3);
+
+       __m128 Result[4];
+       Result[0] = TmpA4;
+       Result[1] = TmpB4;
+       Result[2] = TmpC4;
+       Result[3] = _mm_set_ps(1, 0, 0, 0);
+
+       //tmat4x4<valType> Result(uninitialize);
+       //Result[0] = m[0] * Rotate[0][0] + m[1] * Rotate[0][1] + m[2] * Rotate[0][2];
+       //Result[1] = m[0] * Rotate[1][0] + m[1] * Rotate[1][1] + m[2] * Rotate[1][2];
+       //Result[2] = m[0] * Rotate[2][0] + m[1] * Rotate[2][1] + m[2] * Rotate[2][2];
+       //Result[3] = m[3];
+       //return Result;
+       sse_mul_ps(in, Result, out);
+}
+*/
+GLM_FUNC_QUALIFIER void glm_mat4_outerProduct(__m128 const & c, __m128 const & r, __m128 out[4])
+{
+       out[0] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(0, 0, 0, 0)));
+       out[1] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(1, 1, 1, 1)));
+       out[2] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(2, 2, 2, 2)));
+       out[3] = _mm_mul_ps(c, _mm_shuffle_ps(r, r, _MM_SHUFFLE(3, 3, 3, 3)));
+}
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/packing.h b/core/deps/glm/glm/simd/packing.h
new file mode 100755 (executable)
index 0000000..609163e
--- /dev/null
@@ -0,0 +1,8 @@
+/// @ref simd
+/// @file glm/simd/packing.h
+
+#pragma once
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/simd/platform.h b/core/deps/glm/glm/simd/platform.h
new file mode 100755 (executable)
index 0000000..f779390
--- /dev/null
@@ -0,0 +1,452 @@
+/// @ref simd
+/// @file glm/simd/platform.h
+
+#pragma once
+
+///////////////////////////////////////////////////////////////////////////////////
+// Platform
+
+#define GLM_PLATFORM_UNKNOWN           0x00000000
+#define GLM_PLATFORM_WINDOWS           0x00010000
+#define GLM_PLATFORM_LINUX                     0x00020000
+#define GLM_PLATFORM_APPLE                     0x00040000
+//#define GLM_PLATFORM_IOS                     0x00080000
+#define GLM_PLATFORM_ANDROID           0x00100000
+#define GLM_PLATFORM_CHROME_NACL       0x00200000
+#define GLM_PLATFORM_UNIX                      0x00400000
+#define GLM_PLATFORM_QNXNTO                    0x00800000
+#define GLM_PLATFORM_WINCE                     0x01000000
+#define GLM_PLATFORM_CYGWIN                    0x02000000
+
+#ifdef GLM_FORCE_PLATFORM_UNKNOWN
+#      define GLM_PLATFORM GLM_PLATFORM_UNKNOWN
+#elif defined(__CYGWIN__)
+#      define GLM_PLATFORM GLM_PLATFORM_CYGWIN
+#elif defined(__QNXNTO__)
+#      define GLM_PLATFORM GLM_PLATFORM_QNXNTO
+#elif defined(__APPLE__)
+#      define GLM_PLATFORM GLM_PLATFORM_APPLE
+#elif defined(WINCE)
+#      define GLM_PLATFORM GLM_PLATFORM_WINCE
+#elif defined(_WIN32)
+#      define GLM_PLATFORM GLM_PLATFORM_WINDOWS
+#elif defined(__native_client__)
+#      define GLM_PLATFORM GLM_PLATFORM_CHROME_NACL
+#elif defined(__ANDROID__)
+#      define GLM_PLATFORM GLM_PLATFORM_ANDROID
+#elif defined(__linux)
+#      define GLM_PLATFORM GLM_PLATFORM_LINUX
+#elif defined(__unix)
+#      define GLM_PLATFORM GLM_PLATFORM_UNIX
+#else
+#      define GLM_PLATFORM GLM_PLATFORM_UNKNOWN
+#endif//
+
+// Report platform detection
+#if GLM_MESSAGES == GLM_MESSAGES_ENABLED && !defined(GLM_MESSAGE_PLATFORM_DISPLAYED)
+#      define GLM_MESSAGE_PLATFORM_DISPLAYED
+#      if(GLM_PLATFORM & GLM_PLATFORM_QNXNTO)
+#              pragma message("GLM: QNX platform detected")
+//#    elif(GLM_PLATFORM & GLM_PLATFORM_IOS)
+//#            pragma message("GLM: iOS platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_APPLE)
+#              pragma message("GLM: Apple platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_WINCE)
+#              pragma message("GLM: WinCE platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_WINDOWS)
+#              pragma message("GLM: Windows platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_CHROME_NACL)
+#              pragma message("GLM: Native Client detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_ANDROID)
+#              pragma message("GLM: Android platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_LINUX)
+#              pragma message("GLM: Linux platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_UNIX)
+#              pragma message("GLM: UNIX platform detected")
+#      elif(GLM_PLATFORM & GLM_PLATFORM_UNKNOWN)
+#              pragma message("GLM: platform unknown")
+#      else
+#              pragma message("GLM: platform not detected")
+#      endif
+#endif//GLM_MESSAGES
+
+///////////////////////////////////////////////////////////////////////////////////
+// Compiler
+
+#define GLM_COMPILER_UNKNOWN           0x00000000
+
+// Intel
+#define GLM_COMPILER_INTEL                     0x00100000
+#define GLM_COMPILER_INTEL12           0x00100010
+#define GLM_COMPILER_INTEL12_1         0x00100020
+#define GLM_COMPILER_INTEL13           0x00100030
+#define GLM_COMPILER_INTEL14           0x00100040
+#define GLM_COMPILER_INTEL15           0x00100050
+#define GLM_COMPILER_INTEL16           0x00100060
+
+// Visual C++ defines
+#define GLM_COMPILER_VC                                0x01000000
+#define GLM_COMPILER_VC10                      0x01000090
+#define GLM_COMPILER_VC11                      0x010000A0
+#define GLM_COMPILER_VC12                      0x010000B0
+#define GLM_COMPILER_VC14                      0x010000C0
+#define GLM_COMPILER_VC15                      0x010000D0
+
+// GCC defines
+#define GLM_COMPILER_GCC                       0x02000000
+#define GLM_COMPILER_GCC44                     0x020000B0
+#define GLM_COMPILER_GCC45                     0x020000C0
+#define GLM_COMPILER_GCC46                     0x020000D0
+#define GLM_COMPILER_GCC47                     0x020000E0
+#define GLM_COMPILER_GCC48                     0x020000F0
+#define GLM_COMPILER_GCC49                     0x02000100
+#define GLM_COMPILER_GCC50                     0x02000200
+#define GLM_COMPILER_GCC51                     0x02000300
+#define GLM_COMPILER_GCC52                     0x02000400
+#define GLM_COMPILER_GCC53                     0x02000500
+#define GLM_COMPILER_GCC54                     0x02000600
+#define GLM_COMPILER_GCC60                     0x02000700
+#define GLM_COMPILER_GCC61                     0x02000800
+#define GLM_COMPILER_GCC62                     0x02000900
+#define GLM_COMPILER_GCC70                     0x02000A00
+#define GLM_COMPILER_GCC71                     0x02000B00
+#define GLM_COMPILER_GCC72                     0x02000C00
+#define GLM_COMPILER_GCC80                     0x02000D00
+
+// CUDA
+#define GLM_COMPILER_CUDA                      0x10000000
+#define GLM_COMPILER_CUDA40                    0x10000040
+#define GLM_COMPILER_CUDA41                    0x10000050
+#define GLM_COMPILER_CUDA42                    0x10000060
+#define GLM_COMPILER_CUDA50                    0x10000070
+#define GLM_COMPILER_CUDA60                    0x10000080
+#define GLM_COMPILER_CUDA65                    0x10000090
+#define GLM_COMPILER_CUDA70                    0x100000A0
+#define GLM_COMPILER_CUDA75                    0x100000B0
+#define GLM_COMPILER_CUDA80                    0x100000C0
+
+// Clang
+#define GLM_COMPILER_CLANG                     0x20000000
+#define GLM_COMPILER_CLANG32           0x20000030
+#define GLM_COMPILER_CLANG33           0x20000040
+#define GLM_COMPILER_CLANG34           0x20000050
+#define GLM_COMPILER_CLANG35           0x20000060
+#define GLM_COMPILER_CLANG36           0x20000070
+#define GLM_COMPILER_CLANG37           0x20000080
+#define GLM_COMPILER_CLANG38           0x20000090
+#define GLM_COMPILER_CLANG39           0x200000A0
+#define GLM_COMPILER_CLANG40           0x200000B0
+#define GLM_COMPILER_CLANG41           0x200000C0
+#define GLM_COMPILER_CLANG42           0x200000D0
+
+// Build model
+#define GLM_MODEL_32                           0x00000010
+#define GLM_MODEL_64                           0x00000020
+
+// Force generic C++ compiler
+#ifdef GLM_FORCE_COMPILER_UNKNOWN
+#      define GLM_COMPILER GLM_COMPILER_UNKNOWN
+
+#elif defined(__INTEL_COMPILER)
+#      if __INTEL_COMPILER == 1200
+#              define GLM_COMPILER GLM_COMPILER_INTEL12
+#      elif __INTEL_COMPILER == 1210
+#              define GLM_COMPILER GLM_COMPILER_INTEL12_1
+#      elif __INTEL_COMPILER == 1300
+#              define GLM_COMPILER GLM_COMPILER_INTEL13
+#      elif __INTEL_COMPILER == 1400
+#              define GLM_COMPILER GLM_COMPILER_INTEL14
+#      elif __INTEL_COMPILER == 1500
+#              define GLM_COMPILER GLM_COMPILER_INTEL15
+#      elif __INTEL_COMPILER >= 1600
+#              define GLM_COMPILER GLM_COMPILER_INTEL16
+#      else
+#              define GLM_COMPILER GLM_COMPILER_INTEL
+#      endif
+
+// CUDA
+#elif defined(__CUDACC__)
+#      if !defined(CUDA_VERSION) && !defined(GLM_FORCE_CUDA)
+#              include <cuda.h>  // make sure version is defined since nvcc does not define it itself!
+#      endif
+#      if CUDA_VERSION < 3000
+#              error "GLM requires CUDA 3.0 or higher"
+#      else
+#              define GLM_COMPILER GLM_COMPILER_CUDA
+#      endif
+
+// Clang
+#elif defined(__clang__)
+#      if GLM_PLATFORM & GLM_PLATFORM_APPLE
+#              if __clang_major__ == 5 && __clang_minor__ == 0
+#                      define GLM_COMPILER GLM_COMPILER_CLANG33
+#              elif __clang_major__ == 5 && __clang_minor__ == 1
+#                      define GLM_COMPILER GLM_COMPILER_CLANG34
+#              elif __clang_major__ == 6 && __clang_minor__ == 0
+#                      define GLM_COMPILER GLM_COMPILER_CLANG35
+#              elif __clang_major__ == 6 && __clang_minor__ >= 1
+#                      define GLM_COMPILER GLM_COMPILER_CLANG36
+#              elif __clang_major__ >= 7
+#                      define GLM_COMPILER GLM_COMPILER_CLANG37
+#              else
+#                      define GLM_COMPILER GLM_COMPILER_CLANG
+#              endif
+#      else
+#              if __clang_major__ == 3 && __clang_minor__ == 0
+#                      define GLM_COMPILER GLM_COMPILER_CLANG30
+#              elif __clang_major__ == 3 && __clang_minor__ == 1
+#                      define GLM_COMPILER GLM_COMPILER_CLANG31
+#              elif __clang_major__ == 3 && __clang_minor__ == 2
+#                      define GLM_COMPILER GLM_COMPILER_CLANG32
+#              elif __clang_major__ == 3 && __clang_minor__ == 3
+#                      define GLM_COMPILER GLM_COMPILER_CLANG33
+#              elif __clang_major__ == 3 && __clang_minor__ == 4
+#                      define GLM_COMPILER GLM_COMPILER_CLANG34
+#              elif __clang_major__ == 3 && __clang_minor__ == 5
+#                      define GLM_COMPILER GLM_COMPILER_CLANG35
+#              elif __clang_major__ == 3 && __clang_minor__ == 6
+#                      define GLM_COMPILER GLM_COMPILER_CLANG36
+#              elif __clang_major__ == 3 && __clang_minor__ == 7
+#                      define GLM_COMPILER GLM_COMPILER_CLANG37
+#              elif __clang_major__ == 3 && __clang_minor__ == 8
+#                      define GLM_COMPILER GLM_COMPILER_CLANG38
+#              elif __clang_major__ == 3 && __clang_minor__ >= 9
+#                      define GLM_COMPILER GLM_COMPILER_CLANG39
+#              elif __clang_major__ == 4 && __clang_minor__ == 0
+#                      define GLM_COMPILER GLM_COMPILER_CLANG40
+#              elif __clang_major__ == 4 && __clang_minor__ == 1
+#                      define GLM_COMPILER GLM_COMPILER_CLANG41
+#              elif __clang_major__ == 4 && __clang_minor__ >= 2
+#                      define GLM_COMPILER GLM_COMPILER_CLANG42
+#              elif __clang_major__ >= 4
+#                      define GLM_COMPILER GLM_COMPILER_CLANG42
+#              else
+#                      define GLM_COMPILER GLM_COMPILER_CLANG
+#              endif
+#      endif
+
+// Visual C++
+#elif defined(_MSC_VER)
+#      if _MSC_VER < 1600
+#              error "GLM requires Visual C++ 10 - 2010 or higher"
+#      elif _MSC_VER == 1600
+#              define GLM_COMPILER GLM_COMPILER_VC11
+#      elif _MSC_VER == 1700
+#              define GLM_COMPILER GLM_COMPILER_VC11
+#      elif _MSC_VER == 1800
+#              define GLM_COMPILER GLM_COMPILER_VC12
+#      elif _MSC_VER == 1900
+#              define GLM_COMPILER GLM_COMPILER_VC14
+#      elif _MSC_VER >= 1910
+#              define GLM_COMPILER GLM_COMPILER_VC15
+#      else//_MSC_VER
+#              define GLM_COMPILER GLM_COMPILER_VC
+#      endif//_MSC_VER
+
+// G++
+#elif defined(__GNUC__) || defined(__MINGW32__)
+#      if (__GNUC__ == 4) && (__GNUC_MINOR__ == 2)
+#              define GLM_COMPILER (GLM_COMPILER_GCC42)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
+#              define GLM_COMPILER (GLM_COMPILER_GCC43)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 4)
+#              define GLM_COMPILER (GLM_COMPILER_GCC44)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 5)
+#              define GLM_COMPILER (GLM_COMPILER_GCC45)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 6)
+#              define GLM_COMPILER (GLM_COMPILER_GCC46)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 7)
+#              define GLM_COMPILER (GLM_COMPILER_GCC47)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ == 8)
+#              define GLM_COMPILER (GLM_COMPILER_GCC48)
+#      elif (__GNUC__ == 4) && (__GNUC_MINOR__ >= 9)
+#              define GLM_COMPILER (GLM_COMPILER_GCC49)
+#      elif (__GNUC__ == 5) && (__GNUC_MINOR__ == 0)
+#              define GLM_COMPILER (GLM_COMPILER_GCC50)
+#      elif (__GNUC__ == 5) && (__GNUC_MINOR__ == 1)
+#              define GLM_COMPILER (GLM_COMPILER_GCC51)
+#      elif (__GNUC__ == 5) && (__GNUC_MINOR__ == 2)
+#              define GLM_COMPILER (GLM_COMPILER_GCC52)
+#      elif (__GNUC__ == 5) && (__GNUC_MINOR__ == 3)
+#              define GLM_COMPILER (GLM_COMPILER_GCC53)
+#      elif (__GNUC__ == 5) && (__GNUC_MINOR__ >= 4)
+#              define GLM_COMPILER (GLM_COMPILER_GCC54)
+#      elif (__GNUC__ == 6) && (__GNUC_MINOR__ == 0)
+#              define GLM_COMPILER (GLM_COMPILER_GCC60)
+#      elif (__GNUC__ == 6) && (__GNUC_MINOR__ == 1)
+#              define GLM_COMPILER (GLM_COMPILER_GCC61)
+#      elif (__GNUC__ == 6) && (__GNUC_MINOR__ >= 2)
+#              define GLM_COMPILER (GLM_COMPILER_GCC62)
+#      elif (__GNUC__ == 7) && (__GNUC_MINOR__ == 0)
+#              define GLM_COMPILER (GLM_COMPILER_GCC70)
+#      elif (__GNUC__ == 7) && (__GNUC_MINOR__ == 1)
+#              define GLM_COMPILER (GLM_COMPILER_GCC71)
+#      elif (__GNUC__ == 7) && (__GNUC_MINOR__ == 2)
+#              define GLM_COMPILER (GLM_COMPILER_GCC72)
+#      elif (__GNUC__ >= 8)
+#              define GLM_COMPILER (GLM_COMPILER_GCC80)
+#      else
+#              define GLM_COMPILER (GLM_COMPILER_GCC)
+#      endif
+
+#else
+#      define GLM_COMPILER GLM_COMPILER_UNKNOWN
+#endif
+
+#ifndef GLM_COMPILER
+#      error "GLM_COMPILER undefined, your compiler may not be supported by GLM. Add #define GLM_COMPILER 0 to ignore this message."
+#endif//GLM_COMPILER
+
+///////////////////////////////////////////////////////////////////////////////////
+// Instruction sets
+
+// User defines: GLM_FORCE_PURE GLM_FORCE_SSE2 GLM_FORCE_SSE3 GLM_FORCE_AVX GLM_FORCE_AVX2 GLM_FORCE_AVX2
+
+#define GLM_ARCH_X86_BIT               0x00000001
+#define GLM_ARCH_SSE2_BIT              0x00000002
+#define GLM_ARCH_SSE3_BIT              0x00000004
+#define GLM_ARCH_SSSE3_BIT             0x00000008
+#define GLM_ARCH_SSE41_BIT             0x00000010
+#define GLM_ARCH_SSE42_BIT             0x00000020
+#define GLM_ARCH_AVX_BIT               0x00000040
+#define GLM_ARCH_AVX2_BIT              0x00000080
+#define GLM_ARCH_AVX512_BIT            0x00000100 // Skylake subset
+#define GLM_ARCH_ARM_BIT               0x00000100
+#define GLM_ARCH_NEON_BIT              0x00000200
+#define GLM_ARCH_MIPS_BIT              0x00010000
+#define GLM_ARCH_PPC_BIT               0x01000000
+
+#define GLM_ARCH_PURE          (0x00000000)
+#define GLM_ARCH_X86           (GLM_ARCH_X86_BIT)
+#define GLM_ARCH_SSE2          (GLM_ARCH_SSE2_BIT | GLM_ARCH_X86)
+#define GLM_ARCH_SSE3          (GLM_ARCH_SSE3_BIT | GLM_ARCH_SSE2)
+#define GLM_ARCH_SSSE3         (GLM_ARCH_SSSE3_BIT | GLM_ARCH_SSE3)
+#define GLM_ARCH_SSE41         (GLM_ARCH_SSE41_BIT | GLM_ARCH_SSSE3)
+#define GLM_ARCH_SSE42         (GLM_ARCH_SSE42_BIT | GLM_ARCH_SSE41)
+#define GLM_ARCH_AVX           (GLM_ARCH_AVX_BIT | GLM_ARCH_SSE42)
+#define GLM_ARCH_AVX2          (GLM_ARCH_AVX2_BIT | GLM_ARCH_AVX)
+#define GLM_ARCH_AVX512                (GLM_ARCH_AVX512_BIT | GLM_ARCH_AVX2) // Skylake subset
+#define GLM_ARCH_ARM           (GLM_ARCH_ARM_BIT)
+#define GLM_ARCH_NEON          (GLM_ARCH_NEON_BIT | GLM_ARCH_ARM)
+#define GLM_ARCH_MIPS          (GLM_ARCH_MIPS_BIT)
+#define GLM_ARCH_PPC           (GLM_ARCH_PPC_BIT)
+
+#if defined(GLM_FORCE_PURE)
+#      define GLM_ARCH GLM_ARCH_PURE
+#elif defined(GLM_FORCE_MIPS)
+#      define GLM_ARCH (GLM_ARCH_MIPS)
+#elif defined(GLM_FORCE_PPC)
+#      define GLM_ARCH (GLM_ARCH_PPC)
+#elif defined(GLM_FORCE_NEON)
+#      define GLM_ARCH (GLM_ARCH_NEON)
+#elif defined(GLM_FORCE_AVX512)
+#      define GLM_ARCH (GLM_ARCH_AVX512)
+#elif defined(GLM_FORCE_AVX2)
+#      define GLM_ARCH (GLM_ARCH_AVX2)
+#elif defined(GLM_FORCE_AVX)
+#      define GLM_ARCH (GLM_ARCH_AVX)
+#elif defined(GLM_FORCE_SSE42)
+#      define GLM_ARCH (GLM_ARCH_SSE42)
+#elif defined(GLM_FORCE_SSE41)
+#      define GLM_ARCH (GLM_ARCH_SSE41)
+#elif defined(GLM_FORCE_SSSE3)
+#      define GLM_ARCH (GLM_ARCH_SSSE3)
+#elif defined(GLM_FORCE_SSE3)
+#      define GLM_ARCH (GLM_ARCH_SSE3)
+#elif defined(GLM_FORCE_SSE2)
+#      define GLM_ARCH (GLM_ARCH_SSE2)
+#elif (GLM_COMPILER & (GLM_COMPILER_CLANG | GLM_COMPILER_GCC)) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_LINUX))
+//     This is Skylake set of instruction set
+#      if defined(__AVX512BW__) && defined(__AVX512F__) && defined(__AVX512CD__) && defined(__AVX512VL__) && defined(__AVX512DQ__)
+#              define GLM_ARCH (GLM_ARCH_AVX512)
+#      elif defined(__AVX2__)
+#              define GLM_ARCH (GLM_ARCH_AVX2)
+#      elif defined(__AVX__)
+#              define GLM_ARCH (GLM_ARCH_AVX)
+#      elif defined(__SSE4_2__)
+#              define GLM_ARCH (GLM_ARCH_SSE42)
+#      elif defined(__SSE4_1__)
+#              define GLM_ARCH (GLM_ARCH_SSE41)
+#      elif defined(__SSSE3__)
+#              define GLM_ARCH (GLM_ARCH_SSSE3)
+#      elif defined(__SSE3__)
+#              define GLM_ARCH (GLM_ARCH_SSE3)
+#      elif defined(__SSE2__)
+#              define GLM_ARCH (GLM_ARCH_SSE2)
+#      elif defined(__i386__) || defined(__x86_64__)
+#              define GLM_ARCH (GLM_ARCH_X86)
+#      elif defined(__ARM_NEON)
+#              define GLM_ARCH (GLM_ARCH_ARM | GLM_ARCH_NEON)
+#      elif defined(__arm__ )
+#              define GLM_ARCH (GLM_ARCH_ARM)
+#      elif defined(__mips__ )
+#              define GLM_ARCH (GLM_ARCH_MIPS)
+#      elif defined(__powerpc__ )
+#              define GLM_ARCH (GLM_ARCH_PPC)
+#      else
+#              define GLM_ARCH (GLM_ARCH_PURE)
+#      endif
+#elif (GLM_COMPILER & GLM_COMPILER_VC) || ((GLM_COMPILER & GLM_COMPILER_INTEL) && (GLM_PLATFORM & GLM_PLATFORM_WINDOWS))
+#      if defined(_M_ARM)
+#              define GLM_ARCH (GLM_ARCH_ARM)
+#      elif defined(__AVX2__)
+#              define GLM_ARCH (GLM_ARCH_AVX2)
+#      elif defined(__AVX__)
+#              define GLM_ARCH (GLM_ARCH_AVX)
+#      elif defined(_M_X64)
+#              define GLM_ARCH (GLM_ARCH_SSE2)
+#      elif defined(_M_IX86_FP)
+#              if _M_IX86_FP >= 2
+#                      define GLM_ARCH (GLM_ARCH_SSE2)
+#              else
+#                      define GLM_ARCH (GLM_ARCH_PURE)
+#              endif
+#      elif defined(_M_PPC)
+#              define GLM_ARCH (GLM_ARCH_PPC)
+#      else
+#              define GLM_ARCH (GLM_ARCH_PURE)
+#      endif
+#else
+#      define GLM_ARCH GLM_ARCH_PURE
+#endif
+
+// With MinGW-W64, including intrinsic headers before intrin.h will produce some errors. The problem is
+// that windows.h (and maybe other headers) will silently include intrin.h, which of course causes problems.
+// To fix, we just explicitly include intrin.h here.
+#if defined(__MINGW64__) && (GLM_ARCH != GLM_ARCH_PURE)
+#      include <intrin.h>
+#endif
+
+#if GLM_ARCH & GLM_ARCH_AVX2_BIT
+#      include <immintrin.h>
+#elif GLM_ARCH & GLM_ARCH_AVX_BIT
+#      include <immintrin.h>
+#elif GLM_ARCH & GLM_ARCH_SSE42_BIT
+#      if GLM_COMPILER & GLM_COMPILER_CLANG
+#              include <popcntintrin.h>
+#      endif
+#      include <nmmintrin.h>
+#elif GLM_ARCH & GLM_ARCH_SSE41_BIT
+#      include <smmintrin.h>
+#elif GLM_ARCH & GLM_ARCH_SSSE3_BIT
+#      include <tmmintrin.h>
+#elif GLM_ARCH & GLM_ARCH_SSE3_BIT
+#      include <pmmintrin.h>
+#elif GLM_ARCH & GLM_ARCH_SSE2_BIT
+#      include <emmintrin.h>
+#endif//GLM_ARCH
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+       typedef __m128          glm_vec4;
+       typedef __m128i         glm_ivec4;
+       typedef __m128i         glm_uvec4;
+#endif
+
+#if GLM_ARCH & GLM_ARCH_AVX_BIT
+       typedef __m256d         glm_dvec4;
+#endif
+
+#if GLM_ARCH & GLM_ARCH_AVX2_BIT
+       typedef __m256i         glm_i64vec4;
+       typedef __m256i         glm_u64vec4;
+#endif
diff --git a/core/deps/glm/glm/simd/trigonometric.h b/core/deps/glm/glm/simd/trigonometric.h
new file mode 100755 (executable)
index 0000000..739b796
--- /dev/null
@@ -0,0 +1,9 @@
+/// @ref simd
+/// @file glm/simd/trigonometric.h
+
+#pragma once
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
+
diff --git a/core/deps/glm/glm/simd/vector_relational.h b/core/deps/glm/glm/simd/vector_relational.h
new file mode 100755 (executable)
index 0000000..f7385e9
--- /dev/null
@@ -0,0 +1,8 @@
+/// @ref simd
+/// @file glm/simd/vector_relational.h
+
+#pragma once
+
+#if GLM_ARCH & GLM_ARCH_SSE2_BIT
+
+#endif//GLM_ARCH & GLM_ARCH_SSE2_BIT
diff --git a/core/deps/glm/glm/trigonometric.hpp b/core/deps/glm/glm/trigonometric.hpp
new file mode 100755 (executable)
index 0000000..a9ce87c
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/trigonometric.hpp
+
+#pragma once
+
+#include "detail/func_trigonometric.hpp"
diff --git a/core/deps/glm/glm/vec2.hpp b/core/deps/glm/glm/vec2.hpp
new file mode 100755 (executable)
index 0000000..764c2e0
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/vec2.hpp
+
+#pragma once
+
+#include "detail/type_vec2.hpp"
diff --git a/core/deps/glm/glm/vec3.hpp b/core/deps/glm/glm/vec3.hpp
new file mode 100755 (executable)
index 0000000..eccda31
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/vec3.hpp
+
+#pragma once
+
+#include "detail/type_vec3.hpp"
diff --git a/core/deps/glm/glm/vec4.hpp b/core/deps/glm/glm/vec4.hpp
new file mode 100755 (executable)
index 0000000..ad66f5e
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/vec4.hpp
+
+#pragma once
+
+#include "detail/type_vec4.hpp"
diff --git a/core/deps/glm/glm/vector_relational.hpp b/core/deps/glm/glm/vector_relational.hpp
new file mode 100755 (executable)
index 0000000..d234190
--- /dev/null
@@ -0,0 +1,6 @@
+/// @ref core
+/// @file glm/vector_relational.hpp
+
+#pragma once
+
+#include "detail/func_vector_relational.hpp"
diff --git a/core/deps/glm/readme.md b/core/deps/glm/readme.md
new file mode 100755 (executable)
index 0000000..b411c27
--- /dev/null
@@ -0,0 +1,982 @@
+![glm](doc/logo.png)
+
+[OpenGL Mathematics](http://glm.g-truc.net/) (*GLM*) is a header only C++ mathematics library for graphics software based on the [OpenGL Shading Language (GLSL) specifications](https://www.opengl.org/registry/doc/GLSLangSpec.4.50.diff.pdf).
+
+*GLM* provides classes and functions designed and implemented with the same naming conventions and functionalities than *GLSL* so that anyone who knows *GLSL*, can use *GLM* as well in C++.
+
+This project isn't limited to *GLSL* features. An extension system, based on the *GLSL* extension conventions, provides extended capabilities: matrix transformations, quaternions, data packing, random numbers, noise, etc...
+
+This library works perfectly with *[OpenGL](https://www.opengl.org)* but it also ensures interoperability with other third party libraries and SDK. It is a good candidate for software rendering (raytracing / rasterisation), image processing, physic simulations and any development context that requires a simple and convenient mathematics library.
+
+*GLM* is written in C++98 but can take advantage of C++11 when supported by the compiler. It is a platform independent library with no dependence and it officially supports the following compilers:
+- [Apple Clang 4.0](https://developer.apple.com/library/mac/documentation/CompilerTools/Conceptual/LLVMCompilerOverview/index.html) and higher
+- [GCC](http://gcc.gnu.org/) 4.2 and higher
+- [Intel C++ Composer](https://software.intel.com/en-us/intel-compilers) XE 2013 and higher
+- [LLVM](http://llvm.org/) 3.0 and higher
+- [Visual C++](http://www.visualstudio.com/) 2010 and higher
+- [CUDA](https://developer.nvidia.com/about-cuda) 4.0 and higher (experimental)
+- Any conform C++98 or C++11 compiler
+
+For more information about *GLM*, please have a look at the [manual](http://glm.g-truc.net/0.9.7/glm-0.9.7.pdf) and the [API reference documentation](http://glm.g-truc.net/0.9.7/api/index.html).
+The source code and the documentation are licensed under the [Happy Bunny License (Modified MIT) or the MIT License](./copying.txt).
+
+Thanks for contributing to the project by [submitting issues](https://github.com/g-truc/glm/issues) for bug reports and feature requests. Any feedback is welcome at [glm@g-truc.net](mailto://glm@g-truc.net).
+
+
+```c++
+#include <glm/vec3.hpp> // glm::vec3
+#include <glm/vec4.hpp> // glm::vec4
+#include <glm/mat4x4.hpp> // glm::mat4
+#include <glm/gtc/matrix_transform.hpp> // glm::translate, glm::rotate, glm::scale, glm::perspective
+#include <glm/gtc/constants.hpp> // glm::pi
+
+glm::mat4 camera(float Translate, glm::vec2 const & Rotate)
+{
+       glm::mat4 Projection = glm::perspective(glm::pi<float>() * 0.25f, 4.0f / 3.0f, 0.1f, 100.f);
+       glm::mat4 View = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -Translate));
+       View = glm::rotate(View, Rotate.y, glm::vec3(-1.0f, 0.0f, 0.0f));
+       View = glm::rotate(View, Rotate.x, glm::vec3(0.0f, 1.0f, 0.0f));
+       glm::mat4 Model = glm::scale(glm::mat4(1.0f), glm::vec3(0.5f));
+       return Projection * View * Model;
+}
+```
+
+## Project Health
+
+| Service | System | Compiler | Status |
+| ------- | ------ | -------- | ------ |
+| [Drone](https://drone.io/github.com/g-truc/glm) | Linux 64 bits | GCC 4.6.3 | [![Build Status](https://drone.io/github.com/g-truc/glm/status.png)](https://drone.io/github.com/g-truc/glm/latest) |
+
+## [Lastest release](https://github.com/g-truc/glm/releases/latest)
+
+## Release notes
+
+#### [GLM 0.9.8.4](https://github.com/g-truc/glm/releases/tag/0.9.8.4) - 2017-01-22
+##### Fixes:
+- Fixed GTC_packing test failing on GCC x86 due to denorms #212 #577
+- Fixed POPCNT optimization build in Clang #512
+- Fixed intersectRayPlane returns true in parallel case #578
+- Fixed GCC 6.2 compiler warnings #580
+- Fixed GTX_matrix_decompose decompose #582 #448
+- Fixed GCC 4.5 and older build #566
+- Fixed Visual C++ internal error when declaring a global vec type with siwzzle expression enabled #594
+- Fixed GLM_FORCE_CXX11 with Clang and libstlc++ which wasn't using C++11 STL features. #604
+
+#### [GLM 0.9.8.3](https://github.com/g-truc/glm/releases/tag/0.9.8.3) - 2016-11-12
+##### Improvements:
+- Broader support of GLM_FORCE_UNRESTRICTED_GENTYPE #378
+
+##### Fixes:
+- Fixed Android build error with C++11 compiler but C++98 STL #284 #564
+- Fixed GTX_transform2 shear* functions #403
+- Fixed interaction between GLM_FORCE_UNRESTRICTED_GENTYPE and ortho function #568
+- Fixed bitCount with AVX on 32 bit builds #567
+- Fixed CMake find_package with version specification #572 #573
+
+#### [GLM 0.9.8.2](https://github.com/g-truc/glm/releases/tag/0.9.8.2) - 2016-11-01
+##### Improvements:
+- Added Visual C++ 15 detection
+- Added Clang 4.0 detection
+- Added warning messages when using GLM_FORCE_CXX** but the compiler
+  is known to not fully support the requested C++ version #555
+- Refactored GLM_COMPILER_VC values
+- Made quat, vec, mat type component length() static #565
+
+##### Fixes:
+- Fixed Visual C++ constexpr build error #555, #556
+
+#### [GLM 0.9.8.1](https://github.com/g-truc/glm/releases/tag/0.9.8.1) - 2016-09-25
+##### Improvements:
+- Optimized quaternion log function #554
+
+##### Fixes:
+- Fixed GCC warning filtering, replaced -pedantic by -Wpedantic
+- Fixed SIMD faceforward bug. #549
+- Fixed GCC 4.8 with C++11 compilation option #550
+- Fixed Visual Studio aligned type W4 warning #548
+- Fixed packing/unpacking function fixed for 5_6_5 and 5_5_5_1 #552
+
+#### [GLM 0.9.8.0](https://github.com/g-truc/glm/releases/tag/0.9.8.0) - 2016-09-11
+##### Features:
+- Added right and left handed projection and clip control support #447 #415 #119
+- Added compNormalize and compScale functions to GTX_component_wise
+- Added packF3x9_E1x5 and unpackF3x9_E1x5 to GTC_packing for RGB9E5 #416
+- Added (un)packHalf to GTC_packing
+- Added (un)packUnorm and (un)packSnorm to GTC_packing
+- Added 16bit pack and unpack to GTC_packing
+- Added 8bit pack and unpack to GTC_packing
+- Added missing bvec* && and || operators
+- Added iround and uround to GTC_integer, fast round on positive values
+- Added raw SIMD API
+- Added 'aligned' qualifiers
+- Added GTC_type_aligned with aligned *vec* types
+- Added GTC_functions extension
+- Added quaternion version of isnan and isinf #521
+- Added lowestBitValue to GTX_bit #536
+- Added GLM_FORCE_UNRESTRICTED_GENTYPE allowing non basic genType #543
+
+##### Improvements:
+- Improved SIMD and swizzle operators interactions with GCC and Clang #474
+- Improved GTC_random linearRand documentation
+- Improved GTC_reciprocal documentation
+- Improved GLM_FORCE_EXPLICIT_CTOR coverage #481
+- Improved OpenMP support detection for Clang, GCC, ICC and VC
+- Improved GTX_wrap for SIMD friendliness
+- Added constexpr for *vec*, *mat*, *quat* and *dual_quat* types #493
+- Added NEON instruction set detection
+- Added MIPS CPUs detection
+- Added PowerPC CPUs detection
+- Use Cuda built-in function for abs function implementation with Cuda compiler
+- Factorized GLM_COMPILER_LLVM and GLM_COMPILER_APPLE_CLANG into GLM_COMPILER_CLANG
+- No more warnings for use of long long
+- Added more information to build messages
+
+##### Fixes:
+- Fixed GTX_extended_min_max filename typo #386
+- Fixed intersectRayTriangle to not do any unintentional backface culling
+- Fixed long long warnings when using C++98 on GCC and Clang #482
+- Fixed sign with signed integer function on non-x86 architecture
+- Fixed strict aliasing warnings #473
+- Fixed missing vec1 overload to length2 and distance2 functions #431
+- Fixed GLM test '/fp:fast' and '/Za' command-line options are incompatible
+- Fixed quaterion to mat3 cast function mat3_cast from GTC_quaternion #542
+- Fixed GLM_GTX_io for Cuda #547 #546
+
+##### Deprecation:
+- Removed GLM_FORCE_SIZE_FUNC define
+- Deprecated GLM_GTX_simd_vec4 extension
+- Deprecated GLM_GTX_simd_mat4 extension
+- Deprecated GLM_GTX_simd_quat extension
+- Deprecated GLM_SWIZZLE, use GLM_FORCE_SWIZZLE instead
+- Deprecated GLM_MESSAGES, use GLM_FORCE_MESSAGES instead
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.6](https://github.com/g-truc/glm/releases/tag/0.9.7.6) - 2016-07-16
+##### Improvements:
+- Added pkg-config file #509
+- Updated list of compiler versions detected
+- Improved C++ 11 STL detection #523
+
+##### Fixes:
+- Fixed STL for C++11 detection on ICC #510
+- Fixed missing vec1 overload to length2 and distance2 functions #431
+- Fixed long long warnings when using C++98 on GCC and Clang #482
+- Fixed scalar reciprocal functions (GTC_reciprocal) #520
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.5](https://github.com/g-truc/glm/releases/tag/0.9.7.5) - 2016-05-24
+##### Improvements:
+- Added Visual C++ Clang toolset detection
+
+##### Fixes:
+- Fixed uaddCarry warning #497
+- Fixed roundPowerOfTwo and floorPowerOfTwo #503
+- Fixed Visual C++ SIMD instruction set automatic detection in 64 bits
+- Fixed to_string when used with GLM_FORCE_INLINE #506
+- Fixed GLM_FORCE_INLINE with binary vec4 operators
+- Fixed GTX_extended_min_max filename typo #386
+- Fixed intersectRayTriangle to not do any unintentional backface culling
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.4](https://github.com/g-truc/glm/releases/tag/0.9.7.4) - 2016-03-19
+##### Fixes:
+- Fixed asinh and atanh warning with C++98 STL #484
+- Fixed polar coordinates function latitude #485
+- Fixed outerProduct defintions and operator signatures for mat2x4 and vec4 #475
+- Fixed eulerAngles precision error, returns NaN  #451
+- Fixed undefined reference errors #489
+- Fixed missing GLM_PLATFORM_CYGWIN declaration #495
+- Fixed various undefined reference errors #490
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.3](https://github.com/g-truc/glm/releases/tag/0.9.7.3) - 2016-02-21
+##### Improvements:
+- Added AVX512 detection
+
+##### Fixes:
+- Fixed CMake policy warning
+- Fixed GCC 6.0 detection #477
+- Fixed Clang build on Windows #479
+- Fixed 64 bits constants warnings on GCC #463
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.2](https://github.com/g-truc/glm/releases/tag/0.9.7.2) - 2016-01-03
+##### Fixes:
+- Fixed GTC_round floorMultiple/ceilMultiple #412
+- Fixed GTC_packing unpackUnorm3x10_1x2 #414
+- Fixed GTC_matrix_inverse affineInverse #192
+- Fixed ICC on Linux build errors #449
+- Fixed ldexp and frexp compilation errors
+- Fixed "Declaration shadows a field" warning #468
+- Fixed 'GLM_COMPILER_VC2005 is not defined' warning #468
+- Fixed various 'X is not defined' warnings #468
+- Fixed missing unary + operator #435
+- Fixed Cygwin build errors when using C++11 #405
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.1](https://github.com/g-truc/glm/releases/tag/0.9.7.1) - 2015-09-07
+##### Improvements:
+- Improved constexpr for constant functions coverage #198
+- Added to_string for quat and dual_quat in GTX_string_cast #375
+- Improved overall execution time of unit tests #396
+
+##### Fixes:
+- Fixed strict alignment warnings #235 #370
+- Fixed link errors on compilers not supported default function #377
+- Fixed compilation warnings in vec4
+- Fixed non-identity quaternions for equal vectors #234
+- Fixed excessive GTX_fast_trigonometry execution time #396
+- Fixed Visual Studio 2015 'hides class member' warnings #394
+- Fixed builtin bitscan never being used #392
+- Removed unused func_noise.* files #398
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.7.0](https://github.com/g-truc/glm/releases/tag/0.9.7.0) - 2015-08-02
+##### Features:
+- Added GTC_color_space: convertLinearToSRGB and convertSRGBToLinear functions
+- Added 'fmod' overload to GTX_common with tests #308
+- Left handed perspective and lookAt functions #314
+- Added functions eulerAngleXYZ and extractEulerAngleXYZ #311
+- Added <glm/gtx/hash.hpp> to perform std::hash on GLM types #320 #367
+- Added <glm/gtx/wrap.hpp> for texcoord wrapping
+- Added static components and precision members to all vector and quat types #350
+- Added .gitignore #349
+- Added support of defaulted functions to GLM types, to use them in unions #366
+
+##### Improvements:
+- Changed usage of __has_include to support Intel compiler #307
+- Specialized integer implementation of YCoCg-R #310
+- Don't show status message in 'FindGLM' if 'QUIET' option is set. #317
+- Added master branch continuous integration service on Linux 64 #332
+- Clarified manual regarding angle unit in GLM, added FAQ 11 #326
+- Updated list of compiler versions
+
+##### Fixes:
+- Fixed default precision for quat and dual_quat type #312
+- Fixed (u)int64 MSB/LSB handling on BE archs #306
+- Fixed multi-line comment warning in g++. #315
+- Fixed specifier removal by 'std::make_pair<>' #333
+- Fixed perspective fovy argument documentation #327
+- Removed -m64 causing build issues on Linux 32 #331
+- Fixed isfinite with C++98 compilers #343
+- Fixed Intel compiler build error on Linux #354
+- Fixed use of libstdc++ with Clang #351
+- Fixed quaternion pow #346
+- Fixed decompose warnings #373
+- Fixed matrix conversions #371
+
+##### Deprecation:
+- Removed integer specification for 'mod' in GTC_integer #308
+- Removed GTX_multiple, replaced by GTC_round
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.6.3](https://github.com/g-truc/glm/releases/tag/0.9.6.3) - 2015-02-15
+- Fixed Android doesn't have C++ 11 STL #284
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.6.2](https://github.com/g-truc/glm/releases/tag/0.9.6.2) - 2015-02-15
+##### Features:
+- Added display of GLM version with other GLM_MESSAGES
+- Added ARM instruction set detection
+
+--------------------------------------------------------------------------------
+##### Improvements:
+- Removed assert for perspective with zFar < zNear #298
+- Added Visual Studio natvis support for vec1, quat and dualqual types
+- Cleaned up C++11 feature detections
+- Clarify GLM licensing
+
+##### Fixes:
+- Fixed faceforward build #289
+- Fixed conflict with Xlib #define True 1 #293
+- Fixed decompose function VS2010 templating issues #294
+- Fixed mat4x3 = mat2x3 * mat4x2 operator #297
+- Fixed warnings in F2x11_1x10 packing function in GTC_packing #295
+- Fixed Visual Studio natvis support for vec4 #288
+- Fixed GTC_packing *pack*norm*x* build and added tests #292
+- Disabled GTX_scalar_multiplication for GCC, failing to build tests #242
+- Fixed Visual C++ 2015 constexpr errors: Disabled only partial support
+- Fixed functions not inlined with Clang #302
+- Fixed memory corruption (undefined behaviour) #303
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.6.1](https://github.com/g-truc/glm/releases/tag/0.9.6.1) - 2014-12-10
+##### Features:
+- Added GLM_LANG_CXX14_FLAG and GLM_LANG_CXX1Z_FLAG language feature flags
+- Added C++14 detection
+
+##### Improvements:
+- Clean up GLM_MESSAGES compilation log to report only detected capabilities
+
+##### Fixes:
+- Fixed scalar uaddCarry build error with Cuda #276
+- Fixed C++11 explicit conversion operators detection #282
+- Fixed missing explicit conversion when using integer log2 with *vec1 types
+- Fixed 64 bits integer GTX_string_cast to_string on VC 32 bit compiler
+- Fixed Android build issue, STL C++11 is not supported by the NDK #284
+- Fixed unsupported _BitScanForward64 and _BitScanReverse64 in VC10
+- Fixed Visual C++ 32 bit build #283
+- Fixed GLM_FORCE_SIZE_FUNC pragma message
+- Fixed C++98 only build
+- Fixed conflict between GTX_compatibility and GTC_quaternion #286
+- Fixed C++ language restriction using GLM_FORCE_CXX**
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.6.0](https://github.com/g-truc/glm/releases/tag/0.9.6.0) - 2014-11-30
+##### Features:
+- Exposed template vector and matrix types in 'glm' namespace #239, #244
+- Added GTX_scalar_multiplication for C++ 11 compiler only #242
+- Added GTX_range for C++ 11 compiler only #240
+- Added closestPointOnLine function for tvec2 to GTX_closest_point #238
+- Added GTC_vec1 extension, *vec1 support to *vec* types
+- Updated GTX_associated_min_max with vec1 support
+- Added support of precision and integers to linearRand #230
+- Added Integer types support to GTX_string_cast #249
+- Added vec3 slerp #237
+- Added GTX_common with isdenomal #223
+- Added GLM_FORCE_SIZE_FUNC to replace .length() by .size() #245
+- Added GLM_FORCE_NO_CTOR_INIT
+- Added 'uninitialize' to explicitly not initialize a GLM type
+- Added GTC_bitfield extension, promoted GTX_bit
+- Added GTC_integer extension, promoted GTX_bit and GTX_integer
+- Added GTC_round extension, promoted GTX_bit
+- Added GLM_FORCE_EXPLICIT_CTOR to require explicit type conversions #269
+- Added GTX_type_aligned for aligned vector, matrix and quaternion types
+
+##### Improvements:
+- Rely on C++11 to implement isinf and isnan
+- Removed GLM_FORCE_CUDA, Cuda is implicitly detected
+- Separated Apple Clang and LLVM compiler detection
+- Used pragma once
+- Undetected C++ compiler automatically compile with GLM_FORCE_CXX98 and 
+  GLM_FORCE_PURE
+- Added not function (from GLSL specification) on VC12
+- Optimized bitfieldReverse and bitCount functions
+- Optimized findLSB and findMSB functions.
+- Optimized matrix-vector multiple performance with Cuda #257, #258
+- Reduced integer type redifinitions #233
+- Rewrited of GTX_fast_trigonometry #264 #265
+- Made types trivially copyable #263
+- Removed <iostream> in GLM tests
+- Used std features within GLM without redeclaring
+- Optimized cot function #272
+- Optimized sign function #272
+- Added explicit cast from quat to mat3 and mat4 #275
+
+##### Fixes:
+- Fixed std::nextafter not supported with C++11 on Android #217
+- Fixed missing value_type for dual quaternion
+- Fixed return type of dual quaternion length
+- Fixed infinite loop in isfinite function with GCC #221
+- Fixed Visual Studio 14 compiler warnings
+- Fixed implicit conversion from another tvec2 type to another tvec2 #241
+- Fixed lack of consistency of quat and dualquat constructors
+- Fixed uaddCarray #253
+- Fixed float comparison warnings #270
+
+##### Deprecation:
+- Removed degrees for function parameters
+- Removed GLM_FORCE_RADIANS, active by default
+- Removed VC 2005 / 8 and 2008 / 9 support
+- Removed GCC 3.4 to 4.3 support
+- Removed LLVM GCC support
+- Removed LLVM 2.6 to 3.1 support
+- Removed CUDA 3.0 to 3.2 support
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.5.4 - 2014-06-21](https://github.com/g-truc/glm/releases/tag/0.9.5.4)
+- Fixed non-utf8 character #196
+- Added FindGLM install for CMake #189
+- Fixed GTX_color_space - saturation #195
+- Fixed glm::isinf and glm::isnan for with Android NDK 9d #191
+- Fixed builtin GLM_ARCH_SSE4 #204
+- Optimized Quaternion vector rotation #205
+- Fixed missing doxygen @endcond tag #211
+- Fixed instruction set detection with Clang #158
+- Fixed orientate3 function #207
+- Fixed lerp when cosTheta is close to 1 in quaternion slerp #210
+- Added GTX_io for io with <iostream> #144
+- Fixed fastDistance ambiguity #215
+- Fixed tweakedInfinitePerspective #208 and added user-defined epsilon to
+  tweakedInfinitePerspective
+- Fixed std::copy and std::vector with GLM types #214
+- Fixed strict aliasing issues #212, #152
+- Fixed std::nextafter not supported with C++11 on Android #213
+- Fixed corner cases in exp and log functions for quaternions #199
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.5.3 - 2014-04-02
+- Added instruction set auto detection with Visual C++ using _M_IX86_FP - /arch
+  compiler argument
+- Fixed GTX_raw_data code dependency
+- Fixed GCC instruction set detection
+- Added GLM_GTX_matrix_transform_2d extension (#178, #176)
+- Fixed CUDA issues (#169, #168, #183, #182)
+- Added support for all extensions but GTX_string_cast to CUDA
+- Fixed strict aliasing warnings in GCC 4.8.1 / Android NDK 9c (#152)
+- Fixed missing bitfieldInterleave definisions
+- Fixed usubBorrow (#171)
+- Fixed eulerAngle*** not consistent for right-handed coordinate system (#173)
+- Added full tests for eulerAngle*** functions (#173)
+- Added workaround for a CUDA compiler bug (#186, #185)
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.5.2 - 2014-02-08
+- Fixed initializer list ambiguity (#159, #160)
+- Fixed warnings with the Android NDK 9c
+- Fixed non power of two matrix products
+- Fixed mix function link error
+- Fixed SSE code included in GLM tests on "pure" platforms
+- Fixed undefined reference to fastInverseSqrt (#161)
+- Fixed GLM_FORCE_RADIANS with <glm/ext.hpp> build error (#165)
+- Fix dot product clamp range for vector angle functions. (#163)
+- Tentative fix for strict aliasing warning in GCC 4.8.1 / Android NDK 9c (#152)
+- Fixed GLM_GTC_constants description brief (#162)
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.5.1 - 2014-01-11
+- Fixed angle and orientedAngle that sometimes return NaN values (#145)
+- Deprecated degrees for function parameters and display a message
+- Added possible static_cast conversion of GLM types (#72)
+- Fixed error 'inverse' is not a member of 'glm' from glm::unProject (#146)
+- Fixed mismatch between some declarations and definitions
+- Fixed inverse link error when using namespace glm; (#147)
+- Optimized matrix inverse and division code (#149)
+- Added intersectRayPlane function (#153)
+- Fixed outerProduct return type (#155)
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.5.0 - 2013-12-25
+- Added forward declarations (glm/fwd.hpp) for faster compilations
+- Added per feature headers
+- Minimized GLM internal dependencies
+- Improved Intel Compiler detection
+- Added bitfieldInterleave and _mm_bit_interleave_si128 functions
+- Added GTX_scalar_relational
+- Added GTX_dual_quaternion
+- Added rotation function to GTX_quaternion (#22)
+- Added precision variation of each type
+- Added quaternion comparison functions
+- Fixed GTX_multiple for negative value
+- Removed GTX_ocl_type extension
+- Fixed post increment and decrement operators
+- Fixed perspective with zNear == 0 (#71)
+- Removed l-value swizzle operators
+- Cleaned up compiler detection code for unsupported compilers
+- Replaced C cast by C++ casts
+- Fixed .length() that should return a int and not a size_t
+- Added GLM_FORCE_SIZE_T_LENGTH and glm::length_t
+- Removed unnecessary conversions
+- Optimized packing and unpacking functions
+- Removed the normalization of the up argument of lookAt function (#114)
+- Added low precision specializations of inversesqrt
+- Fixed ldexp and frexp implementations
+- Increased assert coverage
+- Increased static_assert coverage
+- Replaced GLM traits by STL traits when possible
+- Allowed including individual core feature
+- Increased unit tests completness
+- Added creating of a quaternion from two vectors
+- Added C++11 initializer lists
+- Fixed umulExtended and imulExtended implementations for vector types (#76)
+- Fixed CUDA coverage for GTC extensions
+- Added GTX_io extension
+- Improved GLM messages enabled when defining GLM_MESSAGES
+- Hidden matrix _inverse function implementation detail into private section
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.4.6](https://github.com/g-truc/glm/releases/tag/0.9.4.6) - 2013-09-20
+- Fixed detection to select the last known compiler if newer version #106
+- Fixed is_int and is_uint code duplication with GCC and C++11 #107 
+- Fixed test suite build while using Clang in C++11 mode
+- Added c++1y mode support in CMake test suite
+- Removed ms extension mode to CMake when no using Visual C++
+- Added pedantic mode to CMake test suite for Clang and GCC
+- Added use of GCC frontend on Unix for ICC and Visual C++ fronted on Windows
+  for ICC
+- Added compilation errors for unsupported compiler versions
+- Fixed glm::orientation with GLM_FORCE_RADIANS defined #112
+- Fixed const ref issue on assignment operator taking a scalar parameter #116
+- Fixed glm::eulerAngleY implementation #117
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.5 - 2013-08-12
+- Fixed CUDA support
+- Fixed inclusion of intrinsics in "pure" mode #92
+- Fixed language detection on GCC when the C++0x mode isn't enabled #95
+- Fixed issue #97: register is deprecated in C++11
+- Fixed issue #96: CUDA issues
+- Added Windows CE detection #92
+- Added missing value_ptr for quaternions #99
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.4 - 2013-05-29
+- Fixed slerp when costheta is close to 1 #65
+- Fixed mat4x2 value_type constructor #70
+- Fixed glm.natvis for Visual C++ 12 #82
+- Added assert in inversesqrt to detect division by zero #61
+- Fixed missing swizzle operators #86
+- Fixed CUDA warnings #86
+- Fixed GLM natvis for VC11 #82
+- Fixed GLM_GTX_multiple with negative values #79
+- Fixed glm::perspective when zNear is zero #71
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.3 - 2013-03-20
+- Detected qualifier for Clang
+- Fixed C++11 mode for GCC, couldn't be enabled without MS extensions
+- Fixed squad, intermediate and exp quaternion functions
+- Fixed GTX_polar_coordinates euclidean function, takes a vec2 instead of a vec3
+- Clarify the license applying on the manual
+- Added a docx copy of the manual
+- Fixed GLM_GTX_matrix_interpolation
+- Fixed isnan and isinf on Android with Clang
+- Autodetected C++ version using __cplusplus value
+- Fixed mix for bool and bvec* third parameter
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.2 - 2013-02-14
+- Fixed compAdd from GTX_component_wise
+- Fixed SIMD support for Intel compiler on Windows
+- Fixed isnan and isinf for CUDA compiler
+- Fixed GLM_FORCE_RADIANS on glm::perspective
+- Fixed GCC warnings
+- Fixed packDouble2x32 on Xcode
+- Fixed mix for vec4 SSE implementation
+- Fixed 0x2013 dash character in comments that cause issue in Windows 
+  Japanese mode
+- Fixed documentation warnings
+- Fixed CUDA warnings
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.1 - 2012-12-22
+- Improved half support: -0.0 case and implicit conversions
+- Fixed Intel Composer Compiler support on Linux
+- Fixed interaction between quaternion and euler angles
+- Fixed GTC_constants build
+- Fixed GTX_multiple
+- Fixed quat slerp using mix function when cosTheta close to 1
+- Improved fvec4SIMD and fmat4x4SIMD implementations
+- Fixed assert messages
+- Added slerp and lerp quaternion functions and tests
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.4.0 - 2012-11-18
+- Added Intel Composer Compiler support
+- Promoted GTC_espilon extension
+- Promoted GTC_ulp extension
+- Removed GLM website from the source repository
+- Added GLM_FORCE_RADIANS so that all functions takes radians for arguments
+- Fixed detection of Clang and LLVM GCC on MacOS X
+- Added debugger visualizers for Visual C++ 2012
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.3.4](https://github.com/g-truc/glm/releases/tag/0.9.3.4) - 2012-06-30
+- Added SSE4 and AVX2 detection.
+- Removed VIRTREV_xstream and the incompatibility generated with GCC
+- Fixed C++11 compiler option for GCC
+- Removed MS language extension option for GCC (not fonctionnal)
+- Fixed bitfieldExtract for vector types
+- Fixed warnings
+- Fixed SSE includes
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.3 - 2012-05-10
+- Fixed isinf and isnan
+- Improved compatibility with Intel compiler
+- Added CMake test build options: SIMD, C++11, fast math and MS land ext
+- Fixed SIMD mat4 test on GCC
+- Fixed perspectiveFov implementation
+- Fixed matrixCompMult for none-square matrices
+- Fixed namespace issue on stream operators
+- Fixed various warnings
+- Added VC11 support
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.2 - 2012-03-15
+- Fixed doxygen documentation
+- Fixed Clang version detection
+- Fixed simd mat4 /= operator
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.1 - 2012-01-25
+- Fixed platform detection
+- Fixed warnings
+- Removed detail code from Doxygen doc
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.0 - 2012-01-09
+- Added CPP Check project
+- Fixed conflict with Windows headers
+- Fixed isinf implementation
+- Fixed Boost conflict
+- Fixed warnings
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.B - 2011-12-12
+- Added support for Chrone Native Client
+- Added epsilon constant
+- Removed value_size function from vector types
+- Fixed roundEven on GCC
+- Improved API documentation
+- Fixed modf implementation
+- Fixed step function accuracy
+- Fixed outerProduct
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.3.A - 2011-11-11
+- Improved doxygen documentation
+- Added new swizzle operators for C++11 compilers
+- Added new swizzle operators declared as functions
+- Added GLSL 4.20 length for vector and matrix types
+- Promoted GLM_GTC_noise extension: simplex, perlin, periodic noise functions
+- Promoted GLM_GTC_random extension: linear, gaussian and various random number 
+generation distribution
+- Added GLM_GTX_constants: provides useful constants
+- Added extension versioning
+- Removed many unused namespaces
+- Fixed half based type contructors
+- Added GLSL core noise functions
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.2.7](https://github.com/g-truc/glm/releases/tag/0.9.2.7) - 2011-10-24
+- Added more swizzling constructors
+- Added missing none-squared matrix products
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.2.6](https://github.com/g-truc/glm/releases/tag/0.9.2.6) - 2011-10-01
+- Fixed half based type build on old GCC
+- Fixed /W4 warnings on Visual C++
+- Fixed some missing l-value swizzle operators
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.5 - 2011-09-20
+- Fixed floatBitToXint functions
+- Fixed pack and unpack functions
+- Fixed round functions
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.4 - 2011-09-03
+- Fixed extensions bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.3 - 2011-06-08
+- Fixed build issues
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.2 - 2011-06-02
+- Expend matrix constructors flexibility
+- Improved quaternion implementation
+- Fixed many warnings across platforms and compilers
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.1 - 2011-05-24
+- Automatically detect CUDA support
+- Improved compiler detection
+- Fixed errors and warnings in VC with C++ extensions disabled
+- Fixed and tested GLM_GTX_vector_angle
+- Fixed and tested GLM_GTX_rotate_vector
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.2.0 - 2011-05-09
+- Added CUDA support
+- Added CTest test suite
+- Added GLM_GTX_ulp extension
+- Added GLM_GTX_noise extension
+- Added GLM_GTX_matrix_interpolation extension
+- Updated quaternion slerp interpolation
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.1.3](https://github.com/g-truc/glm/releases/tag/0.9.1.3) - 2011-05-07
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.1.2 - 2011-04-15
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.1.1 - 2011-03-17
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.1.0 - 2011-03-03
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.1.B - 2011-02-13
+- Updated API documentation
+- Improved SIMD implementation
+- Fixed Linux build
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.0.8](https://github.com/g-truc/glm/releases/tag/0.9.0.8) - 2011-02-13
+- Added quaternion product operator.
+- Clarify that GLM is a header only library.
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.1.A - 2011-01-31
+- Added SIMD support
+- Added new swizzle functions
+- Improved static assert error message with C++0x static_assert
+- New setup system
+- Reduced branching
+- Fixed trunc implementation
+
+--------------------------------------------------------------------------------
+#### [GLM 0.9.0.7](https://github.com/g-truc/glm/releases/tag/0.9.0.7) - 2011-01-30
+- Added GLSL 4.10 packing functions
+- Added == and != operators for every types.
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.6 - 2010-12-21
+- Many matrices bugs fixed
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.5 - 2010-11-01
+- Improved Clang support
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.4 - 2010-10-04
+- Added autoexp for GLM
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.3 - 2010-08-26
+- Fixed non-squared matrix operators
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.2 - 2010-07-08
+- Added GLM_GTX_int_10_10_10_2
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.1 - 2010-06-21
+- Fixed extensions errors
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.0.0 - 2010-05-25
+- Objective-C support
+- Fixed warnings
+- Updated documentation
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.B.2 - 2010-04-30
+- Git transition
+- Removed experimental code from releases
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.B.1 - 2010-04-03
+- Based on GLSL 4.00 specification
+- Added the new core functions
+- Added some implicit conversion support
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.A.2 - 2010-02-20
+- Improved some possible errors messages
+- Improved declarations and definitions match
+
+--------------------------------------------------------------------------------
+#### GLM 0.9.A.1 - 2010-02-09
+- Removed deprecated features
+- Internal redesign
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.4.4 final - 2010-01-25
+- Fixed warnings
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.4.3 final - 2009-11-16
+- Fixed Half float arithmetic
+- Fixed setup defines
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.4.2 final - 2009-10-19
+- Fixed Half float adds
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.4.1 final - 2009-10-05
+- Updated documentation
+- Fixed MacOS X build
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.4.0 final - 2009-09-16
+- Added GCC 4.4 and VC2010 support
+- Added matrix optimizations
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.5 final - 2009-08-11
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.4 final - 2009-08-10
+- Updated GLM according GLSL 1.5 spec
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.3 final - 2009-06-25
+- Fixed bugs
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.2 final - 2009-06-04
+- Added GLM_GTC_quaternion
+- Added GLM_GTC_type_precision
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.1 final - 2009-05-21
+- Fixed old extension system.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.3.0 final - 2009-05-06
+- Added stable extensions.
+- Added new extension system.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.2.3 final - 2009-04-01
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.2.2 final - 2009-02-24
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.2.1 final - 2009-02-13
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.2 final - 2009-01-21
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.1 final - 2008-10-30
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.0 final - 2008-10-23
+- New method to use extension.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.0 beta3 - 2008-10-10
+- Added CMake support for GLM tests.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.0 beta2 - 2008-10-04
+- Improved half scalars and vectors support.
+
+--------------------------------------------------------------------------------
+#### GLM 0.8.0 beta1 - 2008-09-26
+- Improved GLSL conformance
+- Added GLSL 1.30 support
+- Improved API documentation
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.6 final - 2008-08-08
+- Improved C++ standard comformance
+- Added Static assert for types checking
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.5 final - 2008-07-05
+- Added build message system with Visual Studio
+- Pedantic build with GCC
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.4 final - 2008-06-01
+- Added external dependencies system.
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.3 final - 2008-05-24
+- Fixed bugs
+- Added new extension group
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.2 final - 2008-04-27
+- Updated documentation
+- Added preprocessor options
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.1 final - 2008-03-24
+- Disabled half on GCC
+- Fixed extensions
+
+--------------------------------------------------------------------------------
+#### GLM 0.7.0 final - 2008-03-22
+- Changed to MIT license
+- Added new documentation
+
+--------------------------------------------------------------------------------
+#### GLM 0.6.4 - 2007-12-10
+- Fixed swizzle operators
+
+--------------------------------------------------------------------------------
+#### GLM 0.6.3 - 2007-11-05
+- Fixed type data accesses
+- Fixed 3DSMax sdk conflict
+
+--------------------------------------------------------------------------------
+#### GLM 0.6.2 - 2007-10-08
+- Fixed extension
+
+--------------------------------------------------------------------------------
+#### GLM 0.6.1 - 2007-10-07
+- Fixed a namespace error
+- Added extensions
+
+--------------------------------------------------------------------------------
+#### GLM 0.6.0 : 2007-09-16
+- Added new extension namespace mecanium
+- Added Automatic compiler detection
+
+--------------------------------------------------------------------------------
+#### GLM 0.5.1 - 2007-02-19
+- Fixed swizzle operators
+
+--------------------------------------------------------------------------------
+#### GLM 0.5.0 - 2007-01-06
+- Upgrated to GLSL 1.2
+- Added swizzle operators
+- Added setup settings
+
+--------------------------------------------------------------------------------
+#### GLM 0.4.1 - 2006-05-22
+- Added OpenGL examples
+
+--------------------------------------------------------------------------------
+#### GLM 0.4.0 - 2006-05-17
+- Added missing operators to vec* and mat*
+- Added first GLSL 1.2 features
+- Fixed windows.h before glm.h when windows.h required
+
+--------------------------------------------------------------------------------
+#### GLM 0.3.2 - 2006-04-21
+- Fixed texcoord components access.
+- Fixed mat4 and imat4 division operators.
+
+--------------------------------------------------------------------------------
+#### GLM 0.3.1 - 2006-03-28
+- Added GCC 4.0 support under MacOS X.
+- Added GCC 4.0 and 4.1 support under Linux.
+- Added code optimisations.
+
+--------------------------------------------------------------------------------
+#### GLM 0.3 - 2006-02-19
+- Improved GLSL type conversion and construction compliance.
+- Added experimental extensions.
+- Added Doxygen Documentation.
+- Added code optimisations.
+- Fixed bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.2 - 2005-05-05
+- Improve adaptative from GLSL.
+- Add experimental extensions based on OpenGL extension process.
+- Fixe bugs.
+
+--------------------------------------------------------------------------------
+#### GLM 0.1 - 2005-02-21
+- Add vec2, vec3, vec4 GLSL types
+- Add ivec2, ivec3, ivec4 GLSL types
+- Add bvec2, bvec3, bvec4 GLSL types
+- Add mat2, mat3, mat4 GLSL types
+- Add almost all functions
+
diff --git a/core/deps/hash-library/README.md b/core/deps/hash-library/README.md
new file mode 100644 (file)
index 0000000..5515bd4
--- /dev/null
@@ -0,0 +1,24 @@
+# hash-library - MD5
+
+We are using the MD5 functionality found in Stephan Brumme's
+C++ Hashing Library. 
+
+http://create.stephan-brumme.com/hash-library/
+
+MD5s are computed in one place in Tangram ES, mbtilesTileTask.cpp.
+The raw data contents of a tile are hashed to create and MD5 hash.
+This hash is a key between the map and images table in an MBTiles database.
+
+## Git Repo
+
+http://create.stephan-brumme.com/hash-library/.git
+
+## Notes
+
+I commented out the `#include <endian.h>` in md5.cpp, because
+different platforms may or may not have this header. In fact,
+Mac OS X has it as `#include<machine/endian.h>`. Without this,
+md5.cpp assumes that we are operating as little endian. This should
+be addressed if we plan on supporting a big endian machine.
+
+http://create.stephan-brumme.com/disclaimer.html
diff --git a/core/deps/hash-library/md5.cpp b/core/deps/hash-library/md5.cpp
new file mode 100644 (file)
index 0000000..98d503b
--- /dev/null
@@ -0,0 +1,380 @@
+// //////////////////////////////////////////////////////////
+// md5.cpp
+// Copyright (c) 2014,2015 Stephan Brumme. All rights reserved.
+// see http://create.stephan-brumme.com/disclaimer.html
+//
+
+#include "md5.h"
+
+#ifndef _MSC_VER
+//#include <endian.h>
+#endif
+
+
+/// same as reset()
+MD5::MD5()
+{
+  reset();
+}
+
+
+/// restart
+void MD5::reset()
+{
+  m_numBytes   = 0;
+  m_bufferSize = 0;
+
+  // according to RFC 1321
+  m_hash[0] = 0x67452301;
+  m_hash[1] = 0xefcdab89;
+  m_hash[2] = 0x98badcfe;
+  m_hash[3] = 0x10325476;
+}
+
+
+namespace
+{
+  // mix functions for processBlock()
+  inline uint32_t f1(uint32_t b, uint32_t c, uint32_t d)
+  {
+    return d ^ (b & (c ^ d)); // original: f = (b & c) | ((~b) & d);
+  }
+
+  inline uint32_t f2(uint32_t b, uint32_t c, uint32_t d)
+  {
+    return c ^ (d & (b ^ c)); // original: f = (b & d) | (c & (~d));
+  }
+
+  inline uint32_t f3(uint32_t b, uint32_t c, uint32_t d)
+  {
+    return b ^ c ^ d;
+  }
+
+  inline uint32_t f4(uint32_t b, uint32_t c, uint32_t d)
+  {
+    return c ^ (b | ~d);
+  }
+
+  inline uint32_t rotate(uint32_t a, uint32_t c)
+  {
+    return (a << c) | (a >> (32 - c));
+  }
+
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
+  inline uint32_t swap(uint32_t x)
+  {
+#if defined(__GNUC__) || defined(__clang__)
+    return __builtin_bswap32(x);
+#endif
+#ifdef MSC_VER
+    return _byteswap_ulong(x);
+#endif
+
+    return (x >> 24) |
+          ((x >>  8) & 0x0000FF00) |
+          ((x <<  8) & 0x00FF0000) |
+           (x << 24);
+  }
+#endif
+}
+
+
+/// process 64 bytes
+void MD5::processBlock(const void* data)
+{
+  // get last hash
+  uint32_t a = m_hash[0];
+  uint32_t b = m_hash[1];
+  uint32_t c = m_hash[2];
+  uint32_t d = m_hash[3];
+
+  // data represented as 16x 32-bit words
+  const uint32_t* words = (uint32_t*) data;
+
+  // computations are little endian, swap data if necessary
+#if defined(__BYTE_ORDER) && (__BYTE_ORDER != 0) && (__BYTE_ORDER == __BIG_ENDIAN)
+#define LITTLEENDIAN(x) swap(x)
+#else
+#define LITTLEENDIAN(x) (x)
+#endif
+
+  // first round
+  uint32_t word0  = LITTLEENDIAN(words[ 0]);
+  a = rotate(a + f1(b,c,d) + word0  + 0xd76aa478,  7) + b;
+  uint32_t word1  = LITTLEENDIAN(words[ 1]);
+  d = rotate(d + f1(a,b,c) + word1  + 0xe8c7b756, 12) + a;
+  uint32_t word2  = LITTLEENDIAN(words[ 2]);
+  c = rotate(c + f1(d,a,b) + word2  + 0x242070db, 17) + d;
+  uint32_t word3  = LITTLEENDIAN(words[ 3]);
+  b = rotate(b + f1(c,d,a) + word3  + 0xc1bdceee, 22) + c;
+
+  uint32_t word4  = LITTLEENDIAN(words[ 4]);
+  a = rotate(a + f1(b,c,d) + word4  + 0xf57c0faf,  7) + b;
+  uint32_t word5  = LITTLEENDIAN(words[ 5]);
+  d = rotate(d + f1(a,b,c) + word5  + 0x4787c62a, 12) + a;
+  uint32_t word6  = LITTLEENDIAN(words[ 6]);
+  c = rotate(c + f1(d,a,b) + word6  + 0xa8304613, 17) + d;
+  uint32_t word7  = LITTLEENDIAN(words[ 7]);
+  b = rotate(b + f1(c,d,a) + word7  + 0xfd469501, 22) + c;
+
+  uint32_t word8  = LITTLEENDIAN(words[ 8]);
+  a = rotate(a + f1(b,c,d) + word8  + 0x698098d8,  7) + b;
+  uint32_t word9  = LITTLEENDIAN(words[ 9]);
+  d = rotate(d + f1(a,b,c) + word9  + 0x8b44f7af, 12) + a;
+  uint32_t word10 = LITTLEENDIAN(words[10]);
+  c = rotate(c + f1(d,a,b) + word10 + 0xffff5bb1, 17) + d;
+  uint32_t word11 = LITTLEENDIAN(words[11]);
+  b = rotate(b + f1(c,d,a) + word11 + 0x895cd7be, 22) + c;
+
+  uint32_t word12 = LITTLEENDIAN(words[12]);
+  a = rotate(a + f1(b,c,d) + word12 + 0x6b901122,  7) + b;
+  uint32_t word13 = LITTLEENDIAN(words[13]);
+  d = rotate(d + f1(a,b,c) + word13 + 0xfd987193, 12) + a;
+  uint32_t word14 = LITTLEENDIAN(words[14]);
+  c = rotate(c + f1(d,a,b) + word14 + 0xa679438e, 17) + d;
+  uint32_t word15 = LITTLEENDIAN(words[15]);
+  b = rotate(b + f1(c,d,a) + word15 + 0x49b40821, 22) + c;
+
+  // second round
+  a = rotate(a + f2(b,c,d) + word1  + 0xf61e2562,  5) + b;
+  d = rotate(d + f2(a,b,c) + word6  + 0xc040b340,  9) + a;
+  c = rotate(c + f2(d,a,b) + word11 + 0x265e5a51, 14) + d;
+  b = rotate(b + f2(c,d,a) + word0  + 0xe9b6c7aa, 20) + c;
+
+  a = rotate(a + f2(b,c,d) + word5  + 0xd62f105d,  5) + b;
+  d = rotate(d + f2(a,b,c) + word10 + 0x02441453,  9) + a;
+  c = rotate(c + f2(d,a,b) + word15 + 0xd8a1e681, 14) + d;
+  b = rotate(b + f2(c,d,a) + word4  + 0xe7d3fbc8, 20) + c;
+
+  a = rotate(a + f2(b,c,d) + word9  + 0x21e1cde6,  5) + b;
+  d = rotate(d + f2(a,b,c) + word14 + 0xc33707d6,  9) + a;
+  c = rotate(c + f2(d,a,b) + word3  + 0xf4d50d87, 14) + d;
+  b = rotate(b + f2(c,d,a) + word8  + 0x455a14ed, 20) + c;
+
+  a = rotate(a + f2(b,c,d) + word13 + 0xa9e3e905,  5) + b;
+  d = rotate(d + f2(a,b,c) + word2  + 0xfcefa3f8,  9) + a;
+  c = rotate(c + f2(d,a,b) + word7  + 0x676f02d9, 14) + d;
+  b = rotate(b + f2(c,d,a) + word12 + 0x8d2a4c8a, 20) + c;
+
+  // third round
+  a = rotate(a + f3(b,c,d) + word5  + 0xfffa3942,  4) + b;
+  d = rotate(d + f3(a,b,c) + word8  + 0x8771f681, 11) + a;
+  c = rotate(c + f3(d,a,b) + word11 + 0x6d9d6122, 16) + d;
+  b = rotate(b + f3(c,d,a) + word14 + 0xfde5380c, 23) + c;
+
+  a = rotate(a + f3(b,c,d) + word1  + 0xa4beea44,  4) + b;
+  d = rotate(d + f3(a,b,c) + word4  + 0x4bdecfa9, 11) + a;
+  c = rotate(c + f3(d,a,b) + word7  + 0xf6bb4b60, 16) + d;
+  b = rotate(b + f3(c,d,a) + word10 + 0xbebfbc70, 23) + c;
+
+  a = rotate(a + f3(b,c,d) + word13 + 0x289b7ec6,  4) + b;
+  d = rotate(d + f3(a,b,c) + word0  + 0xeaa127fa, 11) + a;
+  c = rotate(c + f3(d,a,b) + word3  + 0xd4ef3085, 16) + d;
+  b = rotate(b + f3(c,d,a) + word6  + 0x04881d05, 23) + c;
+
+  a = rotate(a + f3(b,c,d) + word9  + 0xd9d4d039,  4) + b;
+  d = rotate(d + f3(a,b,c) + word12 + 0xe6db99e5, 11) + a;
+  c = rotate(c + f3(d,a,b) + word15 + 0x1fa27cf8, 16) + d;
+  b = rotate(b + f3(c,d,a) + word2  + 0xc4ac5665, 23) + c;
+
+  // fourth round
+  a = rotate(a + f4(b,c,d) + word0  + 0xf4292244,  6) + b;
+  d = rotate(d + f4(a,b,c) + word7  + 0x432aff97, 10) + a;
+  c = rotate(c + f4(d,a,b) + word14 + 0xab9423a7, 15) + d;
+  b = rotate(b + f4(c,d,a) + word5  + 0xfc93a039, 21) + c;
+
+  a = rotate(a + f4(b,c,d) + word12 + 0x655b59c3,  6) + b;
+  d = rotate(d + f4(a,b,c) + word3  + 0x8f0ccc92, 10) + a;
+  c = rotate(c + f4(d,a,b) + word10 + 0xffeff47d, 15) + d;
+  b = rotate(b + f4(c,d,a) + word1  + 0x85845dd1, 21) + c;
+
+  a = rotate(a + f4(b,c,d) + word8  + 0x6fa87e4f,  6) + b;
+  d = rotate(d + f4(a,b,c) + word15 + 0xfe2ce6e0, 10) + a;
+  c = rotate(c + f4(d,a,b) + word6  + 0xa3014314, 15) + d;
+  b = rotate(b + f4(c,d,a) + word13 + 0x4e0811a1, 21) + c;
+
+  a = rotate(a + f4(b,c,d) + word4  + 0xf7537e82,  6) + b;
+  d = rotate(d + f4(a,b,c) + word11 + 0xbd3af235, 10) + a;
+  c = rotate(c + f4(d,a,b) + word2  + 0x2ad7d2bb, 15) + d;
+  b = rotate(b + f4(c,d,a) + word9  + 0xeb86d391, 21) + c;
+
+  // update hash
+  m_hash[0] += a;
+  m_hash[1] += b;
+  m_hash[2] += c;
+  m_hash[3] += d;
+}
+
+
+/// add arbitrary number of bytes
+void MD5::add(const void* data, size_t numBytes)
+{
+  const uint8_t* current = (const uint8_t*) data;
+
+  if (m_bufferSize > 0)
+  {
+    while (numBytes > 0 && m_bufferSize < BlockSize)
+    {
+      m_buffer[m_bufferSize++] = *current++;
+      numBytes--;
+    }
+  }
+
+  // full buffer
+  if (m_bufferSize == BlockSize)
+  {
+    processBlock(m_buffer);
+    m_numBytes  += BlockSize;
+    m_bufferSize = 0;
+  }
+
+  // no more data ?
+  if (numBytes == 0)
+    return;
+
+  // process full blocks
+  while (numBytes >= BlockSize)
+  {
+    processBlock(current);
+    current    += BlockSize;
+    m_numBytes += BlockSize;
+    numBytes   -= BlockSize;
+  }
+
+  // keep remaining bytes in buffer
+  while (numBytes > 0)
+  {
+    m_buffer[m_bufferSize++] = *current++;
+    numBytes--;
+  }
+}
+
+
+/// process final block, less than 64 bytes
+void MD5::processBuffer()
+{
+  // the input bytes are considered as bits strings, where the first bit is the most significant bit of the byte
+
+  // - append "1" bit to message
+  // - append "0" bits until message length in bit mod 512 is 448
+  // - append length as 64 bit integer
+
+  // number of bits
+  size_t paddedLength = m_bufferSize * 8;
+
+  // plus one bit set to 1 (always appended)
+  paddedLength++;
+
+  // number of bits must be (numBits % 512) = 448
+  size_t lower11Bits = paddedLength & 511;
+  if (lower11Bits <= 448)
+    paddedLength +=       448 - lower11Bits;
+  else
+    paddedLength += 512 + 448 - lower11Bits;
+  // convert from bits to bytes
+  paddedLength /= 8;
+
+  // only needed if additional data flows over into a second block
+  unsigned char extra[BlockSize];
+
+  // append a "1" bit, 128 => binary 10000000
+  if (m_bufferSize < BlockSize)
+    m_buffer[m_bufferSize] = 128;
+  else
+    extra[0] = 128;
+
+  size_t i;
+  for (i = m_bufferSize + 1; i < BlockSize; i++)
+    m_buffer[i] = 0;
+  for (; i < paddedLength; i++)
+    extra[i - BlockSize] = 0;
+
+  // add message length in bits as 64 bit number
+  uint64_t msgBits = 8 * (m_numBytes + m_bufferSize);
+  // find right position
+  unsigned char* addLength;
+  if (paddedLength < BlockSize)
+    addLength = m_buffer + paddedLength;
+  else
+    addLength = extra + paddedLength - BlockSize;
+
+  // must be little endian
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF; msgBits >>= 8;
+  *addLength++ = msgBits & 0xFF;
+
+  // process blocks
+  processBlock(m_buffer);
+  // flowed over into a second block ?
+  if (paddedLength > BlockSize)
+    processBlock(extra);
+}
+
+
+/// return latest hash as 32 hex characters
+std::string MD5::getHash()
+{
+  // compute hash (as raw bytes)
+  unsigned char rawHash[HashBytes];
+  getHash(rawHash);
+
+  // convert to hex string
+  std::string result;
+  result.reserve(2 * HashBytes);
+  for (int i = 0; i < HashBytes; i++)
+  {
+    static const char dec2hex[16+1] = "0123456789abcdef";
+    result += dec2hex[(rawHash[i] >> 4) & 15];
+    result += dec2hex[ rawHash[i]       & 15];
+  }
+
+  return result;
+}
+
+
+/// return latest hash as bytes
+void MD5::getHash(unsigned char buffer[MD5::HashBytes])
+{
+  // save old hash if buffer is partially filled
+  uint32_t oldHash[HashValues];
+  for (int i = 0; i < HashValues; i++)
+    oldHash[i] = m_hash[i];
+
+  // process remaining bytes
+  processBuffer();
+
+  unsigned char* current = buffer;
+  for (int i = 0; i < HashValues; i++)
+  {
+    *current++ =  m_hash[i]        & 0xFF;
+    *current++ = (m_hash[i] >>  8) & 0xFF;
+    *current++ = (m_hash[i] >> 16) & 0xFF;
+    *current++ = (m_hash[i] >> 24) & 0xFF;
+
+    // restore old hash
+    m_hash[i] = oldHash[i];
+  }
+}
+
+
+/// compute MD5 of a memory block
+std::string MD5::operator()(const void* data, size_t numBytes)
+{
+  reset();
+  add(data, numBytes);
+  return getHash();
+}
+
+
+/// compute MD5 of a string, excluding final zero
+std::string MD5::operator()(const std::string& text)
+{
+  reset();
+  add(text.c_str(), text.size());
+  return getHash();
+}
diff --git a/core/deps/hash-library/md5.h b/core/deps/hash-library/md5.h
new file mode 100644 (file)
index 0000000..f53e2d9
--- /dev/null
@@ -0,0 +1,78 @@
+// //////////////////////////////////////////////////////////
+// md5.h
+// Copyright (c) 2014 Stephan Brumme. All rights reserved.
+// see http://create.stephan-brumme.com/disclaimer.html
+//
+
+#pragma once
+
+//#include "hash.h"
+#include <string>
+
+// define fixed size integer types
+#ifdef _MSC_VER
+// Windows
+typedef unsigned __int8  uint8_t;
+typedef unsigned __int32 uint32_t;
+typedef unsigned __int64 uint64_t;
+#else
+// GCC
+#include <stdint.h>
+#endif
+
+
+/// compute MD5 hash
+/** Usage:
+    MD5 md5;
+    std::string myHash  = md5("Hello World");     // std::string
+    std::string myHash2 = md5("How are you", 11); // arbitrary data, 11 bytes
+
+    // or in a streaming fashion:
+
+    MD5 md5;
+    while (more data available)
+      md5.add(pointer to fresh data, number of new bytes);
+    std::string myHash3 = md5.getHash();
+  */
+class MD5 //: public Hash
+{
+public:
+  /// split into 64 byte blocks (=> 512 bits), hash is 16 bytes long
+  enum { BlockSize = 512 / 8, HashBytes = 16 };
+
+  /// same as reset()
+  MD5();
+
+  /// compute MD5 of a memory block
+  std::string operator()(const void* data, size_t numBytes);
+  /// compute MD5 of a string, excluding final zero
+  std::string operator()(const std::string& text);
+
+  /// add arbitrary number of bytes
+  void add(const void* data, size_t numBytes);
+
+  /// return latest hash as 32 hex characters
+  std::string getHash();
+  /// return latest hash as bytes
+  void        getHash(unsigned char buffer[HashBytes]);
+
+  /// restart
+  void reset();
+
+private:
+  /// process 64 bytes
+  void processBlock(const void* data);
+  /// process everything left in the internal buffer
+  void processBuffer();
+
+  /// size of processed data in bytes
+  uint64_t m_numBytes;
+  /// valid bytes in m_buffer
+  size_t   m_bufferSize;
+  /// bytes not processed yet
+  uint8_t  m_buffer[BlockSize];
+
+  enum { HashValues = HashBytes / 4 };
+  /// hash, stored as integers
+  uint32_t m_hash[HashValues];
+};
diff --git a/core/deps/mapbox/geojsonvt_custom_tags.hpp b/core/deps/mapbox/geojsonvt_custom_tags.hpp
new file mode 100644 (file)
index 0000000..aa8bc06
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "data/properties.h"
+#include "data/propertyItem.h"
+
+#include <memory>
+
+namespace mapbox {
+namespace util {
+namespace geojsonvt {
+
+struct Tags {
+    Tags() : map(std::make_shared<Tangram::Properties>()){}
+
+    Tags(std::shared_ptr<Tangram::Properties> _props) :
+        map(std::move(_props)){}
+
+    Tags(const Tangram::Properties& _props) :
+        map(std::make_shared<Tangram::Properties>(_props)){}
+
+    std::shared_ptr<Tangram::Properties> map;
+
+    void emplace(std::string key, std::string value) {
+        map->set(std::move(key), std::move(value));
+    }
+
+};
+
+} // namespace geojsonvt
+} // namespace util
+} // namespace mapbox
diff --git a/core/deps/mapbox/variant.hpp b/core/deps/mapbox/variant.hpp
new file mode 100644 (file)
index 0000000..3cd68be
--- /dev/null
@@ -0,0 +1,2 @@
+// Substitute for Mapbox mason-installed header
+#include "variant/include/mapbox/variant.hpp"
diff --git a/core/deps/miniz/miniz.c b/core/deps/miniz/miniz.c
new file mode 100644 (file)
index 0000000..c25d0fd
--- /dev/null
@@ -0,0 +1,7241 @@
+/**************************************************************************
+ *
+ * Copyright 2013-2014 RAD Game Tools and Valve Software
+ * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+#include  "miniz.h"
+
+typedef unsigned char mz_validate_uint16[sizeof(mz_uint16) == 2 ? 1 : -1];
+typedef unsigned char mz_validate_uint32[sizeof(mz_uint32) == 4 ? 1 : -1];
+typedef unsigned char mz_validate_uint64[sizeof(mz_uint64) == 8 ? 1 : -1];
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- zlib-style API's */
+
+mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len)
+{
+    mz_uint32 i, s1 = (mz_uint32)(adler & 0xffff), s2 = (mz_uint32)(adler >> 16);
+    size_t block_len = buf_len % 5552;
+    if (!ptr)
+        return MZ_ADLER32_INIT;
+    while (buf_len)
+    {
+        for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+        {
+            s1 += ptr[0], s2 += s1;
+            s1 += ptr[1], s2 += s1;
+            s1 += ptr[2], s2 += s1;
+            s1 += ptr[3], s2 += s1;
+            s1 += ptr[4], s2 += s1;
+            s1 += ptr[5], s2 += s1;
+            s1 += ptr[6], s2 += s1;
+            s1 += ptr[7], s2 += s1;
+        }
+        for (; i < block_len; ++i)
+            s1 += *ptr++, s2 += s1;
+        s1 %= 65521U, s2 %= 65521U;
+        buf_len -= block_len;
+        block_len = 5552;
+    }
+    return (s2 << 16) + s1;
+}
+
+/* Karl Malbrain's compact CRC-32. See "A compact CCITT crc16 and crc32 C implementation that balances processor cache usage against speed": http://www.geocities.com/malbrain/ */
+#if 0
+    mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
+    {
+        static const mz_uint32 s_crc32[16] = { 0, 0x1db71064, 0x3b6e20c8, 0x26d930ac, 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
+                                               0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c, 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c };
+        mz_uint32 crcu32 = (mz_uint32)crc;
+        if (!ptr)
+            return MZ_CRC32_INIT;
+        crcu32 = ~crcu32;
+        while (buf_len--)
+        {
+            mz_uint8 b = *ptr++;
+            crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b & 0xF)];
+            crcu32 = (crcu32 >> 4) ^ s_crc32[(crcu32 & 0xF) ^ (b >> 4)];
+        }
+        return ~crcu32;
+    }
+#else
+/* Faster, but larger CPU cache footprint.
+ */
+mz_ulong mz_crc32(mz_ulong crc, const mz_uint8 *ptr, size_t buf_len)
+{
+    static const mz_uint32 s_crc_table[256] =
+        {
+            0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, 0x706AF48F, 0xE963A535,
+            0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD,
+            0xE7B82D07, 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, 0x1ADAD47D,
+            0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC,
+            0x14015C4F, 0x63066CD9, 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
+            0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, 0x35B5A8FA, 0x42B2986C,
+            0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC,
+            0x51DE003A, 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, 0xB8BDA50F,
+            0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, 0x2F6F7C87, 0x58684C11, 0xC1611DAB,
+            0xB6662D3D, 0x76DC4190, 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
+            0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, 0xE10E9818, 0x7F6A0DBB,
+            0x086D3D2D, 0x91646C97, 0xE6635C01, 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E,
+            0x6C0695ED, 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, 0x8BBEB8EA,
+            0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, 0xFBD44C65, 0x4DB26158, 0x3AB551CE,
+            0xA3BC0074, 0xD4BB30E2, 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
+            0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, 0xAA0A4C5F, 0xDD0D7CC9,
+            0x5005713C, 0x270241AA, 0xBE0B1010, 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409,
+            0xCE61E49F, 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, 0x2EB40D81,
+            0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, 0x03B6E20C, 0x74B1D29A, 0xEAD54739,
+            0x9DD277AF, 0x04DB2615, 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
+            0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, 0x8708A3D2, 0x1E01F268,
+            0x6906C2FE, 0xF762575D, 0x806567CB, 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0,
+            0x10DA7A5A, 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, 0xD6D6A3E8,
+            0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, 0xA6BC5767, 0x3FB506DD, 0x48B2364B,
+            0xD80D2BDA, 0xAF0A1B4C, 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
+            0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, 0xCC0C7795, 0xBB0B4703,
+            0x220216B9, 0x5505262F, 0xC5BA3BBE, 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7,
+            0xB5D0CF31, 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, 0x026D930A,
+            0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE,
+            0x0CB61B38, 0x92D28E9B, 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
+            0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, 0x18B74777, 0x88085AE6,
+            0xFF0F6A70, 0x66063BCA, 0x11010B5C, 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45,
+            0xA00AE278, 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, 0x4969474D,
+            0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5,
+            0x47B2CF7F, 0x30B5FFE9, 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
+            0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, 0x5D681B02, 0x2A6F2B94,
+            0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, 0x2D02EF8D
+        };
+
+    mz_uint32 crc32 = (mz_uint32)crc ^ 0xFFFFFFFF;
+    const mz_uint8 *pByte_buf = (const mz_uint8 *)ptr;
+
+    while (buf_len >= 4)
+    {
+        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
+        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[1]) & 0xFF];
+        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[2]) & 0xFF];
+        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[3]) & 0xFF];
+        pByte_buf += 4;
+        buf_len -= 4;
+    }
+
+    while (buf_len)
+    {
+        crc32 = (crc32 >> 8) ^ s_crc_table[(crc32 ^ pByte_buf[0]) & 0xFF];
+        ++pByte_buf;
+        --buf_len;
+    }
+
+    return ~crc32;
+}
+#endif
+
+void mz_free(void *p)
+{
+    MZ_FREE(p);
+}
+
+void *miniz_def_alloc_func(void *opaque, size_t items, size_t size)
+{
+    (void)opaque, (void)items, (void)size;
+    return MZ_MALLOC(items * size);
+}
+void miniz_def_free_func(void *opaque, void *address)
+{
+    (void)opaque, (void)address;
+    MZ_FREE(address);
+}
+void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size)
+{
+    (void)opaque, (void)address, (void)items, (void)size;
+    return MZ_REALLOC(address, items * size);
+}
+
+const char *mz_version(void)
+{
+    return MZ_VERSION;
+}
+
+#ifndef MINIZ_NO_ZLIB_APIS
+
+int mz_deflateInit(mz_streamp pStream, int level)
+{
+    return mz_deflateInit2(pStream, level, MZ_DEFLATED, MZ_DEFAULT_WINDOW_BITS, 9, MZ_DEFAULT_STRATEGY);
+}
+
+int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy)
+{
+    tdefl_compressor *pComp;
+    mz_uint comp_flags = TDEFL_COMPUTE_ADLER32 | tdefl_create_comp_flags_from_zip_params(level, window_bits, strategy);
+
+    if (!pStream)
+        return MZ_STREAM_ERROR;
+    if ((method != MZ_DEFLATED) || ((mem_level < 1) || (mem_level > 9)) || ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS)))
+        return MZ_PARAM_ERROR;
+
+    pStream->data_type = 0;
+    pStream->adler = MZ_ADLER32_INIT;
+    pStream->msg = NULL;
+    pStream->reserved = 0;
+    pStream->total_in = 0;
+    pStream->total_out = 0;
+    if (!pStream->zalloc)
+        pStream->zalloc = miniz_def_alloc_func;
+    if (!pStream->zfree)
+        pStream->zfree = miniz_def_free_func;
+
+    pComp = (tdefl_compressor *)pStream->zalloc(pStream->opaque, 1, sizeof(tdefl_compressor));
+    if (!pComp)
+        return MZ_MEM_ERROR;
+
+    pStream->state = (struct mz_internal_state *)pComp;
+
+    if (tdefl_init(pComp, NULL, NULL, comp_flags) != TDEFL_STATUS_OKAY)
+    {
+        mz_deflateEnd(pStream);
+        return MZ_PARAM_ERROR;
+    }
+
+    return MZ_OK;
+}
+
+int mz_deflateReset(mz_streamp pStream)
+{
+    if ((!pStream) || (!pStream->state) || (!pStream->zalloc) || (!pStream->zfree))
+        return MZ_STREAM_ERROR;
+    pStream->total_in = pStream->total_out = 0;
+    tdefl_init((tdefl_compressor *)pStream->state, NULL, NULL, ((tdefl_compressor *)pStream->state)->m_flags);
+    return MZ_OK;
+}
+
+int mz_deflate(mz_streamp pStream, int flush)
+{
+    size_t in_bytes, out_bytes;
+    mz_ulong orig_total_in, orig_total_out;
+    int mz_status = MZ_OK;
+
+    if ((!pStream) || (!pStream->state) || (flush < 0) || (flush > MZ_FINISH) || (!pStream->next_out))
+        return MZ_STREAM_ERROR;
+    if (!pStream->avail_out)
+        return MZ_BUF_ERROR;
+
+    if (flush == MZ_PARTIAL_FLUSH)
+        flush = MZ_SYNC_FLUSH;
+
+    if (((tdefl_compressor *)pStream->state)->m_prev_return_status == TDEFL_STATUS_DONE)
+        return (flush == MZ_FINISH) ? MZ_STREAM_END : MZ_BUF_ERROR;
+
+    orig_total_in = pStream->total_in;
+    orig_total_out = pStream->total_out;
+    for (;;)
+    {
+        tdefl_status defl_status;
+        in_bytes = pStream->avail_in;
+        out_bytes = pStream->avail_out;
+
+        defl_status = tdefl_compress((tdefl_compressor *)pStream->state, pStream->next_in, &in_bytes, pStream->next_out, &out_bytes, (tdefl_flush)flush);
+        pStream->next_in += (mz_uint)in_bytes;
+        pStream->avail_in -= (mz_uint)in_bytes;
+        pStream->total_in += (mz_uint)in_bytes;
+        pStream->adler = tdefl_get_adler32((tdefl_compressor *)pStream->state);
+
+        pStream->next_out += (mz_uint)out_bytes;
+        pStream->avail_out -= (mz_uint)out_bytes;
+        pStream->total_out += (mz_uint)out_bytes;
+
+        if (defl_status < 0)
+        {
+            mz_status = MZ_STREAM_ERROR;
+            break;
+        }
+        else if (defl_status == TDEFL_STATUS_DONE)
+        {
+            mz_status = MZ_STREAM_END;
+            break;
+        }
+        else if (!pStream->avail_out)
+            break;
+        else if ((!pStream->avail_in) && (flush != MZ_FINISH))
+        {
+            if ((flush) || (pStream->total_in != orig_total_in) || (pStream->total_out != orig_total_out))
+                break;
+            return MZ_BUF_ERROR; /* Can't make forward progress without some input.
+ */
+        }
+    }
+    return mz_status;
+}
+
+int mz_deflateEnd(mz_streamp pStream)
+{
+    if (!pStream)
+        return MZ_STREAM_ERROR;
+    if (pStream->state)
+    {
+        pStream->zfree(pStream->opaque, pStream->state);
+        pStream->state = NULL;
+    }
+    return MZ_OK;
+}
+
+mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len)
+{
+    (void)pStream;
+    /* This is really over conservative. (And lame, but it's actually pretty tricky to compute a true upper bound given the way tdefl's blocking works.) */
+    return MZ_MAX(128 + (source_len * 110) / 100, 128 + source_len + ((source_len / (31 * 1024)) + 1) * 5);
+}
+
+int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level)
+{
+    int status;
+    mz_stream stream;
+    memset(&stream, 0, sizeof(stream));
+
+    /* In case mz_ulong is 64-bits (argh I hate longs). */
+    if ((source_len | *pDest_len) > 0xFFFFFFFFU)
+        return MZ_PARAM_ERROR;
+
+    stream.next_in = pSource;
+    stream.avail_in = (mz_uint32)source_len;
+    stream.next_out = pDest;
+    stream.avail_out = (mz_uint32) * pDest_len;
+
+    status = mz_deflateInit(&stream, level);
+    if (status != MZ_OK)
+        return status;
+
+    status = mz_deflate(&stream, MZ_FINISH);
+    if (status != MZ_STREAM_END)
+    {
+        mz_deflateEnd(&stream);
+        return (status == MZ_OK) ? MZ_BUF_ERROR : status;
+    }
+
+    *pDest_len = stream.total_out;
+    return mz_deflateEnd(&stream);
+}
+
+int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
+{
+    return mz_compress2(pDest, pDest_len, pSource, source_len, MZ_DEFAULT_COMPRESSION);
+}
+
+mz_ulong mz_compressBound(mz_ulong source_len)
+{
+    return mz_deflateBound(NULL, source_len);
+}
+
+typedef struct
+{
+    tinfl_decompressor m_decomp;
+    mz_uint m_dict_ofs, m_dict_avail, m_first_call, m_has_flushed;
+    int m_window_bits;
+    mz_uint8 m_dict[TINFL_LZ_DICT_SIZE];
+    tinfl_status m_last_status;
+} inflate_state;
+
+int mz_inflateInit2(mz_streamp pStream, int window_bits)
+{
+    inflate_state *pDecomp;
+    if (!pStream)
+        return MZ_STREAM_ERROR;
+    if ((window_bits != MZ_DEFAULT_WINDOW_BITS) && (-window_bits != MZ_DEFAULT_WINDOW_BITS))
+        return MZ_PARAM_ERROR;
+
+    pStream->data_type = 0;
+    pStream->adler = 0;
+    pStream->msg = NULL;
+    pStream->total_in = 0;
+    pStream->total_out = 0;
+    pStream->reserved = 0;
+    if (!pStream->zalloc)
+        pStream->zalloc = miniz_def_alloc_func;
+    if (!pStream->zfree)
+        pStream->zfree = miniz_def_free_func;
+
+    pDecomp = (inflate_state *)pStream->zalloc(pStream->opaque, 1, sizeof(inflate_state));
+    if (!pDecomp)
+        return MZ_MEM_ERROR;
+
+    pStream->state = (struct mz_internal_state *)pDecomp;
+
+    tinfl_init(&pDecomp->m_decomp);
+    pDecomp->m_dict_ofs = 0;
+    pDecomp->m_dict_avail = 0;
+    pDecomp->m_last_status = TINFL_STATUS_NEEDS_MORE_INPUT;
+    pDecomp->m_first_call = 1;
+    pDecomp->m_has_flushed = 0;
+    pDecomp->m_window_bits = window_bits;
+
+    return MZ_OK;
+}
+
+int mz_inflateInit(mz_streamp pStream)
+{
+    return mz_inflateInit2(pStream, MZ_DEFAULT_WINDOW_BITS);
+}
+
+int mz_inflate(mz_streamp pStream, int flush)
+{
+    inflate_state *pState;
+    mz_uint n, first_call, decomp_flags = TINFL_FLAG_COMPUTE_ADLER32;
+    size_t in_bytes, out_bytes, orig_avail_in;
+    tinfl_status status;
+
+    if ((!pStream) || (!pStream->state))
+        return MZ_STREAM_ERROR;
+    if (flush == MZ_PARTIAL_FLUSH)
+        flush = MZ_SYNC_FLUSH;
+    if ((flush) && (flush != MZ_SYNC_FLUSH) && (flush != MZ_FINISH))
+        return MZ_STREAM_ERROR;
+
+    pState = (inflate_state *)pStream->state;
+    if (pState->m_window_bits > 0)
+        decomp_flags |= TINFL_FLAG_PARSE_ZLIB_HEADER;
+    orig_avail_in = pStream->avail_in;
+
+    first_call = pState->m_first_call;
+    pState->m_first_call = 0;
+    if (pState->m_last_status < 0)
+        return MZ_DATA_ERROR;
+
+    if (pState->m_has_flushed && (flush != MZ_FINISH))
+        return MZ_STREAM_ERROR;
+    pState->m_has_flushed |= (flush == MZ_FINISH);
+
+    if ((flush == MZ_FINISH) && (first_call))
+    {
+        /* MZ_FINISH on the first call implies that the input and output buffers are large enough to hold the entire compressed/decompressed file. */
+        decomp_flags |= TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF;
+        in_bytes = pStream->avail_in;
+        out_bytes = pStream->avail_out;
+        status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pStream->next_out, pStream->next_out, &out_bytes, decomp_flags);
+        pState->m_last_status = status;
+        pStream->next_in += (mz_uint)in_bytes;
+        pStream->avail_in -= (mz_uint)in_bytes;
+        pStream->total_in += (mz_uint)in_bytes;
+        pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+        pStream->next_out += (mz_uint)out_bytes;
+        pStream->avail_out -= (mz_uint)out_bytes;
+        pStream->total_out += (mz_uint)out_bytes;
+
+        if (status < 0)
+            return MZ_DATA_ERROR;
+        else if (status != TINFL_STATUS_DONE)
+        {
+            pState->m_last_status = TINFL_STATUS_FAILED;
+            return MZ_BUF_ERROR;
+        }
+        return MZ_STREAM_END;
+    }
+    /* flush != MZ_FINISH then we must assume there's more input. */
+    if (flush != MZ_FINISH)
+        decomp_flags |= TINFL_FLAG_HAS_MORE_INPUT;
+
+    if (pState->m_dict_avail)
+    {
+        n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+        memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+        pStream->next_out += n;
+        pStream->avail_out -= n;
+        pStream->total_out += n;
+        pState->m_dict_avail -= n;
+        pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+        return ((pState->m_last_status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+    }
+
+    for (;;)
+    {
+        in_bytes = pStream->avail_in;
+        out_bytes = TINFL_LZ_DICT_SIZE - pState->m_dict_ofs;
+
+        status = tinfl_decompress(&pState->m_decomp, pStream->next_in, &in_bytes, pState->m_dict, pState->m_dict + pState->m_dict_ofs, &out_bytes, decomp_flags);
+        pState->m_last_status = status;
+
+        pStream->next_in += (mz_uint)in_bytes;
+        pStream->avail_in -= (mz_uint)in_bytes;
+        pStream->total_in += (mz_uint)in_bytes;
+        pStream->adler = tinfl_get_adler32(&pState->m_decomp);
+
+        pState->m_dict_avail = (mz_uint)out_bytes;
+
+        n = MZ_MIN(pState->m_dict_avail, pStream->avail_out);
+        memcpy(pStream->next_out, pState->m_dict + pState->m_dict_ofs, n);
+        pStream->next_out += n;
+        pStream->avail_out -= n;
+        pStream->total_out += n;
+        pState->m_dict_avail -= n;
+        pState->m_dict_ofs = (pState->m_dict_ofs + n) & (TINFL_LZ_DICT_SIZE - 1);
+
+        if (status < 0)
+            return MZ_DATA_ERROR; /* Stream is corrupted (there could be some uncompressed data left in the output dictionary - oh well). */
+        else if ((status == TINFL_STATUS_NEEDS_MORE_INPUT) && (!orig_avail_in))
+            return MZ_BUF_ERROR; /* Signal caller that we can't make forward progress without supplying more input or by setting flush to MZ_FINISH. */
+        else if (flush == MZ_FINISH)
+        {
+            /* The output buffer MUST be large to hold the remaining uncompressed data when flush==MZ_FINISH. */
+            if (status == TINFL_STATUS_DONE)
+                return pState->m_dict_avail ? MZ_BUF_ERROR : MZ_STREAM_END;
+            /* status here must be TINFL_STATUS_HAS_MORE_OUTPUT, which means there's at least 1 more byte on the way. If there's no more room left in the output buffer then something is wrong. */
+            else if (!pStream->avail_out)
+                return MZ_BUF_ERROR;
+        }
+        else if ((status == TINFL_STATUS_DONE) || (!pStream->avail_in) || (!pStream->avail_out) || (pState->m_dict_avail))
+            break;
+    }
+
+    return ((status == TINFL_STATUS_DONE) && (!pState->m_dict_avail)) ? MZ_STREAM_END : MZ_OK;
+}
+
+int mz_inflateEnd(mz_streamp pStream)
+{
+    if (!pStream)
+        return MZ_STREAM_ERROR;
+    if (pStream->state)
+    {
+        pStream->zfree(pStream->opaque, pStream->state);
+        pStream->state = NULL;
+    }
+    return MZ_OK;
+}
+
+int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len)
+{
+    mz_stream stream;
+    int status;
+    memset(&stream, 0, sizeof(stream));
+
+    /* In case mz_ulong is 64-bits (argh I hate longs). */
+    if ((source_len | *pDest_len) > 0xFFFFFFFFU)
+        return MZ_PARAM_ERROR;
+
+    stream.next_in = pSource;
+    stream.avail_in = (mz_uint32)source_len;
+    stream.next_out = pDest;
+    stream.avail_out = (mz_uint32) * pDest_len;
+
+    status = mz_inflateInit(&stream);
+    if (status != MZ_OK)
+        return status;
+
+    status = mz_inflate(&stream, MZ_FINISH);
+    if (status != MZ_STREAM_END)
+    {
+        mz_inflateEnd(&stream);
+        return ((status == MZ_BUF_ERROR) && (!stream.avail_in)) ? MZ_DATA_ERROR : status;
+    }
+    *pDest_len = stream.total_out;
+
+    return mz_inflateEnd(&stream);
+}
+
+const char *mz_error(int err)
+{
+    static struct
+    {
+        int m_err;
+        const char *m_pDesc;
+    } s_error_descs[] =
+          {
+              { MZ_OK, "" }, { MZ_STREAM_END, "stream end" }, { MZ_NEED_DICT, "need dictionary" }, { MZ_ERRNO, "file error" }, { MZ_STREAM_ERROR, "stream error" },
+              { MZ_DATA_ERROR, "data error" }, { MZ_MEM_ERROR, "out of memory" }, { MZ_BUF_ERROR, "buf error" }, { MZ_VERSION_ERROR, "version error" }, { MZ_PARAM_ERROR, "parameter error" }
+          };
+    mz_uint i;
+    for (i = 0; i < sizeof(s_error_descs) / sizeof(s_error_descs[0]); ++i)
+        if (s_error_descs[i].m_err == err)
+            return s_error_descs[i].m_pDesc;
+    return NULL;
+}
+
+#endif /*MINIZ_NO_ZLIB_APIS */
+
+#ifdef __cplusplus
+}
+#endif
+
+/*
+  This is free and unencumbered software released into the public domain.
+
+  Anyone is free to copy, modify, publish, use, compile, sell, or
+  distribute this software, either in source code form or as a compiled
+  binary, for any purpose, commercial or non-commercial, and by any
+  means.
+
+  In jurisdictions that recognize copyright laws, the author or authors
+  of this software dedicate any and all copyright interest in the
+  software to the public domain. We make this dedication for the benefit
+  of the public at large and to the detriment of our heirs and
+  successors. We intend this dedication to be an overt act of
+  relinquishment in perpetuity of all present and future rights to this
+  software under copyright law.
+
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+  IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+  OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+  ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+  OTHER DEALINGS IN THE SOFTWARE.
+
+  For more information, please refer to <http://unlicense.org/>
+*/
+/**************************************************************************
+ *
+ * Copyright 2013-2014 RAD Game Tools and Valve Software
+ * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- Low-level Compression (independent from all decompression API's) */
+
+/* Purposely making these tables static for faster init and thread safety. */
+static const mz_uint16 s_tdefl_len_sym[256] =
+    {
+        257, 258, 259, 260, 261, 262, 263, 264, 265, 265, 266, 266, 267, 267, 268, 268, 269, 269, 269, 269, 270, 270, 270, 270, 271, 271, 271, 271, 272, 272, 272, 272,
+        273, 273, 273, 273, 273, 273, 273, 273, 274, 274, 274, 274, 274, 274, 274, 274, 275, 275, 275, 275, 275, 275, 275, 275, 276, 276, 276, 276, 276, 276, 276, 276,
+        277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 277, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278, 278,
+        279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 279, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280, 280,
+        281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281, 281,
+        282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282, 282,
+        283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283, 283,
+        284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 284, 285
+    };
+
+static const mz_uint8 s_tdefl_len_extra[256] =
+    {
+        0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+        4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 0
+    };
+
+static const mz_uint8 s_tdefl_small_dist_sym[512] =
+    {
+        0, 1, 2, 3, 4, 4, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11,
+        11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13,
+        13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+        14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+        14, 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+        15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16,
+        16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+        17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+        17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+        17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17
+    };
+
+static const mz_uint8 s_tdefl_small_dist_extra[512] =
+    {
+        0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5,
+        5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+        6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+        7, 7, 7, 7, 7, 7, 7, 7
+    };
+
+static const mz_uint8 s_tdefl_large_dist_sym[128] =
+    {
+        0, 0, 18, 19, 20, 20, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26,
+        26, 26, 26, 26, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+        28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29, 29
+    };
+
+static const mz_uint8 s_tdefl_large_dist_extra[128] =
+    {
+        0, 0, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+        12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+        13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13
+    };
+
+/* Radix sorts tdefl_sym_freq[] array by 16-bit key m_key. Returns ptr to sorted values. */
+typedef struct
+{
+    mz_uint16 m_key, m_sym_index;
+} tdefl_sym_freq;
+static tdefl_sym_freq *tdefl_radix_sort_syms(mz_uint num_syms, tdefl_sym_freq *pSyms0, tdefl_sym_freq *pSyms1)
+{
+    mz_uint32 total_passes = 2, pass_shift, pass, i, hist[256 * 2];
+    tdefl_sym_freq *pCur_syms = pSyms0, *pNew_syms = pSyms1;
+    MZ_CLEAR_OBJ(hist);
+    for (i = 0; i < num_syms; i++)
+    {
+        mz_uint freq = pSyms0[i].m_key;
+        hist[freq & 0xFF]++;
+        hist[256 + ((freq >> 8) & 0xFF)]++;
+    }
+    while ((total_passes > 1) && (num_syms == hist[(total_passes - 1) * 256]))
+        total_passes--;
+    for (pass_shift = 0, pass = 0; pass < total_passes; pass++, pass_shift += 8)
+    {
+        const mz_uint32 *pHist = &hist[pass << 8];
+        mz_uint offsets[256], cur_ofs = 0;
+        for (i = 0; i < 256; i++)
+        {
+            offsets[i] = cur_ofs;
+            cur_ofs += pHist[i];
+        }
+        for (i = 0; i < num_syms; i++)
+            pNew_syms[offsets[(pCur_syms[i].m_key >> pass_shift) & 0xFF]++] = pCur_syms[i];
+        {
+            tdefl_sym_freq *t = pCur_syms;
+            pCur_syms = pNew_syms;
+            pNew_syms = t;
+        }
+    }
+    return pCur_syms;
+}
+
+/* tdefl_calculate_minimum_redundancy() originally written by: Alistair Moffat, alistair@cs.mu.oz.au, Jyrki Katajainen, jyrki@diku.dk, November 1996. */
+static void tdefl_calculate_minimum_redundancy(tdefl_sym_freq *A, int n)
+{
+    int root, leaf, next, avbl, used, dpth;
+    if (n == 0)
+        return;
+    else if (n == 1)
+    {
+        A[0].m_key = 1;
+        return;
+    }
+    A[0].m_key += A[1].m_key;
+    root = 0;
+    leaf = 2;
+    for (next = 1; next < n - 1; next++)
+    {
+        if (leaf >= n || A[root].m_key < A[leaf].m_key)
+        {
+            A[next].m_key = A[root].m_key;
+            A[root++].m_key = (mz_uint16)next;
+        }
+        else
+            A[next].m_key = A[leaf++].m_key;
+        if (leaf >= n || (root < next && A[root].m_key < A[leaf].m_key))
+        {
+            A[next].m_key = (mz_uint16)(A[next].m_key + A[root].m_key);
+            A[root++].m_key = (mz_uint16)next;
+        }
+        else
+            A[next].m_key = (mz_uint16)(A[next].m_key + A[leaf++].m_key);
+    }
+    A[n - 2].m_key = 0;
+    for (next = n - 3; next >= 0; next--)
+        A[next].m_key = A[A[next].m_key].m_key + 1;
+    avbl = 1;
+    used = dpth = 0;
+    root = n - 2;
+    next = n - 1;
+    while (avbl > 0)
+    {
+        while (root >= 0 && (int)A[root].m_key == dpth)
+        {
+            used++;
+            root--;
+        }
+        while (avbl > used)
+        {
+            A[next--].m_key = (mz_uint16)(dpth);
+            avbl--;
+        }
+        avbl = 2 * used;
+        dpth++;
+        used = 0;
+    }
+}
+
+/* Limits canonical Huffman code table's max code size. */
+enum
+{
+    TDEFL_MAX_SUPPORTED_HUFF_CODESIZE = 32
+};
+static void tdefl_huffman_enforce_max_code_size(int *pNum_codes, int code_list_len, int max_code_size)
+{
+    int i;
+    mz_uint32 total = 0;
+    if (code_list_len <= 1)
+        return;
+    for (i = max_code_size + 1; i <= TDEFL_MAX_SUPPORTED_HUFF_CODESIZE; i++)
+        pNum_codes[max_code_size] += pNum_codes[i];
+    for (i = max_code_size; i > 0; i--)
+        total += (((mz_uint32)pNum_codes[i]) << (max_code_size - i));
+    while (total != (1UL << max_code_size))
+    {
+        pNum_codes[max_code_size]--;
+        for (i = max_code_size - 1; i > 0; i--)
+            if (pNum_codes[i])
+            {
+                pNum_codes[i]--;
+                pNum_codes[i + 1] += 2;
+                break;
+            }
+        total--;
+    }
+}
+
+static void tdefl_optimize_huffman_table(tdefl_compressor *d, int table_num, int table_len, int code_size_limit, int static_table)
+{
+    int i, j, l, num_codes[1 + TDEFL_MAX_SUPPORTED_HUFF_CODESIZE];
+    mz_uint next_code[TDEFL_MAX_SUPPORTED_HUFF_CODESIZE + 1];
+    MZ_CLEAR_OBJ(num_codes);
+    if (static_table)
+    {
+        for (i = 0; i < table_len; i++)
+            num_codes[d->m_huff_code_sizes[table_num][i]]++;
+    }
+    else
+    {
+        tdefl_sym_freq syms0[TDEFL_MAX_HUFF_SYMBOLS], syms1[TDEFL_MAX_HUFF_SYMBOLS], *pSyms;
+        int num_used_syms = 0;
+        const mz_uint16 *pSym_count = &d->m_huff_count[table_num][0];
+        for (i = 0; i < table_len; i++)
+            if (pSym_count[i])
+            {
+                syms0[num_used_syms].m_key = (mz_uint16)pSym_count[i];
+                syms0[num_used_syms++].m_sym_index = (mz_uint16)i;
+            }
+
+        pSyms = tdefl_radix_sort_syms(num_used_syms, syms0, syms1);
+        tdefl_calculate_minimum_redundancy(pSyms, num_used_syms);
+
+        for (i = 0; i < num_used_syms; i++)
+            num_codes[pSyms[i].m_key]++;
+
+        tdefl_huffman_enforce_max_code_size(num_codes, num_used_syms, code_size_limit);
+
+        MZ_CLEAR_OBJ(d->m_huff_code_sizes[table_num]);
+        MZ_CLEAR_OBJ(d->m_huff_codes[table_num]);
+        for (i = 1, j = num_used_syms; i <= code_size_limit; i++)
+            for (l = num_codes[i]; l > 0; l--)
+                d->m_huff_code_sizes[table_num][pSyms[--j].m_sym_index] = (mz_uint8)(i);
+    }
+
+    next_code[1] = 0;
+    for (j = 0, i = 2; i <= code_size_limit; i++)
+        next_code[i] = j = ((j + num_codes[i - 1]) << 1);
+
+    for (i = 0; i < table_len; i++)
+    {
+        mz_uint rev_code = 0, code, code_size;
+        if ((code_size = d->m_huff_code_sizes[table_num][i]) == 0)
+            continue;
+        code = next_code[code_size]++;
+        for (l = code_size; l > 0; l--, code >>= 1)
+            rev_code = (rev_code << 1) | (code & 1);
+        d->m_huff_codes[table_num][i] = (mz_uint16)rev_code;
+    }
+}
+
+#define TDEFL_PUT_BITS(b, l)                                       \
+    do                                                             \
+    {                                                              \
+        mz_uint bits = b;                                          \
+        mz_uint len = l;                                           \
+        MZ_ASSERT(bits <= ((1U << len) - 1U));                     \
+        d->m_bit_buffer |= (bits << d->m_bits_in);                 \
+        d->m_bits_in += len;                                       \
+        while (d->m_bits_in >= 8)                                  \
+        {                                                          \
+            if (d->m_pOutput_buf < d->m_pOutput_buf_end)           \
+                *d->m_pOutput_buf++ = (mz_uint8)(d->m_bit_buffer); \
+            d->m_bit_buffer >>= 8;                                 \
+            d->m_bits_in -= 8;                                     \
+        }                                                          \
+    }                                                              \
+    MZ_MACRO_END
+
+#define TDEFL_RLE_PREV_CODE_SIZE()                                                                                       \
+    {                                                                                                                    \
+        if (rle_repeat_count)                                                                                            \
+        {                                                                                                                \
+            if (rle_repeat_count < 3)                                                                                    \
+            {                                                                                                            \
+                d->m_huff_count[2][prev_code_size] = (mz_uint16)(d->m_huff_count[2][prev_code_size] + rle_repeat_count); \
+                while (rle_repeat_count--)                                                                               \
+                    packed_code_sizes[num_packed_code_sizes++] = prev_code_size;                                         \
+            }                                                                                                            \
+            else                                                                                                         \
+            {                                                                                                            \
+                d->m_huff_count[2][16] = (mz_uint16)(d->m_huff_count[2][16] + 1);                                        \
+                packed_code_sizes[num_packed_code_sizes++] = 16;                                                         \
+                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_repeat_count - 3);                           \
+            }                                                                                                            \
+            rle_repeat_count = 0;                                                                                        \
+        }                                                                                                                \
+    }
+
+#define TDEFL_RLE_ZERO_CODE_SIZE()                                                         \
+    {                                                                                      \
+        if (rle_z_count)                                                                   \
+        {                                                                                  \
+            if (rle_z_count < 3)                                                           \
+            {                                                                              \
+                d->m_huff_count[2][0] = (mz_uint16)(d->m_huff_count[2][0] + rle_z_count);  \
+                while (rle_z_count--)                                                      \
+                    packed_code_sizes[num_packed_code_sizes++] = 0;                        \
+            }                                                                              \
+            else if (rle_z_count <= 10)                                                    \
+            {                                                                              \
+                d->m_huff_count[2][17] = (mz_uint16)(d->m_huff_count[2][17] + 1);          \
+                packed_code_sizes[num_packed_code_sizes++] = 17;                           \
+                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 3);  \
+            }                                                                              \
+            else                                                                           \
+            {                                                                              \
+                d->m_huff_count[2][18] = (mz_uint16)(d->m_huff_count[2][18] + 1);          \
+                packed_code_sizes[num_packed_code_sizes++] = 18;                           \
+                packed_code_sizes[num_packed_code_sizes++] = (mz_uint8)(rle_z_count - 11); \
+            }                                                                              \
+            rle_z_count = 0;                                                               \
+        }                                                                                  \
+    }
+
+static mz_uint8 s_tdefl_packed_code_size_syms_swizzle[] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+
+static void tdefl_start_dynamic_block(tdefl_compressor *d)
+{
+    int num_lit_codes, num_dist_codes, num_bit_lengths;
+    mz_uint i, total_code_sizes_to_pack, num_packed_code_sizes, rle_z_count, rle_repeat_count, packed_code_sizes_index;
+    mz_uint8 code_sizes_to_pack[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], packed_code_sizes[TDEFL_MAX_HUFF_SYMBOLS_0 + TDEFL_MAX_HUFF_SYMBOLS_1], prev_code_size = 0xFF;
+
+    d->m_huff_count[0][256] = 1;
+
+    tdefl_optimize_huffman_table(d, 0, TDEFL_MAX_HUFF_SYMBOLS_0, 15, MZ_FALSE);
+    tdefl_optimize_huffman_table(d, 1, TDEFL_MAX_HUFF_SYMBOLS_1, 15, MZ_FALSE);
+
+    for (num_lit_codes = 286; num_lit_codes > 257; num_lit_codes--)
+        if (d->m_huff_code_sizes[0][num_lit_codes - 1])
+            break;
+    for (num_dist_codes = 30; num_dist_codes > 1; num_dist_codes--)
+        if (d->m_huff_code_sizes[1][num_dist_codes - 1])
+            break;
+
+    memcpy(code_sizes_to_pack, &d->m_huff_code_sizes[0][0], num_lit_codes);
+    memcpy(code_sizes_to_pack + num_lit_codes, &d->m_huff_code_sizes[1][0], num_dist_codes);
+    total_code_sizes_to_pack = num_lit_codes + num_dist_codes;
+    num_packed_code_sizes = 0;
+    rle_z_count = 0;
+    rle_repeat_count = 0;
+
+    memset(&d->m_huff_count[2][0], 0, sizeof(d->m_huff_count[2][0]) * TDEFL_MAX_HUFF_SYMBOLS_2);
+    for (i = 0; i < total_code_sizes_to_pack; i++)
+    {
+        mz_uint8 code_size = code_sizes_to_pack[i];
+        if (!code_size)
+        {
+            TDEFL_RLE_PREV_CODE_SIZE();
+            if (++rle_z_count == 138)
+            {
+                TDEFL_RLE_ZERO_CODE_SIZE();
+            }
+        }
+        else
+        {
+            TDEFL_RLE_ZERO_CODE_SIZE();
+            if (code_size != prev_code_size)
+            {
+                TDEFL_RLE_PREV_CODE_SIZE();
+                d->m_huff_count[2][code_size] = (mz_uint16)(d->m_huff_count[2][code_size] + 1);
+                packed_code_sizes[num_packed_code_sizes++] = code_size;
+            }
+            else if (++rle_repeat_count == 6)
+            {
+                TDEFL_RLE_PREV_CODE_SIZE();
+            }
+        }
+        prev_code_size = code_size;
+    }
+    if (rle_repeat_count)
+    {
+        TDEFL_RLE_PREV_CODE_SIZE();
+    }
+    else
+    {
+        TDEFL_RLE_ZERO_CODE_SIZE();
+    }
+
+    tdefl_optimize_huffman_table(d, 2, TDEFL_MAX_HUFF_SYMBOLS_2, 7, MZ_FALSE);
+
+    TDEFL_PUT_BITS(2, 2);
+
+    TDEFL_PUT_BITS(num_lit_codes - 257, 5);
+    TDEFL_PUT_BITS(num_dist_codes - 1, 5);
+
+    for (num_bit_lengths = 18; num_bit_lengths >= 0; num_bit_lengths--)
+        if (d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[num_bit_lengths]])
+            break;
+    num_bit_lengths = MZ_MAX(4, (num_bit_lengths + 1));
+    TDEFL_PUT_BITS(num_bit_lengths - 4, 4);
+    for (i = 0; (int)i < num_bit_lengths; i++)
+        TDEFL_PUT_BITS(d->m_huff_code_sizes[2][s_tdefl_packed_code_size_syms_swizzle[i]], 3);
+
+    for (packed_code_sizes_index = 0; packed_code_sizes_index < num_packed_code_sizes;)
+    {
+        mz_uint code = packed_code_sizes[packed_code_sizes_index++];
+        MZ_ASSERT(code < TDEFL_MAX_HUFF_SYMBOLS_2);
+        TDEFL_PUT_BITS(d->m_huff_codes[2][code], d->m_huff_code_sizes[2][code]);
+        if (code >= 16)
+            TDEFL_PUT_BITS(packed_code_sizes[packed_code_sizes_index++], "\02\03\07"[code - 16]);
+    }
+}
+
+static void tdefl_start_static_block(tdefl_compressor *d)
+{
+    mz_uint i;
+    mz_uint8 *p = &d->m_huff_code_sizes[0][0];
+
+    for (i = 0; i <= 143; ++i)
+        *p++ = 8;
+    for (; i <= 255; ++i)
+        *p++ = 9;
+    for (; i <= 279; ++i)
+        *p++ = 7;
+    for (; i <= 287; ++i)
+        *p++ = 8;
+
+    memset(d->m_huff_code_sizes[1], 5, 32);
+
+    tdefl_optimize_huffman_table(d, 0, 288, 15, MZ_TRUE);
+    tdefl_optimize_huffman_table(d, 1, 32, 15, MZ_TRUE);
+
+    TDEFL_PUT_BITS(1, 2);
+}
+
+static const mz_uint mz_bitmasks[17] = { 0x0000, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF, 0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF, 0xFFFF };
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES &&MINIZ_LITTLE_ENDIAN &&MINIZ_HAS_64BIT_REGISTERS
+static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
+{
+    mz_uint flags;
+    mz_uint8 *pLZ_codes;
+    mz_uint8 *pOutput_buf = d->m_pOutput_buf;
+    mz_uint8 *pLZ_code_buf_end = d->m_pLZ_code_buf;
+    mz_uint64 bit_buffer = d->m_bit_buffer;
+    mz_uint bits_in = d->m_bits_in;
+
+#define TDEFL_PUT_BITS_FAST(b, l)                    \
+    {                                                \
+        bit_buffer |= (((mz_uint64)(b)) << bits_in); \
+        bits_in += (l);                              \
+    }
+
+    flags = 1;
+    for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < pLZ_code_buf_end; flags >>= 1)
+    {
+        if (flags == 1)
+            flags = *pLZ_codes++ | 0x100;
+
+        if (flags & 1)
+        {
+            mz_uint s0, s1, n0, n1, sym, num_extra_bits;
+            mz_uint match_len = pLZ_codes[0], match_dist = *(const mz_uint16 *)(pLZ_codes + 1);
+            pLZ_codes += 3;
+
+            MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+            TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+            TDEFL_PUT_BITS_FAST(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
+
+            /* This sequence coaxes MSVC into using cmov's vs. jmp's. */
+            s0 = s_tdefl_small_dist_sym[match_dist & 511];
+            n0 = s_tdefl_small_dist_extra[match_dist & 511];
+            s1 = s_tdefl_large_dist_sym[match_dist >> 8];
+            n1 = s_tdefl_large_dist_extra[match_dist >> 8];
+            sym = (match_dist < 512) ? s0 : s1;
+            num_extra_bits = (match_dist < 512) ? n0 : n1;
+
+            MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
+            TDEFL_PUT_BITS_FAST(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
+            TDEFL_PUT_BITS_FAST(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
+        }
+        else
+        {
+            mz_uint lit = *pLZ_codes++;
+            MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+            TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+
+            if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
+            {
+                flags >>= 1;
+                lit = *pLZ_codes++;
+                MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+                TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+
+                if (((flags & 2) == 0) && (pLZ_codes < pLZ_code_buf_end))
+                {
+                    flags >>= 1;
+                    lit = *pLZ_codes++;
+                    MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+                    TDEFL_PUT_BITS_FAST(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+                }
+            }
+        }
+
+        if (pOutput_buf >= d->m_pOutput_buf_end)
+            return MZ_FALSE;
+
+        *(mz_uint64 *)pOutput_buf = bit_buffer;
+        pOutput_buf += (bits_in >> 3);
+        bit_buffer >>= (bits_in & ~7);
+        bits_in &= 7;
+    }
+
+#undef TDEFL_PUT_BITS_FAST
+
+    d->m_pOutput_buf = pOutput_buf;
+    d->m_bits_in = 0;
+    d->m_bit_buffer = 0;
+
+    while (bits_in)
+    {
+        mz_uint32 n = MZ_MIN(bits_in, 16);
+        TDEFL_PUT_BITS((mz_uint)bit_buffer & mz_bitmasks[n], n);
+        bit_buffer >>= n;
+        bits_in -= n;
+    }
+
+    TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
+
+    return (d->m_pOutput_buf < d->m_pOutput_buf_end);
+}
+#else
+static mz_bool tdefl_compress_lz_codes(tdefl_compressor *d)
+{
+    mz_uint flags;
+    mz_uint8 *pLZ_codes;
+
+    flags = 1;
+    for (pLZ_codes = d->m_lz_code_buf; pLZ_codes < d->m_pLZ_code_buf; flags >>= 1)
+    {
+        if (flags == 1)
+            flags = *pLZ_codes++ | 0x100;
+        if (flags & 1)
+        {
+            mz_uint sym, num_extra_bits;
+            mz_uint match_len = pLZ_codes[0], match_dist = (pLZ_codes[1] | (pLZ_codes[2] << 8));
+            pLZ_codes += 3;
+
+            MZ_ASSERT(d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+            TDEFL_PUT_BITS(d->m_huff_codes[0][s_tdefl_len_sym[match_len]], d->m_huff_code_sizes[0][s_tdefl_len_sym[match_len]]);
+            TDEFL_PUT_BITS(match_len & mz_bitmasks[s_tdefl_len_extra[match_len]], s_tdefl_len_extra[match_len]);
+
+            if (match_dist < 512)
+            {
+                sym = s_tdefl_small_dist_sym[match_dist];
+                num_extra_bits = s_tdefl_small_dist_extra[match_dist];
+            }
+            else
+            {
+                sym = s_tdefl_large_dist_sym[match_dist >> 8];
+                num_extra_bits = s_tdefl_large_dist_extra[match_dist >> 8];
+            }
+            MZ_ASSERT(d->m_huff_code_sizes[1][sym]);
+            TDEFL_PUT_BITS(d->m_huff_codes[1][sym], d->m_huff_code_sizes[1][sym]);
+            TDEFL_PUT_BITS(match_dist & mz_bitmasks[num_extra_bits], num_extra_bits);
+        }
+        else
+        {
+            mz_uint lit = *pLZ_codes++;
+            MZ_ASSERT(d->m_huff_code_sizes[0][lit]);
+            TDEFL_PUT_BITS(d->m_huff_codes[0][lit], d->m_huff_code_sizes[0][lit]);
+        }
+    }
+
+    TDEFL_PUT_BITS(d->m_huff_codes[0][256], d->m_huff_code_sizes[0][256]);
+
+    return (d->m_pOutput_buf < d->m_pOutput_buf_end);
+}
+#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN && MINIZ_HAS_64BIT_REGISTERS */
+
+static mz_bool tdefl_compress_block(tdefl_compressor *d, mz_bool static_block)
+{
+    if (static_block)
+        tdefl_start_static_block(d);
+    else
+        tdefl_start_dynamic_block(d);
+    return tdefl_compress_lz_codes(d);
+}
+
+static int tdefl_flush_block(tdefl_compressor *d, int flush)
+{
+    mz_uint saved_bit_buf, saved_bits_in;
+    mz_uint8 *pSaved_output_buf;
+    mz_bool comp_block_succeeded = MZ_FALSE;
+    int n, use_raw_block = ((d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS) != 0) && (d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size;
+    mz_uint8 *pOutput_buf_start = ((d->m_pPut_buf_func == NULL) && ((*d->m_pOut_buf_size - d->m_out_buf_ofs) >= TDEFL_OUT_BUF_SIZE)) ? ((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs) : d->m_output_buf;
+
+    d->m_pOutput_buf = pOutput_buf_start;
+    d->m_pOutput_buf_end = d->m_pOutput_buf + TDEFL_OUT_BUF_SIZE - 16;
+
+    MZ_ASSERT(!d->m_output_flush_remaining);
+    d->m_output_flush_ofs = 0;
+    d->m_output_flush_remaining = 0;
+
+    *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> d->m_num_flags_left);
+    d->m_pLZ_code_buf -= (d->m_num_flags_left == 8);
+
+    if ((d->m_flags & TDEFL_WRITE_ZLIB_HEADER) && (!d->m_block_index))
+    {
+        TDEFL_PUT_BITS(0x78, 8);
+        TDEFL_PUT_BITS(0x01, 8);
+    }
+
+    TDEFL_PUT_BITS(flush == TDEFL_FINISH, 1);
+
+    pSaved_output_buf = d->m_pOutput_buf;
+    saved_bit_buf = d->m_bit_buffer;
+    saved_bits_in = d->m_bits_in;
+
+    if (!use_raw_block)
+        comp_block_succeeded = tdefl_compress_block(d, (d->m_flags & TDEFL_FORCE_ALL_STATIC_BLOCKS) || (d->m_total_lz_bytes < 48));
+
+    /* If the block gets expanded, forget the current contents of the output buffer and send a raw block instead. */
+    if (((use_raw_block) || ((d->m_total_lz_bytes) && ((d->m_pOutput_buf - pSaved_output_buf + 1U) >= d->m_total_lz_bytes))) &&
+        ((d->m_lookahead_pos - d->m_lz_code_buf_dict_pos) <= d->m_dict_size))
+    {
+        mz_uint i;
+        d->m_pOutput_buf = pSaved_output_buf;
+        d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
+        TDEFL_PUT_BITS(0, 2);
+        if (d->m_bits_in)
+        {
+            TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
+        }
+        for (i = 2; i; --i, d->m_total_lz_bytes ^= 0xFFFF)
+        {
+            TDEFL_PUT_BITS(d->m_total_lz_bytes & 0xFFFF, 16);
+        }
+        for (i = 0; i < d->m_total_lz_bytes; ++i)
+        {
+            TDEFL_PUT_BITS(d->m_dict[(d->m_lz_code_buf_dict_pos + i) & TDEFL_LZ_DICT_SIZE_MASK], 8);
+        }
+    }
+    /* Check for the extremely unlikely (if not impossible) case of the compressed block not fitting into the output buffer when using dynamic codes. */
+    else if (!comp_block_succeeded)
+    {
+        d->m_pOutput_buf = pSaved_output_buf;
+        d->m_bit_buffer = saved_bit_buf, d->m_bits_in = saved_bits_in;
+        tdefl_compress_block(d, MZ_TRUE);
+    }
+
+    if (flush)
+    {
+        if (flush == TDEFL_FINISH)
+        {
+            if (d->m_bits_in)
+            {
+                TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
+            }
+            if (d->m_flags & TDEFL_WRITE_ZLIB_HEADER)
+            {
+                mz_uint i, a = d->m_adler32;
+                for (i = 0; i < 4; i++)
+                {
+                    TDEFL_PUT_BITS((a >> 24) & 0xFF, 8);
+                    a <<= 8;
+                }
+            }
+        }
+        else
+        {
+            mz_uint i, z = 0;
+            TDEFL_PUT_BITS(0, 3);
+            if (d->m_bits_in)
+            {
+                TDEFL_PUT_BITS(0, 8 - d->m_bits_in);
+            }
+            for (i = 2; i; --i, z ^= 0xFFFF)
+            {
+                TDEFL_PUT_BITS(z & 0xFFFF, 16);
+            }
+        }
+    }
+
+    MZ_ASSERT(d->m_pOutput_buf < d->m_pOutput_buf_end);
+
+    memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
+    memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
+
+    d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
+    d->m_pLZ_flags = d->m_lz_code_buf;
+    d->m_num_flags_left = 8;
+    d->m_lz_code_buf_dict_pos += d->m_total_lz_bytes;
+    d->m_total_lz_bytes = 0;
+    d->m_block_index++;
+
+    if ((n = (int)(d->m_pOutput_buf - pOutput_buf_start)) != 0)
+    {
+        if (d->m_pPut_buf_func)
+        {
+            *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
+            if (!(*d->m_pPut_buf_func)(d->m_output_buf, n, d->m_pPut_buf_user))
+                return (d->m_prev_return_status = TDEFL_STATUS_PUT_BUF_FAILED);
+        }
+        else if (pOutput_buf_start == d->m_output_buf)
+        {
+            int bytes_to_copy = (int)MZ_MIN((size_t)n, (size_t)(*d->m_pOut_buf_size - d->m_out_buf_ofs));
+            memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf, bytes_to_copy);
+            d->m_out_buf_ofs += bytes_to_copy;
+            if ((n -= bytes_to_copy) != 0)
+            {
+                d->m_output_flush_ofs = bytes_to_copy;
+                d->m_output_flush_remaining = n;
+            }
+        }
+        else
+        {
+            d->m_out_buf_ofs += n;
+        }
+    }
+
+    return d->m_output_flush_remaining;
+}
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+#define TDEFL_READ_UNALIGNED_WORD(p) *(const mz_uint16 *)(p)
+static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
+{
+    mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
+    mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
+    const mz_uint16 *s = (const mz_uint16 *)(d->m_dict + pos), *p, *q;
+    mz_uint16 c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]), s01 = TDEFL_READ_UNALIGNED_WORD(s);
+    MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
+    if (max_match_len <= match_len)
+        return;
+    for (;;)
+    {
+        for (;;)
+        {
+            if (--num_probes_left == 0)
+                return;
+#define TDEFL_PROBE                                                                             \
+    next_probe_pos = d->m_next[probe_pos];                                                      \
+    if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist)) \
+        return;                                                                                 \
+    probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK;                                       \
+    if (TDEFL_READ_UNALIGNED_WORD(&d->m_dict[probe_pos + match_len - 1]) == c01)                \
+        break;
+            TDEFL_PROBE;
+            TDEFL_PROBE;
+            TDEFL_PROBE;
+        }
+        if (!dist)
+            break;
+        q = (const mz_uint16 *)(d->m_dict + probe_pos);
+        if (TDEFL_READ_UNALIGNED_WORD(q) != s01)
+            continue;
+        p = s;
+        probe_len = 32;
+        do
+        {
+        } while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
+                 (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0));
+        if (!probe_len)
+        {
+            *pMatch_dist = dist;
+            *pMatch_len = MZ_MIN(max_match_len, (mz_uint)TDEFL_MAX_MATCH_LEN);
+            break;
+        }
+        else if ((probe_len = ((mz_uint)(p - s) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q)) > match_len)
+        {
+            *pMatch_dist = dist;
+            if ((*pMatch_len = match_len = MZ_MIN(max_match_len, probe_len)) == max_match_len)
+                break;
+            c01 = TDEFL_READ_UNALIGNED_WORD(&d->m_dict[pos + match_len - 1]);
+        }
+    }
+}
+#else
+static MZ_FORCEINLINE void tdefl_find_match(tdefl_compressor *d, mz_uint lookahead_pos, mz_uint max_dist, mz_uint max_match_len, mz_uint *pMatch_dist, mz_uint *pMatch_len)
+{
+    mz_uint dist, pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK, match_len = *pMatch_len, probe_pos = pos, next_probe_pos, probe_len;
+    mz_uint num_probes_left = d->m_max_probes[match_len >= 32];
+    const mz_uint8 *s = d->m_dict + pos, *p, *q;
+    mz_uint8 c0 = d->m_dict[pos + match_len], c1 = d->m_dict[pos + match_len - 1];
+    MZ_ASSERT(max_match_len <= TDEFL_MAX_MATCH_LEN);
+    if (max_match_len <= match_len)
+        return;
+    for (;;)
+    {
+        for (;;)
+        {
+            if (--num_probes_left == 0)
+                return;
+#define TDEFL_PROBE                                                                               \
+    next_probe_pos = d->m_next[probe_pos];                                                        \
+    if ((!next_probe_pos) || ((dist = (mz_uint16)(lookahead_pos - next_probe_pos)) > max_dist))   \
+        return;                                                                                   \
+    probe_pos = next_probe_pos & TDEFL_LZ_DICT_SIZE_MASK;                                         \
+    if ((d->m_dict[probe_pos + match_len] == c0) && (d->m_dict[probe_pos + match_len - 1] == c1)) \
+        break;
+            TDEFL_PROBE;
+            TDEFL_PROBE;
+            TDEFL_PROBE;
+        }
+        if (!dist)
+            break;
+        p = s;
+        q = d->m_dict + probe_pos;
+        for (probe_len = 0; probe_len < max_match_len; probe_len++)
+            if (*p++ != *q++)
+                break;
+        if (probe_len > match_len)
+        {
+            *pMatch_dist = dist;
+            if ((*pMatch_len = match_len = probe_len) == max_match_len)
+                return;
+            c0 = d->m_dict[pos + match_len];
+            c1 = d->m_dict[pos + match_len - 1];
+        }
+    }
+}
+#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES */
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES &&MINIZ_LITTLE_ENDIAN
+static mz_bool tdefl_compress_fast(tdefl_compressor *d)
+{
+    /* Faster, minimally featured LZRW1-style match+parse loop with better register utilization. Intended for applications where raw throughput is valued more highly than ratio. */
+    mz_uint lookahead_pos = d->m_lookahead_pos, lookahead_size = d->m_lookahead_size, dict_size = d->m_dict_size, total_lz_bytes = d->m_total_lz_bytes, num_flags_left = d->m_num_flags_left;
+    mz_uint8 *pLZ_code_buf = d->m_pLZ_code_buf, *pLZ_flags = d->m_pLZ_flags;
+    mz_uint cur_pos = lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
+
+    while ((d->m_src_buf_left) || ((d->m_flush) && (lookahead_size)))
+    {
+        const mz_uint TDEFL_COMP_FAST_LOOKAHEAD_SIZE = 4096;
+        mz_uint dst_pos = (lookahead_pos + lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
+        mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(d->m_src_buf_left, TDEFL_COMP_FAST_LOOKAHEAD_SIZE - lookahead_size);
+        d->m_src_buf_left -= num_bytes_to_process;
+        lookahead_size += num_bytes_to_process;
+
+        while (num_bytes_to_process)
+        {
+            mz_uint32 n = MZ_MIN(TDEFL_LZ_DICT_SIZE - dst_pos, num_bytes_to_process);
+            memcpy(d->m_dict + dst_pos, d->m_pSrc, n);
+            if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
+                memcpy(d->m_dict + TDEFL_LZ_DICT_SIZE + dst_pos, d->m_pSrc, MZ_MIN(n, (TDEFL_MAX_MATCH_LEN - 1) - dst_pos));
+            d->m_pSrc += n;
+            dst_pos = (dst_pos + n) & TDEFL_LZ_DICT_SIZE_MASK;
+            num_bytes_to_process -= n;
+        }
+
+        dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - lookahead_size, dict_size);
+        if ((!d->m_flush) && (lookahead_size < TDEFL_COMP_FAST_LOOKAHEAD_SIZE))
+            break;
+
+        while (lookahead_size >= 4)
+        {
+            mz_uint cur_match_dist, cur_match_len = 1;
+            mz_uint8 *pCur_dict = d->m_dict + cur_pos;
+            mz_uint first_trigram = (*(const mz_uint32 *)pCur_dict) & 0xFFFFFF;
+            mz_uint hash = (first_trigram ^ (first_trigram >> (24 - (TDEFL_LZ_HASH_BITS - 8)))) & TDEFL_LEVEL1_HASH_SIZE_MASK;
+            mz_uint probe_pos = d->m_hash[hash];
+            d->m_hash[hash] = (mz_uint16)lookahead_pos;
+
+            if (((cur_match_dist = (mz_uint16)(lookahead_pos - probe_pos)) <= dict_size) && ((*(const mz_uint32 *)(d->m_dict + (probe_pos &= TDEFL_LZ_DICT_SIZE_MASK)) & 0xFFFFFF) == first_trigram))
+            {
+                const mz_uint16 *p = (const mz_uint16 *)pCur_dict;
+                const mz_uint16 *q = (const mz_uint16 *)(d->m_dict + probe_pos);
+                mz_uint32 probe_len = 32;
+                do
+                {
+                } while ((TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) &&
+                         (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (TDEFL_READ_UNALIGNED_WORD(++p) == TDEFL_READ_UNALIGNED_WORD(++q)) && (--probe_len > 0));
+                cur_match_len = ((mz_uint)(p - (const mz_uint16 *)pCur_dict) * 2) + (mz_uint)(*(const mz_uint8 *)p == *(const mz_uint8 *)q);
+                if (!probe_len)
+                    cur_match_len = cur_match_dist ? TDEFL_MAX_MATCH_LEN : 0;
+
+                if ((cur_match_len < TDEFL_MIN_MATCH_LEN) || ((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)))
+                {
+                    cur_match_len = 1;
+                    *pLZ_code_buf++ = (mz_uint8)first_trigram;
+                    *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+                    d->m_huff_count[0][(mz_uint8)first_trigram]++;
+                }
+                else
+                {
+                    mz_uint32 s0, s1;
+                    cur_match_len = MZ_MIN(cur_match_len, lookahead_size);
+
+                    MZ_ASSERT((cur_match_len >= TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 1) && (cur_match_dist <= TDEFL_LZ_DICT_SIZE));
+
+                    cur_match_dist--;
+
+                    pLZ_code_buf[0] = (mz_uint8)(cur_match_len - TDEFL_MIN_MATCH_LEN);
+                    *(mz_uint16 *)(&pLZ_code_buf[1]) = (mz_uint16)cur_match_dist;
+                    pLZ_code_buf += 3;
+                    *pLZ_flags = (mz_uint8)((*pLZ_flags >> 1) | 0x80);
+
+                    s0 = s_tdefl_small_dist_sym[cur_match_dist & 511];
+                    s1 = s_tdefl_large_dist_sym[cur_match_dist >> 8];
+                    d->m_huff_count[1][(cur_match_dist < 512) ? s0 : s1]++;
+
+                    d->m_huff_count[0][s_tdefl_len_sym[cur_match_len - TDEFL_MIN_MATCH_LEN]]++;
+                }
+            }
+            else
+            {
+                *pLZ_code_buf++ = (mz_uint8)first_trigram;
+                *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+                d->m_huff_count[0][(mz_uint8)first_trigram]++;
+            }
+
+            if (--num_flags_left == 0)
+            {
+                num_flags_left = 8;
+                pLZ_flags = pLZ_code_buf++;
+            }
+
+            total_lz_bytes += cur_match_len;
+            lookahead_pos += cur_match_len;
+            dict_size = MZ_MIN(dict_size + cur_match_len, (mz_uint)TDEFL_LZ_DICT_SIZE);
+            cur_pos = (cur_pos + cur_match_len) & TDEFL_LZ_DICT_SIZE_MASK;
+            MZ_ASSERT(lookahead_size >= cur_match_len);
+            lookahead_size -= cur_match_len;
+
+            if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
+            {
+                int n;
+                d->m_lookahead_pos = lookahead_pos;
+                d->m_lookahead_size = lookahead_size;
+                d->m_dict_size = dict_size;
+                d->m_total_lz_bytes = total_lz_bytes;
+                d->m_pLZ_code_buf = pLZ_code_buf;
+                d->m_pLZ_flags = pLZ_flags;
+                d->m_num_flags_left = num_flags_left;
+                if ((n = tdefl_flush_block(d, 0)) != 0)
+                    return (n < 0) ? MZ_FALSE : MZ_TRUE;
+                total_lz_bytes = d->m_total_lz_bytes;
+                pLZ_code_buf = d->m_pLZ_code_buf;
+                pLZ_flags = d->m_pLZ_flags;
+                num_flags_left = d->m_num_flags_left;
+            }
+        }
+
+        while (lookahead_size)
+        {
+            mz_uint8 lit = d->m_dict[cur_pos];
+
+            total_lz_bytes++;
+            *pLZ_code_buf++ = lit;
+            *pLZ_flags = (mz_uint8)(*pLZ_flags >> 1);
+            if (--num_flags_left == 0)
+            {
+                num_flags_left = 8;
+                pLZ_flags = pLZ_code_buf++;
+            }
+
+            d->m_huff_count[0][lit]++;
+
+            lookahead_pos++;
+            dict_size = MZ_MIN(dict_size + 1, (mz_uint)TDEFL_LZ_DICT_SIZE);
+            cur_pos = (cur_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
+            lookahead_size--;
+
+            if (pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8])
+            {
+                int n;
+                d->m_lookahead_pos = lookahead_pos;
+                d->m_lookahead_size = lookahead_size;
+                d->m_dict_size = dict_size;
+                d->m_total_lz_bytes = total_lz_bytes;
+                d->m_pLZ_code_buf = pLZ_code_buf;
+                d->m_pLZ_flags = pLZ_flags;
+                d->m_num_flags_left = num_flags_left;
+                if ((n = tdefl_flush_block(d, 0)) != 0)
+                    return (n < 0) ? MZ_FALSE : MZ_TRUE;
+                total_lz_bytes = d->m_total_lz_bytes;
+                pLZ_code_buf = d->m_pLZ_code_buf;
+                pLZ_flags = d->m_pLZ_flags;
+                num_flags_left = d->m_num_flags_left;
+            }
+        }
+    }
+
+    d->m_lookahead_pos = lookahead_pos;
+    d->m_lookahead_size = lookahead_size;
+    d->m_dict_size = dict_size;
+    d->m_total_lz_bytes = total_lz_bytes;
+    d->m_pLZ_code_buf = pLZ_code_buf;
+    d->m_pLZ_flags = pLZ_flags;
+    d->m_num_flags_left = num_flags_left;
+    return MZ_TRUE;
+}
+#endif /* MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
+
+static MZ_FORCEINLINE void tdefl_record_literal(tdefl_compressor *d, mz_uint8 lit)
+{
+    d->m_total_lz_bytes++;
+    *d->m_pLZ_code_buf++ = lit;
+    *d->m_pLZ_flags = (mz_uint8)(*d->m_pLZ_flags >> 1);
+    if (--d->m_num_flags_left == 0)
+    {
+        d->m_num_flags_left = 8;
+        d->m_pLZ_flags = d->m_pLZ_code_buf++;
+    }
+    d->m_huff_count[0][lit]++;
+}
+
+static MZ_FORCEINLINE void tdefl_record_match(tdefl_compressor *d, mz_uint match_len, mz_uint match_dist)
+{
+    mz_uint32 s0, s1;
+
+    MZ_ASSERT((match_len >= TDEFL_MIN_MATCH_LEN) && (match_dist >= 1) && (match_dist <= TDEFL_LZ_DICT_SIZE));
+
+    d->m_total_lz_bytes += match_len;
+
+    d->m_pLZ_code_buf[0] = (mz_uint8)(match_len - TDEFL_MIN_MATCH_LEN);
+
+    match_dist -= 1;
+    d->m_pLZ_code_buf[1] = (mz_uint8)(match_dist & 0xFF);
+    d->m_pLZ_code_buf[2] = (mz_uint8)(match_dist >> 8);
+    d->m_pLZ_code_buf += 3;
+
+    *d->m_pLZ_flags = (mz_uint8)((*d->m_pLZ_flags >> 1) | 0x80);
+    if (--d->m_num_flags_left == 0)
+    {
+        d->m_num_flags_left = 8;
+        d->m_pLZ_flags = d->m_pLZ_code_buf++;
+    }
+
+    s0 = s_tdefl_small_dist_sym[match_dist & 511];
+    s1 = s_tdefl_large_dist_sym[(match_dist >> 8) & 127];
+    d->m_huff_count[1][(match_dist < 512) ? s0 : s1]++;
+
+    if (match_len >= TDEFL_MIN_MATCH_LEN)
+        d->m_huff_count[0][s_tdefl_len_sym[match_len - TDEFL_MIN_MATCH_LEN]]++;
+}
+
+static mz_bool tdefl_compress_normal(tdefl_compressor *d)
+{
+    const mz_uint8 *pSrc = d->m_pSrc;
+    size_t src_buf_left = d->m_src_buf_left;
+    tdefl_flush flush = d->m_flush;
+
+    while ((src_buf_left) || ((flush) && (d->m_lookahead_size)))
+    {
+        mz_uint len_to_move, cur_match_dist, cur_match_len, cur_pos;
+        /* Update dictionary and hash chains. Keeps the lookahead size equal to TDEFL_MAX_MATCH_LEN. */
+        if ((d->m_lookahead_size + d->m_dict_size) >= (TDEFL_MIN_MATCH_LEN - 1))
+        {
+            mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK, ins_pos = d->m_lookahead_pos + d->m_lookahead_size - 2;
+            mz_uint hash = (d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK];
+            mz_uint num_bytes_to_process = (mz_uint)MZ_MIN(src_buf_left, TDEFL_MAX_MATCH_LEN - d->m_lookahead_size);
+            const mz_uint8 *pSrc_end = pSrc + num_bytes_to_process;
+            src_buf_left -= num_bytes_to_process;
+            d->m_lookahead_size += num_bytes_to_process;
+            while (pSrc != pSrc_end)
+            {
+                mz_uint8 c = *pSrc++;
+                d->m_dict[dst_pos] = c;
+                if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
+                    d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
+                hash = ((hash << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
+                d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
+                d->m_hash[hash] = (mz_uint16)(ins_pos);
+                dst_pos = (dst_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK;
+                ins_pos++;
+            }
+        }
+        else
+        {
+            while ((src_buf_left) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
+            {
+                mz_uint8 c = *pSrc++;
+                mz_uint dst_pos = (d->m_lookahead_pos + d->m_lookahead_size) & TDEFL_LZ_DICT_SIZE_MASK;
+                src_buf_left--;
+                d->m_dict[dst_pos] = c;
+                if (dst_pos < (TDEFL_MAX_MATCH_LEN - 1))
+                    d->m_dict[TDEFL_LZ_DICT_SIZE + dst_pos] = c;
+                if ((++d->m_lookahead_size + d->m_dict_size) >= TDEFL_MIN_MATCH_LEN)
+                {
+                    mz_uint ins_pos = d->m_lookahead_pos + (d->m_lookahead_size - 1) - 2;
+                    mz_uint hash = ((d->m_dict[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] << (TDEFL_LZ_HASH_SHIFT * 2)) ^ (d->m_dict[(ins_pos + 1) & TDEFL_LZ_DICT_SIZE_MASK] << TDEFL_LZ_HASH_SHIFT) ^ c) & (TDEFL_LZ_HASH_SIZE - 1);
+                    d->m_next[ins_pos & TDEFL_LZ_DICT_SIZE_MASK] = d->m_hash[hash];
+                    d->m_hash[hash] = (mz_uint16)(ins_pos);
+                }
+            }
+        }
+        d->m_dict_size = MZ_MIN(TDEFL_LZ_DICT_SIZE - d->m_lookahead_size, d->m_dict_size);
+        if ((!flush) && (d->m_lookahead_size < TDEFL_MAX_MATCH_LEN))
+            break;
+
+        /* Simple lazy/greedy parsing state machine. */
+        len_to_move = 1;
+        cur_match_dist = 0;
+        cur_match_len = d->m_saved_match_len ? d->m_saved_match_len : (TDEFL_MIN_MATCH_LEN - 1);
+        cur_pos = d->m_lookahead_pos & TDEFL_LZ_DICT_SIZE_MASK;
+        if (d->m_flags & (TDEFL_RLE_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS))
+        {
+            if ((d->m_dict_size) && (!(d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS)))
+            {
+                mz_uint8 c = d->m_dict[(cur_pos - 1) & TDEFL_LZ_DICT_SIZE_MASK];
+                cur_match_len = 0;
+                while (cur_match_len < d->m_lookahead_size)
+                {
+                    if (d->m_dict[cur_pos + cur_match_len] != c)
+                        break;
+                    cur_match_len++;
+                }
+                if (cur_match_len < TDEFL_MIN_MATCH_LEN)
+                    cur_match_len = 0;
+                else
+                    cur_match_dist = 1;
+            }
+        }
+        else
+        {
+            tdefl_find_match(d, d->m_lookahead_pos, d->m_dict_size, d->m_lookahead_size, &cur_match_dist, &cur_match_len);
+        }
+        if (((cur_match_len == TDEFL_MIN_MATCH_LEN) && (cur_match_dist >= 8U * 1024U)) || (cur_pos == cur_match_dist) || ((d->m_flags & TDEFL_FILTER_MATCHES) && (cur_match_len <= 5)))
+        {
+            cur_match_dist = cur_match_len = 0;
+        }
+        if (d->m_saved_match_len)
+        {
+            if (cur_match_len > d->m_saved_match_len)
+            {
+                tdefl_record_literal(d, (mz_uint8)d->m_saved_lit);
+                if (cur_match_len >= 128)
+                {
+                    tdefl_record_match(d, cur_match_len, cur_match_dist);
+                    d->m_saved_match_len = 0;
+                    len_to_move = cur_match_len;
+                }
+                else
+                {
+                    d->m_saved_lit = d->m_dict[cur_pos];
+                    d->m_saved_match_dist = cur_match_dist;
+                    d->m_saved_match_len = cur_match_len;
+                }
+            }
+            else
+            {
+                tdefl_record_match(d, d->m_saved_match_len, d->m_saved_match_dist);
+                len_to_move = d->m_saved_match_len - 1;
+                d->m_saved_match_len = 0;
+            }
+        }
+        else if (!cur_match_dist)
+            tdefl_record_literal(d, d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)]);
+        else if ((d->m_greedy_parsing) || (d->m_flags & TDEFL_RLE_MATCHES) || (cur_match_len >= 128))
+        {
+            tdefl_record_match(d, cur_match_len, cur_match_dist);
+            len_to_move = cur_match_len;
+        }
+        else
+        {
+            d->m_saved_lit = d->m_dict[MZ_MIN(cur_pos, sizeof(d->m_dict) - 1)];
+            d->m_saved_match_dist = cur_match_dist;
+            d->m_saved_match_len = cur_match_len;
+        }
+        /* Move the lookahead forward by len_to_move bytes. */
+        d->m_lookahead_pos += len_to_move;
+        MZ_ASSERT(d->m_lookahead_size >= len_to_move);
+        d->m_lookahead_size -= len_to_move;
+        d->m_dict_size = MZ_MIN(d->m_dict_size + len_to_move, (mz_uint)TDEFL_LZ_DICT_SIZE);
+        /* Check if it's time to flush the current LZ codes to the internal output buffer. */
+        if ((d->m_pLZ_code_buf > &d->m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE - 8]) ||
+            ((d->m_total_lz_bytes > 31 * 1024) && (((((mz_uint)(d->m_pLZ_code_buf - d->m_lz_code_buf) * 115) >> 7) >= d->m_total_lz_bytes) || (d->m_flags & TDEFL_FORCE_ALL_RAW_BLOCKS))))
+        {
+            int n;
+            d->m_pSrc = pSrc;
+            d->m_src_buf_left = src_buf_left;
+            if ((n = tdefl_flush_block(d, 0)) != 0)
+                return (n < 0) ? MZ_FALSE : MZ_TRUE;
+        }
+    }
+
+    d->m_pSrc = pSrc;
+    d->m_src_buf_left = src_buf_left;
+    return MZ_TRUE;
+}
+
+static tdefl_status tdefl_flush_output_buffer(tdefl_compressor *d)
+{
+    if (d->m_pIn_buf_size)
+    {
+        *d->m_pIn_buf_size = d->m_pSrc - (const mz_uint8 *)d->m_pIn_buf;
+    }
+
+    if (d->m_pOut_buf_size)
+    {
+        size_t n = MZ_MIN(*d->m_pOut_buf_size - d->m_out_buf_ofs, d->m_output_flush_remaining);
+        memcpy((mz_uint8 *)d->m_pOut_buf + d->m_out_buf_ofs, d->m_output_buf + d->m_output_flush_ofs, n);
+        d->m_output_flush_ofs += (mz_uint)n;
+        d->m_output_flush_remaining -= (mz_uint)n;
+        d->m_out_buf_ofs += n;
+
+        *d->m_pOut_buf_size = d->m_out_buf_ofs;
+    }
+
+    return (d->m_finished && !d->m_output_flush_remaining) ? TDEFL_STATUS_DONE : TDEFL_STATUS_OKAY;
+}
+
+tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush)
+{
+    if (!d)
+    {
+        if (pIn_buf_size)
+            *pIn_buf_size = 0;
+        if (pOut_buf_size)
+            *pOut_buf_size = 0;
+        return TDEFL_STATUS_BAD_PARAM;
+    }
+
+    d->m_pIn_buf = pIn_buf;
+    d->m_pIn_buf_size = pIn_buf_size;
+    d->m_pOut_buf = pOut_buf;
+    d->m_pOut_buf_size = pOut_buf_size;
+    d->m_pSrc = (const mz_uint8 *)(pIn_buf);
+    d->m_src_buf_left = pIn_buf_size ? *pIn_buf_size : 0;
+    d->m_out_buf_ofs = 0;
+    d->m_flush = flush;
+
+    if (((d->m_pPut_buf_func != NULL) == ((pOut_buf != NULL) || (pOut_buf_size != NULL))) || (d->m_prev_return_status != TDEFL_STATUS_OKAY) ||
+        (d->m_wants_to_finish && (flush != TDEFL_FINISH)) || (pIn_buf_size && *pIn_buf_size && !pIn_buf) || (pOut_buf_size && *pOut_buf_size && !pOut_buf))
+    {
+        if (pIn_buf_size)
+            *pIn_buf_size = 0;
+        if (pOut_buf_size)
+            *pOut_buf_size = 0;
+        return (d->m_prev_return_status = TDEFL_STATUS_BAD_PARAM);
+    }
+    d->m_wants_to_finish |= (flush == TDEFL_FINISH);
+
+    if ((d->m_output_flush_remaining) || (d->m_finished))
+        return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES &&MINIZ_LITTLE_ENDIAN
+    if (((d->m_flags & TDEFL_MAX_PROBES_MASK) == 1) &&
+        ((d->m_flags & TDEFL_GREEDY_PARSING_FLAG) != 0) &&
+        ((d->m_flags & (TDEFL_FILTER_MATCHES | TDEFL_FORCE_ALL_RAW_BLOCKS | TDEFL_RLE_MATCHES)) == 0))
+    {
+        if (!tdefl_compress_fast(d))
+            return d->m_prev_return_status;
+    }
+    else
+#endif /* #if MINIZ_USE_UNALIGNED_LOADS_AND_STORES && MINIZ_LITTLE_ENDIAN */
+    {
+        if (!tdefl_compress_normal(d))
+            return d->m_prev_return_status;
+    }
+
+    if ((d->m_flags & (TDEFL_WRITE_ZLIB_HEADER | TDEFL_COMPUTE_ADLER32)) && (pIn_buf))
+        d->m_adler32 = (mz_uint32)mz_adler32(d->m_adler32, (const mz_uint8 *)pIn_buf, d->m_pSrc - (const mz_uint8 *)pIn_buf);
+
+    if ((flush) && (!d->m_lookahead_size) && (!d->m_src_buf_left) && (!d->m_output_flush_remaining))
+    {
+        if (tdefl_flush_block(d, flush) < 0)
+            return d->m_prev_return_status;
+        d->m_finished = (flush == TDEFL_FINISH);
+        if (flush == TDEFL_FULL_FLUSH)
+        {
+            MZ_CLEAR_OBJ(d->m_hash);
+            MZ_CLEAR_OBJ(d->m_next);
+            d->m_dict_size = 0;
+        }
+    }
+
+    return (d->m_prev_return_status = tdefl_flush_output_buffer(d));
+}
+
+tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush)
+{
+    MZ_ASSERT(d->m_pPut_buf_func);
+    return tdefl_compress(d, pIn_buf, &in_buf_size, NULL, NULL, flush);
+}
+
+tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+    d->m_pPut_buf_func = pPut_buf_func;
+    d->m_pPut_buf_user = pPut_buf_user;
+    d->m_flags = (mz_uint)(flags);
+    d->m_max_probes[0] = 1 + ((flags & 0xFFF) + 2) / 3;
+    d->m_greedy_parsing = (flags & TDEFL_GREEDY_PARSING_FLAG) != 0;
+    d->m_max_probes[1] = 1 + (((flags & 0xFFF) >> 2) + 2) / 3;
+    if (!(flags & TDEFL_NONDETERMINISTIC_PARSING_FLAG))
+        MZ_CLEAR_OBJ(d->m_hash);
+    d->m_lookahead_pos = d->m_lookahead_size = d->m_dict_size = d->m_total_lz_bytes = d->m_lz_code_buf_dict_pos = d->m_bits_in = 0;
+    d->m_output_flush_ofs = d->m_output_flush_remaining = d->m_finished = d->m_block_index = d->m_bit_buffer = d->m_wants_to_finish = 0;
+    d->m_pLZ_code_buf = d->m_lz_code_buf + 1;
+    d->m_pLZ_flags = d->m_lz_code_buf;
+    d->m_num_flags_left = 8;
+    d->m_pOutput_buf = d->m_output_buf;
+    d->m_pOutput_buf_end = d->m_output_buf;
+    d->m_prev_return_status = TDEFL_STATUS_OKAY;
+    d->m_saved_match_dist = d->m_saved_match_len = d->m_saved_lit = 0;
+    d->m_adler32 = 1;
+    d->m_pIn_buf = NULL;
+    d->m_pOut_buf = NULL;
+    d->m_pIn_buf_size = NULL;
+    d->m_pOut_buf_size = NULL;
+    d->m_flush = TDEFL_NO_FLUSH;
+    d->m_pSrc = NULL;
+    d->m_src_buf_left = 0;
+    d->m_out_buf_ofs = 0;
+    memset(&d->m_huff_count[0][0], 0, sizeof(d->m_huff_count[0][0]) * TDEFL_MAX_HUFF_SYMBOLS_0);
+    memset(&d->m_huff_count[1][0], 0, sizeof(d->m_huff_count[1][0]) * TDEFL_MAX_HUFF_SYMBOLS_1);
+    return TDEFL_STATUS_OKAY;
+}
+
+tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d)
+{
+    return d->m_prev_return_status;
+}
+
+mz_uint32 tdefl_get_adler32(tdefl_compressor *d)
+{
+    return d->m_adler32;
+}
+
+mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+    tdefl_compressor *pComp;
+    mz_bool succeeded;
+    if (((buf_len) && (!pBuf)) || (!pPut_buf_func))
+        return MZ_FALSE;
+    pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
+    if (!pComp)
+        return MZ_FALSE;
+    succeeded = (tdefl_init(pComp, pPut_buf_func, pPut_buf_user, flags) == TDEFL_STATUS_OKAY);
+    succeeded = succeeded && (tdefl_compress_buffer(pComp, pBuf, buf_len, TDEFL_FINISH) == TDEFL_STATUS_DONE);
+    MZ_FREE(pComp);
+    return succeeded;
+}
+
+typedef struct
+{
+    size_t m_size, m_capacity;
+    mz_uint8 *m_pBuf;
+    mz_bool m_expandable;
+} tdefl_output_buffer;
+
+static mz_bool tdefl_output_buffer_putter(const void *pBuf, int len, void *pUser)
+{
+    tdefl_output_buffer *p = (tdefl_output_buffer *)pUser;
+    size_t new_size = p->m_size + len;
+    if (new_size > p->m_capacity)
+    {
+        size_t new_capacity = p->m_capacity;
+        mz_uint8 *pNew_buf;
+        if (!p->m_expandable)
+            return MZ_FALSE;
+        do
+        {
+            new_capacity = MZ_MAX(128U, new_capacity << 1U);
+        } while (new_size > new_capacity);
+        pNew_buf = (mz_uint8 *)MZ_REALLOC(p->m_pBuf, new_capacity);
+        if (!pNew_buf)
+            return MZ_FALSE;
+        p->m_pBuf = pNew_buf;
+        p->m_capacity = new_capacity;
+    }
+    memcpy((mz_uint8 *)p->m_pBuf + p->m_size, pBuf, len);
+    p->m_size = new_size;
+    return MZ_TRUE;
+}
+
+void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
+{
+    tdefl_output_buffer out_buf;
+    MZ_CLEAR_OBJ(out_buf);
+    if (!pOut_len)
+        return MZ_FALSE;
+    else
+        *pOut_len = 0;
+    out_buf.m_expandable = MZ_TRUE;
+    if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
+        return NULL;
+    *pOut_len = out_buf.m_size;
+    return out_buf.m_pBuf;
+}
+
+size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
+{
+    tdefl_output_buffer out_buf;
+    MZ_CLEAR_OBJ(out_buf);
+    if (!pOut_buf)
+        return 0;
+    out_buf.m_pBuf = (mz_uint8 *)pOut_buf;
+    out_buf.m_capacity = out_buf_len;
+    if (!tdefl_compress_mem_to_output(pSrc_buf, src_buf_len, tdefl_output_buffer_putter, &out_buf, flags))
+        return 0;
+    return out_buf.m_size;
+}
+
+static const mz_uint s_tdefl_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
+
+/* level may actually range from [0,10] (10 is a "hidden" max level, where we want a bit more compression and it's fine if throughput to fall off a cliff on some files). */
+mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy)
+{
+    mz_uint comp_flags = s_tdefl_num_probes[(level >= 0) ? MZ_MIN(10, level) : MZ_DEFAULT_LEVEL] | ((level <= 3) ? TDEFL_GREEDY_PARSING_FLAG : 0);
+    if (window_bits > 0)
+        comp_flags |= TDEFL_WRITE_ZLIB_HEADER;
+
+    if (!level)
+        comp_flags |= TDEFL_FORCE_ALL_RAW_BLOCKS;
+    else if (strategy == MZ_FILTERED)
+        comp_flags |= TDEFL_FILTER_MATCHES;
+    else if (strategy == MZ_HUFFMAN_ONLY)
+        comp_flags &= ~TDEFL_MAX_PROBES_MASK;
+    else if (strategy == MZ_FIXED)
+        comp_flags |= TDEFL_FORCE_ALL_STATIC_BLOCKS;
+    else if (strategy == MZ_RLE)
+        comp_flags |= TDEFL_RLE_MATCHES;
+
+    return comp_flags;
+}
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable : 4204) /* nonstandard extension used : non-constant aggregate initializer (also supported by GNU C and C99, so no big deal) */
+#endif
+
+/* Simple PNG writer function by Alex Evans, 2011. Released into the public domain: https://gist.github.com/908299, more context at
+ http://altdevblogaday.org/2011/04/06/a-smaller-jpg-encoder/.
+ This is actually a modification of Alex's original code so PNG files generated by this function pass pngcheck. */
+void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip)
+{
+    /* Using a local copy of this array here in case MINIZ_NO_ZLIB_APIS was defined. */
+    static const mz_uint s_tdefl_png_num_probes[11] = { 0, 1, 6, 32, 16, 32, 128, 256, 512, 768, 1500 };
+    tdefl_compressor *pComp = (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
+    tdefl_output_buffer out_buf;
+    int i, bpl = w * num_chans, y, z;
+    mz_uint32 c;
+    *pLen_out = 0;
+    if (!pComp)
+        return NULL;
+    MZ_CLEAR_OBJ(out_buf);
+    out_buf.m_expandable = MZ_TRUE;
+    out_buf.m_capacity = 57 + MZ_MAX(64, (1 + bpl) * h);
+    if (NULL == (out_buf.m_pBuf = (mz_uint8 *)MZ_MALLOC(out_buf.m_capacity)))
+    {
+        MZ_FREE(pComp);
+        return NULL;
+    }
+    /* write dummy header */
+    for (z = 41; z; --z)
+        tdefl_output_buffer_putter(&z, 1, &out_buf);
+    /* compress image data */
+    tdefl_init(pComp, tdefl_output_buffer_putter, &out_buf, s_tdefl_png_num_probes[MZ_MIN(10, level)] | TDEFL_WRITE_ZLIB_HEADER);
+    for (y = 0; y < h; ++y)
+    {
+        tdefl_compress_buffer(pComp, &z, 1, TDEFL_NO_FLUSH);
+        tdefl_compress_buffer(pComp, (mz_uint8 *)pImage + (flip ? (h - 1 - y) : y) * bpl, bpl, TDEFL_NO_FLUSH);
+    }
+    if (tdefl_compress_buffer(pComp, NULL, 0, TDEFL_FINISH) != TDEFL_STATUS_DONE)
+    {
+        MZ_FREE(pComp);
+        MZ_FREE(out_buf.m_pBuf);
+        return NULL;
+    }
+    /* write real header */
+    *pLen_out = out_buf.m_size - 41;
+    {
+        static const mz_uint8 chans[] = { 0x00, 0x00, 0x04, 0x02, 0x06 };
+        mz_uint8 pnghdr[41] = { 0x89, 0x50, 0x4e, 0x47, 0x0d, 
+                                                               0x0a, 0x1a, 0x0a, 0x00, 0x00, 
+                                                               0x00, 0x0d, 0x49, 0x48, 0x44, 
+                                                               0x52, 0x00, 0x00, 0x00, 0x00, 
+                                                               0x00, 0x00, 0x00, 0x00, 0x08, 
+                                                               0x00, 0x00, 0x00, 0x00, 0x00, 
+                                                               0x00, 0x00, 0x00, 0x00, 0x00, 
+                                                               0x00, 0x00, 0x49, 0x44, 0x41, 
+                                                               0x54 };
+               pnghdr[18] = (mz_uint8)(w >> 8);
+               pnghdr[19] = (mz_uint8)w;
+               pnghdr[22] = (mz_uint8)(h >> 8);
+               pnghdr[22] = (mz_uint8)h;
+               pnghdr[25] = chans[num_chans];
+               pnghdr[33] = (mz_uint8)(*pLen_out >> 24);
+               pnghdr[34] = (mz_uint8)(*pLen_out >> 16);
+               pnghdr[35] = (mz_uint8)(*pLen_out >> 8);
+               pnghdr[36] = (mz_uint8)*pLen_out;
+        c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, pnghdr + 12, 17);
+        for (i = 0; i < 4; ++i, c <<= 8)
+            ((mz_uint8 *)(pnghdr + 29))[i] = (mz_uint8)(c >> 24);
+        memcpy(out_buf.m_pBuf, pnghdr, 41);
+    }
+    /* write footer (IDAT CRC-32, followed by IEND chunk) */
+    if (!tdefl_output_buffer_putter("\0\0\0\0\0\0\0\0\x49\x45\x4e\x44\xae\x42\x60\x82", 16, &out_buf))
+    {
+        *pLen_out = 0;
+        MZ_FREE(pComp);
+        MZ_FREE(out_buf.m_pBuf);
+        return NULL;
+    }
+    c = (mz_uint32)mz_crc32(MZ_CRC32_INIT, out_buf.m_pBuf + 41 - 4, *pLen_out + 4);
+    for (i = 0; i < 4; ++i, c <<= 8)
+        (out_buf.m_pBuf + out_buf.m_size - 16)[i] = (mz_uint8)(c >> 24);
+    /* compute final size of file, grab compressed data buffer and return */
+    *pLen_out += 57;
+    MZ_FREE(pComp);
+    return out_buf.m_pBuf;
+}
+void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out)
+{
+    /* Level 6 corresponds to TDEFL_DEFAULT_MAX_PROBES or MZ_DEFAULT_LEVEL (but we can't depend on MZ_DEFAULT_LEVEL being available in case the zlib API's where #defined out) */
+    return tdefl_write_image_to_png_file_in_memory_ex(pImage, w, h, num_chans, pLen_out, 6, MZ_FALSE);
+}
+
+/* Allocate the tdefl_compressor and tinfl_decompressor structures in C so that */
+/* non-C language bindings to tdefL_ and tinfl_ API don't need to worry about */
+/* structure size and allocation mechanism. */
+tdefl_compressor *tdefl_compressor_alloc()
+{
+    return (tdefl_compressor *)MZ_MALLOC(sizeof(tdefl_compressor));
+}
+
+void tdefl_compressor_free(tdefl_compressor *pComp)
+{
+    MZ_FREE(pComp);
+}
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+/**************************************************************************
+ *
+ * Copyright 2013-2014 RAD Game Tools and Valve Software
+ * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- Low-level Decompression (completely independent from all compression API's) */
+
+#define TINFL_MEMCPY(d, s, l) memcpy(d, s, l)
+#define TINFL_MEMSET(p, c, l) memset(p, c, l)
+
+#define TINFL_CR_BEGIN  \
+    switch (r->m_state) \
+    {                   \
+        case 0:
+#define TINFL_CR_RETURN(state_index, result) \
+    do                                       \
+    {                                        \
+        status = result;                     \
+        r->m_state = state_index;            \
+        goto common_exit;                    \
+        case state_index:                    \
+            ;                                \
+    }                                        \
+    MZ_MACRO_END
+#define TINFL_CR_RETURN_FOREVER(state_index, result) \
+    do                                               \
+    {                                                \
+        for (;;)                                     \
+        {                                            \
+            TINFL_CR_RETURN(state_index, result);    \
+        }                                            \
+    }                                                \
+    MZ_MACRO_END
+#define TINFL_CR_FINISH }
+
+#define TINFL_GET_BYTE(state_index, c)                                                                                                                          \
+    do                                                                                                                                                          \
+    {                                                                                                                                                           \
+        while (pIn_buf_cur >= pIn_buf_end)                                                                                                                      \
+        {                                                                                                                                                       \
+            TINFL_CR_RETURN(state_index, (decomp_flags &TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS); \
+        }                                                                                                                                                       \
+        c = *pIn_buf_cur++;                                                                                                                                     \
+    }                                                                                                                                                           \
+    MZ_MACRO_END
+
+#define TINFL_NEED_BITS(state_index, n)                \
+    do                                                 \
+    {                                                  \
+        mz_uint c;                                     \
+        TINFL_GET_BYTE(state_index, c);                \
+        bit_buf |= (((tinfl_bit_buf_t)c) << num_bits); \
+        num_bits += 8;                                 \
+    } while (num_bits < (mz_uint)(n))
+#define TINFL_SKIP_BITS(state_index, n)      \
+    do                                       \
+    {                                        \
+        if (num_bits < (mz_uint)(n))         \
+        {                                    \
+            TINFL_NEED_BITS(state_index, n); \
+        }                                    \
+        bit_buf >>= (n);                     \
+        num_bits -= (n);                     \
+    }                                        \
+    MZ_MACRO_END
+#define TINFL_GET_BITS(state_index, b, n)    \
+    do                                       \
+    {                                        \
+        if (num_bits < (mz_uint)(n))         \
+        {                                    \
+            TINFL_NEED_BITS(state_index, n); \
+        }                                    \
+        b = bit_buf & ((1 << (n)) - 1);      \
+        bit_buf >>= (n);                     \
+        num_bits -= (n);                     \
+    }                                        \
+    MZ_MACRO_END
+
+/* TINFL_HUFF_BITBUF_FILL() is only used rarely, when the number of bytes remaining in the input buffer falls below 2. */
+/* It reads just enough bytes from the input stream that are needed to decode the next Huffman code (and absolutely no more). It works by trying to fully decode a */
+/* Huffman code by using whatever bits are currently present in the bit buffer. If this fails, it reads another byte, and tries again until it succeeds or until the */
+/* bit buffer contains >=15 bits (deflate's max. Huffman code size). */
+#define TINFL_HUFF_BITBUF_FILL(state_index, pHuff)                             \
+    do                                                                         \
+    {                                                                          \
+        temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)];     \
+        if (temp >= 0)                                                         \
+        {                                                                      \
+            code_len = temp >> 9;                                              \
+            if ((code_len) && (num_bits >= code_len))                          \
+                break;                                                         \
+        }                                                                      \
+        else if (num_bits > TINFL_FAST_LOOKUP_BITS)                            \
+        {                                                                      \
+            code_len = TINFL_FAST_LOOKUP_BITS;                                 \
+            do                                                                 \
+            {                                                                  \
+                temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)]; \
+            } while ((temp < 0) && (num_bits >= (code_len + 1)));              \
+            if (temp >= 0)                                                     \
+                break;                                                         \
+        }                                                                      \
+        TINFL_GET_BYTE(state_index, c);                                        \
+        bit_buf |= (((tinfl_bit_buf_t)c) << num_bits);                         \
+        num_bits += 8;                                                         \
+    } while (num_bits < 15);
+
+/* TINFL_HUFF_DECODE() decodes the next Huffman coded symbol. It's more complex than you would initially expect because the zlib API expects the decompressor to never read */
+/* beyond the final byte of the deflate stream. (In other words, when this macro wants to read another byte from the input, it REALLY needs another byte in order to fully */
+/* decode the next Huffman code.) Handling this properly is particularly important on raw deflate (non-zlib) streams, which aren't followed by a byte aligned adler-32. */
+/* The slow path is only executed at the very end of the input buffer. */
+/* v1.16: The original macro handled the case at the very end of the passed-in input buffer, but we also need to handle the case where the user passes in 1+zillion bytes */
+/* following the deflate data and our non-conservative read-ahead path won't kick in here on this code. This is much trickier. */
+#define TINFL_HUFF_DECODE(state_index, sym, pHuff)                                                                                  \
+    do                                                                                                                              \
+    {                                                                                                                               \
+        int temp;                                                                                                                   \
+        mz_uint code_len, c;                                                                                                        \
+        if (num_bits < 15)                                                                                                          \
+        {                                                                                                                           \
+            if ((pIn_buf_end - pIn_buf_cur) < 2)                                                                                    \
+            {                                                                                                                       \
+                TINFL_HUFF_BITBUF_FILL(state_index, pHuff);                                                                         \
+            }                                                                                                                       \
+            else                                                                                                                    \
+            {                                                                                                                       \
+                bit_buf |= (((tinfl_bit_buf_t)pIn_buf_cur[0]) << num_bits) | (((tinfl_bit_buf_t)pIn_buf_cur[1]) << (num_bits + 8)); \
+                pIn_buf_cur += 2;                                                                                                   \
+                num_bits += 16;                                                                                                     \
+            }                                                                                                                       \
+        }                                                                                                                           \
+        if ((temp = (pHuff)->m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)                                               \
+            code_len = temp >> 9, temp &= 511;                                                                                      \
+        else                                                                                                                        \
+        {                                                                                                                           \
+            code_len = TINFL_FAST_LOOKUP_BITS;                                                                                      \
+            do                                                                                                                      \
+            {                                                                                                                       \
+                temp = (pHuff)->m_tree[~temp + ((bit_buf >> code_len++) & 1)];                                                      \
+            } while (temp < 0);                                                                                                     \
+        }                                                                                                                           \
+        sym = temp;                                                                                                                 \
+        bit_buf >>= code_len;                                                                                                       \
+        num_bits -= code_len;                                                                                                       \
+    }                                                                                                                               \
+    MZ_MACRO_END
+
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags)
+{
+    static const int s_length_base[31] = { 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0 };
+    static const int s_length_extra[31] = { 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 0, 0 };
+    static const int s_dist_base[32] = { 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577, 0, 0 };
+    static const int s_dist_extra[32] = { 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13 };
+    static const mz_uint8 s_length_dezigzag[19] = { 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 };
+    static const int s_min_table_sizes[3] = { 257, 1, 4 };
+
+    tinfl_status status = TINFL_STATUS_FAILED;
+    mz_uint32 num_bits, dist, counter, num_extra;
+    tinfl_bit_buf_t bit_buf;
+    const mz_uint8 *pIn_buf_cur = pIn_buf_next, *const pIn_buf_end = pIn_buf_next + *pIn_buf_size;
+    mz_uint8 *pOut_buf_cur = pOut_buf_next, *const pOut_buf_end = pOut_buf_next + *pOut_buf_size;
+    size_t out_buf_size_mask = (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF) ? (size_t) - 1 : ((pOut_buf_next - pOut_buf_start) + *pOut_buf_size) - 1, dist_from_out_buf_start;
+
+    /* Ensure the output buffer's size is a power of 2, unless the output buffer is large enough to hold the entire output file (in which case it doesn't matter). */
+    if (((out_buf_size_mask + 1) & out_buf_size_mask) || (pOut_buf_next < pOut_buf_start))
+    {
+        *pIn_buf_size = *pOut_buf_size = 0;
+        return TINFL_STATUS_BAD_PARAM;
+    }
+
+    num_bits = r->m_num_bits;
+    bit_buf = r->m_bit_buf;
+    dist = r->m_dist;
+    counter = r->m_counter;
+    num_extra = r->m_num_extra;
+    dist_from_out_buf_start = r->m_dist_from_out_buf_start;
+    TINFL_CR_BEGIN
+
+    bit_buf = num_bits = dist = counter = num_extra = r->m_zhdr0 = r->m_zhdr1 = 0;
+    r->m_z_adler32 = r->m_check_adler32 = 1;
+    if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+    {
+        TINFL_GET_BYTE(1, r->m_zhdr0);
+        TINFL_GET_BYTE(2, r->m_zhdr1);
+        counter = (((r->m_zhdr0 * 256 + r->m_zhdr1) % 31 != 0) || (r->m_zhdr1 & 32) || ((r->m_zhdr0 & 15) != 8));
+        if (!(decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+            counter |= (((1U << (8U + (r->m_zhdr0 >> 4))) > 32768U) || ((out_buf_size_mask + 1) < (size_t)(1U << (8U + (r->m_zhdr0 >> 4)))));
+        if (counter)
+        {
+            TINFL_CR_RETURN_FOREVER(36, TINFL_STATUS_FAILED);
+        }
+    }
+
+    do
+    {
+        TINFL_GET_BITS(3, r->m_final, 3);
+        r->m_type = r->m_final >> 1;
+        if (r->m_type == 0)
+        {
+            TINFL_SKIP_BITS(5, num_bits & 7);
+            for (counter = 0; counter < 4; ++counter)
+            {
+                if (num_bits)
+                    TINFL_GET_BITS(6, r->m_raw_header[counter], 8);
+                else
+                    TINFL_GET_BYTE(7, r->m_raw_header[counter]);
+            }
+            if ((counter = (r->m_raw_header[0] | (r->m_raw_header[1] << 8))) != (mz_uint)(0xFFFF ^ (r->m_raw_header[2] | (r->m_raw_header[3] << 8))))
+            {
+                TINFL_CR_RETURN_FOREVER(39, TINFL_STATUS_FAILED);
+            }
+            while ((counter) && (num_bits))
+            {
+                TINFL_GET_BITS(51, dist, 8);
+                while (pOut_buf_cur >= pOut_buf_end)
+                {
+                    TINFL_CR_RETURN(52, TINFL_STATUS_HAS_MORE_OUTPUT);
+                }
+                *pOut_buf_cur++ = (mz_uint8)dist;
+                counter--;
+            }
+            while (counter)
+            {
+                size_t n;
+                while (pOut_buf_cur >= pOut_buf_end)
+                {
+                    TINFL_CR_RETURN(9, TINFL_STATUS_HAS_MORE_OUTPUT);
+                }
+                while (pIn_buf_cur >= pIn_buf_end)
+                {
+                    TINFL_CR_RETURN(38, (decomp_flags & TINFL_FLAG_HAS_MORE_INPUT) ? TINFL_STATUS_NEEDS_MORE_INPUT : TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS);
+                }
+                n = MZ_MIN(MZ_MIN((size_t)(pOut_buf_end - pOut_buf_cur), (size_t)(pIn_buf_end - pIn_buf_cur)), counter);
+                TINFL_MEMCPY(pOut_buf_cur, pIn_buf_cur, n);
+                pIn_buf_cur += n;
+                pOut_buf_cur += n;
+                counter -= (mz_uint)n;
+            }
+        }
+        else if (r->m_type == 3)
+        {
+            TINFL_CR_RETURN_FOREVER(10, TINFL_STATUS_FAILED);
+        }
+        else
+        {
+            if (r->m_type == 1)
+            {
+                mz_uint8 *p = r->m_tables[0].m_code_size;
+                mz_uint i;
+                r->m_table_sizes[0] = 288;
+                r->m_table_sizes[1] = 32;
+                TINFL_MEMSET(r->m_tables[1].m_code_size, 5, 32);
+                for (i = 0; i <= 143; ++i)
+                    *p++ = 8;
+                for (; i <= 255; ++i)
+                    *p++ = 9;
+                for (; i <= 279; ++i)
+                    *p++ = 7;
+                for (; i <= 287; ++i)
+                    *p++ = 8;
+            }
+            else
+            {
+                for (counter = 0; counter < 3; counter++)
+                {
+                    TINFL_GET_BITS(11, r->m_table_sizes[counter], "\05\05\04"[counter]);
+                    r->m_table_sizes[counter] += s_min_table_sizes[counter];
+                }
+                MZ_CLEAR_OBJ(r->m_tables[2].m_code_size);
+                for (counter = 0; counter < r->m_table_sizes[2]; counter++)
+                {
+                    mz_uint s;
+                    TINFL_GET_BITS(14, s, 3);
+                    r->m_tables[2].m_code_size[s_length_dezigzag[counter]] = (mz_uint8)s;
+                }
+                r->m_table_sizes[2] = 19;
+            }
+            for (; (int)r->m_type >= 0; r->m_type--)
+            {
+                int tree_next, tree_cur;
+                tinfl_huff_table *pTable;
+                mz_uint i, j, used_syms, total, sym_index, next_code[17], total_syms[16];
+                pTable = &r->m_tables[r->m_type];
+                MZ_CLEAR_OBJ(total_syms);
+                MZ_CLEAR_OBJ(pTable->m_look_up);
+                MZ_CLEAR_OBJ(pTable->m_tree);
+                for (i = 0; i < r->m_table_sizes[r->m_type]; ++i)
+                    total_syms[pTable->m_code_size[i]]++;
+                used_syms = 0, total = 0;
+                next_code[0] = next_code[1] = 0;
+                for (i = 1; i <= 15; ++i)
+                {
+                    used_syms += total_syms[i];
+                    next_code[i + 1] = (total = ((total + total_syms[i]) << 1));
+                }
+                if ((65536 != total) && (used_syms > 1))
+                {
+                    TINFL_CR_RETURN_FOREVER(35, TINFL_STATUS_FAILED);
+                }
+                for (tree_next = -1, sym_index = 0; sym_index < r->m_table_sizes[r->m_type]; ++sym_index)
+                {
+                    mz_uint rev_code = 0, l, cur_code, code_size = pTable->m_code_size[sym_index];
+                    if (!code_size)
+                        continue;
+                    cur_code = next_code[code_size]++;
+                    for (l = code_size; l > 0; l--, cur_code >>= 1)
+                        rev_code = (rev_code << 1) | (cur_code & 1);
+                    if (code_size <= TINFL_FAST_LOOKUP_BITS)
+                    {
+                        mz_int16 k = (mz_int16)((code_size << 9) | sym_index);
+                        while (rev_code < TINFL_FAST_LOOKUP_SIZE)
+                        {
+                            pTable->m_look_up[rev_code] = k;
+                            rev_code += (1 << code_size);
+                        }
+                        continue;
+                    }
+                    if (0 == (tree_cur = pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)]))
+                    {
+                        pTable->m_look_up[rev_code & (TINFL_FAST_LOOKUP_SIZE - 1)] = (mz_int16)tree_next;
+                        tree_cur = tree_next;
+                        tree_next -= 2;
+                    }
+                    rev_code >>= (TINFL_FAST_LOOKUP_BITS - 1);
+                    for (j = code_size; j > (TINFL_FAST_LOOKUP_BITS + 1); j--)
+                    {
+                        tree_cur -= ((rev_code >>= 1) & 1);
+                        if (!pTable->m_tree[-tree_cur - 1])
+                        {
+                            pTable->m_tree[-tree_cur - 1] = (mz_int16)tree_next;
+                            tree_cur = tree_next;
+                            tree_next -= 2;
+                        }
+                        else
+                            tree_cur = pTable->m_tree[-tree_cur - 1];
+                    }
+                    tree_cur -= ((rev_code >>= 1) & 1);
+                    pTable->m_tree[-tree_cur - 1] = (mz_int16)sym_index;
+                }
+                if (r->m_type == 2)
+                {
+                    for (counter = 0; counter < (r->m_table_sizes[0] + r->m_table_sizes[1]);)
+                    {
+                        mz_uint s;
+                        TINFL_HUFF_DECODE(16, dist, &r->m_tables[2]);
+                        if (dist < 16)
+                        {
+                            r->m_len_codes[counter++] = (mz_uint8)dist;
+                            continue;
+                        }
+                        if ((dist == 16) && (!counter))
+                        {
+                            TINFL_CR_RETURN_FOREVER(17, TINFL_STATUS_FAILED);
+                        }
+                        num_extra = "\02\03\07"[dist - 16];
+                        TINFL_GET_BITS(18, s, num_extra);
+                        s += "\03\03\013"[dist - 16];
+                        TINFL_MEMSET(r->m_len_codes + counter, (dist == 16) ? r->m_len_codes[counter - 1] : 0, s);
+                        counter += s;
+                    }
+                    if ((r->m_table_sizes[0] + r->m_table_sizes[1]) != counter)
+                    {
+                        TINFL_CR_RETURN_FOREVER(21, TINFL_STATUS_FAILED);
+                    }
+                    TINFL_MEMCPY(r->m_tables[0].m_code_size, r->m_len_codes, r->m_table_sizes[0]);
+                    TINFL_MEMCPY(r->m_tables[1].m_code_size, r->m_len_codes + r->m_table_sizes[0], r->m_table_sizes[1]);
+                }
+            }
+            for (;;)
+            {
+                mz_uint8 *pSrc;
+                for (;;)
+                {
+                    if (((pIn_buf_end - pIn_buf_cur) < 4) || ((pOut_buf_end - pOut_buf_cur) < 2))
+                    {
+                        TINFL_HUFF_DECODE(23, counter, &r->m_tables[0]);
+                        if (counter >= 256)
+                            break;
+                        while (pOut_buf_cur >= pOut_buf_end)
+                        {
+                            TINFL_CR_RETURN(24, TINFL_STATUS_HAS_MORE_OUTPUT);
+                        }
+                        *pOut_buf_cur++ = (mz_uint8)counter;
+                    }
+                    else
+                    {
+                        int sym2;
+                        mz_uint code_len;
+#if TINFL_USE_64BIT_BITBUF
+                        if (num_bits < 30)
+                        {
+                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE32(pIn_buf_cur)) << num_bits);
+                            pIn_buf_cur += 4;
+                            num_bits += 32;
+                        }
+#else
+                        if (num_bits < 15)
+                        {
+                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
+                            pIn_buf_cur += 2;
+                            num_bits += 16;
+                        }
+#endif
+                        if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+                            code_len = sym2 >> 9;
+                        else
+                        {
+                            code_len = TINFL_FAST_LOOKUP_BITS;
+                            do
+                            {
+                                sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
+                            } while (sym2 < 0);
+                        }
+                        counter = sym2;
+                        bit_buf >>= code_len;
+                        num_bits -= code_len;
+                        if (counter & 256)
+                            break;
+
+#if !TINFL_USE_64BIT_BITBUF
+                        if (num_bits < 15)
+                        {
+                            bit_buf |= (((tinfl_bit_buf_t)MZ_READ_LE16(pIn_buf_cur)) << num_bits);
+                            pIn_buf_cur += 2;
+                            num_bits += 16;
+                        }
+#endif
+                        if ((sym2 = r->m_tables[0].m_look_up[bit_buf & (TINFL_FAST_LOOKUP_SIZE - 1)]) >= 0)
+                            code_len = sym2 >> 9;
+                        else
+                        {
+                            code_len = TINFL_FAST_LOOKUP_BITS;
+                            do
+                            {
+                                sym2 = r->m_tables[0].m_tree[~sym2 + ((bit_buf >> code_len++) & 1)];
+                            } while (sym2 < 0);
+                        }
+                        bit_buf >>= code_len;
+                        num_bits -= code_len;
+
+                        pOut_buf_cur[0] = (mz_uint8)counter;
+                        if (sym2 & 256)
+                        {
+                            pOut_buf_cur++;
+                            counter = sym2;
+                            break;
+                        }
+                        pOut_buf_cur[1] = (mz_uint8)sym2;
+                        pOut_buf_cur += 2;
+                    }
+                }
+                if ((counter &= 511) == 256)
+                    break;
+
+                num_extra = s_length_extra[counter - 257];
+                counter = s_length_base[counter - 257];
+                if (num_extra)
+                {
+                    mz_uint extra_bits;
+                    TINFL_GET_BITS(25, extra_bits, num_extra);
+                    counter += extra_bits;
+                }
+
+                TINFL_HUFF_DECODE(26, dist, &r->m_tables[1]);
+                num_extra = s_dist_extra[dist];
+                dist = s_dist_base[dist];
+                if (num_extra)
+                {
+                    mz_uint extra_bits;
+                    TINFL_GET_BITS(27, extra_bits, num_extra);
+                    dist += extra_bits;
+                }
+
+                dist_from_out_buf_start = pOut_buf_cur - pOut_buf_start;
+                if ((dist > dist_from_out_buf_start) && (decomp_flags & TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF))
+                {
+                    TINFL_CR_RETURN_FOREVER(37, TINFL_STATUS_FAILED);
+                }
+
+                pSrc = pOut_buf_start + ((dist_from_out_buf_start - dist) & out_buf_size_mask);
+
+                if ((MZ_MAX(pOut_buf_cur, pSrc) + counter) > pOut_buf_end)
+                {
+                    while (counter--)
+                    {
+                        while (pOut_buf_cur >= pOut_buf_end)
+                        {
+                            TINFL_CR_RETURN(53, TINFL_STATUS_HAS_MORE_OUTPUT);
+                        }
+                        *pOut_buf_cur++ = pOut_buf_start[(dist_from_out_buf_start++ - dist) & out_buf_size_mask];
+                    }
+                    continue;
+                }
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES
+                else if ((counter >= 9) && (counter <= dist))
+                {
+                    const mz_uint8 *pSrc_end = pSrc + (counter & ~7);
+                    do
+                    {
+                        ((mz_uint32 *)pOut_buf_cur)[0] = ((const mz_uint32 *)pSrc)[0];
+                        ((mz_uint32 *)pOut_buf_cur)[1] = ((const mz_uint32 *)pSrc)[1];
+                        pOut_buf_cur += 8;
+                    } while ((pSrc += 8) < pSrc_end);
+                    if ((counter &= 7) < 3)
+                    {
+                        if (counter)
+                        {
+                            pOut_buf_cur[0] = pSrc[0];
+                            if (counter > 1)
+                                pOut_buf_cur[1] = pSrc[1];
+                            pOut_buf_cur += counter;
+                        }
+                        continue;
+                    }
+                }
+#endif
+                do
+                {
+                    pOut_buf_cur[0] = pSrc[0];
+                    pOut_buf_cur[1] = pSrc[1];
+                    pOut_buf_cur[2] = pSrc[2];
+                    pOut_buf_cur += 3;
+                    pSrc += 3;
+                } while ((int)(counter -= 3) > 2);
+                if ((int)counter > 0)
+                {
+                    pOut_buf_cur[0] = pSrc[0];
+                    if ((int)counter > 1)
+                        pOut_buf_cur[1] = pSrc[1];
+                    pOut_buf_cur += counter;
+                }
+            }
+        }
+    } while (!(r->m_final & 1));
+
+    /* Ensure byte alignment and put back any bytes from the bitbuf if we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */
+    /* I'm being super conservative here. A number of simplifications can be made to the byte alignment part, and the Adler32 check shouldn't ever need to worry about reading from the bitbuf now. */
+    TINFL_SKIP_BITS(32, num_bits & 7);
+    while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))
+    {
+        --pIn_buf_cur;
+        num_bits -= 8;
+    }
+    bit_buf &= (tinfl_bit_buf_t)(( ((mz_uint64)1) << num_bits) - (mz_uint64)1);
+    MZ_ASSERT(!num_bits); /* if this assert fires then we've read beyond the end of non-deflate/zlib streams with following data (such as gzip streams). */
+
+    if (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER)
+    {
+        for (counter = 0; counter < 4; ++counter)
+        {
+            mz_uint s;
+            if (num_bits)
+                TINFL_GET_BITS(41, s, 8);
+            else
+                TINFL_GET_BYTE(42, s);
+            r->m_z_adler32 = (r->m_z_adler32 << 8) | s;
+        }
+    }
+    TINFL_CR_RETURN_FOREVER(34, TINFL_STATUS_DONE);
+
+    TINFL_CR_FINISH
+
+common_exit:
+    /* As long as we aren't telling the caller that we NEED more input to make forward progress: */
+    /* Put back any bytes from the bitbuf in case we've looked ahead too far on gzip, or other Deflate streams followed by arbitrary data. */
+    /* We need to be very careful here to NOT push back any bytes we definitely know we need to make forward progress, though, or we'll lock the caller up into an inf loop. */
+    if ((status != TINFL_STATUS_NEEDS_MORE_INPUT) && (status != TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS))
+    {
+        while ((pIn_buf_cur > pIn_buf_next) && (num_bits >= 8))
+        {
+            --pIn_buf_cur;
+            num_bits -= 8;
+        }
+    }
+    r->m_num_bits = num_bits;
+    r->m_bit_buf = bit_buf & (tinfl_bit_buf_t)(( ((mz_uint64)1) << num_bits) - (mz_uint64)1);
+    r->m_dist = dist;
+    r->m_counter = counter;
+    r->m_num_extra = num_extra;
+    r->m_dist_from_out_buf_start = dist_from_out_buf_start;
+    *pIn_buf_size = pIn_buf_cur - pIn_buf_next;
+    *pOut_buf_size = pOut_buf_cur - pOut_buf_next;
+    if ((decomp_flags & (TINFL_FLAG_PARSE_ZLIB_HEADER | TINFL_FLAG_COMPUTE_ADLER32)) && (status >= 0))
+    {
+        const mz_uint8 *ptr = pOut_buf_next;
+        size_t buf_len = *pOut_buf_size;
+        mz_uint32 i, s1 = r->m_check_adler32 & 0xffff, s2 = r->m_check_adler32 >> 16;
+        size_t block_len = buf_len % 5552;
+        while (buf_len)
+        {
+            for (i = 0; i + 7 < block_len; i += 8, ptr += 8)
+            {
+                s1 += ptr[0], s2 += s1;
+                s1 += ptr[1], s2 += s1;
+                s1 += ptr[2], s2 += s1;
+                s1 += ptr[3], s2 += s1;
+                s1 += ptr[4], s2 += s1;
+                s1 += ptr[5], s2 += s1;
+                s1 += ptr[6], s2 += s1;
+                s1 += ptr[7], s2 += s1;
+            }
+            for (; i < block_len; ++i)
+                s1 += *ptr++, s2 += s1;
+            s1 %= 65521U, s2 %= 65521U;
+            buf_len -= block_len;
+            block_len = 5552;
+        }
+        r->m_check_adler32 = (s2 << 16) + s1;
+        if ((status == TINFL_STATUS_DONE) && (decomp_flags & TINFL_FLAG_PARSE_ZLIB_HEADER) && (r->m_check_adler32 != r->m_z_adler32))
+            status = TINFL_STATUS_ADLER32_MISMATCH;
+    }
+    return status;
+}
+
+/* Higher level helper functions. */
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags)
+{
+    tinfl_decompressor decomp;
+    void *pBuf = NULL, *pNew_buf;
+    size_t src_buf_ofs = 0, out_buf_capacity = 0;
+    *pOut_len = 0;
+    tinfl_init(&decomp);
+    for (;;)
+    {
+        size_t src_buf_size = src_buf_len - src_buf_ofs, dst_buf_size = out_buf_capacity - *pOut_len, new_out_buf_capacity;
+        tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf + src_buf_ofs, &src_buf_size, (mz_uint8 *)pBuf, pBuf ? (mz_uint8 *)pBuf + *pOut_len : NULL, &dst_buf_size,
+                                               (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+        if ((status < 0) || (status == TINFL_STATUS_NEEDS_MORE_INPUT))
+        {
+            MZ_FREE(pBuf);
+            *pOut_len = 0;
+            return NULL;
+        }
+        src_buf_ofs += src_buf_size;
+        *pOut_len += dst_buf_size;
+        if (status == TINFL_STATUS_DONE)
+            break;
+        new_out_buf_capacity = out_buf_capacity * 2;
+        if (new_out_buf_capacity < 128)
+            new_out_buf_capacity = 128;
+        pNew_buf = MZ_REALLOC(pBuf, new_out_buf_capacity);
+        if (!pNew_buf)
+        {
+            MZ_FREE(pBuf);
+            *pOut_len = 0;
+            return NULL;
+        }
+        pBuf = pNew_buf;
+        out_buf_capacity = new_out_buf_capacity;
+    }
+    return pBuf;
+}
+
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags)
+{
+    tinfl_decompressor decomp;
+    tinfl_status status;
+    tinfl_init(&decomp);
+    status = tinfl_decompress(&decomp, (const mz_uint8 *)pSrc_buf, &src_buf_len, (mz_uint8 *)pOut_buf, (mz_uint8 *)pOut_buf, &out_buf_len, (flags & ~TINFL_FLAG_HAS_MORE_INPUT) | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF);
+    return (status != TINFL_STATUS_DONE) ? TINFL_DECOMPRESS_MEM_TO_MEM_FAILED : out_buf_len;
+}
+
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags)
+{
+    int result = 0;
+    tinfl_decompressor decomp;
+    mz_uint8 *pDict = (mz_uint8 *)MZ_MALLOC(TINFL_LZ_DICT_SIZE);
+    size_t in_buf_ofs = 0, dict_ofs = 0;
+    if (!pDict)
+        return TINFL_STATUS_FAILED;
+    tinfl_init(&decomp);
+    for (;;)
+    {
+        size_t in_buf_size = *pIn_buf_size - in_buf_ofs, dst_buf_size = TINFL_LZ_DICT_SIZE - dict_ofs;
+        tinfl_status status = tinfl_decompress(&decomp, (const mz_uint8 *)pIn_buf + in_buf_ofs, &in_buf_size, pDict, pDict + dict_ofs, &dst_buf_size,
+                                               (flags & ~(TINFL_FLAG_HAS_MORE_INPUT | TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF)));
+        in_buf_ofs += in_buf_size;
+        if ((dst_buf_size) && (!(*pPut_buf_func)(pDict + dict_ofs, (int)dst_buf_size, pPut_buf_user)))
+            break;
+        if (status != TINFL_STATUS_HAS_MORE_OUTPUT)
+        {
+            result = (status == TINFL_STATUS_DONE);
+            break;
+        }
+        dict_ofs = (dict_ofs + dst_buf_size) & (TINFL_LZ_DICT_SIZE - 1);
+    }
+    MZ_FREE(pDict);
+    *pIn_buf_size = in_buf_ofs;
+    return result;
+}
+
+tinfl_decompressor *tinfl_decompressor_alloc()
+{
+    tinfl_decompressor *pDecomp = (tinfl_decompressor *)MZ_MALLOC(sizeof(tinfl_decompressor));
+    if (pDecomp)
+        tinfl_init(pDecomp);
+    return pDecomp;
+}
+
+void tinfl_decompressor_free(tinfl_decompressor *pDecomp)
+{
+    MZ_FREE(pDecomp);
+}
+
+#ifdef __cplusplus
+}
+#endif
+/**************************************************************************
+ *
+ * Copyright 2013-2014 RAD Game Tools and Valve Software
+ * Copyright 2010-2014 Rich Geldreich and Tenacious Software LLC
+ * Copyright 2016 Martin Raiber
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ **************************************************************************/
+
+
+#ifndef MINIZ_NO_ARCHIVE_APIS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- .ZIP archive reading */
+
+#ifdef MINIZ_NO_STDIO
+#define MZ_FILE void *
+#else
+#include <sys/stat.h>
+
+#if defined(_MSC_VER) || defined(__MINGW64__)
+static FILE *mz_fopen(const char *pFilename, const char *pMode)
+{
+    FILE *pFile = NULL;
+    fopen_s(&pFile, pFilename, pMode);
+    return pFile;
+}
+static FILE *mz_freopen(const char *pPath, const char *pMode, FILE *pStream)
+{
+    FILE *pFile = NULL;
+    if (freopen_s(&pFile, pPath, pMode, pStream))
+        return NULL;
+    return pFile;
+}
+#ifndef MINIZ_NO_TIME
+#include <sys/utime.h>
+#endif
+#define MZ_FOPEN mz_fopen
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#define MZ_FTELL64 _ftelli64
+#define MZ_FSEEK64 _fseeki64
+#define MZ_FILE_STAT_STRUCT _stat
+#define MZ_FILE_STAT _stat
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN mz_freopen
+#define MZ_DELETE_FILE remove
+#elif defined(__MINGW32__)
+#ifndef MINIZ_NO_TIME
+#include <sys/utime.h>
+#endif
+#define MZ_FOPEN(f, m) fopen(f, m)
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#define MZ_FTELL64 ftello64
+#define MZ_FSEEK64 fseeko64
+#define MZ_FILE_STAT_STRUCT _stat
+#define MZ_FILE_STAT _stat
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
+#define MZ_DELETE_FILE remove
+#elif defined(__TINYC__)
+#ifndef MINIZ_NO_TIME
+#include <sys/utime.h>
+#endif
+#define MZ_FOPEN(f, m) fopen(f, m)
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#define MZ_FTELL64 ftell
+#define MZ_FSEEK64 fseek
+#define MZ_FILE_STAT_STRUCT stat
+#define MZ_FILE_STAT stat
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
+#define MZ_DELETE_FILE remove
+#elif defined(__GNUC__) && _LARGEFILE64_SOURCE
+#ifndef MINIZ_NO_TIME
+#include <utime.h>
+#endif
+#define MZ_FOPEN(f, m) fopen64(f, m)
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#define MZ_FTELL64 ftello64
+#define MZ_FSEEK64 fseeko64
+#define MZ_FILE_STAT_STRUCT stat64
+#define MZ_FILE_STAT stat64
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN(p, m, s) freopen64(p, m, s)
+#define MZ_DELETE_FILE remove
+#elif defined(__APPLE__) && _LARGEFILE64_SOURCE
+#ifndef MINIZ_NO_TIME
+#include <utime.h>
+#endif
+#define MZ_FOPEN(f, m) fopen(f, m)
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#define MZ_FTELL64 ftello
+#define MZ_FSEEK64 fseeko
+#define MZ_FILE_STAT_STRUCT stat
+#define MZ_FILE_STAT stat
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN(p, m, s) freopen(p, m, s)
+#define MZ_DELETE_FILE remove
+
+#else
+#pragma message("Using fopen, ftello, fseeko, stat() etc. path for file I/O - this path may not support large files.")
+#ifndef MINIZ_NO_TIME
+#include <utime.h>
+#endif
+#define MZ_FOPEN(f, m) fopen(f, m)
+#define MZ_FCLOSE fclose
+#define MZ_FREAD fread
+#define MZ_FWRITE fwrite
+#ifdef __STRICT_ANSI__
+#define MZ_FTELL64 ftell
+#define MZ_FSEEK64 fseek
+#else
+#define MZ_FTELL64 ftello
+#define MZ_FSEEK64 fseeko
+#endif
+#define MZ_FILE_STAT_STRUCT stat
+#define MZ_FILE_STAT stat
+#define MZ_FFLUSH fflush
+#define MZ_FREOPEN(f, m, s) freopen(f, m, s)
+#define MZ_DELETE_FILE remove
+#endif /* #ifdef _MSC_VER */
+#endif /* #ifdef MINIZ_NO_STDIO */
+
+#define MZ_TOLOWER(c) ((((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c))
+
+/* Various ZIP archive enums. To completely avoid cross platform compiler alignment and platform endian issues, miniz.c doesn't use structs for any of this stuff. */
+enum
+{
+    /* ZIP archive identifiers and record sizes */
+    MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06054b50,
+    MZ_ZIP_CENTRAL_DIR_HEADER_SIG = 0x02014b50,
+    MZ_ZIP_LOCAL_DIR_HEADER_SIG = 0x04034b50,
+    MZ_ZIP_LOCAL_DIR_HEADER_SIZE = 30,
+    MZ_ZIP_CENTRAL_DIR_HEADER_SIZE = 46,
+    MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE = 22,
+
+    /* ZIP64 archive identifier and record sizes */
+    MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG = 0x06064b50,
+    MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG = 0x07064b50,
+    MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE = 56,
+    MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE = 20,
+    MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID = 0x0001,
+    MZ_ZIP_DATA_DESCRIPTOR_ID = 0x08074b50,
+    MZ_ZIP_DATA_DESCRIPTER_SIZE64 = 24,
+    MZ_ZIP_DATA_DESCRIPTER_SIZE32 = 16,
+
+    /* Central directory header record offsets */
+    MZ_ZIP_CDH_SIG_OFS = 0,
+    MZ_ZIP_CDH_VERSION_MADE_BY_OFS = 4,
+    MZ_ZIP_CDH_VERSION_NEEDED_OFS = 6,
+    MZ_ZIP_CDH_BIT_FLAG_OFS = 8,
+    MZ_ZIP_CDH_METHOD_OFS = 10,
+    MZ_ZIP_CDH_FILE_TIME_OFS = 12,
+    MZ_ZIP_CDH_FILE_DATE_OFS = 14,
+    MZ_ZIP_CDH_CRC32_OFS = 16,
+    MZ_ZIP_CDH_COMPRESSED_SIZE_OFS = 20,
+    MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS = 24,
+    MZ_ZIP_CDH_FILENAME_LEN_OFS = 28,
+    MZ_ZIP_CDH_EXTRA_LEN_OFS = 30,
+    MZ_ZIP_CDH_COMMENT_LEN_OFS = 32,
+    MZ_ZIP_CDH_DISK_START_OFS = 34,
+    MZ_ZIP_CDH_INTERNAL_ATTR_OFS = 36,
+    MZ_ZIP_CDH_EXTERNAL_ATTR_OFS = 38,
+    MZ_ZIP_CDH_LOCAL_HEADER_OFS = 42,
+
+    /* Local directory header offsets */
+    MZ_ZIP_LDH_SIG_OFS = 0,
+    MZ_ZIP_LDH_VERSION_NEEDED_OFS = 4,
+    MZ_ZIP_LDH_BIT_FLAG_OFS = 6,
+    MZ_ZIP_LDH_METHOD_OFS = 8,
+    MZ_ZIP_LDH_FILE_TIME_OFS = 10,
+    MZ_ZIP_LDH_FILE_DATE_OFS = 12,
+    MZ_ZIP_LDH_CRC32_OFS = 14,
+    MZ_ZIP_LDH_COMPRESSED_SIZE_OFS = 18,
+    MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS = 22,
+    MZ_ZIP_LDH_FILENAME_LEN_OFS = 26,
+    MZ_ZIP_LDH_EXTRA_LEN_OFS = 28,
+    MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR = 1 << 3,
+
+    /* End of central directory offsets */
+    MZ_ZIP_ECDH_SIG_OFS = 0,
+    MZ_ZIP_ECDH_NUM_THIS_DISK_OFS = 4,
+    MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS = 6,
+    MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 8,
+    MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS = 10,
+    MZ_ZIP_ECDH_CDIR_SIZE_OFS = 12,
+    MZ_ZIP_ECDH_CDIR_OFS_OFS = 16,
+    MZ_ZIP_ECDH_COMMENT_SIZE_OFS = 20,
+
+    /* ZIP64 End of central directory locator offsets */
+    MZ_ZIP64_ECDL_SIG_OFS = 0,                    /* 4 bytes */
+    MZ_ZIP64_ECDL_NUM_DISK_CDIR_OFS = 4,          /* 4 bytes */
+    MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS = 8,  /* 8 bytes */
+    MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS = 16, /* 4 bytes */
+
+    /* ZIP64 End of central directory header offsets */
+    MZ_ZIP64_ECDH_SIG_OFS = 0,                       /* 4 bytes */
+    MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS = 4,            /* 8 bytes */
+    MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS = 12,          /* 2 bytes */
+    MZ_ZIP64_ECDH_VERSION_NEEDED_OFS = 14,           /* 2 bytes */
+    MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS = 16,            /* 4 bytes */
+    MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS = 20,            /* 4 bytes */
+    MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS = 24, /* 8 bytes */
+    MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS = 32,       /* 8 bytes */
+    MZ_ZIP64_ECDH_CDIR_SIZE_OFS = 40,                /* 8 bytes */
+    MZ_ZIP64_ECDH_CDIR_OFS_OFS = 48,                 /* 8 bytes */
+    MZ_ZIP_VERSION_MADE_BY_DOS_FILESYSTEM_ID = 0,
+    MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG = 0x10,
+    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED = 1,
+    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG = 32,
+    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION = 64,
+    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED = 8192,
+    MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 = 1 << 11
+};
+
+typedef struct
+{
+    void *m_p;
+    size_t m_size, m_capacity;
+    mz_uint m_element_size;
+} mz_zip_array;
+
+struct mz_zip_internal_state_tag
+{
+    mz_zip_array m_central_dir;
+    mz_zip_array m_central_dir_offsets;
+    mz_zip_array m_sorted_central_dir_offsets;
+
+    /* The flags passed in when the archive is initially opened. */
+    uint32_t m_init_flags;
+
+    /* MZ_TRUE if the archive has a zip64 end of central directory headers, etc. */
+    mz_bool m_zip64;
+
+    /* MZ_TRUE if we found zip64 extended info in the central directory (m_zip64 will also be slammed to true too, even if we didn't find a zip64 end of central dir header, etc.) */
+    mz_bool m_zip64_has_extended_info_fields;
+
+    /* These fields are used by the file, FILE, memory, and memory/heap read/write helpers. */
+    MZ_FILE *m_pFile;
+    mz_uint64 m_file_archive_start_ofs;
+
+    void *m_pMem;
+    size_t m_mem_size;
+    size_t m_mem_capacity;
+};
+
+#define MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(array_ptr, element_size) (array_ptr)->m_element_size = element_size
+
+#if defined(DEBUG) || defined(_DEBUG) || defined(NDEBUG)
+static MZ_FORCEINLINE mz_uint mz_zip_array_range_check(const mz_zip_array *pArray, mz_uint index)
+{
+    MZ_ASSERT(index < pArray->m_size);
+    return index;
+}
+#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[mz_zip_array_range_check(array_ptr, index)]
+#else
+#define MZ_ZIP_ARRAY_ELEMENT(array_ptr, element_type, index) ((element_type *)((array_ptr)->m_p))[index]
+#endif
+
+static MZ_FORCEINLINE void mz_zip_array_init(mz_zip_array *pArray, mz_uint32 element_size)
+{
+    memset(pArray, 0, sizeof(mz_zip_array));
+    pArray->m_element_size = element_size;
+}
+
+static MZ_FORCEINLINE void mz_zip_array_clear(mz_zip_archive *pZip, mz_zip_array *pArray)
+{
+    pZip->m_pFree(pZip->m_pAlloc_opaque, pArray->m_p);
+    memset(pArray, 0, sizeof(mz_zip_array));
+}
+
+static mz_bool mz_zip_array_ensure_capacity(mz_zip_archive *pZip, mz_zip_array *pArray, size_t min_new_capacity, mz_uint growing)
+{
+    void *pNew_p;
+    size_t new_capacity = min_new_capacity;
+    MZ_ASSERT(pArray->m_element_size);
+    if (pArray->m_capacity >= min_new_capacity)
+        return MZ_TRUE;
+    if (growing)
+    {
+        new_capacity = MZ_MAX(1, pArray->m_capacity);
+        while (new_capacity < min_new_capacity)
+            new_capacity *= 2;
+    }
+    if (NULL == (pNew_p = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pArray->m_p, pArray->m_element_size, new_capacity)))
+        return MZ_FALSE;
+    pArray->m_p = pNew_p;
+    pArray->m_capacity = new_capacity;
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_array_reserve(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_capacity, mz_uint growing)
+{
+    if (new_capacity > pArray->m_capacity)
+    {
+        if (!mz_zip_array_ensure_capacity(pZip, pArray, new_capacity, growing))
+            return MZ_FALSE;
+    }
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_array_resize(mz_zip_archive *pZip, mz_zip_array *pArray, size_t new_size, mz_uint growing)
+{
+    if (new_size > pArray->m_capacity)
+    {
+        if (!mz_zip_array_ensure_capacity(pZip, pArray, new_size, growing))
+            return MZ_FALSE;
+    }
+    pArray->m_size = new_size;
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_array_ensure_room(mz_zip_archive *pZip, mz_zip_array *pArray, size_t n)
+{
+    return mz_zip_array_reserve(pZip, pArray, pArray->m_size + n, MZ_TRUE);
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_array_push_back(mz_zip_archive *pZip, mz_zip_array *pArray, const void *pElements, size_t n)
+{
+    size_t orig_size = pArray->m_size;
+    if (!mz_zip_array_resize(pZip, pArray, orig_size + n, MZ_TRUE))
+        return MZ_FALSE;
+    memcpy((mz_uint8 *)pArray->m_p + orig_size * pArray->m_element_size, pElements, n * pArray->m_element_size);
+    return MZ_TRUE;
+}
+
+#ifndef MINIZ_NO_TIME
+static MZ_TIME_T mz_zip_dos_to_time_t(int dos_time, int dos_date)
+{
+    struct tm tm;
+    memset(&tm, 0, sizeof(tm));
+    tm.tm_isdst = -1;
+    tm.tm_year = ((dos_date >> 9) & 127) + 1980 - 1900;
+    tm.tm_mon = ((dos_date >> 5) & 15) - 1;
+    tm.tm_mday = dos_date & 31;
+    tm.tm_hour = (dos_time >> 11) & 31;
+    tm.tm_min = (dos_time >> 5) & 63;
+    tm.tm_sec = (dos_time << 1) & 62;
+    return mktime(&tm);
+}
+
+#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
+static void mz_zip_time_t_to_dos_time(MZ_TIME_T time, mz_uint16 *pDOS_time, mz_uint16 *pDOS_date)
+{
+#ifdef _MSC_VER
+    struct tm tm_struct;
+    struct tm *tm = &tm_struct;
+    errno_t err = localtime_s(tm, &time);
+    if (err)
+    {
+        *pDOS_date = 0;
+        *pDOS_time = 0;
+        return;
+    }
+#else
+    struct tm *tm = localtime(&time);
+#endif /* #ifdef _MSC_VER */
+
+    *pDOS_time = (mz_uint16)(((tm->tm_hour) << 11) + ((tm->tm_min) << 5) + ((tm->tm_sec) >> 1));
+    *pDOS_date = (mz_uint16)(((tm->tm_year + 1900 - 1980) << 9) + ((tm->tm_mon + 1) << 5) + tm->tm_mday);
+}
+#endif /* MINIZ_NO_ARCHIVE_WRITING_APIS */
+
+#ifndef MINIZ_NO_STDIO
+#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
+static mz_bool mz_zip_get_file_modified_time(const char *pFilename, MZ_TIME_T *pTime)
+{
+    struct MZ_FILE_STAT_STRUCT file_stat;
+
+    /* On Linux with x86 glibc, this call will fail on large files (I think >= 0x80000000 bytes) unless you compiled with _LARGEFILE64_SOURCE. Argh. */
+    if (MZ_FILE_STAT(pFilename, &file_stat) != 0)
+        return MZ_FALSE;
+
+    *pTime = file_stat.st_mtime;
+
+    return MZ_TRUE;
+}
+#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS*/
+
+static mz_bool mz_zip_set_file_times(const char *pFilename, MZ_TIME_T access_time, MZ_TIME_T modified_time)
+{
+    struct utimbuf t;
+
+    memset(&t, 0, sizeof(t));
+    t.actime = access_time;
+    t.modtime = modified_time;
+
+    return !utime(pFilename, &t);
+}
+#endif /* #ifndef MINIZ_NO_STDIO */
+#endif /* #ifndef MINIZ_NO_TIME */
+
+static MZ_FORCEINLINE mz_bool mz_zip_set_error(mz_zip_archive *pZip, mz_zip_error err_num)
+{
+    if (pZip)
+        pZip->m_last_error = err_num;
+    return MZ_FALSE;
+}
+
+static mz_bool mz_zip_reader_init_internal(mz_zip_archive *pZip, mz_uint flags)
+{
+    (void)flags;
+    if ((!pZip) || (pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!pZip->m_pAlloc)
+        pZip->m_pAlloc = miniz_def_alloc_func;
+    if (!pZip->m_pFree)
+        pZip->m_pFree = miniz_def_free_func;
+    if (!pZip->m_pRealloc)
+        pZip->m_pRealloc = miniz_def_realloc_func;
+
+    pZip->m_archive_size = 0;
+    pZip->m_central_directory_file_ofs = 0;
+    pZip->m_total_files = 0;
+    pZip->m_last_error = MZ_ZIP_NO_ERROR;
+
+    if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
+    pZip->m_pState->m_init_flags = flags;
+    pZip->m_pState->m_zip64 = MZ_FALSE;
+    pZip->m_pState->m_zip64_has_extended_info_fields = MZ_FALSE;
+
+    pZip->m_zip_mode = MZ_ZIP_MODE_READING;
+
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_reader_filename_less(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, mz_uint r_index)
+{
+    const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
+    const mz_uint8 *pR = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, r_index));
+    mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS), r_len = MZ_READ_LE16(pR + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    mz_uint8 l = 0, r = 0;
+    pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
+    pR += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
+    pE = pL + MZ_MIN(l_len, r_len);
+    while (pL < pE)
+    {
+        if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
+            break;
+        pL++;
+        pR++;
+    }
+    return (pL == pE) ? (l_len < r_len) : (l < r);
+}
+
+#define MZ_SWAP_UINT32(a, b) \
+    do                       \
+    {                        \
+        mz_uint32 t = a;     \
+        a = b;               \
+        b = t;               \
+    }                        \
+    MZ_MACRO_END
+
+/* Heap sort of lowercased filenames, used to help accelerate plain central directory searches by mz_zip_reader_locate_file(). (Could also use qsort(), but it could allocate memory.) */
+static void mz_zip_reader_sort_central_dir_offsets_by_filename(mz_zip_archive *pZip)
+{
+    mz_zip_internal_state *pState = pZip->m_pState;
+    const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
+    const mz_zip_array *pCentral_dir = &pState->m_central_dir;
+    mz_uint32 *pIndices;
+    mz_uint32 start, end;
+    const mz_uint32 size = pZip->m_total_files;
+
+    if (size <= 1U)
+        return;
+
+    pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
+
+    start = (size - 2U) >> 1U;
+    for (;;)
+    {
+        mz_uint64 child, root = start;
+        for (;;)
+        {
+            if ((child = (root << 1U) + 1U) >= size)
+                break;
+            child += (((child + 1U) < size) && (mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U])));
+            if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
+                break;
+            MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
+            root = child;
+        }
+        if (!start)
+            break;
+        start--;
+    }
+
+    end = size - 1;
+    while (end > 0)
+    {
+        mz_uint64 child, root = 0;
+        MZ_SWAP_UINT32(pIndices[end], pIndices[0]);
+        for (;;)
+        {
+            if ((child = (root << 1U) + 1U) >= end)
+                break;
+            child += (((child + 1U) < end) && mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[child], pIndices[child + 1U]));
+            if (!mz_zip_reader_filename_less(pCentral_dir, pCentral_dir_offsets, pIndices[root], pIndices[child]))
+                break;
+            MZ_SWAP_UINT32(pIndices[root], pIndices[child]);
+            root = child;
+        }
+        end--;
+    }
+}
+
+static mz_bool mz_zip_reader_locate_header_sig(mz_zip_archive *pZip, mz_uint32 record_sig, mz_uint32 record_size, mz_int64 *pOfs)
+{
+    mz_int64 cur_file_ofs;
+    mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
+    mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
+
+    /* Basic sanity checks - reject files which are too small */
+    if (pZip->m_archive_size < record_size)
+        return MZ_FALSE;
+
+    /* Find the record by scanning the file from the end towards the beginning. */
+    cur_file_ofs = MZ_MAX((mz_int64)pZip->m_archive_size - (mz_int64)sizeof(buf_u32), 0);
+    for (;;)
+    {
+        int i, n = (int)MZ_MIN(sizeof(buf_u32), pZip->m_archive_size - cur_file_ofs);
+
+        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, n) != (mz_uint)n)
+            return MZ_FALSE;
+
+        for (i = n - 4; i >= 0; --i)
+        {
+            mz_uint s = MZ_READ_LE32(pBuf + i);
+            if (s == record_sig)
+            {
+                if ((pZip->m_archive_size - (cur_file_ofs + i)) >= record_size)
+                    break;
+            }
+        }
+
+        if (i >= 0)
+        {
+            cur_file_ofs += i;
+            break;
+        }
+
+        /* Give up if we've searched the entire file, or we've gone back "too far" (~64kb) */
+        if ((!cur_file_ofs) || ((pZip->m_archive_size - cur_file_ofs) >= (MZ_UINT16_MAX + record_size)))
+            return MZ_FALSE;
+
+        cur_file_ofs = MZ_MAX(cur_file_ofs - (sizeof(buf_u32) - 3), 0);
+    }
+
+    *pOfs = cur_file_ofs;
+    return MZ_TRUE;
+}
+
+static mz_bool mz_zip_reader_read_central_dir(mz_zip_archive *pZip, mz_uint flags)
+{
+    mz_uint cdir_size = 0, cdir_entries_on_this_disk = 0, num_this_disk = 0, cdir_disk_index = 0;
+    mz_uint64 cdir_ofs = 0;
+    mz_int64 cur_file_ofs = 0;
+    const mz_uint8 *p;
+
+    mz_uint32 buf_u32[4096 / sizeof(mz_uint32)];
+    mz_uint8 *pBuf = (mz_uint8 *)buf_u32;
+    mz_bool sort_central_dir = ((flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0);
+    mz_uint32 zip64_end_of_central_dir_locator_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pZip64_locator = (mz_uint8 *)zip64_end_of_central_dir_locator_u32;
+
+    mz_uint32 zip64_end_of_central_dir_header_u32[(MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pZip64_end_of_central_dir = (mz_uint8 *)zip64_end_of_central_dir_header_u32;
+
+    mz_uint64 zip64_end_of_central_dir_ofs = 0;
+
+    /* Basic sanity checks - reject files which are too small, and check the first 4 bytes of the file to make sure a local header is there. */
+    if (pZip->m_archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+    if (!mz_zip_reader_locate_header_sig(pZip, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE, &cur_file_ofs))
+        return mz_zip_set_error(pZip, MZ_ZIP_FAILED_FINDING_CENTRAL_DIR);
+
+    /* Read and verify the end of central directory record. */
+    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+    if (MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_SIG_OFS) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+    if (cur_file_ofs >= (MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE + MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
+    {
+        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs - MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE, pZip64_locator, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)
+        {
+            if (MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG)
+            {
+                zip64_end_of_central_dir_ofs = MZ_READ_LE64(pZip64_locator + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS);
+                if (zip64_end_of_central_dir_ofs > (pZip->m_archive_size - MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE))
+                    return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+                if (pZip->m_pRead(pZip->m_pIO_opaque, zip64_end_of_central_dir_ofs, pZip64_end_of_central_dir, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)
+                {
+                    if (MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIG_OFS) == MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG)
+                    {
+                        pZip->m_pState->m_zip64 = MZ_TRUE;
+                    }
+                }
+            }
+        }
+    }
+
+    pZip->m_total_files = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS);
+    cdir_entries_on_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
+    num_this_disk = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_THIS_DISK_OFS);
+    cdir_disk_index = MZ_READ_LE16(pBuf + MZ_ZIP_ECDH_NUM_DISK_CDIR_OFS);
+    cdir_size = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_SIZE_OFS);
+    cdir_ofs = MZ_READ_LE32(pBuf + MZ_ZIP_ECDH_CDIR_OFS_OFS);
+
+    if (pZip->m_pState->m_zip64)
+    {
+        mz_uint32 zip64_total_num_of_disks = MZ_READ_LE32(pZip64_locator + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS);
+        mz_uint64 zip64_cdir_total_entries = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS);
+        mz_uint64 zip64_cdir_total_entries_on_this_disk = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS);
+        mz_uint64 zip64_size_of_end_of_central_dir_record = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS);
+        mz_uint64 zip64_size_of_central_directory = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_SIZE_OFS);
+
+        if (zip64_size_of_end_of_central_dir_record < (MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - 12))
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+        if (zip64_total_num_of_disks != 1U)
+            return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+        /* Check for miniz's practical limits */
+        if (zip64_cdir_total_entries > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+
+        pZip->m_total_files = (mz_uint32)zip64_cdir_total_entries;
+
+        if (zip64_cdir_total_entries_on_this_disk > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+
+        cdir_entries_on_this_disk = (mz_uint32)zip64_cdir_total_entries_on_this_disk;
+
+        /* Check for miniz's current practical limits (sorry, this should be enough for millions of files) */
+        if (zip64_size_of_central_directory > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+        cdir_size = (mz_uint32)zip64_size_of_central_directory;
+
+        num_this_disk = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_THIS_DISK_OFS);
+
+        cdir_disk_index = MZ_READ_LE32(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_NUM_DISK_CDIR_OFS);
+
+        cdir_ofs = MZ_READ_LE64(pZip64_end_of_central_dir + MZ_ZIP64_ECDH_CDIR_OFS_OFS);
+    }
+
+    if (pZip->m_total_files != cdir_entries_on_this_disk)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+    if (((num_this_disk | cdir_disk_index) != 0) && ((num_this_disk != 1) || (cdir_disk_index != 1)))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+    if (cdir_size < pZip->m_total_files * MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    if ((cdir_ofs + (mz_uint64)cdir_size) > pZip->m_archive_size)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    pZip->m_central_directory_file_ofs = cdir_ofs;
+
+    if (pZip->m_total_files)
+    {
+        mz_uint i, n;
+        /* Read the entire central directory into a heap block, and allocate another heap block to hold the unsorted central dir file record offsets, and possibly another to hold the sorted indices. */
+        if ((!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir, cdir_size, MZ_FALSE)) ||
+            (!mz_zip_array_resize(pZip, &pZip->m_pState->m_central_dir_offsets, pZip->m_total_files, MZ_FALSE)))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+        if (sort_central_dir)
+        {
+            if (!mz_zip_array_resize(pZip, &pZip->m_pState->m_sorted_central_dir_offsets, pZip->m_total_files, MZ_FALSE))
+                return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (pZip->m_pRead(pZip->m_pIO_opaque, cdir_ofs, pZip->m_pState->m_central_dir.m_p, cdir_size) != cdir_size)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+        /* Now create an index into the central directory file records, do some basic sanity checking on each record */
+        p = (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p;
+        for (n = cdir_size, i = 0; i < pZip->m_total_files; ++i)
+        {
+            mz_uint total_header_size, disk_index, bit_flags, filename_size, ext_data_size;
+            mz_uint64 comp_size, decomp_size, local_header_ofs;
+
+            if ((n < MZ_ZIP_CENTRAL_DIR_HEADER_SIZE) || (MZ_READ_LE32(p) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG))
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, i) = (mz_uint32)(p - (const mz_uint8 *)pZip->m_pState->m_central_dir.m_p);
+
+            if (sort_central_dir)
+                MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_sorted_central_dir_offsets, mz_uint32, i) = i;
+
+            comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
+            decomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
+            local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
+            filename_size = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+            ext_data_size = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
+
+            if ((!pZip->m_pState->m_zip64_has_extended_info_fields) &&
+                (ext_data_size) &&
+                (MZ_MAX(MZ_MAX(comp_size, decomp_size), local_header_ofs) == MZ_UINT32_MAX))
+            {
+                /* Attempt to find zip64 extended information field in the entry's extra data */
+                mz_uint32 extra_size_remaining = ext_data_size;
+
+                if (extra_size_remaining)
+                {
+                    const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size;
+
+                    do
+                    {
+                                               mz_uint32 field_id;
+                                               mz_uint32 field_data_size;
+
+                        if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                        field_id = MZ_READ_LE16(pExtra_data);
+                        field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+
+                        if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
+                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                        if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
+                        {
+                            /* Ok, the archive didn't have any zip64 headers but it uses a zip64 extended information field so mark it as zip64 anyway (this can occur with infozip's zip util when it reads compresses files from stdin). */
+                            pZip->m_pState->m_zip64 = MZ_TRUE;
+                            pZip->m_pState->m_zip64_has_extended_info_fields = MZ_TRUE;
+                            break;
+                        }
+
+                        pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
+                        extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
+                    } while (extra_size_remaining);
+                }
+            }
+
+            /* I've seen archives that aren't marked as zip64 that uses zip64 ext data, argh */
+            if ((comp_size != MZ_UINT32_MAX) && (decomp_size != MZ_UINT32_MAX))
+            {
+                if (((!MZ_READ_LE32(p + MZ_ZIP_CDH_METHOD_OFS)) && (decomp_size != comp_size)) || (decomp_size && !comp_size))
+                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+            }
+
+            disk_index = MZ_READ_LE16(p + MZ_ZIP_CDH_DISK_START_OFS);
+            if ((disk_index == MZ_UINT16_MAX) || ((disk_index != num_this_disk) && (disk_index != 1)))
+                return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_MULTIDISK);
+
+            if (comp_size != MZ_UINT32_MAX)
+            {
+                if (((mz_uint64)MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS) + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + comp_size) > pZip->m_archive_size)
+                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+            }
+
+            bit_flags = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
+            if (bit_flags & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_LOCAL_DIR_IS_MASKED)
+                return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+
+            if ((total_header_size = MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS)) > n)
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            n -= total_header_size;
+            p += total_header_size;
+        }
+    }
+
+    if (sort_central_dir)
+        mz_zip_reader_sort_central_dir_offsets_by_filename(pZip);
+
+    return MZ_TRUE;
+}
+
+void mz_zip_zero_struct(mz_zip_archive *pZip)
+{
+    if (pZip)
+        MZ_CLEAR_OBJ(*pZip);
+}
+
+static mz_bool mz_zip_reader_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)
+{
+    mz_bool status = MZ_TRUE;
+
+    if (!pZip)
+        return MZ_FALSE;
+
+    if ((!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
+    {
+        if (set_last_error)
+            pZip->m_last_error = MZ_ZIP_INVALID_PARAMETER;
+
+        return MZ_FALSE;
+    }
+
+    if (pZip->m_pState)
+    {
+        mz_zip_internal_state *pState = pZip->m_pState;
+        pZip->m_pState = NULL;
+
+        mz_zip_array_clear(pZip, &pState->m_central_dir);
+        mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
+        mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
+
+#ifndef MINIZ_NO_STDIO
+        if (pState->m_pFile)
+        {
+            if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
+            {
+                if (MZ_FCLOSE(pState->m_pFile) == EOF)
+                {
+                    if (set_last_error)
+                        pZip->m_last_error = MZ_ZIP_FILE_CLOSE_FAILED;
+                    status = MZ_FALSE;
+                }
+            }
+            pState->m_pFile = NULL;
+        }
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
+    }
+    pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
+
+    return status;
+}
+
+mz_bool mz_zip_reader_end(mz_zip_archive *pZip)
+{
+    return mz_zip_reader_end_internal(pZip, MZ_TRUE);
+}
+mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags)
+{
+    if ((!pZip) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_reader_init_internal(pZip, flags))
+        return MZ_FALSE;
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_USER;
+    pZip->m_archive_size = size;
+
+    if (!mz_zip_reader_read_central_dir(pZip, flags))
+    {
+        mz_zip_reader_end_internal(pZip, MZ_FALSE);
+        return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+static size_t mz_zip_mem_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
+{
+    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
+    size_t s = (file_ofs >= pZip->m_archive_size) ? 0 : (size_t)MZ_MIN(pZip->m_archive_size - file_ofs, n);
+    memcpy(pBuf, (const mz_uint8 *)pZip->m_pState->m_pMem + file_ofs, s);
+    return s;
+}
+
+mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags)
+{
+    if (!pMem)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+    if (!mz_zip_reader_init_internal(pZip, flags))
+        return MZ_FALSE;
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_MEMORY;
+    pZip->m_archive_size = size;
+    pZip->m_pRead = mz_zip_mem_read_func;
+    pZip->m_pIO_opaque = pZip;
+       pZip->m_pNeeds_keepalive = NULL;
+
+#ifdef __cplusplus
+    pZip->m_pState->m_pMem = const_cast<void *>(pMem);
+#else
+    pZip->m_pState->m_pMem = (void *)pMem;
+#endif
+
+    pZip->m_pState->m_mem_size = size;
+
+    if (!mz_zip_reader_read_central_dir(pZip, flags))
+    {
+        mz_zip_reader_end_internal(pZip, MZ_FALSE);
+        return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+#ifndef MINIZ_NO_STDIO
+static size_t mz_zip_file_read_func(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n)
+{
+    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
+    mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
+
+    file_ofs += pZip->m_pState->m_file_archive_start_ofs;
+
+    if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
+        return 0;
+
+    return MZ_FREAD(pBuf, 1, n, pZip->m_pState->m_pFile);
+}
+
+mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags)
+{
+    return mz_zip_reader_init_file_v2(pZip, pFilename, flags, 0, 0);
+}
+
+mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size)
+{
+       mz_uint64 file_size;
+       MZ_FILE *pFile;
+
+    if ((!pZip) || (!pFilename) || ((archive_size) && (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+       pFile = MZ_FOPEN(pFilename, "rb");
+    if (!pFile)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+
+    file_size = archive_size;
+    if (!file_size)
+    {
+        if (MZ_FSEEK64(pFile, 0, SEEK_END))
+        {
+            MZ_FCLOSE(pFile);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
+        }
+
+        file_size = MZ_FTELL64(pFile);
+    }
+
+    /* TODO: Better sanity check archive_size and the # of actual remaining bytes */
+
+    if (file_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+
+    if (!mz_zip_reader_init_internal(pZip, flags))
+    {
+        MZ_FCLOSE(pFile);
+        return MZ_FALSE;
+    }
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
+    pZip->m_pRead = mz_zip_file_read_func;
+    pZip->m_pIO_opaque = pZip;
+    pZip->m_pState->m_pFile = pFile;
+    pZip->m_archive_size = file_size;
+    pZip->m_pState->m_file_archive_start_ofs = file_start_ofs;
+
+    if (!mz_zip_reader_read_central_dir(pZip, flags))
+    {
+        mz_zip_reader_end_internal(pZip, MZ_FALSE);
+        return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags)
+{
+    mz_uint64 cur_file_ofs;
+
+    if ((!pZip) || (!pFile))
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+
+    cur_file_ofs = MZ_FTELL64(pFile);
+
+    if (!archive_size)
+    {
+        if (MZ_FSEEK64(pFile, 0, SEEK_END))
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
+
+        archive_size = MZ_FTELL64(pFile) - cur_file_ofs;
+
+        if (archive_size < MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+            return mz_zip_set_error(pZip, MZ_ZIP_NOT_AN_ARCHIVE);
+    }
+
+    if (!mz_zip_reader_init_internal(pZip, flags))
+        return MZ_FALSE;
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
+    pZip->m_pRead = mz_zip_file_read_func;
+
+    pZip->m_pIO_opaque = pZip;
+    pZip->m_pState->m_pFile = pFile;
+    pZip->m_archive_size = archive_size;
+    pZip->m_pState->m_file_archive_start_ofs = cur_file_ofs;
+
+    if (!mz_zip_reader_read_central_dir(pZip, flags))
+    {
+        mz_zip_reader_end_internal(pZip, MZ_FALSE);
+        return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+static MZ_FORCEINLINE const mz_uint8 *mz_zip_get_cdh(mz_zip_archive *pZip, mz_uint file_index)
+{
+    if ((!pZip) || (!pZip->m_pState) || (file_index >= pZip->m_total_files))
+        return NULL;
+    return &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
+}
+
+mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index)
+{
+    mz_uint m_bit_flag;
+    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
+    if (!p)
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return MZ_FALSE;
+    }
+
+    m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
+    return (m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION)) != 0;
+}
+
+mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index)
+{
+    mz_uint bit_flag;
+    mz_uint method;
+
+    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
+    if (!p)
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return MZ_FALSE;
+    }
+
+    method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
+    bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
+
+    if ((method != 0) && (method != MZ_DEFLATED))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
+        return MZ_FALSE;
+    }
+
+    if (bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+        return MZ_FALSE;
+    }
+
+    if (bit_flag & MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG)
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
+        return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index)
+{
+    mz_uint filename_len, attribute_mapping_id, external_attr;
+    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
+    if (!p)
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return MZ_FALSE;
+    }
+
+    filename_len = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    if (filename_len)
+    {
+        if (*(p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_len - 1) == '/')
+            return MZ_TRUE;
+    }
+
+    /* Bugfix: This code was also checking if the internal attribute was non-zero, which wasn't correct. */
+    /* Most/all zip writers (hopefully) set DOS file/directory attributes in the low 16-bits, so check for the DOS directory flag and ignore the source OS ID in the created by field. */
+    /* FIXME: Remove this check? Is it necessary - we already check the filename. */
+    attribute_mapping_id = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS) >> 8;
+    (void)attribute_mapping_id;
+
+    external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
+    if ((external_attr & MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG) != 0)
+    {
+        return MZ_TRUE;
+    }
+
+    return MZ_FALSE;
+}
+
+static mz_bool mz_zip_file_stat_internal(mz_zip_archive *pZip, mz_uint file_index, const mz_uint8 *pCentral_dir_header, mz_zip_archive_file_stat *pStat, mz_bool *pFound_zip64_extra_data)
+{
+    mz_uint n;
+    const mz_uint8 *p = pCentral_dir_header;
+
+    if (pFound_zip64_extra_data)
+        *pFound_zip64_extra_data = MZ_FALSE;
+
+    if ((!p) || (!pStat))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    /* Extract fields from the central directory record. */
+    pStat->m_file_index = file_index;
+    pStat->m_central_dir_ofs = MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index);
+    pStat->m_version_made_by = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_MADE_BY_OFS);
+    pStat->m_version_needed = MZ_READ_LE16(p + MZ_ZIP_CDH_VERSION_NEEDED_OFS);
+    pStat->m_bit_flag = MZ_READ_LE16(p + MZ_ZIP_CDH_BIT_FLAG_OFS);
+    pStat->m_method = MZ_READ_LE16(p + MZ_ZIP_CDH_METHOD_OFS);
+#ifndef MINIZ_NO_TIME
+    pStat->m_time = mz_zip_dos_to_time_t(MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_TIME_OFS), MZ_READ_LE16(p + MZ_ZIP_CDH_FILE_DATE_OFS));
+#endif
+    pStat->m_crc32 = MZ_READ_LE32(p + MZ_ZIP_CDH_CRC32_OFS);
+    pStat->m_comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
+    pStat->m_uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
+    pStat->m_internal_attr = MZ_READ_LE16(p + MZ_ZIP_CDH_INTERNAL_ATTR_OFS);
+    pStat->m_external_attr = MZ_READ_LE32(p + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS);
+    pStat->m_local_header_ofs = MZ_READ_LE32(p + MZ_ZIP_CDH_LOCAL_HEADER_OFS);
+
+    /* Copy as much of the filename and comment as possible. */
+    n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE - 1);
+    memcpy(pStat->m_filename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
+    pStat->m_filename[n] = '\0';
+
+    n = MZ_READ_LE16(p + MZ_ZIP_CDH_COMMENT_LEN_OFS);
+    n = MZ_MIN(n, MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE - 1);
+    pStat->m_comment_size = n;
+    memcpy(pStat->m_comment, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS) + MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS), n);
+    pStat->m_comment[n] = '\0';
+
+    /* Set some flags for convienance */
+    pStat->m_is_directory = mz_zip_reader_is_file_a_directory(pZip, file_index);
+    pStat->m_is_encrypted = mz_zip_reader_is_file_encrypted(pZip, file_index);
+    pStat->m_is_supported = mz_zip_reader_is_file_supported(pZip, file_index);
+
+    /* See if we need to read any zip64 extended information fields. */
+    /* Confusingly, these zip64 fields can be present even on non-zip64 archives (Debian zip on a huge files from stdin piped to stdout creates them). */
+    if (MZ_MAX(MZ_MAX(pStat->m_comp_size, pStat->m_uncomp_size), pStat->m_local_header_ofs) == MZ_UINT32_MAX)
+    {
+        /* Attempt to find zip64 extended information field in the entry's extra data */
+        mz_uint32 extra_size_remaining = MZ_READ_LE16(p + MZ_ZIP_CDH_EXTRA_LEN_OFS);
+
+        if (extra_size_remaining)
+        {
+            const mz_uint8 *pExtra_data = p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+
+            do
+            {
+                               mz_uint32 field_id;
+                               mz_uint32 field_data_size;
+
+                if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                field_id = MZ_READ_LE16(pExtra_data);
+                field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+
+                if ((field_data_size + sizeof(mz_uint16) * 2) > extra_size_remaining)
+                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
+                {
+                    const mz_uint8 *pField_data = pExtra_data + sizeof(mz_uint16) * 2;
+                    mz_uint32 field_data_remaining = field_data_size;
+
+                    if (pFound_zip64_extra_data)
+                        *pFound_zip64_extra_data = MZ_TRUE;
+
+                    if (pStat->m_uncomp_size == MZ_UINT32_MAX)
+                    {
+                        if (field_data_remaining < sizeof(mz_uint64))
+                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                        pStat->m_uncomp_size = MZ_READ_LE64(pField_data);
+                        pField_data += sizeof(mz_uint64);
+                        field_data_remaining -= sizeof(mz_uint64);
+                    }
+
+                    if (pStat->m_comp_size == MZ_UINT32_MAX)
+                    {
+                        if (field_data_remaining < sizeof(mz_uint64))
+                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                        pStat->m_comp_size = MZ_READ_LE64(pField_data);
+                        pField_data += sizeof(mz_uint64);
+                        field_data_remaining -= sizeof(mz_uint64);
+                    }
+
+                    if (pStat->m_local_header_ofs == MZ_UINT32_MAX)
+                    {
+                        if (field_data_remaining < sizeof(mz_uint64))
+                            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+                        pStat->m_local_header_ofs = MZ_READ_LE64(pField_data);
+                        pField_data += sizeof(mz_uint64);
+                        field_data_remaining -= sizeof(mz_uint64);
+                    }
+
+                    break;
+                }
+
+                pExtra_data += sizeof(mz_uint16) * 2 + field_data_size;
+                extra_size_remaining = extra_size_remaining - sizeof(mz_uint16) * 2 - field_data_size;
+            } while (extra_size_remaining);
+        }
+    }
+
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE mz_bool mz_zip_string_equal(const char *pA, const char *pB, mz_uint len, mz_uint flags)
+{
+    mz_uint i;
+    if (flags & MZ_ZIP_FLAG_CASE_SENSITIVE)
+        return 0 == memcmp(pA, pB, len);
+    for (i = 0; i < len; ++i)
+        if (MZ_TOLOWER(pA[i]) != MZ_TOLOWER(pB[i]))
+            return MZ_FALSE;
+    return MZ_TRUE;
+}
+
+static MZ_FORCEINLINE int mz_zip_filename_compare(const mz_zip_array *pCentral_dir_array, const mz_zip_array *pCentral_dir_offsets, mz_uint l_index, const char *pR, mz_uint r_len)
+{
+    const mz_uint8 *pL = &MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_array, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(pCentral_dir_offsets, mz_uint32, l_index)), *pE;
+    mz_uint l_len = MZ_READ_LE16(pL + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    mz_uint8 l = 0, r = 0;
+    pL += MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
+    pE = pL + MZ_MIN(l_len, r_len);
+    while (pL < pE)
+    {
+        if ((l = MZ_TOLOWER(*pL)) != (r = MZ_TOLOWER(*pR)))
+            break;
+        pL++;
+        pR++;
+    }
+    return (pL == pE) ? (int)(l_len - r_len) : (l - r);
+}
+
+static mz_bool mz_zip_locate_file_binary_search(mz_zip_archive *pZip, const char *pFilename, mz_uint32 *pIndex)
+{
+    mz_zip_internal_state *pState = pZip->m_pState;
+    const mz_zip_array *pCentral_dir_offsets = &pState->m_central_dir_offsets;
+    const mz_zip_array *pCentral_dir = &pState->m_central_dir;
+    mz_uint32 *pIndices = &MZ_ZIP_ARRAY_ELEMENT(&pState->m_sorted_central_dir_offsets, mz_uint32, 0);
+    const uint32_t size = pZip->m_total_files;
+    const mz_uint filename_len = (mz_uint)strlen(pFilename);
+
+    if (pIndex)
+        *pIndex = 0;
+
+    if (size)
+    {
+        /* yes I could use uint32_t's, but then we would have to add some special case checks in the loop, argh, and */
+        /* honestly the major expense here on 32-bit CPU's will still be the filename compare */
+        mz_int64 l = 0, h = (mz_int64)size - 1;
+
+        while (l <= h)
+        {
+            mz_int64 m = l + ((h - l) >> 1);
+            uint32_t file_index = pIndices[(uint32_t)m];
+
+            int comp = mz_zip_filename_compare(pCentral_dir, pCentral_dir_offsets, file_index, pFilename, filename_len);
+            if (!comp)
+            {
+                if (pIndex)
+                    *pIndex = file_index;
+                return MZ_TRUE;
+            }
+            else if (comp < 0)
+                l = m + 1;
+            else
+                h = m - 1;
+        }
+    }
+
+    return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
+}
+
+int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags)
+{
+    mz_uint32 index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pName, pComment, flags, &index))
+        return -1;
+    else
+        return (int)index;
+}
+
+mz_bool mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex)
+{
+    mz_uint file_index;
+    size_t name_len, comment_len;
+
+    if (pIndex)
+        *pIndex = 0;
+
+    if ((!pZip) || (!pZip->m_pState) || (!pName))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    /* See if we can use a binary search */
+    if (((pZip->m_pState->m_init_flags & MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY) == 0) &&
+        (pZip->m_zip_mode == MZ_ZIP_MODE_READING) &&
+        ((flags & (MZ_ZIP_FLAG_IGNORE_PATH | MZ_ZIP_FLAG_CASE_SENSITIVE)) == 0) && (!pComment) && (pZip->m_pState->m_sorted_central_dir_offsets.m_size))
+    {
+        return mz_zip_locate_file_binary_search(pZip, pName, pIndex);
+    }
+
+    /* Locate the entry by scanning the entire central directory */
+    name_len = strlen(pName);
+    if (name_len > MZ_UINT16_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    comment_len = pComment ? strlen(pComment) : 0;
+    if (comment_len > MZ_UINT16_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    for (file_index = 0; file_index < pZip->m_total_files; file_index++)
+    {
+        const mz_uint8 *pHeader = &MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir, mz_uint8, MZ_ZIP_ARRAY_ELEMENT(&pZip->m_pState->m_central_dir_offsets, mz_uint32, file_index));
+        mz_uint filename_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+        const char *pFilename = (const char *)pHeader + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE;
+        if (filename_len < name_len)
+            continue;
+        if (comment_len)
+        {
+            mz_uint file_extra_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_EXTRA_LEN_OFS), file_comment_len = MZ_READ_LE16(pHeader + MZ_ZIP_CDH_COMMENT_LEN_OFS);
+            const char *pFile_comment = pFilename + filename_len + file_extra_len;
+            if ((file_comment_len != comment_len) || (!mz_zip_string_equal(pComment, pFile_comment, file_comment_len, flags)))
+                continue;
+        }
+        if ((flags & MZ_ZIP_FLAG_IGNORE_PATH) && (filename_len))
+        {
+            int ofs = filename_len - 1;
+            do
+            {
+                if ((pFilename[ofs] == '/') || (pFilename[ofs] == '\\') || (pFilename[ofs] == ':'))
+                    break;
+            } while (--ofs >= 0);
+            ofs++;
+            pFilename += ofs;
+            filename_len -= ofs;
+        }
+        if ((filename_len == name_len) && (mz_zip_string_equal(pName, pFilename, filename_len, flags)))
+        {
+            if (pIndex)
+                *pIndex = file_index;
+            return MZ_TRUE;
+        }
+    }
+
+    return mz_zip_set_error(pZip, MZ_ZIP_FILE_NOT_FOUND);
+}
+
+mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
+{
+    int status = TINFL_STATUS_DONE;
+    mz_uint64 needed_size, cur_file_ofs, comp_remaining, out_buf_ofs = 0, read_buf_size, read_buf_ofs = 0, read_buf_avail;
+    mz_zip_archive_file_stat file_stat;
+    void *pRead_buf;
+    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
+    tinfl_decompressor inflator;
+
+    if ((!pZip) || (!pZip->m_pState) || ((buf_size) && (!pBuf)) || ((user_read_buf_size) && (!pUser_read_buf)) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
+        return MZ_FALSE;
+
+    /* A directory or zero length file */
+    if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
+        return MZ_TRUE;
+
+    /* Encryption and patch files are not supported. */
+    if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+
+    /* This function only supports decompressing stored and deflate. */
+    if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
+
+    /* Ensure supplied output buffer is large enough. */
+    needed_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? file_stat.m_comp_size : file_stat.m_uncomp_size;
+    if (buf_size < needed_size)
+        return mz_zip_set_error(pZip, MZ_ZIP_BUF_TOO_SMALL);
+
+    /* Read and parse the local directory entry. */
+    cur_file_ofs = file_stat.m_local_header_ofs;
+    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
+    if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
+    {
+        /* The file is stored or the caller has requested the compressed data. */
+        if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pBuf, (size_t)needed_size) != needed_size)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+        if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) == 0)
+        {
+            if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
+                return mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
+        }
+#endif
+
+        return MZ_TRUE;
+    }
+
+    /* Decompress the file either directly from memory or from a file input buffer. */
+    tinfl_init(&inflator);
+
+    if (pZip->m_pState->m_pMem)
+    {
+        /* Read directly from the archive in memory. */
+        pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
+        read_buf_size = read_buf_avail = file_stat.m_comp_size;
+        comp_remaining = 0;
+    }
+    else if (pUser_read_buf)
+    {
+        /* Use a user provided read buffer. */
+        if (!user_read_buf_size)
+            return MZ_FALSE;
+        pRead_buf = (mz_uint8 *)pUser_read_buf;
+        read_buf_size = user_read_buf_size;
+        read_buf_avail = 0;
+        comp_remaining = file_stat.m_comp_size;
+    }
+    else
+    {
+        /* Temporarily allocate a read buffer. */
+        read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
+        if (((sizeof(size_t) == sizeof(mz_uint32))) && (read_buf_size > 0x7FFFFFFF))
+            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+        if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+        read_buf_avail = 0;
+        comp_remaining = file_stat.m_comp_size;
+    }
+
+    do
+    {
+        /* The size_t cast here should be OK because we've verified that the output buffer is >= file_stat.m_uncomp_size above */
+        size_t in_buf_size, out_buf_size = (size_t)(file_stat.m_uncomp_size - out_buf_ofs);
+        if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
+        {
+            read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
+            if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
+            {
+                status = TINFL_STATUS_FAILED;
+                mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
+                break;
+            }
+            cur_file_ofs += read_buf_avail;
+            comp_remaining -= read_buf_avail;
+            read_buf_ofs = 0;
+        }
+        in_buf_size = (size_t)read_buf_avail;
+        status = tinfl_decompress(&inflator, (mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pBuf, (mz_uint8 *)pBuf + out_buf_ofs, &out_buf_size, TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF | (comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0));
+        read_buf_avail -= in_buf_size;
+        read_buf_ofs += in_buf_size;
+        out_buf_ofs += out_buf_size;
+    } while (status == TINFL_STATUS_NEEDS_MORE_INPUT);
+
+    if (status == TINFL_STATUS_DONE)
+    {
+        /* Make sure the entire file was decompressed, and check its CRC. */
+        if (out_buf_ofs != file_stat.m_uncomp_size)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
+            status = TINFL_STATUS_FAILED;
+        }
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+        else if (mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, (size_t)file_stat.m_uncomp_size) != file_stat.m_crc32)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_CRC_CHECK_FAILED);
+            status = TINFL_STATUS_FAILED;
+        }
+#endif
+    }
+
+    if ((!pZip->m_pState->m_pMem) && (!pUser_read_buf))
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+
+    return status == TINFL_STATUS_DONE;
+}
+
+mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size)
+{
+    mz_uint32 file_index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
+        return MZ_FALSE;
+    return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, pUser_read_buf, user_read_buf_size);
+}
+
+mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags)
+{
+    return mz_zip_reader_extract_to_mem_no_alloc(pZip, file_index, pBuf, buf_size, flags, NULL, 0);
+}
+
+mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags)
+{
+    return mz_zip_reader_extract_file_to_mem_no_alloc(pZip, pFilename, pBuf, buf_size, flags, NULL, 0);
+}
+
+void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags)
+{
+    mz_uint64 comp_size, uncomp_size, alloc_size;
+    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
+    void *pBuf;
+
+    if (pSize)
+        *pSize = 0;
+
+    if (!p)
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return NULL;
+    }
+
+    comp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS);
+    uncomp_size = MZ_READ_LE32(p + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS);
+
+    alloc_size = (flags & MZ_ZIP_FLAG_COMPRESSED_DATA) ? comp_size : uncomp_size;
+    if (((sizeof(size_t) == sizeof(mz_uint32))) && (alloc_size > 0x7FFFFFFF))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+        return NULL;
+    }
+
+    if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)alloc_size)))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        return NULL;
+    }
+
+    if (!mz_zip_reader_extract_to_mem(pZip, file_index, pBuf, (size_t)alloc_size, flags))
+    {
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+        return NULL;
+    }
+
+    if (pSize)
+        *pSize = (size_t)alloc_size;
+    return pBuf;
+}
+
+void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags)
+{
+    mz_uint32 file_index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
+    {
+        if (pSize)
+            *pSize = 0;
+        return MZ_FALSE;
+    }
+    return mz_zip_reader_extract_to_heap(pZip, file_index, pSize, flags);
+}
+
+mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
+{
+    int status = TINFL_STATUS_DONE;
+    mz_uint file_crc32 = MZ_CRC32_INIT;
+    mz_uint64 read_buf_size, read_buf_ofs = 0, read_buf_avail, comp_remaining, out_buf_ofs = 0, cur_file_ofs;
+    mz_zip_archive_file_stat file_stat;
+    void *pRead_buf = NULL;
+    void *pWrite_buf = NULL;
+    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
+
+    if ((!pZip) || (!pZip->m_pState) || (!pCallback) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
+        return MZ_FALSE;
+
+    /* A directory or zero length file */
+    if ((file_stat.m_is_directory) || (!file_stat.m_comp_size))
+        return MZ_TRUE;
+
+    /* Encryption and patch files are not supported. */
+    if (file_stat.m_bit_flag & (MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_IS_ENCRYPTED | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_USES_STRONG_ENCRYPTION | MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_COMPRESSED_PATCH_FLAG))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+
+    /* This function only supports decompressing stored and deflate. */
+    if ((!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
+
+    /* Read and do some minimal validation of the local directory entry (this doesn't crack the zip64 stuff, which we already have from the central dir) */
+    cur_file_ofs = file_stat.m_local_header_ofs;
+    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    cur_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS) + MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
+    if ((cur_file_ofs + file_stat.m_comp_size) > pZip->m_archive_size)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    /* Decompress the file either directly from memory or from a file input buffer. */
+    if (pZip->m_pState->m_pMem)
+    {
+        pRead_buf = (mz_uint8 *)pZip->m_pState->m_pMem + cur_file_ofs;
+        read_buf_size = read_buf_avail = file_stat.m_comp_size;
+        comp_remaining = 0;
+    }
+    else
+    {
+        read_buf_size = MZ_MIN(file_stat.m_comp_size, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
+        if (NULL == (pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)read_buf_size)))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+        read_buf_avail = 0;
+        comp_remaining = file_stat.m_comp_size;
+    }
+
+    if ((flags & MZ_ZIP_FLAG_COMPRESSED_DATA) || (!file_stat.m_method))
+    {
+        /* The file is stored or the caller has requested the compressed data. */
+        if (pZip->m_pState->m_pMem)
+        {
+            if (((sizeof(size_t) == sizeof(mz_uint32))) && (file_stat.m_comp_size > MZ_UINT32_MAX))
+                return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+            if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)file_stat.m_comp_size) != file_stat.m_comp_size)
+            {
+                mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
+                status = TINFL_STATUS_FAILED;
+            }
+            else if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
+            {
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+                file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)file_stat.m_comp_size);
+#endif
+            }
+
+            cur_file_ofs += file_stat.m_comp_size;
+            out_buf_ofs += file_stat.m_comp_size;
+            comp_remaining = 0;
+        }
+        else
+        {
+            while (comp_remaining)
+            {
+                read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
+                if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
+                {
+                    mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+                    status = TINFL_STATUS_FAILED;
+                    break;
+                }
+
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+                if (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
+                {
+                    file_crc32 = (mz_uint32)mz_crc32(file_crc32, (const mz_uint8 *)pRead_buf, (size_t)read_buf_avail);
+                }
+#endif
+
+                if (pCallback(pOpaque, out_buf_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
+                {
+                    mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
+                    status = TINFL_STATUS_FAILED;
+                    break;
+                }
+
+                cur_file_ofs += read_buf_avail;
+                out_buf_ofs += read_buf_avail;
+                comp_remaining -= read_buf_avail;
+            }
+        }
+    }
+    else
+    {
+        tinfl_decompressor inflator;
+        tinfl_init(&inflator);
+
+        if (NULL == (pWrite_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, TINFL_LZ_DICT_SIZE)))
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+            status = TINFL_STATUS_FAILED;
+        }
+        else
+        {
+            do
+            {
+                mz_uint8 *pWrite_buf_cur = (mz_uint8 *)pWrite_buf + (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
+                size_t in_buf_size, out_buf_size = TINFL_LZ_DICT_SIZE - (out_buf_ofs & (TINFL_LZ_DICT_SIZE - 1));
+                if ((!read_buf_avail) && (!pZip->m_pState->m_pMem))
+                {
+                    read_buf_avail = MZ_MIN(read_buf_size, comp_remaining);
+                    if (pZip->m_pRead(pZip->m_pIO_opaque, cur_file_ofs, pRead_buf, (size_t)read_buf_avail) != read_buf_avail)
+                    {
+                        mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+                        status = TINFL_STATUS_FAILED;
+                        break;
+                    }
+                    cur_file_ofs += read_buf_avail;
+                    comp_remaining -= read_buf_avail;
+                    read_buf_ofs = 0;
+                }
+
+                in_buf_size = (size_t)read_buf_avail;
+                status = tinfl_decompress(&inflator, (const mz_uint8 *)pRead_buf + read_buf_ofs, &in_buf_size, (mz_uint8 *)pWrite_buf, pWrite_buf_cur, &out_buf_size, comp_remaining ? TINFL_FLAG_HAS_MORE_INPUT : 0);
+                read_buf_avail -= in_buf_size;
+                read_buf_ofs += in_buf_size;
+
+                if (out_buf_size)
+                {
+                    if (pCallback(pOpaque, out_buf_ofs, pWrite_buf_cur, out_buf_size) != out_buf_size)
+                    {
+                        mz_zip_set_error(pZip, MZ_ZIP_WRITE_CALLBACK_FAILED);
+                        status = TINFL_STATUS_FAILED;
+                        break;
+                    }
+
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+                    file_crc32 = (mz_uint32)mz_crc32(file_crc32, pWrite_buf_cur, out_buf_size);
+#endif
+                    if ((out_buf_ofs += out_buf_size) > file_stat.m_uncomp_size)
+                    {
+                        mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
+                        status = TINFL_STATUS_FAILED;
+                        break;
+                    }
+                }
+            } while ((status == TINFL_STATUS_NEEDS_MORE_INPUT) || (status == TINFL_STATUS_HAS_MORE_OUTPUT));
+        }
+    }
+
+    if ((status == TINFL_STATUS_DONE) && (!(flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
+    {
+        /* Make sure the entire file was decompressed, and check its CRC. */
+        if (out_buf_ofs != file_stat.m_uncomp_size)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE);
+            status = TINFL_STATUS_FAILED;
+        }
+#ifndef MINIZ_DISABLE_ZIP_READER_CRC32_CHECKS
+        else if (file_crc32 != file_stat.m_crc32)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_DECOMPRESSION_FAILED);
+            status = TINFL_STATUS_FAILED;
+        }
+#endif
+    }
+
+    if (!pZip->m_pState->m_pMem)
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+
+    if (pWrite_buf)
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pWrite_buf);
+
+    return status == TINFL_STATUS_DONE;
+}
+
+mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags)
+{
+    mz_uint32 file_index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pFilename, NULL, flags, &file_index))
+        return MZ_FALSE;
+
+    return mz_zip_reader_extract_to_callback(pZip, file_index, pCallback, pOpaque, flags);
+}
+
+#ifndef MINIZ_NO_STDIO
+static size_t mz_zip_file_write_callback(void *pOpaque, mz_uint64 ofs, const void *pBuf, size_t n)
+{
+    (void)ofs;
+
+    return MZ_FWRITE(pBuf, 1, n, (MZ_FILE *)pOpaque);
+}
+
+mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags)
+{
+    mz_bool status;
+    mz_zip_archive_file_stat file_stat;
+    MZ_FILE *pFile;
+
+    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
+        return MZ_FALSE;
+
+    if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
+
+    pFile = MZ_FOPEN(pDst_filename, "wb");
+    if (!pFile)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+
+    status = mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
+
+    if (MZ_FCLOSE(pFile) == EOF)
+    {
+        if (status)
+            mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
+
+        status = MZ_FALSE;
+    }
+
+#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
+    if (status)
+        mz_zip_set_file_times(pDst_filename, file_stat.m_time, file_stat.m_time);
+#endif
+
+    return status;
+}
+
+mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags)
+{
+    mz_uint32 file_index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))
+        return MZ_FALSE;
+
+    return mz_zip_reader_extract_to_file(pZip, file_index, pDst_filename, flags);
+}
+
+mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *pFile, mz_uint flags)
+{
+    mz_zip_archive_file_stat file_stat;
+
+    if (!mz_zip_reader_file_stat(pZip, file_index, &file_stat))
+        return MZ_FALSE;
+
+    if ((file_stat.m_is_directory) || (!file_stat.m_is_supported))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
+
+    return mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_file_write_callback, pFile, flags);
+}
+
+mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags)
+{
+    mz_uint32 file_index;
+    if (!mz_zip_reader_locate_file_v2(pZip, pArchive_filename, NULL, flags, &file_index))
+        return MZ_FALSE;
+
+    return mz_zip_reader_extract_to_cfile(pZip, file_index, pFile, flags);
+}
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+static size_t mz_zip_compute_crc32_callback(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
+{
+    mz_uint32 *p = (mz_uint32 *)pOpaque;
+    (void)file_ofs;
+    *p = (mz_uint32)mz_crc32(*p, (const mz_uint8 *)pBuf, n);
+    return n;
+}
+
+mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags)
+{
+    mz_zip_archive_file_stat file_stat;
+    mz_zip_internal_state *pState;
+    const mz_uint8 *pCentral_dir_header;
+    mz_bool found_zip64_ext_data_in_cdir = MZ_FALSE;
+    mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
+    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
+    mz_uint64 local_header_ofs = 0;
+    mz_uint32 local_header_filename_len, local_header_extra_len, local_header_crc32;
+    mz_uint64 local_header_comp_size, local_header_uncomp_size;
+    mz_uint32 uncomp_crc32 = MZ_CRC32_INIT;
+    mz_bool has_data_descriptor;
+    mz_uint32 local_header_bit_flags;
+
+    mz_zip_array file_data_array;
+    mz_zip_array_init(&file_data_array, 1);
+
+    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (file_index > pZip->m_total_files)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    pCentral_dir_header = mz_zip_get_cdh(pZip, file_index);
+
+    if (!mz_zip_file_stat_internal(pZip, file_index, pCentral_dir_header, &file_stat, &found_zip64_ext_data_in_cdir))
+        return MZ_FALSE;
+
+    /* A directory or zero length file */
+    if ((file_stat.m_is_directory) || (!file_stat.m_uncomp_size))
+        return MZ_TRUE;
+
+    /* Encryption and patch files are not supported. */
+    if (file_stat.m_is_encrypted)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_ENCRYPTION);
+
+    /* This function only supports stored and deflate. */
+    if ((file_stat.m_method != 0) && (file_stat.m_method != MZ_DEFLATED))
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_METHOD);
+
+    if (!file_stat.m_is_supported)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_FEATURE);
+
+    /* Read and parse the local directory entry. */
+    local_header_ofs = file_stat.m_local_header_ofs;
+    if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    local_header_filename_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
+    local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
+    local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
+    local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
+    local_header_crc32 = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_CRC32_OFS);
+    local_header_bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
+    has_data_descriptor = (local_header_bit_flags & 8) != 0;
+
+    if (local_header_filename_len != strlen(file_stat.m_filename))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    if ((local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size) > pZip->m_archive_size)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    if (!mz_zip_array_resize(pZip, &file_data_array, MZ_MAX(local_header_filename_len, local_header_extra_len), MZ_FALSE))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    if (local_header_filename_len)
+    {
+        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE, file_data_array.m_p, local_header_filename_len) != local_header_filename_len)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+            goto handle_failure;
+        }
+
+        /* I've seen 1 archive that had the same pathname, but used backslashes in the local dir and forward slashes in the central dir. Do we care about this? For now, this case will fail validation. */
+        if (memcmp(file_stat.m_filename, file_data_array.m_p, local_header_filename_len) != 0)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
+            goto handle_failure;
+        }
+    }
+
+    if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))
+    {
+               mz_uint32 extra_size_remaining = local_header_extra_len;
+               const mz_uint8 *pExtra_data = (const mz_uint8 *)file_data_array.m_p;
+
+        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+            goto handle_failure;
+        }
+
+        do
+        {
+            mz_uint32 field_id, field_data_size, field_total_size;
+
+            if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            field_id = MZ_READ_LE16(pExtra_data);
+            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+            field_total_size = field_data_size + sizeof(mz_uint16) * 2;
+
+            if (field_total_size > extra_size_remaining)
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
+            {
+                const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
+
+                if (field_data_size < sizeof(mz_uint64) * 2)
+                {
+                    mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+                    goto handle_failure;
+                }
+
+                local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
+                local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64));
+
+                found_zip64_ext_data_in_ldir = MZ_TRUE;
+                break;
+            }
+
+            pExtra_data += field_total_size;
+            extra_size_remaining -= field_total_size;
+        } while (extra_size_remaining);
+    }
+
+    /* TODO: parse local header extra data when local_header_comp_size is 0xFFFFFFFF! (big_descriptor.zip) */
+    /* I've seen zips in the wild with the data descriptor bit set, but proper local header values and bogus data descriptors */
+    if ((has_data_descriptor) && (!local_header_comp_size) && (!local_header_crc32))
+    {
+        mz_uint8 descriptor_buf[32];
+               mz_bool has_id;
+               const mz_uint8 *pSrc;
+               mz_uint32 file_crc32;
+               mz_uint64 comp_size = 0, uncomp_size = 0;
+
+        mz_uint32 num_descriptor_uint32s = ((pState->m_zip64) || (found_zip64_ext_data_in_ldir)) ? 6 : 4;
+
+        if (pZip->m_pRead(pZip->m_pIO_opaque, local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_len + local_header_extra_len + file_stat.m_comp_size, descriptor_buf, sizeof(mz_uint32) * num_descriptor_uint32s) != (sizeof(mz_uint32) * num_descriptor_uint32s))
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+            goto handle_failure;
+        }
+
+        has_id = (MZ_READ_LE32(descriptor_buf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
+               pSrc = has_id ? (descriptor_buf + sizeof(mz_uint32)) : descriptor_buf;
+
+        file_crc32 = MZ_READ_LE32(pSrc);        
+
+        if ((pState->m_zip64) || (found_zip64_ext_data_in_ldir))
+        {
+            comp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32));
+            uncomp_size = MZ_READ_LE64(pSrc + sizeof(mz_uint32) + sizeof(mz_uint64));
+        }
+        else
+        {
+            comp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32));
+            uncomp_size = MZ_READ_LE32(pSrc + sizeof(mz_uint32) + sizeof(mz_uint32));
+        }
+
+        if ((file_crc32 != file_stat.m_crc32) || (comp_size != file_stat.m_comp_size) || (uncomp_size != file_stat.m_uncomp_size))
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
+            goto handle_failure;
+        }
+    }
+    else
+    {
+        if ((local_header_crc32 != file_stat.m_crc32) || (local_header_comp_size != file_stat.m_comp_size) || (local_header_uncomp_size != file_stat.m_uncomp_size))
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
+            goto handle_failure;
+        }
+    }
+
+    mz_zip_array_clear(pZip, &file_data_array);
+
+    if ((flags & MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY) == 0)
+    {
+        if (!mz_zip_reader_extract_to_callback(pZip, file_index, mz_zip_compute_crc32_callback, &uncomp_crc32, 0))
+            return MZ_FALSE;
+
+        /* 1 more check to be sure, although the extract checks too. */
+        if (uncomp_crc32 != file_stat.m_crc32)
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
+            return MZ_FALSE;
+        }
+    }
+
+    return MZ_TRUE;
+
+handle_failure:
+    mz_zip_array_clear(pZip, &file_data_array);
+    return MZ_FALSE;
+}
+
+mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags)
+{
+    mz_zip_internal_state *pState;
+    uint32_t i;
+
+    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    /* Basic sanity checks */
+    if (!pState->m_zip64)
+    {
+        if (pZip->m_total_files > MZ_UINT16_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+        if (pZip->m_archive_size > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+    }
+    else
+    {
+        if (pZip->m_total_files >= MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+        if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+    }
+
+    for (i = 0; i < pZip->m_total_files; i++)
+    {
+        if (MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG & flags)
+        {
+            mz_uint32 found_index;
+            mz_zip_archive_file_stat stat;
+
+            if (!mz_zip_reader_file_stat(pZip, i, &stat))
+                return MZ_FALSE;
+
+            if (!mz_zip_reader_locate_file_v2(pZip, stat.m_filename, NULL, 0, &found_index))
+                return MZ_FALSE;
+
+            /* This check can fail if there are duplicate filenames in the archive (which we don't check for when writing - that's up to the user) */
+            if (found_index != i)
+                return mz_zip_set_error(pZip, MZ_ZIP_VALIDATION_FAILED);
+        }
+
+        if (!mz_zip_validate_file(pZip, i, flags))
+            return MZ_FALSE;
+    }
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr)
+{
+    mz_bool success = MZ_TRUE;
+    mz_zip_archive zip;
+    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
+
+    if ((!pMem) || (!size))
+    {
+        if (pErr)
+            *pErr = MZ_ZIP_INVALID_PARAMETER;
+        return MZ_FALSE;
+    }
+
+    mz_zip_zero_struct(&zip);
+
+    if (!mz_zip_reader_init_mem(&zip, pMem, size, flags))
+    {
+        if (pErr)
+            *pErr = zip.m_last_error;
+        return MZ_FALSE;
+    }
+
+    if (!mz_zip_validate_archive(&zip, flags))
+    {
+        actual_err = zip.m_last_error;
+        success = MZ_FALSE;
+    }
+
+    if (!mz_zip_reader_end_internal(&zip, success))
+    {
+        if (!actual_err)
+            actual_err = zip.m_last_error;
+        success = MZ_FALSE;
+    }
+
+    if (pErr)
+        *pErr = actual_err;
+
+    return success;
+}
+
+#ifndef MINIZ_NO_STDIO
+mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr)
+{
+    mz_bool success = MZ_TRUE;
+    mz_zip_archive zip;
+    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
+
+    if (!pFilename)
+    {
+        if (pErr)
+            *pErr = MZ_ZIP_INVALID_PARAMETER;
+        return MZ_FALSE;
+    }
+
+    mz_zip_zero_struct(&zip);
+
+    if (!mz_zip_reader_init_file_v2(&zip, pFilename, flags, 0, 0))
+    {
+        if (pErr)
+            *pErr = zip.m_last_error;
+        return MZ_FALSE;
+    }
+
+    if (!mz_zip_validate_archive(&zip, flags))
+    {
+        actual_err = zip.m_last_error;
+        success = MZ_FALSE;
+    }
+
+    if (!mz_zip_reader_end_internal(&zip, success))
+    {
+        if (!actual_err)
+            actual_err = zip.m_last_error;
+        success = MZ_FALSE;
+    }
+
+    if (pErr)
+        *pErr = actual_err;
+
+    return success;
+}
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+/* ------------------- .ZIP archive writing */
+
+#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
+
+static MZ_FORCEINLINE void mz_write_le16(mz_uint8 *p, mz_uint16 v)
+{
+    p[0] = (mz_uint8)v;
+    p[1] = (mz_uint8)(v >> 8);
+}
+static MZ_FORCEINLINE void mz_write_le32(mz_uint8 *p, mz_uint32 v)
+{
+    p[0] = (mz_uint8)v;
+    p[1] = (mz_uint8)(v >> 8);
+    p[2] = (mz_uint8)(v >> 16);
+    p[3] = (mz_uint8)(v >> 24);
+}
+static MZ_FORCEINLINE void mz_write_le64(mz_uint8 *p, mz_uint64 v)
+{
+    mz_write_le32(p, (mz_uint32)v);
+    mz_write_le32(p + sizeof(mz_uint32), (mz_uint32)(v >> 32));
+}
+
+#define MZ_WRITE_LE16(p, v) mz_write_le16((mz_uint8 *)(p), (mz_uint16)(v))
+#define MZ_WRITE_LE32(p, v) mz_write_le32((mz_uint8 *)(p), (mz_uint32)(v))
+#define MZ_WRITE_LE64(p, v) mz_write_le64((mz_uint8 *)(p), (mz_uint64)(v))
+
+static size_t mz_zip_heap_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
+{
+    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
+    mz_zip_internal_state *pState = pZip->m_pState;
+    mz_uint64 new_size = MZ_MAX(file_ofs + n, pState->m_mem_size);
+
+    if (!n)
+        return 0;
+
+    /* An allocation this big is likely to just fail on 32-bit systems, so don't even go there. */
+    if ((sizeof(size_t) == sizeof(mz_uint32)) && (new_size > 0x7FFFFFFF))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
+        return 0;
+    }
+
+    if (new_size > pState->m_mem_capacity)
+    {
+        void *pNew_block;
+        size_t new_capacity = MZ_MAX(64, pState->m_mem_capacity);
+
+        while (new_capacity < new_size)
+            new_capacity *= 2;
+
+        if (NULL == (pNew_block = pZip->m_pRealloc(pZip->m_pAlloc_opaque, pState->m_pMem, 1, new_capacity)))
+        {
+            mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+            return 0;
+        }
+
+        pState->m_pMem = pNew_block;
+        pState->m_mem_capacity = new_capacity;
+    }
+    memcpy((mz_uint8 *)pState->m_pMem + file_ofs, pBuf, n);
+    pState->m_mem_size = (size_t)new_size;
+    return n;
+}
+
+static mz_bool mz_zip_writer_end_internal(mz_zip_archive *pZip, mz_bool set_last_error)
+{
+    mz_zip_internal_state *pState;
+    mz_bool status = MZ_TRUE;
+
+    if ((!pZip) || (!pZip->m_pState) || (!pZip->m_pAlloc) || (!pZip->m_pFree) || ((pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) && (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED)))
+    {
+        if (set_last_error)
+            mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return MZ_FALSE;
+    }
+
+    pState = pZip->m_pState;
+    pZip->m_pState = NULL;
+    mz_zip_array_clear(pZip, &pState->m_central_dir);
+    mz_zip_array_clear(pZip, &pState->m_central_dir_offsets);
+    mz_zip_array_clear(pZip, &pState->m_sorted_central_dir_offsets);
+
+#ifndef MINIZ_NO_STDIO
+    if (pState->m_pFile)
+    {
+        if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
+        {
+            if (MZ_FCLOSE(pState->m_pFile) == EOF)
+            {
+                if (set_last_error)
+                    mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
+                status = MZ_FALSE;
+            }
+        }
+
+        pState->m_pFile = NULL;
+    }
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+    if ((pZip->m_pWrite == mz_zip_heap_write_func) && (pState->m_pMem))
+    {
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pState->m_pMem);
+        pState->m_pMem = NULL;
+    }
+
+    pZip->m_pFree(pZip->m_pAlloc_opaque, pState);
+    pZip->m_zip_mode = MZ_ZIP_MODE_INVALID;
+    return status;
+}
+
+mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags)
+{
+    mz_bool zip64 = (flags & MZ_ZIP_FLAG_WRITE_ZIP64) != 0;
+
+    if ((!pZip) || (pZip->m_pState) || (!pZip->m_pWrite) || (pZip->m_zip_mode != MZ_ZIP_MODE_INVALID))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
+    {
+        if (!pZip->m_pRead)
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+    }
+
+    if (pZip->m_file_offset_alignment)
+    {
+        /* Ensure user specified file offset alignment is a power of 2. */
+        if (pZip->m_file_offset_alignment & (pZip->m_file_offset_alignment - 1))
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+    }
+
+    if (!pZip->m_pAlloc)
+        pZip->m_pAlloc = miniz_def_alloc_func;
+    if (!pZip->m_pFree)
+        pZip->m_pFree = miniz_def_free_func;
+    if (!pZip->m_pRealloc)
+        pZip->m_pRealloc = miniz_def_realloc_func;
+
+    pZip->m_archive_size = existing_size;
+    pZip->m_central_directory_file_ofs = 0;
+    pZip->m_total_files = 0;
+
+    if (NULL == (pZip->m_pState = (mz_zip_internal_state *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(mz_zip_internal_state))))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    memset(pZip->m_pState, 0, sizeof(mz_zip_internal_state));
+
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir, sizeof(mz_uint8));
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_central_dir_offsets, sizeof(mz_uint32));
+    MZ_ZIP_ARRAY_SET_ELEMENT_SIZE(&pZip->m_pState->m_sorted_central_dir_offsets, sizeof(mz_uint32));
+
+    pZip->m_pState->m_zip64 = zip64;
+    pZip->m_pState->m_zip64_has_extended_info_fields = zip64;
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_USER;
+    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size)
+{
+    return mz_zip_writer_init_v2(pZip, existing_size, 0);
+}
+
+mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags)
+{
+    pZip->m_pWrite = mz_zip_heap_write_func;
+       pZip->m_pNeeds_keepalive = NULL;
+
+    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
+        pZip->m_pRead = mz_zip_mem_read_func;
+
+    pZip->m_pIO_opaque = pZip;
+
+    if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
+        return MZ_FALSE;
+
+    pZip->m_zip_type = MZ_ZIP_TYPE_HEAP;
+
+    if (0 != (initial_allocation_size = MZ_MAX(initial_allocation_size, size_to_reserve_at_beginning)))
+    {
+        if (NULL == (pZip->m_pState->m_pMem = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, initial_allocation_size)))
+        {
+            mz_zip_writer_end_internal(pZip, MZ_FALSE);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+        pZip->m_pState->m_mem_capacity = initial_allocation_size;
+    }
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size)
+{
+    return mz_zip_writer_init_heap_v2(pZip, size_to_reserve_at_beginning, initial_allocation_size, 0);
+}
+
+#ifndef MINIZ_NO_STDIO
+static size_t mz_zip_file_write_func(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n)
+{
+    mz_zip_archive *pZip = (mz_zip_archive *)pOpaque;
+    mz_int64 cur_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
+
+    file_ofs += pZip->m_pState->m_file_archive_start_ofs;
+
+    if (((mz_int64)file_ofs < 0) || (((cur_ofs != (mz_int64)file_ofs)) && (MZ_FSEEK64(pZip->m_pState->m_pFile, (mz_int64)file_ofs, SEEK_SET))))
+    {
+        mz_zip_set_error(pZip, MZ_ZIP_FILE_SEEK_FAILED);
+        return 0;
+    }
+
+    return MZ_FWRITE(pBuf, 1, n, pZip->m_pState->m_pFile);
+}
+
+mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning)
+{
+    return mz_zip_writer_init_file_v2(pZip, pFilename, size_to_reserve_at_beginning, 0);
+}
+
+mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags)
+{
+    MZ_FILE *pFile;
+
+    pZip->m_pWrite = mz_zip_file_write_func;
+       pZip->m_pNeeds_keepalive = NULL;
+
+    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
+        pZip->m_pRead = mz_zip_file_read_func;
+
+    pZip->m_pIO_opaque = pZip;
+
+    if (!mz_zip_writer_init_v2(pZip, size_to_reserve_at_beginning, flags))
+        return MZ_FALSE;
+
+    if (NULL == (pFile = MZ_FOPEN(pFilename, (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING) ? "w+b" : "wb")))
+    {
+        mz_zip_writer_end(pZip);
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+    }
+
+    pZip->m_pState->m_pFile = pFile;
+    pZip->m_zip_type = MZ_ZIP_TYPE_FILE;
+
+    if (size_to_reserve_at_beginning)
+    {
+        mz_uint64 cur_ofs = 0;
+        char buf[4096];
+
+        MZ_CLEAR_OBJ(buf);
+
+        do
+        {
+            size_t n = (size_t)MZ_MIN(sizeof(buf), size_to_reserve_at_beginning);
+            if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_ofs, buf, n) != n)
+            {
+                mz_zip_writer_end(pZip);
+                return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+            }
+            cur_ofs += n;
+            size_to_reserve_at_beginning -= n;
+        } while (size_to_reserve_at_beginning);
+    }
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags)
+{
+    pZip->m_pWrite = mz_zip_file_write_func;
+       pZip->m_pNeeds_keepalive = NULL;
+
+    if (flags & MZ_ZIP_FLAG_WRITE_ALLOW_READING)
+        pZip->m_pRead = mz_zip_file_read_func;
+
+    pZip->m_pIO_opaque = pZip;
+
+    if (!mz_zip_writer_init_v2(pZip, 0, flags))
+        return MZ_FALSE;
+
+    pZip->m_pState->m_pFile = pFile;
+    pZip->m_pState->m_file_archive_start_ofs = MZ_FTELL64(pZip->m_pState->m_pFile);
+    pZip->m_zip_type = MZ_ZIP_TYPE_CFILE;
+
+    return MZ_TRUE;
+}
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags)
+{
+    mz_zip_internal_state *pState;
+
+    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_READING))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (flags & MZ_ZIP_FLAG_WRITE_ZIP64)
+    {
+        /* We don't support converting a non-zip64 file to zip64 - this seems like more trouble than it's worth. (What about the existing 32-bit data descriptors that could follow the compressed data?) */
+        if (!pZip->m_pState->m_zip64)
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+    }
+
+    /* No sense in trying to write to an archive that's already at the support max size */
+    if (pZip->m_pState->m_zip64)
+    {
+        if (pZip->m_total_files == MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+    else
+    {
+        if (pZip->m_total_files == MZ_UINT16_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+
+        if ((pZip->m_archive_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + MZ_ZIP_LOCAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
+    }
+
+    pState = pZip->m_pState;
+
+    if (pState->m_pFile)
+    {
+#ifdef MINIZ_NO_STDIO
+        (void)pFilename;
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+#else
+        if (pZip->m_pIO_opaque != pZip)
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+        if (pZip->m_zip_type == MZ_ZIP_TYPE_FILE)
+        {
+            if (!pFilename)
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+            /* Archive is being read from stdio and was originally opened only for reading. Try to reopen as writable. */
+            if (NULL == (pState->m_pFile = MZ_FREOPEN(pFilename, "r+b", pState->m_pFile)))
+            {
+                /* The mz_zip_archive is now in a bogus state because pState->m_pFile is NULL, so just close it. */
+                mz_zip_reader_end_internal(pZip, MZ_FALSE);
+                return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+            }
+        }
+
+        pZip->m_pWrite = mz_zip_file_write_func;
+               pZip->m_pNeeds_keepalive = NULL;
+#endif /* #ifdef MINIZ_NO_STDIO */
+    }
+    else if (pState->m_pMem)
+    {
+        /* Archive lives in a memory block. Assume it's from the heap that we can resize using the realloc callback. */
+        if (pZip->m_pIO_opaque != pZip)
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+        pState->m_mem_capacity = pState->m_mem_size;
+        pZip->m_pWrite = mz_zip_heap_write_func;
+               pZip->m_pNeeds_keepalive = NULL;
+    }
+    /* Archive is being read via a user provided read function - make sure the user has specified a write function too. */
+    else if (!pZip->m_pWrite)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    /* Start writing new files at the archive's current central directory location. */
+    /* TODO: We could add a flag that lets the user start writing immediately AFTER the existing central dir - this would be safer. */
+    pZip->m_archive_size = pZip->m_central_directory_file_ofs;
+    pZip->m_central_directory_file_ofs = 0;
+
+    /* Clear the sorted central dir offsets, they aren't useful or maintained now. */
+    /* Even though we're now in write mode, files can still be extracted and verified, but file locates will be slow. */
+    /* TODO: We could easily maintain the sorted central directory offsets. */
+    mz_zip_array_clear(pZip, &pZip->m_pState->m_sorted_central_dir_offsets);
+
+    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING;
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename)
+{
+    return mz_zip_writer_init_from_reader_v2(pZip, pFilename, 0);
+}
+
+/* TODO: pArchive_name is a terrible name here! */
+mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags)
+{
+    return mz_zip_writer_add_mem_ex(pZip, pArchive_name, pBuf, buf_size, NULL, 0, level_and_flags, 0, 0);
+}
+
+typedef struct
+{
+    mz_zip_archive *m_pZip;
+    mz_uint64 m_cur_archive_file_ofs;
+    mz_uint64 m_comp_size;
+} mz_zip_writer_add_state;
+
+static mz_bool mz_zip_writer_add_put_buf_callback(const void *pBuf, int len, void *pUser)
+{
+    mz_zip_writer_add_state *pState = (mz_zip_writer_add_state *)pUser;
+    if ((int)pState->m_pZip->m_pWrite(pState->m_pZip->m_pIO_opaque, pState->m_cur_archive_file_ofs, pBuf, len) != len)
+        return MZ_FALSE;
+
+    pState->m_cur_archive_file_ofs += len;
+    pState->m_comp_size += len;
+    return MZ_TRUE;
+}
+
+#define MZ_ZIP64_MAX_LOCAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 2)
+#define MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE (sizeof(mz_uint16) * 2 + sizeof(mz_uint64) * 3)
+static mz_uint32 mz_zip_writer_create_zip64_extra_data(mz_uint8 *pBuf, mz_uint64 *pUncomp_size, mz_uint64 *pComp_size, mz_uint64 *pLocal_header_ofs)
+{
+    mz_uint8 *pDst = pBuf;
+       mz_uint32 field_size = 0;
+
+    MZ_WRITE_LE16(pDst + 0, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
+    MZ_WRITE_LE16(pDst + 2, 0);
+    pDst += sizeof(mz_uint16) * 2;
+
+    if (pUncomp_size)
+    {
+        MZ_WRITE_LE64(pDst, *pUncomp_size);
+        pDst += sizeof(mz_uint64);
+        field_size += sizeof(mz_uint64);
+    }
+
+    if (pComp_size)
+    {
+        MZ_WRITE_LE64(pDst, *pComp_size);
+        pDst += sizeof(mz_uint64);
+        field_size += sizeof(mz_uint64);
+    }
+
+    if (pLocal_header_ofs)
+    {
+        MZ_WRITE_LE64(pDst, *pLocal_header_ofs);
+        pDst += sizeof(mz_uint64);
+        field_size += sizeof(mz_uint64);
+    }
+
+    MZ_WRITE_LE16(pBuf + 2, field_size);
+
+    return (mz_uint32)(pDst - pBuf);
+}
+
+static mz_bool mz_zip_writer_create_local_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst, mz_uint16 filename_size, mz_uint16 extra_size, mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32, mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date)
+{
+    (void)pZip;
+    memset(pDst, 0, MZ_ZIP_LOCAL_DIR_HEADER_SIZE);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_SIG_OFS, MZ_ZIP_LOCAL_DIR_HEADER_SIG);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_VERSION_NEEDED_OFS, method ? 20 : 0);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_BIT_FLAG_OFS, bit_flags);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_METHOD_OFS, method);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_TIME_OFS, dos_time);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILE_DATE_OFS, dos_date);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_CRC32_OFS, uncomp_crc32);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));
+    MZ_WRITE_LE32(pDst + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_FILENAME_LEN_OFS, filename_size);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_LDH_EXTRA_LEN_OFS, extra_size);
+    return MZ_TRUE;
+}
+
+static mz_bool mz_zip_writer_create_central_dir_header(mz_zip_archive *pZip, mz_uint8 *pDst,
+                                                       mz_uint16 filename_size, mz_uint16 extra_size, mz_uint16 comment_size,
+                                                       mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,
+                                                       mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
+                                                       mz_uint64 local_header_ofs, mz_uint32 ext_attributes)
+{
+    (void)pZip;
+    memset(pDst, 0, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_SIG_OFS, MZ_ZIP_CENTRAL_DIR_HEADER_SIG);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_VERSION_NEEDED_OFS, method ? 20 : 0);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_BIT_FLAG_OFS, bit_flags);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_METHOD_OFS, method);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_TIME_OFS, dos_time);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILE_DATE_OFS, dos_date);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_CRC32_OFS, uncomp_crc32);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_MIN(comp_size, MZ_UINT32_MAX));
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_MIN(uncomp_size, MZ_UINT32_MAX));
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_FILENAME_LEN_OFS, filename_size);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_EXTRA_LEN_OFS, extra_size);
+    MZ_WRITE_LE16(pDst + MZ_ZIP_CDH_COMMENT_LEN_OFS, comment_size);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_EXTERNAL_ATTR_OFS, ext_attributes);
+    MZ_WRITE_LE32(pDst + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_MIN(local_header_ofs, MZ_UINT32_MAX));
+    return MZ_TRUE;
+}
+
+static mz_bool mz_zip_writer_add_to_central_dir(mz_zip_archive *pZip, const char *pFilename, mz_uint16 filename_size,
+                                                const void *pExtra, mz_uint16 extra_size, const void *pComment, mz_uint16 comment_size,
+                                                mz_uint64 uncomp_size, mz_uint64 comp_size, mz_uint32 uncomp_crc32,
+                                                mz_uint16 method, mz_uint16 bit_flags, mz_uint16 dos_time, mz_uint16 dos_date,
+                                                mz_uint64 local_header_ofs, mz_uint32 ext_attributes,
+                                                const char *user_extra_data, mz_uint user_extra_data_len)
+{
+    mz_zip_internal_state *pState = pZip->m_pState;
+    mz_uint32 central_dir_ofs = (mz_uint32)pState->m_central_dir.m_size;
+    size_t orig_central_dir_size = pState->m_central_dir.m_size;
+    mz_uint8 central_dir_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
+
+    if (!pZip->m_pState->m_zip64)
+    {
+        if (local_header_ofs > 0xFFFFFFFF)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_TOO_LARGE);
+    }
+
+    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
+    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + filename_size + extra_size + user_extra_data_len + comment_size) >= MZ_UINT32_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+    if (!mz_zip_writer_create_central_dir_header(pZip, central_dir_header, filename_size, extra_size + user_extra_data_len, comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_header_ofs, ext_attributes))
+        return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+    if ((!mz_zip_array_push_back(pZip, &pState->m_central_dir, central_dir_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE)) ||
+        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pFilename, filename_size)) ||
+        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pExtra, extra_size)) ||
+        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, user_extra_data, user_extra_data_len)) ||
+        (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pComment, comment_size)) ||
+        (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &central_dir_ofs, 1)))
+    {
+        /* Try to resize the central directory array back into its original state. */
+        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+    }
+
+    return MZ_TRUE;
+}
+
+static mz_bool mz_zip_writer_validate_archive_name(const char *pArchive_name)
+{
+    /* Basic ZIP archive filename validity checks: Valid filenames cannot start with a forward slash, cannot contain a drive letter, and cannot use DOS-style backward slashes. */
+    if (*pArchive_name == '/')
+        return MZ_FALSE;
+
+    while (*pArchive_name)
+    {
+        if ((*pArchive_name == '\\') || (*pArchive_name == ':'))
+            return MZ_FALSE;
+
+        pArchive_name++;
+    }
+
+    return MZ_TRUE;
+}
+
+static mz_uint mz_zip_writer_compute_padding_needed_for_file_alignment(mz_zip_archive *pZip)
+{
+    mz_uint32 n;
+    if (!pZip->m_file_offset_alignment)
+        return 0;
+    n = (mz_uint32)(pZip->m_archive_size & (pZip->m_file_offset_alignment - 1));
+    return (mz_uint)((pZip->m_file_offset_alignment - n) & (pZip->m_file_offset_alignment - 1));
+}
+
+static mz_bool mz_zip_writer_write_zeros(mz_zip_archive *pZip, mz_uint64 cur_file_ofs, mz_uint32 n)
+{
+    char buf[4096];
+    memset(buf, 0, MZ_MIN(sizeof(buf), n));
+    while (n)
+    {
+        mz_uint32 s = MZ_MIN(sizeof(buf), n);
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_file_ofs, buf, s) != s)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_file_ofs += s;
+        n -= s;
+    }
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
+                                 mz_uint64 uncomp_size, mz_uint32 uncomp_crc32)
+{
+    return mz_zip_writer_add_mem_ex_v2(pZip, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, uncomp_size, uncomp_crc32, NULL, NULL, 0, NULL, 0);
+}
+
+mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size,
+                                    mz_uint level_and_flags, mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified,
+                                    const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
+{
+    mz_uint16 method = 0, dos_time = 0, dos_date = 0;
+    mz_uint level, ext_attributes = 0, num_alignment_padding_bytes;
+    mz_uint64 local_dir_header_ofs = pZip->m_archive_size, cur_archive_file_ofs = pZip->m_archive_size, comp_size = 0;
+    size_t archive_name_size;
+    mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
+    tdefl_compressor *pComp = NULL;
+    mz_bool store_data_uncompressed;
+    mz_zip_internal_state *pState;
+    mz_uint8 *pExtra_data = NULL;
+    mz_uint32 extra_size = 0;
+    mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
+    mz_uint16 bit_flags = 0;
+
+    if (uncomp_size || (buf_size && !(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)))
+        bit_flags |= MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
+
+    if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
+        bit_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
+
+    if ((int)level_and_flags < 0)
+        level_and_flags = MZ_DEFAULT_LEVEL;
+    level = level_and_flags & 0xF;
+    store_data_uncompressed = ((!level) || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA));
+
+    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || ((buf_size) && (!pBuf)) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    if (pState->m_zip64)
+    {
+        if (pZip->m_total_files == MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+    else
+    {
+        if (pZip->m_total_files == MZ_UINT16_MAX)
+        {
+            pState->m_zip64 = MZ_TRUE;
+            /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
+        }
+        if ((buf_size > 0xFFFFFFFF) || (uncomp_size > 0xFFFFFFFF))
+        {
+            pState->m_zip64 = MZ_TRUE;
+            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
+        }
+    }
+
+    if ((!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)) && (uncomp_size))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_writer_validate_archive_name(pArchive_name))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
+
+#ifndef MINIZ_NO_TIME
+    if (last_modified != NULL)
+    {
+        mz_zip_time_t_to_dos_time(*last_modified, &dos_time, &dos_date);
+    }
+    else
+    {
+               MZ_TIME_T cur_time;
+               time(&cur_time);
+               mz_zip_time_t_to_dos_time(cur_time, &dos_time, &dos_date);
+    }
+#endif /* #ifndef MINIZ_NO_TIME */
+
+    archive_name_size = strlen(pArchive_name);
+    if (archive_name_size > MZ_UINT16_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
+
+    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
+
+    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
+    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+    if (!pState->m_zip64)
+    {
+        /* Bail early if the archive would obviously become too large */
+        if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > 0xFFFFFFFF)
+        {
+            pState->m_zip64 = MZ_TRUE;
+            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
+        }
+    }
+
+    if ((archive_name_size) && (pArchive_name[archive_name_size - 1] == '/'))
+    {
+        /* Set DOS Subdirectory attribute bit. */
+        ext_attributes |= MZ_ZIP_DOS_DIR_ATTRIBUTE_BITFLAG;
+
+        /* Subdirectories cannot contain data. */
+        if ((buf_size) || (uncomp_size))
+            return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+    }
+
+    /* Try to do any allocations before writing to the archive, so if an allocation fails the file remains unmodified. (A good idea if we're doing an in-place modification.) */
+    if ((!mz_zip_array_ensure_room(pZip, &pState->m_central_dir, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + (pState->m_zip64 ? MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE : 0))) || (!mz_zip_array_ensure_room(pZip, &pState->m_central_dir_offsets, 1)))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    if ((!store_data_uncompressed) && (buf_size))
+    {
+        if (NULL == (pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor))))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+    }
+
+    if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
+    {
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+        return MZ_FALSE;
+    }
+
+    local_dir_header_ofs += num_alignment_padding_bytes;
+    if (pZip->m_file_offset_alignment)
+    {
+        MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
+    }
+    cur_archive_file_ofs += num_alignment_padding_bytes;
+
+    MZ_CLEAR_OBJ(local_dir_header);
+
+    if (!store_data_uncompressed || (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
+    {
+        method = MZ_DEFLATED;
+    }
+
+    if (pState->m_zip64)
+    {
+        if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
+        {
+            pExtra_data = extra_data;
+            extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
+                                                               (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
+        }
+
+        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))
+            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += sizeof(local_dir_header);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+        cur_archive_file_ofs += archive_name_size;
+
+        if (pExtra_data != NULL)
+        {
+            if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
+                return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+            cur_archive_file_ofs += extra_size;
+        }
+    }
+    else
+    {
+        if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, bit_flags, dos_time, dos_date))
+            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, local_dir_header_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += sizeof(local_dir_header);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+        cur_archive_file_ofs += archive_name_size;
+    }
+
+    if (user_extra_data_len > 0)
+    {
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += user_extra_data_len;
+    }
+
+    if (!(level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA))
+    {
+        uncomp_crc32 = (mz_uint32)mz_crc32(MZ_CRC32_INIT, (const mz_uint8 *)pBuf, buf_size);
+        uncomp_size = buf_size;
+        if (uncomp_size <= 3)
+        {
+            level = 0;
+            store_data_uncompressed = MZ_TRUE;
+        }
+    }
+
+    if (store_data_uncompressed)
+    {
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pBuf, buf_size) != buf_size)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+
+        cur_archive_file_ofs += buf_size;
+        comp_size = buf_size;
+    }
+    else if (buf_size)
+    {
+        mz_zip_writer_add_state state;
+
+        state.m_pZip = pZip;
+        state.m_cur_archive_file_ofs = cur_archive_file_ofs;
+        state.m_comp_size = 0;
+
+        if ((tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY) ||
+            (tdefl_compress_buffer(pComp, pBuf, buf_size, TDEFL_FINISH) != TDEFL_STATUS_DONE))
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+            return mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
+        }
+
+        comp_size = state.m_comp_size;
+        cur_archive_file_ofs = state.m_cur_archive_file_ofs;
+    }
+
+    pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+    pComp = NULL;
+
+    if (uncomp_size)
+    {
+               mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
+               mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
+
+        MZ_ASSERT(bit_flags & MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR);
+
+        MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
+        MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
+        if (pExtra_data == NULL)
+        {
+            if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
+                return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+            MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
+            MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
+        }
+        else
+        {
+            MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
+            MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
+            local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
+        }
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
+            return MZ_FALSE;
+
+        cur_archive_file_ofs += local_dir_footer_size;
+    }
+
+    if (pExtra_data != NULL)
+    {
+        extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
+                                                           (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
+    }
+
+    if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment,
+                                          comment_size, uncomp_size, comp_size, uncomp_crc32, method, bit_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
+                                          user_extra_data_central, user_extra_data_central_len))
+        return MZ_FALSE;
+
+    pZip->m_total_files++;
+    pZip->m_archive_size = cur_archive_file_ofs;
+
+    return MZ_TRUE;
+}
+
+#ifndef MINIZ_NO_STDIO
+mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add, const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
+                                const char *user_extra_data, mz_uint user_extra_data_len, const char *user_extra_data_central, mz_uint user_extra_data_central_len)
+{
+    mz_uint16 gen_flags = MZ_ZIP_LDH_BIT_FLAG_HAS_LOCATOR;
+    mz_uint uncomp_crc32 = MZ_CRC32_INIT, level, num_alignment_padding_bytes;
+    mz_uint16 method = 0, dos_time = 0, dos_date = 0, ext_attributes = 0;
+    mz_uint64 local_dir_header_ofs, cur_archive_file_ofs = pZip->m_archive_size, uncomp_size = size_to_add, comp_size = 0;
+    size_t archive_name_size;
+    mz_uint8 local_dir_header[MZ_ZIP_LOCAL_DIR_HEADER_SIZE];
+    mz_uint8 *pExtra_data = NULL;
+    mz_uint32 extra_size = 0;
+    mz_uint8 extra_data[MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE];
+    mz_zip_internal_state *pState;
+
+    if (!(level_and_flags & MZ_ZIP_FLAG_ASCII_FILENAME))
+        gen_flags |= MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8;
+
+    if ((int)level_and_flags < 0)
+        level_and_flags = MZ_DEFAULT_LEVEL;
+    level = level_and_flags & 0xF;
+
+    /* Sanity checks */
+    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pArchive_name) || ((comment_size) && (!pComment)) || (level > MZ_UBER_COMPRESSION))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    if ((!pState->m_zip64) && (uncomp_size > MZ_UINT32_MAX))
+    {
+        /* Source file is too large for non-zip64 */
+        /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
+        pState->m_zip64 = MZ_TRUE;
+    }
+
+    /* We could support this, but why? */
+    if (level_and_flags & MZ_ZIP_FLAG_COMPRESSED_DATA)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_writer_validate_archive_name(pArchive_name))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
+
+    if (pState->m_zip64)
+    {
+        if (pZip->m_total_files == MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+    else
+    {
+        if (pZip->m_total_files == MZ_UINT16_MAX)
+        {
+            pState->m_zip64 = MZ_TRUE;
+            /*return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES); */
+        }
+    }
+
+    archive_name_size = strlen(pArchive_name);
+    if (archive_name_size > MZ_UINT16_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_FILENAME);
+
+    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
+
+    /* miniz doesn't support central dirs >= MZ_UINT32_MAX bytes yet */
+    if (((mz_uint64)pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP64_MAX_CENTRAL_EXTRA_FIELD_SIZE + comment_size) >= MZ_UINT32_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+    if (!pState->m_zip64)
+    {
+        /* Bail early if the archive would obviously become too large */
+        if ((pZip->m_archive_size + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + archive_name_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + archive_name_size + comment_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 1024) > 0xFFFFFFFF)
+        {
+            pState->m_zip64 = MZ_TRUE;
+            /*return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE); */
+        }
+    }
+
+#ifndef MINIZ_NO_TIME
+    if (pFile_time)
+    {
+        mz_zip_time_t_to_dos_time(*pFile_time, &dos_time, &dos_date);
+    }
+#endif
+
+    if (uncomp_size <= 3)
+        level = 0;
+
+    if (!mz_zip_writer_write_zeros(pZip, cur_archive_file_ofs, num_alignment_padding_bytes))
+    {
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+    }
+
+    cur_archive_file_ofs += num_alignment_padding_bytes;
+    local_dir_header_ofs = cur_archive_file_ofs;
+
+    if (pZip->m_file_offset_alignment)
+    {
+        MZ_ASSERT((cur_archive_file_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
+    }
+
+    if (uncomp_size && level)
+    {
+        method = MZ_DEFLATED;
+    }
+
+    MZ_CLEAR_OBJ(local_dir_header);
+    if (pState->m_zip64)
+    {
+        if (uncomp_size >= MZ_UINT32_MAX || local_dir_header_ofs >= MZ_UINT32_MAX)
+        {
+            pExtra_data = extra_data;
+            extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
+                                                               (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
+        }
+
+        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, extra_size + user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))
+            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += sizeof(local_dir_header);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
+        {
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+
+        cur_archive_file_ofs += archive_name_size;
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, extra_data, extra_size) != extra_size)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += extra_size;
+    }
+    else
+    {
+        if ((comp_size > MZ_UINT32_MAX) || (cur_archive_file_ofs > MZ_UINT32_MAX))
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+        if (!mz_zip_writer_create_local_dir_header(pZip, local_dir_header, (mz_uint16)archive_name_size, user_extra_data_len, 0, 0, 0, method, gen_flags, dos_time, dos_date))
+            return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_header, sizeof(local_dir_header)) != sizeof(local_dir_header))
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += sizeof(local_dir_header);
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pArchive_name, archive_name_size) != archive_name_size)
+        {
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+
+        cur_archive_file_ofs += archive_name_size;
+    }
+
+    if (user_extra_data_len > 0)
+    {
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, user_extra_data, user_extra_data_len) != user_extra_data_len)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        cur_archive_file_ofs += user_extra_data_len;
+    }
+
+    if (uncomp_size)
+    {
+        mz_uint64 uncomp_remaining = uncomp_size;
+        void *pRead_buf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, MZ_ZIP_MAX_IO_BUF_SIZE);
+        if (!pRead_buf)
+        {
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (!level)
+        {
+            while (uncomp_remaining)
+            {
+                mz_uint n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, uncomp_remaining);
+                if ((MZ_FREAD(pRead_buf, 1, n, pSrc_file) != n) || (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, pRead_buf, n) != n))
+                {
+                    pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+                    return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+                }
+                uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, n);
+                uncomp_remaining -= n;
+                cur_archive_file_ofs += n;
+            }
+            comp_size = uncomp_size;
+        }
+        else
+        {
+            mz_bool result = MZ_FALSE;
+            mz_zip_writer_add_state state;
+            tdefl_compressor *pComp = (tdefl_compressor *)pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, sizeof(tdefl_compressor));
+            if (!pComp)
+            {
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+                return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+            }
+
+            state.m_pZip = pZip;
+            state.m_cur_archive_file_ofs = cur_archive_file_ofs;
+            state.m_comp_size = 0;
+
+            if (tdefl_init(pComp, mz_zip_writer_add_put_buf_callback, &state, tdefl_create_comp_flags_from_zip_params(level, -15, MZ_DEFAULT_STRATEGY)) != TDEFL_STATUS_OKAY)
+            {
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+                return mz_zip_set_error(pZip, MZ_ZIP_INTERNAL_ERROR);
+            }
+
+            for (;;)
+            {
+                size_t in_buf_size = (mz_uint32)MZ_MIN(uncomp_remaining, (mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE);
+                tdefl_status status;
+                               tdefl_flush flush = TDEFL_NO_FLUSH;
+
+                if (MZ_FREAD(pRead_buf, 1, in_buf_size, pSrc_file) != in_buf_size)
+                {
+                    mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+                    break;
+                }
+
+                uncomp_crc32 = (mz_uint32)mz_crc32(uncomp_crc32, (const mz_uint8 *)pRead_buf, in_buf_size);
+                uncomp_remaining -= in_buf_size;
+
+                               if (pZip->m_pNeeds_keepalive != NULL && pZip->m_pNeeds_keepalive(pZip->m_pIO_opaque))
+                                       flush = TDEFL_FULL_FLUSH;
+
+                status = tdefl_compress_buffer(pComp, pRead_buf, in_buf_size, uncomp_remaining ? flush : TDEFL_FINISH);
+                if (status == TDEFL_STATUS_DONE)
+                {
+                    result = MZ_TRUE;
+                    break;
+                }
+                else if (status != TDEFL_STATUS_OKAY)
+                {
+                    mz_zip_set_error(pZip, MZ_ZIP_COMPRESSION_FAILED);
+                    break;
+                }
+            }
+
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pComp);
+
+            if (!result)
+            {
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+                return MZ_FALSE;
+            }
+
+            comp_size = state.m_comp_size;
+            cur_archive_file_ofs = state.m_cur_archive_file_ofs;
+        }
+
+        pZip->m_pFree(pZip->m_pAlloc_opaque, pRead_buf);
+    }
+
+       {
+               mz_uint8 local_dir_footer[MZ_ZIP_DATA_DESCRIPTER_SIZE64];
+               mz_uint32 local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE32;
+
+               MZ_WRITE_LE32(local_dir_footer + 0, MZ_ZIP_DATA_DESCRIPTOR_ID);
+               MZ_WRITE_LE32(local_dir_footer + 4, uncomp_crc32);
+               if (pExtra_data == NULL)
+               {
+                       if (comp_size > MZ_UINT32_MAX)
+                               return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+                       MZ_WRITE_LE32(local_dir_footer + 8, comp_size);
+                       MZ_WRITE_LE32(local_dir_footer + 12, uncomp_size);
+               }
+               else
+               {
+                       MZ_WRITE_LE64(local_dir_footer + 8, comp_size);
+                       MZ_WRITE_LE64(local_dir_footer + 16, uncomp_size);
+                       local_dir_footer_size = MZ_ZIP_DATA_DESCRIPTER_SIZE64;
+               }
+
+               if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_archive_file_ofs, local_dir_footer, local_dir_footer_size) != local_dir_footer_size)
+                       return MZ_FALSE;
+
+               cur_archive_file_ofs += local_dir_footer_size;
+       }
+
+    if (pExtra_data != NULL)
+    {
+        extra_size = mz_zip_writer_create_zip64_extra_data(extra_data, (uncomp_size >= MZ_UINT32_MAX) ? &uncomp_size : NULL,
+                                                           (uncomp_size >= MZ_UINT32_MAX) ? &comp_size : NULL, (local_dir_header_ofs >= MZ_UINT32_MAX) ? &local_dir_header_ofs : NULL);
+    }
+
+    if (!mz_zip_writer_add_to_central_dir(pZip, pArchive_name, (mz_uint16)archive_name_size, pExtra_data, extra_size, pComment, comment_size,
+                                          uncomp_size, comp_size, uncomp_crc32, method, gen_flags, dos_time, dos_date, local_dir_header_ofs, ext_attributes,
+                                          user_extra_data_central, user_extra_data_central_len))
+        return MZ_FALSE;
+
+    pZip->m_total_files++;
+    pZip->m_archive_size = cur_archive_file_ofs;
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
+{
+    MZ_FILE *pSrc_file = NULL;
+    mz_uint64 uncomp_size = 0;
+    MZ_TIME_T file_modified_time;
+    MZ_TIME_T *pFile_time = NULL;
+       mz_bool status;
+
+    memset(&file_modified_time, 0, sizeof(file_modified_time));
+
+#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_STDIO)
+    pFile_time = &file_modified_time;
+    if (!mz_zip_get_file_modified_time(pSrc_filename, &file_modified_time))
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_STAT_FAILED);
+#endif
+
+    pSrc_file = MZ_FOPEN(pSrc_filename, "rb");
+    if (!pSrc_file)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_OPEN_FAILED);
+
+    MZ_FSEEK64(pSrc_file, 0, SEEK_END);
+    uncomp_size = MZ_FTELL64(pSrc_file);
+    MZ_FSEEK64(pSrc_file, 0, SEEK_SET);
+
+    status = mz_zip_writer_add_cfile(pZip, pArchive_name, pSrc_file, uncomp_size, pFile_time, pComment, comment_size, level_and_flags, NULL, 0, NULL, 0);
+
+    MZ_FCLOSE(pSrc_file);
+
+    return status;
+}
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+static mz_bool mz_zip_writer_update_zip64_extension_block(mz_zip_array *pNew_ext, mz_zip_archive *pZip, const mz_uint8 *pExt, uint32_t ext_len, mz_uint64 *pComp_size, mz_uint64 *pUncomp_size, mz_uint64 *pLocal_header_ofs, mz_uint32 *pDisk_start)
+{
+    /* + 64 should be enough for any new zip64 data */
+    if (!mz_zip_array_reserve(pZip, pNew_ext, ext_len + 64, MZ_FALSE))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    mz_zip_array_resize(pZip, pNew_ext, 0, MZ_FALSE);
+
+    if ((pUncomp_size) || (pComp_size) || (pLocal_header_ofs) || (pDisk_start))
+    {
+        mz_uint8 new_ext_block[64];
+        mz_uint8 *pDst = new_ext_block;
+        mz_write_le16(pDst, MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID);
+        mz_write_le16(pDst + sizeof(mz_uint16), 0);
+        pDst += sizeof(mz_uint16) * 2;
+
+        if (pUncomp_size)
+        {
+            mz_write_le64(pDst, *pUncomp_size);
+            pDst += sizeof(mz_uint64);
+        }
+
+        if (pComp_size)
+        {
+            mz_write_le64(pDst, *pComp_size);
+            pDst += sizeof(mz_uint64);
+        }
+
+        if (pLocal_header_ofs)
+        {
+            mz_write_le64(pDst, *pLocal_header_ofs);
+            pDst += sizeof(mz_uint64);
+        }
+
+        if (pDisk_start)
+        {
+            mz_write_le32(pDst, *pDisk_start);
+            pDst += sizeof(mz_uint32);
+        }
+
+        mz_write_le16(new_ext_block + sizeof(mz_uint16), (mz_uint16)((pDst - new_ext_block) - sizeof(mz_uint16) * 2));
+
+        if (!mz_zip_array_push_back(pZip, pNew_ext, new_ext_block, pDst - new_ext_block))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+    }
+
+    if ((pExt) && (ext_len))
+    {
+        mz_uint32 extra_size_remaining = ext_len;
+        const mz_uint8 *pExtra_data = pExt;
+
+        do
+        {
+            mz_uint32 field_id, field_data_size, field_total_size;
+
+            if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            field_id = MZ_READ_LE16(pExtra_data);
+            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+            field_total_size = field_data_size + sizeof(mz_uint16) * 2;
+
+            if (field_total_size > extra_size_remaining)
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+            if (field_id != MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
+            {
+                if (!mz_zip_array_push_back(pZip, pNew_ext, pExtra_data, field_total_size))
+                    return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+            }
+
+            pExtra_data += field_total_size;
+            extra_size_remaining -= field_total_size;
+        } while (extra_size_remaining);
+    }
+
+    return MZ_TRUE;
+}
+
+/* TODO: This func is now pretty freakin complex due to zip64, split it up? */
+mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index)
+{
+    mz_uint n, bit_flags, num_alignment_padding_bytes, src_central_dir_following_data_size;
+    mz_uint64 src_archive_bytes_remaining, local_dir_header_ofs;
+    mz_uint64 cur_src_file_ofs, cur_dst_file_ofs;
+    mz_uint32 local_header_u32[(MZ_ZIP_LOCAL_DIR_HEADER_SIZE + sizeof(mz_uint32) - 1) / sizeof(mz_uint32)];
+    mz_uint8 *pLocal_header = (mz_uint8 *)local_header_u32;
+    mz_uint8 new_central_header[MZ_ZIP_CENTRAL_DIR_HEADER_SIZE];
+    size_t orig_central_dir_size;
+    mz_zip_internal_state *pState;
+    void *pBuf;
+    const mz_uint8 *pSrc_central_header;
+    mz_zip_archive_file_stat src_file_stat;
+    mz_uint32 src_filename_len, src_comment_len, src_ext_len;
+    mz_uint32 local_header_filename_size, local_header_extra_len;
+    mz_uint64 local_header_comp_size, local_header_uncomp_size;
+    mz_bool found_zip64_ext_data_in_ldir = MZ_FALSE;
+
+    /* Sanity checks */
+    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING) || (!pSource_zip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    /* Don't support copying files from zip64 archives to non-zip64, even though in some cases this is possible */
+    if ((pSource_zip->m_pState->m_zip64) && (!pZip->m_pState->m_zip64))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    /* Get pointer to the source central dir header and crack it */
+    if (NULL == (pSrc_central_header = mz_zip_get_cdh(pSource_zip, src_file_index)))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (MZ_READ_LE32(pSrc_central_header + MZ_ZIP_CDH_SIG_OFS) != MZ_ZIP_CENTRAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    src_filename_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    src_comment_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_COMMENT_LEN_OFS);
+    src_ext_len = MZ_READ_LE16(pSrc_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS);
+    src_central_dir_following_data_size = src_filename_len + src_ext_len + src_comment_len;
+
+    /* TODO: We don't support central dir's >= MZ_UINT32_MAX bytes right now (+32 fudge factor in case we need to add more extra data) */
+    if ((pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + 32) >= MZ_UINT32_MAX)
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+
+    num_alignment_padding_bytes = mz_zip_writer_compute_padding_needed_for_file_alignment(pZip);
+
+    if (!pState->m_zip64)
+    {
+        if (pZip->m_total_files == MZ_UINT16_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+    else
+    {
+        /* TODO: Our zip64 support still has some 32-bit limits that may not be worth fixing. */
+        if (pZip->m_total_files == MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+
+    if (!mz_zip_file_stat_internal(pSource_zip, src_file_index, pSrc_central_header, &src_file_stat, NULL))
+        return MZ_FALSE;
+
+    cur_src_file_ofs = src_file_stat.m_local_header_ofs;
+    cur_dst_file_ofs = pZip->m_archive_size;
+
+    /* Read the source archive's local dir header */
+    if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+
+    if (MZ_READ_LE32(pLocal_header) != MZ_ZIP_LOCAL_DIR_HEADER_SIG)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+
+    cur_src_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
+
+    /* Compute the total size we need to copy (filename+extra data+compressed data) */
+    local_header_filename_size = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_FILENAME_LEN_OFS);
+    local_header_extra_len = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_EXTRA_LEN_OFS);
+    local_header_comp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_COMPRESSED_SIZE_OFS);
+    local_header_uncomp_size = MZ_READ_LE32(pLocal_header + MZ_ZIP_LDH_DECOMPRESSED_SIZE_OFS);
+    src_archive_bytes_remaining = local_header_filename_size + local_header_extra_len + src_file_stat.m_comp_size;
+
+    /* Try to find a zip64 extended information field */
+    if ((local_header_extra_len) && ((local_header_comp_size == MZ_UINT32_MAX) || (local_header_uncomp_size == MZ_UINT32_MAX)))
+    {
+        mz_zip_array file_data_array;
+               const mz_uint8 *pExtra_data;
+               mz_uint32 extra_size_remaining = local_header_extra_len;
+
+        mz_zip_array_init(&file_data_array, 1);
+        if (!mz_zip_array_resize(pZip, &file_data_array, local_header_extra_len, MZ_FALSE))
+        {
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, src_file_stat.m_local_header_ofs + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + local_header_filename_size, file_data_array.m_p, local_header_extra_len) != local_header_extra_len)
+        {
+            mz_zip_array_clear(pZip, &file_data_array);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+        }
+
+        pExtra_data = (const mz_uint8 *)file_data_array.m_p;
+
+        do
+        {
+            mz_uint32 field_id, field_data_size, field_total_size;
+
+            if (extra_size_remaining < (sizeof(mz_uint16) * 2))
+            {
+                mz_zip_array_clear(pZip, &file_data_array);
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+            }
+
+            field_id = MZ_READ_LE16(pExtra_data);
+            field_data_size = MZ_READ_LE16(pExtra_data + sizeof(mz_uint16));
+            field_total_size = field_data_size + sizeof(mz_uint16) * 2;
+
+            if (field_total_size > extra_size_remaining)
+            {
+                mz_zip_array_clear(pZip, &file_data_array);
+                return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+            }
+
+            if (field_id == MZ_ZIP64_EXTENDED_INFORMATION_FIELD_HEADER_ID)
+            {
+                const mz_uint8 *pSrc_field_data = pExtra_data + sizeof(mz_uint32);
+
+                if (field_data_size < sizeof(mz_uint64) * 2)
+                {
+                    mz_zip_array_clear(pZip, &file_data_array);
+                    return mz_zip_set_error(pZip, MZ_ZIP_INVALID_HEADER_OR_CORRUPTED);
+                }
+
+                local_header_uncomp_size = MZ_READ_LE64(pSrc_field_data);
+                local_header_comp_size = MZ_READ_LE64(pSrc_field_data + sizeof(mz_uint64)); /* may be 0 if there's a descriptor */
+
+                found_zip64_ext_data_in_ldir = MZ_TRUE;
+                break;
+            }
+
+            pExtra_data += field_total_size;
+            extra_size_remaining -= field_total_size;
+        } while (extra_size_remaining);
+
+        mz_zip_array_clear(pZip, &file_data_array);
+    }
+
+    if (!pState->m_zip64)
+    {
+        /* Try to detect if the new archive will most likely wind up too big and bail early (+(sizeof(mz_uint32) * 4) is for the optional descriptor which could be present, +64 is a fudge factor). */
+        /* We also check when the archive is finalized so this doesn't need to be perfect. */
+        mz_uint64 approx_new_archive_size = cur_dst_file_ofs + num_alignment_padding_bytes + MZ_ZIP_LOCAL_DIR_HEADER_SIZE + src_archive_bytes_remaining + (sizeof(mz_uint32) * 4) +
+                                            pState->m_central_dir.m_size + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_central_dir_following_data_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE + 64;
+
+        if (approx_new_archive_size >= MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+    }
+
+    /* Write dest archive padding */
+    if (!mz_zip_writer_write_zeros(pZip, cur_dst_file_ofs, num_alignment_padding_bytes))
+        return MZ_FALSE;
+
+    cur_dst_file_ofs += num_alignment_padding_bytes;
+
+    local_dir_header_ofs = cur_dst_file_ofs;
+    if (pZip->m_file_offset_alignment)
+    {
+        MZ_ASSERT((local_dir_header_ofs & (pZip->m_file_offset_alignment - 1)) == 0);
+    }
+
+    /* The original zip's local header+ext block doesn't change, even with zip64, so we can just copy it over to the dest zip */
+    if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pLocal_header, MZ_ZIP_LOCAL_DIR_HEADER_SIZE) != MZ_ZIP_LOCAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+    cur_dst_file_ofs += MZ_ZIP_LOCAL_DIR_HEADER_SIZE;
+
+    /* Copy over the source archive bytes to the dest archive, also ensure we have enough buf space to handle optional data descriptor */
+    if (NULL == (pBuf = pZip->m_pAlloc(pZip->m_pAlloc_opaque, 1, (size_t)MZ_MAX(32U, MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining)))))
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+    while (src_archive_bytes_remaining)
+    {
+        n = (mz_uint)MZ_MIN((mz_uint64)MZ_ZIP_MAX_IO_BUF_SIZE, src_archive_bytes_remaining);
+        if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, n) != n)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+        }
+        cur_src_file_ofs += n;
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+        cur_dst_file_ofs += n;
+
+        src_archive_bytes_remaining -= n;
+    }
+
+    /* Now deal with the optional data descriptor */
+    bit_flags = MZ_READ_LE16(pLocal_header + MZ_ZIP_LDH_BIT_FLAG_OFS);
+    if (bit_flags & 8)
+    {
+        /* Copy data descriptor */
+        if ((pSource_zip->m_pState->m_zip64) || (found_zip64_ext_data_in_ldir))
+        {
+            /* src is zip64, dest must be zip64 */
+
+            /* name                    uint32_t's */
+            /* id                              1 (optional in zip64?) */
+            /* crc                     1 */
+            /* comp_size       2 */
+            /* uncomp_size 2 */
+            if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, (sizeof(mz_uint32) * 6)) != (sizeof(mz_uint32) * 6))
+            {
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+                return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+            }
+
+            n = sizeof(mz_uint32) * ((MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID) ? 6 : 5);
+        }
+        else
+        {
+            /* src is NOT zip64 */
+            mz_bool has_id;
+
+            if (pSource_zip->m_pRead(pSource_zip->m_pIO_opaque, cur_src_file_ofs, pBuf, sizeof(mz_uint32) * 4) != sizeof(mz_uint32) * 4)
+            {
+                pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+                return mz_zip_set_error(pZip, MZ_ZIP_FILE_READ_FAILED);
+            }
+
+            has_id = (MZ_READ_LE32(pBuf) == MZ_ZIP_DATA_DESCRIPTOR_ID);
+
+            if (pZip->m_pState->m_zip64)
+            {
+                /* dest is zip64, so upgrade the data descriptor */
+                const mz_uint32 *pSrc_descriptor = (const mz_uint32 *)((const mz_uint8 *)pBuf + (has_id ? sizeof(mz_uint32) : 0));
+                const mz_uint32 src_crc32 = pSrc_descriptor[0];
+                const mz_uint64 src_comp_size = pSrc_descriptor[1];
+                const mz_uint64 src_uncomp_size = pSrc_descriptor[2];
+
+                mz_write_le32((mz_uint8 *)pBuf, MZ_ZIP_DATA_DESCRIPTOR_ID);
+                mz_write_le32((mz_uint8 *)pBuf + sizeof(mz_uint32) * 1, src_crc32);
+                mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 2, src_comp_size);
+                mz_write_le64((mz_uint8 *)pBuf + sizeof(mz_uint32) * 4, src_uncomp_size);
+
+                n = sizeof(mz_uint32) * 6;
+            }
+            else
+            {
+                /* dest is NOT zip64, just copy it as-is */
+                n = sizeof(mz_uint32) * (has_id ? 4 : 3);
+            }
+        }
+
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, cur_dst_file_ofs, pBuf, n) != n)
+        {
+            pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+        }
+
+        cur_src_file_ofs += n;
+        cur_dst_file_ofs += n;
+    }
+    pZip->m_pFree(pZip->m_pAlloc_opaque, pBuf);
+
+    /* Finally, add the new central dir header */
+    orig_central_dir_size = pState->m_central_dir.m_size;
+
+    memcpy(new_central_header, pSrc_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE);
+
+    if (pState->m_zip64)
+    {
+        /* This is the painful part: We need to write a new central dir header + ext block with updated zip64 fields, and ensure the old fields (if any) are not included. */
+        const mz_uint8 *pSrc_ext = pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len;
+        mz_zip_array new_ext_block;
+
+        mz_zip_array_init(&new_ext_block, sizeof(mz_uint8));
+
+        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_COMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
+        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_DECOMPRESSED_SIZE_OFS, MZ_UINT32_MAX);
+        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, MZ_UINT32_MAX);
+
+        if (!mz_zip_writer_update_zip64_extension_block(&new_ext_block, pZip, pSrc_ext, src_ext_len, &src_file_stat.m_comp_size, &src_file_stat.m_uncomp_size, &local_dir_header_ofs, NULL))
+        {
+            mz_zip_array_clear(pZip, &new_ext_block);
+            return MZ_FALSE;
+        }
+
+        MZ_WRITE_LE16(new_central_header + MZ_ZIP_CDH_EXTRA_LEN_OFS, new_ext_block.m_size);
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
+        {
+            mz_zip_array_clear(pZip, &new_ext_block);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_filename_len))
+        {
+            mz_zip_array_clear(pZip, &new_ext_block);
+            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_ext_block.m_p, new_ext_block.m_size))
+        {
+            mz_zip_array_clear(pZip, &new_ext_block);
+            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE + src_filename_len + src_ext_len, src_comment_len))
+        {
+            mz_zip_array_clear(pZip, &new_ext_block);
+            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+
+        mz_zip_array_clear(pZip, &new_ext_block);
+    }
+    else
+    {
+        /* sanity checks */
+        if (cur_dst_file_ofs > MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+        if (local_dir_header_ofs >= MZ_UINT32_MAX)
+            return mz_zip_set_error(pZip, MZ_ZIP_ARCHIVE_TOO_LARGE);
+
+        MZ_WRITE_LE32(new_central_header + MZ_ZIP_CDH_LOCAL_HEADER_OFS, local_dir_header_ofs);
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, new_central_header, MZ_ZIP_CENTRAL_DIR_HEADER_SIZE))
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+
+        if (!mz_zip_array_push_back(pZip, &pState->m_central_dir, pSrc_central_header + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, src_central_dir_following_data_size))
+        {
+            mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+            return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+        }
+    }
+
+    /* This shouldn't trigger unless we screwed up during the initial sanity checks */
+    if (pState->m_central_dir.m_size >= MZ_UINT32_MAX)
+    {
+        /* TODO: Support central dirs >= 32-bits in size */
+        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+        return mz_zip_set_error(pZip, MZ_ZIP_UNSUPPORTED_CDIR_SIZE);
+    }
+
+    n = (mz_uint32)orig_central_dir_size;
+    if (!mz_zip_array_push_back(pZip, &pState->m_central_dir_offsets, &n, 1))
+    {
+        mz_zip_array_resize(pZip, &pState->m_central_dir, orig_central_dir_size, MZ_FALSE);
+        return mz_zip_set_error(pZip, MZ_ZIP_ALLOC_FAILED);
+    }
+
+    pZip->m_total_files++;
+    pZip->m_archive_size = cur_dst_file_ofs;
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip)
+{
+    mz_zip_internal_state *pState;
+    mz_uint64 central_dir_ofs, central_dir_size;
+    mz_uint8 hdr[256];
+
+    if ((!pZip) || (!pZip->m_pState) || (pZip->m_zip_mode != MZ_ZIP_MODE_WRITING))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    pState = pZip->m_pState;
+
+    if (pState->m_zip64)
+    {
+        if ((pZip->m_total_files > MZ_UINT32_MAX) || (pState->m_central_dir.m_size >= MZ_UINT32_MAX))
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+    else
+    {
+        if ((pZip->m_total_files > MZ_UINT16_MAX) || ((pZip->m_archive_size + pState->m_central_dir.m_size + MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) > MZ_UINT32_MAX))
+            return mz_zip_set_error(pZip, MZ_ZIP_TOO_MANY_FILES);
+    }
+
+    central_dir_ofs = 0;
+    central_dir_size = 0;
+    if (pZip->m_total_files)
+    {
+        /* Write central directory */
+        central_dir_ofs = pZip->m_archive_size;
+        central_dir_size = pState->m_central_dir.m_size;
+        pZip->m_central_directory_file_ofs = central_dir_ofs;
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, central_dir_ofs, pState->m_central_dir.m_p, (size_t)central_dir_size) != central_dir_size)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        pZip->m_archive_size += central_dir_size;
+    }
+
+    if (pState->m_zip64)
+    {
+        /* Write zip64 end of central directory header */
+        mz_uint64 rel_ofs_to_zip64_ecdr = pZip->m_archive_size;
+
+        MZ_CLEAR_OBJ(hdr);
+        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDH_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIG);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_SIZE_OF_RECORD_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE - sizeof(mz_uint32) - sizeof(mz_uint64));
+        MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_MADE_BY_OFS, 0x031E); /* TODO: always Unix */
+        MZ_WRITE_LE16(hdr + MZ_ZIP64_ECDH_VERSION_NEEDED_OFS, 0x002D);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, pZip->m_total_files);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_TOTAL_ENTRIES_OFS, pZip->m_total_files);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_SIZE_OFS, central_dir_size);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDH_CDIR_OFS_OFS, central_dir_ofs);
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_HEADER_SIZE;
+
+        /* Write zip64 end of central directory locator */
+        MZ_CLEAR_OBJ(hdr);
+        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_SIG_OFS, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIG);
+        MZ_WRITE_LE64(hdr + MZ_ZIP64_ECDL_REL_OFS_TO_ZIP64_ECDR_OFS, rel_ofs_to_zip64_ecdr);
+        MZ_WRITE_LE32(hdr + MZ_ZIP64_ECDL_TOTAL_NUMBER_OF_DISKS_OFS, 1);
+        if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE) != MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE)
+            return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+        pZip->m_archive_size += MZ_ZIP64_END_OF_CENTRAL_DIR_LOCATOR_SIZE;
+    }
+
+    /* Write end of central directory record */
+    MZ_CLEAR_OBJ(hdr);
+    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_SIG_OFS, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIG);
+    MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_NUM_ENTRIES_ON_DISK_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
+    MZ_WRITE_LE16(hdr + MZ_ZIP_ECDH_CDIR_TOTAL_ENTRIES_OFS, MZ_MIN(MZ_UINT16_MAX, pZip->m_total_files));
+    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_SIZE_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_size));
+    MZ_WRITE_LE32(hdr + MZ_ZIP_ECDH_CDIR_OFS_OFS, MZ_MIN(MZ_UINT32_MAX, central_dir_ofs));
+
+    if (pZip->m_pWrite(pZip->m_pIO_opaque, pZip->m_archive_size, hdr, MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE) != MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE)
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_WRITE_FAILED);
+
+#ifndef MINIZ_NO_STDIO
+    if ((pState->m_pFile) && (MZ_FFLUSH(pState->m_pFile) == EOF))
+        return mz_zip_set_error(pZip, MZ_ZIP_FILE_CLOSE_FAILED);
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+    pZip->m_archive_size += MZ_ZIP_END_OF_CENTRAL_DIR_HEADER_SIZE;
+
+    pZip->m_zip_mode = MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED;
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize)
+{
+    if ((!ppBuf) || (!pSize))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    *ppBuf = NULL;
+    *pSize = 0;
+
+    if ((!pZip) || (!pZip->m_pState))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (pZip->m_pWrite != mz_zip_heap_write_func)
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    if (!mz_zip_writer_finalize_archive(pZip))
+        return MZ_FALSE;
+
+    *ppBuf = pZip->m_pState->m_pMem;
+    *pSize = pZip->m_pState->m_mem_size;
+    pZip->m_pState->m_pMem = NULL;
+    pZip->m_pState->m_mem_size = pZip->m_pState->m_mem_capacity = 0;
+
+    return MZ_TRUE;
+}
+
+mz_bool mz_zip_writer_end(mz_zip_archive *pZip)
+{
+    return mz_zip_writer_end_internal(pZip, MZ_TRUE);
+}
+
+#ifndef MINIZ_NO_STDIO
+mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags)
+{
+    return mz_zip_add_mem_to_archive_file_in_place_v2(pZip_filename, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, NULL);
+}
+
+mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr)
+{
+    mz_bool status, created_new_archive = MZ_FALSE;
+    mz_zip_archive zip_archive;
+    struct MZ_FILE_STAT_STRUCT file_stat;
+    mz_zip_error actual_err = MZ_ZIP_NO_ERROR;
+
+    mz_zip_zero_struct(&zip_archive);
+    if ((int)level_and_flags < 0)
+        level_and_flags = MZ_DEFAULT_LEVEL;
+
+    if ((!pZip_filename) || (!pArchive_name) || ((buf_size) && (!pBuf)) || ((comment_size) && (!pComment)) || ((level_and_flags & 0xF) > MZ_UBER_COMPRESSION))
+    {
+        if (pErr)
+            *pErr = MZ_ZIP_INVALID_PARAMETER;
+        return MZ_FALSE;
+    }
+
+    if (!mz_zip_writer_validate_archive_name(pArchive_name))
+    {
+        if (pErr)
+            *pErr = MZ_ZIP_INVALID_FILENAME;
+        return MZ_FALSE;
+    }
+
+    /* Important: The regular non-64 bit version of stat() can fail here if the file is very large, which could cause the archive to be overwritten. */
+    /* So be sure to compile with _LARGEFILE64_SOURCE 1 */
+    if (MZ_FILE_STAT(pZip_filename, &file_stat) != 0)
+    {
+        /* Create a new archive. */
+        if (!mz_zip_writer_init_file_v2(&zip_archive, pZip_filename, 0, level_and_flags))
+        {
+            if (pErr)
+                *pErr = zip_archive.m_last_error;
+            return MZ_FALSE;
+        }
+
+        created_new_archive = MZ_TRUE;
+    }
+    else
+    {
+        /* Append to an existing archive. */
+        if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, level_and_flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
+        {
+            if (pErr)
+                *pErr = zip_archive.m_last_error;
+            return MZ_FALSE;
+        }
+
+        if (!mz_zip_writer_init_from_reader_v2(&zip_archive, pZip_filename, level_and_flags))
+        {
+            if (pErr)
+                *pErr = zip_archive.m_last_error;
+
+            mz_zip_reader_end_internal(&zip_archive, MZ_FALSE);
+
+            return MZ_FALSE;
+        }
+    }
+
+    status = mz_zip_writer_add_mem_ex(&zip_archive, pArchive_name, pBuf, buf_size, pComment, comment_size, level_and_flags, 0, 0);
+    actual_err = zip_archive.m_last_error;
+
+    /* Always finalize, even if adding failed for some reason, so we have a valid central directory. (This may not always succeed, but we can try.) */
+    if (!mz_zip_writer_finalize_archive(&zip_archive))
+    {
+        if (!actual_err)
+            actual_err = zip_archive.m_last_error;
+
+        status = MZ_FALSE;
+    }
+
+    if (!mz_zip_writer_end_internal(&zip_archive, status))
+    {
+        if (!actual_err)
+            actual_err = zip_archive.m_last_error;
+
+        status = MZ_FALSE;
+    }
+
+    if ((!status) && (created_new_archive))
+    {
+        /* It's a new archive and something went wrong, so just delete it. */
+        int ignoredStatus = MZ_DELETE_FILE(pZip_filename);
+        (void)ignoredStatus;
+    }
+
+    if (pErr)
+        *pErr = actual_err;
+
+    return status;
+}
+
+void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr)
+{
+    mz_uint32 file_index;
+    mz_zip_archive zip_archive;
+    void *p = NULL;
+
+    if (pSize)
+        *pSize = 0;
+
+    if ((!pZip_filename) || (!pArchive_name))
+    {
+        if (pErr)
+            *pErr = MZ_ZIP_INVALID_PARAMETER;
+
+        return NULL;
+    }
+
+    mz_zip_zero_struct(&zip_archive);
+    if (!mz_zip_reader_init_file_v2(&zip_archive, pZip_filename, flags | MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY, 0, 0))
+    {
+        if (pErr)
+            *pErr = zip_archive.m_last_error;
+
+        return NULL;
+    }
+
+    if (mz_zip_reader_locate_file_v2(&zip_archive, pArchive_name, pComment, flags, &file_index))
+    {
+        p = mz_zip_reader_extract_to_heap(&zip_archive, file_index, pSize, flags);
+    }
+
+    mz_zip_reader_end_internal(&zip_archive, p != NULL);
+
+    if (pErr)
+        *pErr = zip_archive.m_last_error;
+
+    return p;
+}
+
+void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags)
+{
+    return mz_zip_extract_archive_file_to_heap_v2(pZip_filename, pArchive_name, NULL, pSize, flags, NULL);
+}
+
+#endif /* #ifndef MINIZ_NO_STDIO */
+
+#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
+
+/* ------------------- Misc utils */
+
+mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip)
+{
+    return pZip ? pZip->m_zip_mode : MZ_ZIP_MODE_INVALID;
+}
+
+mz_zip_type mz_zip_get_type(mz_zip_archive *pZip)
+{
+    return pZip ? pZip->m_zip_type : MZ_ZIP_TYPE_INVALID;
+}
+
+mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num)
+{
+    mz_zip_error prev_err;
+
+    if (!pZip)
+        return MZ_ZIP_INVALID_PARAMETER;
+
+    prev_err = pZip->m_last_error;
+
+    pZip->m_last_error = err_num;
+    return prev_err;
+}
+
+mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip)
+{
+    if (!pZip)
+        return MZ_ZIP_INVALID_PARAMETER;
+
+    return pZip->m_last_error;
+}
+
+mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip)
+{
+    return mz_zip_set_last_error(pZip, MZ_ZIP_NO_ERROR);
+}
+
+mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip)
+{
+    mz_zip_error prev_err;
+
+    if (!pZip)
+        return MZ_ZIP_INVALID_PARAMETER;
+
+    prev_err = pZip->m_last_error;
+
+    pZip->m_last_error = MZ_ZIP_NO_ERROR;
+    return prev_err;
+}
+
+const char *mz_zip_get_error_string(mz_zip_error mz_err)
+{
+    switch (mz_err)
+    {
+        case MZ_ZIP_NO_ERROR:
+            return "no error";
+        case MZ_ZIP_UNDEFINED_ERROR:
+            return "undefined error";
+        case MZ_ZIP_TOO_MANY_FILES:
+            return "too many files";
+        case MZ_ZIP_FILE_TOO_LARGE:
+            return "file too large";
+        case MZ_ZIP_UNSUPPORTED_METHOD:
+            return "unsupported method";
+        case MZ_ZIP_UNSUPPORTED_ENCRYPTION:
+            return "unsupported encryption";
+        case MZ_ZIP_UNSUPPORTED_FEATURE:
+            return "unsupported feature";
+        case MZ_ZIP_FAILED_FINDING_CENTRAL_DIR:
+            return "failed finding central directory";
+        case MZ_ZIP_NOT_AN_ARCHIVE:
+            return "not a ZIP archive";
+        case MZ_ZIP_INVALID_HEADER_OR_CORRUPTED:
+            return "invalid header or archive is corrupted";
+        case MZ_ZIP_UNSUPPORTED_MULTIDISK:
+            return "unsupported multidisk archive";
+        case MZ_ZIP_DECOMPRESSION_FAILED:
+            return "decompression failed or archive is corrupted";
+        case MZ_ZIP_COMPRESSION_FAILED:
+            return "compression failed";
+        case MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE:
+            return "unexpected decompressed size";
+        case MZ_ZIP_CRC_CHECK_FAILED:
+            return "CRC-32 check failed";
+        case MZ_ZIP_UNSUPPORTED_CDIR_SIZE:
+            return "unsupported central directory size";
+        case MZ_ZIP_ALLOC_FAILED:
+            return "allocation failed";
+        case MZ_ZIP_FILE_OPEN_FAILED:
+            return "file open failed";
+        case MZ_ZIP_FILE_CREATE_FAILED:
+            return "file create failed";
+        case MZ_ZIP_FILE_WRITE_FAILED:
+            return "file write failed";
+        case MZ_ZIP_FILE_READ_FAILED:
+            return "file read failed";
+        case MZ_ZIP_FILE_CLOSE_FAILED:
+            return "file close failed";
+        case MZ_ZIP_FILE_SEEK_FAILED:
+            return "file seek failed";
+        case MZ_ZIP_FILE_STAT_FAILED:
+            return "file stat failed";
+        case MZ_ZIP_INVALID_PARAMETER:
+            return "invalid parameter";
+        case MZ_ZIP_INVALID_FILENAME:
+            return "invalid filename";
+        case MZ_ZIP_BUF_TOO_SMALL:
+            return "buffer too small";
+        case MZ_ZIP_INTERNAL_ERROR:
+            return "internal error";
+        case MZ_ZIP_FILE_NOT_FOUND:
+            return "file not found";
+        case MZ_ZIP_ARCHIVE_TOO_LARGE:
+            return "archive is too large";
+        case MZ_ZIP_VALIDATION_FAILED:
+            return "validation failed";
+        case MZ_ZIP_WRITE_CALLBACK_FAILED:
+            return "write calledback failed";
+        default:
+            break;
+    }
+
+    return "unknown error";
+}
+
+/* Note: Just because the archive is not zip64 doesn't necessarily mean it doesn't have Zip64 extended information extra field, argh. */
+mz_bool mz_zip_is_zip64(mz_zip_archive *pZip)
+{
+    if ((!pZip) || (!pZip->m_pState))
+        return MZ_FALSE;
+
+    return pZip->m_pState->m_zip64;
+}
+
+size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip)
+{
+    if ((!pZip) || (!pZip->m_pState))
+        return 0;
+
+    return pZip->m_pState->m_central_dir.m_size;
+}
+
+mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip)
+{
+    return pZip ? pZip->m_total_files : 0;
+}
+
+mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip)
+{
+    if (!pZip)
+        return 0;
+    return pZip->m_archive_size;
+}
+
+mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip)
+{
+    if ((!pZip) || (!pZip->m_pState))
+        return 0;
+    return pZip->m_pState->m_file_archive_start_ofs;
+}
+
+MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip)
+{
+    if ((!pZip) || (!pZip->m_pState))
+        return 0;
+    return pZip->m_pState->m_pFile;
+}
+
+size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n)
+{
+    if ((!pZip) || (!pZip->m_pState) || (!pBuf) || (!pZip->m_pRead))
+        return mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+
+    return pZip->m_pRead(pZip->m_pIO_opaque, file_ofs, pBuf, n);
+}
+
+mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size)
+{
+    mz_uint n;
+    const mz_uint8 *p = mz_zip_get_cdh(pZip, file_index);
+    if (!p)
+    {
+        if (filename_buf_size)
+            pFilename[0] = '\0';
+        mz_zip_set_error(pZip, MZ_ZIP_INVALID_PARAMETER);
+        return 0;
+    }
+    n = MZ_READ_LE16(p + MZ_ZIP_CDH_FILENAME_LEN_OFS);
+    if (filename_buf_size)
+    {
+        n = MZ_MIN(n, filename_buf_size - 1);
+        memcpy(pFilename, p + MZ_ZIP_CENTRAL_DIR_HEADER_SIZE, n);
+        pFilename[n] = '\0';
+    }
+    return n + 1;
+}
+
+mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat)
+{
+    return mz_zip_file_stat_internal(pZip, file_index, mz_zip_get_cdh(pZip, file_index), pStat, NULL);
+}
+
+mz_bool mz_zip_end(mz_zip_archive *pZip)
+{
+    if (!pZip)
+        return MZ_FALSE;
+
+    if (pZip->m_zip_mode == MZ_ZIP_MODE_READING)
+        return mz_zip_reader_end(pZip);
+#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
+    else if ((pZip->m_zip_mode == MZ_ZIP_MODE_WRITING) || (pZip->m_zip_mode == MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED))
+        return mz_zip_writer_end(pZip);
+#endif
+
+    return MZ_FALSE;
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /*#ifndef MINIZ_NO_ARCHIVE_APIS*/
+
diff --git a/core/deps/miniz/miniz.h b/core/deps/miniz/miniz.h
new file mode 100644 (file)
index 0000000..ba253ac
--- /dev/null
@@ -0,0 +1,1296 @@
+/* miniz.c v1.16 beta r1 - public domain deflate/inflate, zlib-subset, ZIP reading/writing/appending, PNG writing
+   See "unlicense" statement at the end of this file.
+   Rich Geldreich <richgel99@gmail.com>, last updated Oct. 13, 2013
+   Implements RFC 1950: http://www.ietf.org/rfc/rfc1950.txt and RFC 1951: http://www.ietf.org/rfc/rfc1951.txt
+
+   Most API's defined in miniz.c are optional. For example, to disable the archive related functions just define
+   MINIZ_NO_ARCHIVE_APIS, or to get rid of all stdio usage define MINIZ_NO_STDIO (see the list below for more macros).
+
+   * Low-level Deflate/Inflate implementation notes:
+
+     Compression: Use the "tdefl" API's. The compressor supports raw, static, and dynamic blocks, lazy or
+     greedy parsing, match length filtering, RLE-only, and Huffman-only streams. It performs and compresses
+     approximately as well as zlib.
+
+     Decompression: Use the "tinfl" API's. The entire decompressor is implemented as a single function
+     coroutine: see tinfl_decompress(). It supports decompression into a 32KB (or larger power of 2) wrapping buffer, or into a memory
+     block large enough to hold the entire file.
+
+     The low-level tdefl/tinfl API's do not make any use of dynamic memory allocation.
+
+   * zlib-style API notes:
+
+     miniz.c implements a fairly large subset of zlib. There's enough functionality present for it to be a drop-in
+     zlib replacement in many apps:
+        The z_stream struct, optional memory allocation callbacks
+        deflateInit/deflateInit2/deflate/deflateReset/deflateEnd/deflateBound
+        inflateInit/inflateInit2/inflate/inflateEnd
+        compress, compress2, compressBound, uncompress
+        CRC-32, Adler-32 - Using modern, minimal code size, CPU cache friendly routines.
+        Supports raw deflate streams or standard zlib streams with adler-32 checking.
+
+     Limitations:
+      The callback API's are not implemented yet. No support for gzip headers or zlib static dictionaries.
+      I've tried to closely emulate zlib's various flavors of stream flushing and return status codes, but
+      there are no guarantees that miniz.c pulls this off perfectly.
+
+   * PNG writing: See the tdefl_write_image_to_png_file_in_memory() function, originally written by
+     Alex Evans. Supports 1-4 bytes/pixel images.
+
+   * ZIP archive API notes:
+
+     The ZIP archive API's where designed with simplicity and efficiency in mind, with just enough abstraction to
+     get the job done with minimal fuss. There are simple API's to retrieve file information, read files from
+     existing archives, create new archives, append new files to existing archives, or clone archive data from
+     one archive to another. It supports archives located in memory or the heap, on disk (using stdio.h),
+     or you can specify custom file read/write callbacks.
+
+     - Archive reading: Just call this function to read a single file from a disk archive:
+
+      void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name,
+        size_t *pSize, mz_uint zip_flags);
+
+     For more complex cases, use the "mz_zip_reader" functions. Upon opening an archive, the entire central
+     directory is located and read as-is into memory, and subsequent file access only occurs when reading individual files.
+
+     - Archives file scanning: The simple way is to use this function to scan a loaded archive for a specific file:
+
+     int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
+
+     The locate operation can optionally check file comments too, which (as one example) can be used to identify
+     multiple versions of the same file in an archive. This function uses a simple linear search through the central
+     directory, so it's not very fast.
+
+     Alternately, you can iterate through all the files in an archive (using mz_zip_reader_get_num_files()) and
+     retrieve detailed info on each file by calling mz_zip_reader_file_stat().
+
+     - Archive creation: Use the "mz_zip_writer" functions. The ZIP writer immediately writes compressed file data
+     to disk and builds an exact image of the central directory in memory. The central directory image is written
+     all at once at the end of the archive file when the archive is finalized.
+
+     The archive writer can optionally align each file's local header and file data to any power of 2 alignment,
+     which can be useful when the archive will be read from optical media. Also, the writer supports placing
+     arbitrary data blobs at the very beginning of ZIP archives. Archives written using either feature are still
+     readable by any ZIP tool.
+
+     - Archive appending: The simple way to add a single file to an archive is to call this function:
+
+      mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name,
+        const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
+
+     The archive will be created if it doesn't already exist, otherwise it'll be appended to.
+     Note the appending is done in-place and is not an atomic operation, so if something goes wrong
+     during the operation it's possible the archive could be left without a central directory (although the local
+     file headers and file data will be fine, so the archive will be recoverable).
+
+     For more complex archive modification scenarios:
+     1. The safest way is to use a mz_zip_reader to read the existing archive, cloning only those bits you want to
+     preserve into a new archive using using the mz_zip_writer_add_from_zip_reader() function (which compiles the
+     compressed file data as-is). When you're done, delete the old archive and rename the newly written archive, and
+     you're done. This is safe but requires a bunch of temporary disk space or heap memory.
+
+     2. Or, you can convert an mz_zip_reader in-place to an mz_zip_writer using mz_zip_writer_init_from_reader(),
+     append new files as needed, then finalize the archive which will write an updated central directory to the
+     original archive. (This is basically what mz_zip_add_mem_to_archive_file_in_place() does.) There's a
+     possibility that the archive's central directory could be lost with this method if anything goes wrong, though.
+
+     - ZIP archive support limitations:
+     No zip64 or spanning support. Extraction functions can only handle unencrypted, stored or deflated files.
+     Requires streams capable of seeking.
+
+   * This is a header file library, like stb_image.c. To get only a header file, either cut and paste the
+     below header, or create miniz.h, #define MINIZ_HEADER_FILE_ONLY, and then include miniz.c from it.
+
+   * Important: For best perf. be sure to customize the below macros for your target platform:
+     #define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+     #define MINIZ_LITTLE_ENDIAN 1
+     #define MINIZ_HAS_64BIT_REGISTERS 1
+
+   * On platforms using glibc, Be sure to "#define _LARGEFILE64_SOURCE 1" before including miniz.c to ensure miniz
+     uses the 64-bit variants: fopen64(), stat64(), etc. Otherwise you won't be able to process large files
+     (i.e. 32-bit stat() fails for me on files > 0x7FFFFFFF bytes).
+*/
+#pragma once
+
+
+
+
+
+/* Defines to completely disable specific portions of miniz.c: 
+   If all macros here are defined the only functionality remaining will be CRC-32, adler-32, tinfl, and tdefl. */
+
+/* Define MINIZ_NO_STDIO to disable all usage and any functions which rely on stdio for file I/O. */
+/*#define MINIZ_NO_STDIO */
+
+/* If MINIZ_NO_TIME is specified then the ZIP archive functions will not be able to get the current time, or */
+/* get/set file times, and the C run-time funcs that get/set times won't be called. */
+/* The current downside is the times written to your archives will be from 1979. */
+/*#define MINIZ_NO_TIME */
+
+/* Define MINIZ_NO_ARCHIVE_APIS to disable all ZIP archive API's. */
+/*#define MINIZ_NO_ARCHIVE_APIS */
+
+/* Define MINIZ_NO_ARCHIVE_WRITING_APIS to disable all writing related ZIP archive API's. */
+/*#define MINIZ_NO_ARCHIVE_WRITING_APIS */
+
+/* Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's. */
+/*#define MINIZ_NO_ZLIB_APIS */
+
+/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib. */
+/*#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
+
+/* Define MINIZ_NO_MALLOC to disable all calls to malloc, free, and realloc. 
+   Note if MINIZ_NO_MALLOC is defined then the user must always provide custom user alloc/free/realloc
+   callbacks to the zlib and archive API's, and a few stand-alone helper API's which don't provide custom user
+   functions (such as tdefl_compress_mem_to_heap() and tinfl_decompress_mem_to_heap()) won't work. */
+/*#define MINIZ_NO_MALLOC */
+
+#if defined(__TINYC__) && (defined(__linux) || defined(__linux__))
+/* TODO: Work around "error: include file 'sys\utime.h' when compiling with tcc on Linux */
+#define MINIZ_NO_TIME
+#endif
+
+#include <stddef.h>
+
+#if !defined(MINIZ_NO_TIME) && !defined(MINIZ_NO_ARCHIVE_APIS)
+#include <time.h>
+#endif
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(__i386__) || defined(__i386) || defined(__i486__) || defined(__i486) || defined(i386) || defined(__ia64__) || defined(__x86_64__)
+/* MINIZ_X86_OR_X64_CPU is only used to help set the below macros. */
+#define MINIZ_X86_OR_X64_CPU 1
+#endif
+
+#if (__BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__) || MINIZ_X86_OR_X64_CPU
+/* Set MINIZ_LITTLE_ENDIAN to 1 if the processor is little endian. */
+#define MINIZ_LITTLE_ENDIAN 1
+#endif
+
+#if MINIZ_X86_OR_X64_CPU
+/* Set MINIZ_USE_UNALIGNED_LOADS_AND_STORES to 1 on CPU's that permit efficient integer loads and stores from unaligned addresses. */
+#define MINIZ_USE_UNALIGNED_LOADS_AND_STORES 1
+#endif
+
+#if defined(_M_X64) || defined(_WIN64) || defined(__MINGW64__) || defined(_LP64) || defined(__LP64__) || defined(__ia64__) || defined(__x86_64__)
+/* Set MINIZ_HAS_64BIT_REGISTERS to 1 if operations on 64-bit integers are reasonably fast (and don't involve compiler generated calls to helper functions). */
+#define MINIZ_HAS_64BIT_REGISTERS 1
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ------------------- zlib-style API Definitions. */
+
+/* For more compatibility with zlib, miniz.c uses unsigned long for some parameters/struct members. Beware: mz_ulong can be either 32 or 64-bits! */
+typedef unsigned long mz_ulong;
+
+/* mz_free() internally uses the MZ_FREE() macro (which by default calls free() unless you've modified the MZ_MALLOC macro) to release a block allocated from the heap. */
+void mz_free(void *p);
+
+#define MZ_ADLER32_INIT (1)
+/* mz_adler32() returns the initial adler-32 value to use when called with ptr==NULL. */
+mz_ulong mz_adler32(mz_ulong adler, const unsigned char *ptr, size_t buf_len);
+
+#define MZ_CRC32_INIT (0)
+/* mz_crc32() returns the initial CRC-32 value to use when called with ptr==NULL. */
+mz_ulong mz_crc32(mz_ulong crc, const unsigned char *ptr, size_t buf_len);
+
+/* Compression strategies. */
+enum
+{
+    MZ_DEFAULT_STRATEGY = 0,
+    MZ_FILTERED = 1,
+    MZ_HUFFMAN_ONLY = 2,
+    MZ_RLE = 3,
+    MZ_FIXED = 4
+};
+
+/* Method */
+#define MZ_DEFLATED 8
+
+/* Heap allocation callbacks.
+Note that mz_alloc_func parameter types purpsosely differ from zlib's: items/size is size_t, not unsigned long. */
+typedef void *(*mz_alloc_func)(void *opaque, size_t items, size_t size);
+typedef void(*mz_free_func)(void *opaque, void *address);
+typedef void *(*mz_realloc_func)(void *opaque, void *address, size_t items, size_t size);
+
+/* Compression levels: 0-9 are the standard zlib-style levels, 10 is best possible compression (not zlib compatible, and may be very slow), MZ_DEFAULT_COMPRESSION=MZ_DEFAULT_LEVEL. */
+enum
+{
+       MZ_NO_COMPRESSION = 0,
+       MZ_BEST_SPEED = 1,
+       MZ_BEST_COMPRESSION = 9,
+       MZ_UBER_COMPRESSION = 10,
+       MZ_DEFAULT_LEVEL = 6,
+       MZ_DEFAULT_COMPRESSION = -1
+};
+
+#define MZ_VERSION "10.0.0"
+#define MZ_VERNUM 0xA000
+#define MZ_VER_MAJOR 10
+#define MZ_VER_MINOR 0
+#define MZ_VER_REVISION 0
+#define MZ_VER_SUBREVISION 0
+
+#ifndef MINIZ_NO_ZLIB_APIS
+
+/* Flush values. For typical usage you only need MZ_NO_FLUSH and MZ_FINISH. The other values are for advanced use (refer to the zlib docs). */
+enum
+{
+    MZ_NO_FLUSH = 0,
+    MZ_PARTIAL_FLUSH = 1,
+    MZ_SYNC_FLUSH = 2,
+    MZ_FULL_FLUSH = 3,
+    MZ_FINISH = 4,
+    MZ_BLOCK = 5
+};
+
+/* Return status codes. MZ_PARAM_ERROR is non-standard. */
+enum
+{
+    MZ_OK = 0,
+    MZ_STREAM_END = 1,
+    MZ_NEED_DICT = 2,
+    MZ_ERRNO = -1,
+    MZ_STREAM_ERROR = -2,
+    MZ_DATA_ERROR = -3,
+    MZ_MEM_ERROR = -4,
+    MZ_BUF_ERROR = -5,
+    MZ_VERSION_ERROR = -6,
+    MZ_PARAM_ERROR = -10000
+};
+
+/* Window bits */
+#define MZ_DEFAULT_WINDOW_BITS 15
+
+struct mz_internal_state;
+
+/* Compression/decompression stream struct. */
+typedef struct mz_stream_s
+{
+    const unsigned char *next_in; /* pointer to next byte to read */
+    unsigned int avail_in;        /* number of bytes available at next_in */
+    mz_ulong total_in;            /* total number of bytes consumed so far */
+
+    unsigned char *next_out; /* pointer to next byte to write */
+    unsigned int avail_out;  /* number of bytes that can be written to next_out */
+    mz_ulong total_out;      /* total number of bytes produced so far */
+
+    char *msg;                       /* error msg (unused) */
+    struct mz_internal_state *state; /* internal state, allocated by zalloc/zfree */
+
+    mz_alloc_func zalloc; /* optional heap allocation function (defaults to malloc) */
+    mz_free_func zfree;   /* optional heap free function (defaults to free) */
+    void *opaque;         /* heap alloc function user pointer */
+
+    int data_type;     /* data_type (unused) */
+    mz_ulong adler;    /* adler32 of the source or uncompressed data */
+    mz_ulong reserved; /* not used */
+} mz_stream;
+
+typedef mz_stream *mz_streamp;
+
+/* Returns the version string of miniz.c. */
+const char *mz_version(void);
+
+/* mz_deflateInit() initializes a compressor with default options: */
+/* Parameters: */
+/*  pStream must point to an initialized mz_stream struct. */
+/*  level must be between [MZ_NO_COMPRESSION, MZ_BEST_COMPRESSION]. */
+/*  level 1 enables a specially optimized compression function that's been optimized purely for performance, not ratio. */
+/*  (This special func. is currently only enabled when MINIZ_USE_UNALIGNED_LOADS_AND_STORES and MINIZ_LITTLE_ENDIAN are defined.) */
+/* Return values: */
+/*  MZ_OK on success. */
+/*  MZ_STREAM_ERROR if the stream is bogus. */
+/*  MZ_PARAM_ERROR if the input parameters are bogus. */
+/*  MZ_MEM_ERROR on out of memory. */
+int mz_deflateInit(mz_streamp pStream, int level);
+
+/* mz_deflateInit2() is like mz_deflate(), except with more control: */
+/* Additional parameters: */
+/*   method must be MZ_DEFLATED */
+/*   window_bits must be MZ_DEFAULT_WINDOW_BITS (to wrap the deflate stream with zlib header/adler-32 footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate/no header or footer) */
+/*   mem_level must be between [1, 9] (it's checked but ignored by miniz.c) */
+int mz_deflateInit2(mz_streamp pStream, int level, int method, int window_bits, int mem_level, int strategy);
+
+/* Quickly resets a compressor without having to reallocate anything. Same as calling mz_deflateEnd() followed by mz_deflateInit()/mz_deflateInit2(). */
+int mz_deflateReset(mz_streamp pStream);
+
+/* mz_deflate() compresses the input to output, consuming as much of the input and producing as much output as possible. */
+/* Parameters: */
+/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */
+/*   flush may be MZ_NO_FLUSH, MZ_PARTIAL_FLUSH/MZ_SYNC_FLUSH, MZ_FULL_FLUSH, or MZ_FINISH. */
+/* Return values: */
+/*   MZ_OK on success (when flushing, or if more input is needed but not available, and/or there's more output to be written but the output buffer is full). */
+/*   MZ_STREAM_END if all input has been consumed and all output bytes have been written. Don't call mz_deflate() on the stream anymore. */
+/*   MZ_STREAM_ERROR if the stream is bogus. */
+/*   MZ_PARAM_ERROR if one of the parameters is invalid. */
+/*   MZ_BUF_ERROR if no forward progress is possible because the input and/or output buffers are empty. (Fill up the input buffer or free up some output space and try again.) */
+int mz_deflate(mz_streamp pStream, int flush);
+
+/* mz_deflateEnd() deinitializes a compressor: */
+/* Return values: */
+/*  MZ_OK on success. */
+/*  MZ_STREAM_ERROR if the stream is bogus. */
+int mz_deflateEnd(mz_streamp pStream);
+
+/* mz_deflateBound() returns a (very) conservative upper bound on the amount of data that could be generated by deflate(), assuming flush is set to only MZ_NO_FLUSH or MZ_FINISH. */
+mz_ulong mz_deflateBound(mz_streamp pStream, mz_ulong source_len);
+
+/* Single-call compression functions mz_compress() and mz_compress2(): */
+/* Returns MZ_OK on success, or one of the error codes from mz_deflate() on failure. */
+int mz_compress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
+int mz_compress2(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len, int level);
+
+/* mz_compressBound() returns a (very) conservative upper bound on the amount of data that could be generated by calling mz_compress(). */
+mz_ulong mz_compressBound(mz_ulong source_len);
+
+/* Initializes a decompressor. */
+int mz_inflateInit(mz_streamp pStream);
+
+/* mz_inflateInit2() is like mz_inflateInit() with an additional option that controls the window size and whether or not the stream has been wrapped with a zlib header/footer: */
+/* window_bits must be MZ_DEFAULT_WINDOW_BITS (to parse zlib header/footer) or -MZ_DEFAULT_WINDOW_BITS (raw deflate). */
+int mz_inflateInit2(mz_streamp pStream, int window_bits);
+
+/* Decompresses the input stream to the output, consuming only as much of the input as needed, and writing as much to the output as possible. */
+/* Parameters: */
+/*   pStream is the stream to read from and write to. You must initialize/update the next_in, avail_in, next_out, and avail_out members. */
+/*   flush may be MZ_NO_FLUSH, MZ_SYNC_FLUSH, or MZ_FINISH. */
+/*   On the first call, if flush is MZ_FINISH it's assumed the input and output buffers are both sized large enough to decompress the entire stream in a single call (this is slightly faster). */
+/*   MZ_FINISH implies that there are no more source bytes available beside what's already in the input buffer, and that the output buffer is large enough to hold the rest of the decompressed data. */
+/* Return values: */
+/*   MZ_OK on success. Either more input is needed but not available, and/or there's more output to be written but the output buffer is full. */
+/*   MZ_STREAM_END if all needed input has been consumed and all output bytes have been written. For zlib streams, the adler-32 of the decompressed data has also been verified. */
+/*   MZ_STREAM_ERROR if the stream is bogus. */
+/*   MZ_DATA_ERROR if the deflate stream is invalid. */
+/*   MZ_PARAM_ERROR if one of the parameters is invalid. */
+/*   MZ_BUF_ERROR if no forward progress is possible because the input buffer is empty but the inflater needs more input to continue, or if the output buffer is not large enough. Call mz_inflate() again */
+/*   with more input data, or with more room in the output buffer (except when using single call decompression, described above). */
+int mz_inflate(mz_streamp pStream, int flush);
+
+/* Deinitializes a decompressor. */
+int mz_inflateEnd(mz_streamp pStream);
+
+/* Single-call decompression. */
+/* Returns MZ_OK on success, or one of the error codes from mz_inflate() on failure. */
+int mz_uncompress(unsigned char *pDest, mz_ulong *pDest_len, const unsigned char *pSource, mz_ulong source_len);
+
+/* Returns a string description of the specified error code, or NULL if the error code is invalid. */
+const char *mz_error(int err);
+
+/* Redefine zlib-compatible names to miniz equivalents, so miniz.c can be used as a drop-in replacement for the subset of zlib that miniz.c supports. */
+/* Define MINIZ_NO_ZLIB_COMPATIBLE_NAMES to disable zlib-compatibility if you use zlib in the same project. */
+#ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+typedef unsigned char Byte;
+typedef unsigned int uInt;
+typedef mz_ulong uLong;
+typedef Byte Bytef;
+typedef uInt uIntf;
+typedef char charf;
+typedef int intf;
+typedef void *voidpf;
+typedef uLong uLongf;
+typedef void *voidp;
+typedef void *const voidpc;
+#define Z_NULL 0
+#define Z_NO_FLUSH MZ_NO_FLUSH
+#define Z_PARTIAL_FLUSH MZ_PARTIAL_FLUSH
+#define Z_SYNC_FLUSH MZ_SYNC_FLUSH
+#define Z_FULL_FLUSH MZ_FULL_FLUSH
+#define Z_FINISH MZ_FINISH
+#define Z_BLOCK MZ_BLOCK
+#define Z_OK MZ_OK
+#define Z_STREAM_END MZ_STREAM_END
+#define Z_NEED_DICT MZ_NEED_DICT
+#define Z_ERRNO MZ_ERRNO
+#define Z_STREAM_ERROR MZ_STREAM_ERROR
+#define Z_DATA_ERROR MZ_DATA_ERROR
+#define Z_MEM_ERROR MZ_MEM_ERROR
+#define Z_BUF_ERROR MZ_BUF_ERROR
+#define Z_VERSION_ERROR MZ_VERSION_ERROR
+#define Z_PARAM_ERROR MZ_PARAM_ERROR
+#define Z_NO_COMPRESSION MZ_NO_COMPRESSION
+#define Z_BEST_SPEED MZ_BEST_SPEED
+#define Z_BEST_COMPRESSION MZ_BEST_COMPRESSION
+#define Z_DEFAULT_COMPRESSION MZ_DEFAULT_COMPRESSION
+#define Z_DEFAULT_STRATEGY MZ_DEFAULT_STRATEGY
+#define Z_FILTERED MZ_FILTERED
+#define Z_HUFFMAN_ONLY MZ_HUFFMAN_ONLY
+#define Z_RLE MZ_RLE
+#define Z_FIXED MZ_FIXED
+#define Z_DEFLATED MZ_DEFLATED
+#define Z_DEFAULT_WINDOW_BITS MZ_DEFAULT_WINDOW_BITS
+#define alloc_func mz_alloc_func
+#define free_func mz_free_func
+#define internal_state mz_internal_state
+#define z_stream mz_stream
+#define deflateInit mz_deflateInit
+#define deflateInit2 mz_deflateInit2
+#define deflateReset mz_deflateReset
+#define deflate mz_deflate
+#define deflateEnd mz_deflateEnd
+#define deflateBound mz_deflateBound
+#define compress mz_compress
+#define compress2 mz_compress2
+#define compressBound mz_compressBound
+#define inflateInit mz_inflateInit
+#define inflateInit2 mz_inflateInit2
+#define inflate mz_inflate
+#define inflateEnd mz_inflateEnd
+#define uncompress mz_uncompress
+#define crc32 mz_crc32
+#define adler32 mz_adler32
+#define MAX_WBITS 15
+#define MAX_MEM_LEVEL 9
+#define zError mz_error
+#define ZLIB_VERSION MZ_VERSION
+#define ZLIB_VERNUM MZ_VERNUM
+#define ZLIB_VER_MAJOR MZ_VER_MAJOR
+#define ZLIB_VER_MINOR MZ_VER_MINOR
+#define ZLIB_VER_REVISION MZ_VER_REVISION
+#define ZLIB_VER_SUBREVISION MZ_VER_SUBREVISION
+#define zlibVersion mz_version
+#define zlib_version mz_version()
+#endif /* #ifndef MINIZ_NO_ZLIB_COMPATIBLE_NAMES */
+
+#endif /* MINIZ_NO_ZLIB_APIS */
+
+#ifdef __cplusplus
+}
+#endif
+#pragma once
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+/* ------------------- Types and macros */
+typedef unsigned char mz_uint8;
+typedef signed short mz_int16;
+typedef unsigned short mz_uint16;
+typedef unsigned int mz_uint32;
+typedef unsigned int mz_uint;
+typedef int64_t mz_int64;
+typedef uint64_t mz_uint64;
+typedef int mz_bool;
+
+#define MZ_FALSE (0)
+#define MZ_TRUE (1)
+
+/* Works around MSVC's spammy "warning C4127: conditional expression is constant" message. */
+#ifdef _MSC_VER
+#define MZ_MACRO_END while (0, 0)
+#else
+#define MZ_MACRO_END while (0)
+#endif
+
+#ifdef MINIZ_NO_STDIO
+#define MZ_FILE void *
+#else
+#include <stdio.h>
+#define MZ_FILE FILE
+#endif /* #ifdef MINIZ_NO_STDIO */
+
+#ifdef MINIZ_NO_TIME
+typedef struct mz_dummy_time_t_tag
+{
+    int m_dummy;
+} mz_dummy_time_t;
+#define MZ_TIME_T mz_dummy_time_t
+#else
+#define MZ_TIME_T time_t
+#endif
+
+#define MZ_ASSERT(x) assert(x)
+
+#ifdef MINIZ_NO_MALLOC
+#define MZ_MALLOC(x) NULL
+#define MZ_FREE(x) (void) x, ((void)0)
+#define MZ_REALLOC(p, x) NULL
+#else
+#define MZ_MALLOC(x) malloc(x)
+#define MZ_FREE(x) free(x)
+#define MZ_REALLOC(p, x) realloc(p, x)
+#endif
+
+#define MZ_MAX(a, b) (((a) > (b)) ? (a) : (b))
+#define MZ_MIN(a, b) (((a) < (b)) ? (a) : (b))
+#define MZ_CLEAR_OBJ(obj) memset(&(obj), 0, sizeof(obj))
+
+#if MINIZ_USE_UNALIGNED_LOADS_AND_STORES &&MINIZ_LITTLE_ENDIAN
+#define MZ_READ_LE16(p) *((const mz_uint16 *)(p))
+#define MZ_READ_LE32(p) *((const mz_uint32 *)(p))
+#else
+#define MZ_READ_LE16(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U))
+#define MZ_READ_LE32(p) ((mz_uint32)(((const mz_uint8 *)(p))[0]) | ((mz_uint32)(((const mz_uint8 *)(p))[1]) << 8U) | ((mz_uint32)(((const mz_uint8 *)(p))[2]) << 16U) | ((mz_uint32)(((const mz_uint8 *)(p))[3]) << 24U))
+#endif
+
+#define MZ_READ_LE64(p) (((mz_uint64)MZ_READ_LE32(p)) | (((mz_uint64)MZ_READ_LE32((const mz_uint8 *)(p) + sizeof(mz_uint32))) << 32U))
+
+#ifdef _MSC_VER
+#define MZ_FORCEINLINE __forceinline
+#elif defined(__GNUC__)
+#define MZ_FORCEINLINE __inline__ __attribute__((__always_inline__))
+#else
+#define MZ_FORCEINLINE inline
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern void *miniz_def_alloc_func(void *opaque, size_t items, size_t size);
+extern void miniz_def_free_func(void *opaque, void *address);
+extern void *miniz_def_realloc_func(void *opaque, void *address, size_t items, size_t size);
+
+#define MZ_UINT16_MAX (0xFFFFU)
+#define MZ_UINT32_MAX (0xFFFFFFFFU)
+
+#ifdef __cplusplus
+}
+#endif
+#pragma once
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* ------------------- Low-level Compression API Definitions */
+
+/* Set TDEFL_LESS_MEMORY to 1 to use less memory (compression will be slightly slower, and raw/dynamic blocks will be output more frequently). */
+#define TDEFL_LESS_MEMORY 0
+
+/* tdefl_init() compression flags logically OR'd together (low 12 bits contain the max. number of probes per dictionary search): */
+/* TDEFL_DEFAULT_MAX_PROBES: The compressor defaults to 128 dictionary probes per dictionary search. 0=Huffman only, 1=Huffman+LZ (fastest/crap compression), 4095=Huffman+LZ (slowest/best compression). */
+enum
+{
+    TDEFL_HUFFMAN_ONLY = 0,
+    TDEFL_DEFAULT_MAX_PROBES = 128,
+    TDEFL_MAX_PROBES_MASK = 0xFFF
+};
+
+/* TDEFL_WRITE_ZLIB_HEADER: If set, the compressor outputs a zlib header before the deflate data, and the Adler-32 of the source data at the end. Otherwise, you'll get raw deflate data. */
+/* TDEFL_COMPUTE_ADLER32: Always compute the adler-32 of the input data (even when not writing zlib headers). */
+/* TDEFL_GREEDY_PARSING_FLAG: Set to use faster greedy parsing, instead of more efficient lazy parsing. */
+/* TDEFL_NONDETERMINISTIC_PARSING_FLAG: Enable to decrease the compressor's initialization time to the minimum, but the output may vary from run to run given the same input (depending on the contents of memory). */
+/* TDEFL_RLE_MATCHES: Only look for RLE matches (matches with a distance of 1) */
+/* TDEFL_FILTER_MATCHES: Discards matches <= 5 chars if enabled. */
+/* TDEFL_FORCE_ALL_STATIC_BLOCKS: Disable usage of optimized Huffman tables. */
+/* TDEFL_FORCE_ALL_RAW_BLOCKS: Only use raw (uncompressed) deflate blocks. */
+/* The low 12 bits are reserved to control the max # of hash probes per dictionary lookup (see TDEFL_MAX_PROBES_MASK). */
+enum
+{
+    TDEFL_WRITE_ZLIB_HEADER = 0x01000,
+    TDEFL_COMPUTE_ADLER32 = 0x02000,
+    TDEFL_GREEDY_PARSING_FLAG = 0x04000,
+    TDEFL_NONDETERMINISTIC_PARSING_FLAG = 0x08000,
+    TDEFL_RLE_MATCHES = 0x10000,
+    TDEFL_FILTER_MATCHES = 0x20000,
+    TDEFL_FORCE_ALL_STATIC_BLOCKS = 0x40000,
+    TDEFL_FORCE_ALL_RAW_BLOCKS = 0x80000
+};
+
+/* High level compression functions: */
+/* tdefl_compress_mem_to_heap() compresses a block in memory to a heap block allocated via malloc(). */
+/* On entry: */
+/*  pSrc_buf, src_buf_len: Pointer and size of source block to compress. */
+/*  flags: The max match finder probes (default is 128) logically OR'd against the above flags. Higher probes are slower but improve compression. */
+/* On return: */
+/*  Function returns a pointer to the compressed data, or NULL on failure. */
+/*  *pOut_len will be set to the compressed data's size, which could be larger than src_buf_len on uncompressible data. */
+/*  The caller must free() the returned block when it's no longer needed. */
+void *tdefl_compress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
+
+/* tdefl_compress_mem_to_mem() compresses a block in memory to another block in memory. */
+/* Returns 0 on failure. */
+size_t tdefl_compress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
+
+/* Compresses an image to a compressed PNG file in memory. */
+/* On entry: */
+/*  pImage, w, h, and num_chans describe the image to compress. num_chans may be 1, 2, 3, or 4. */
+/*  The image pitch in bytes per scanline will be w*num_chans. The leftmost pixel on the top scanline is stored first in memory. */
+/*  level may range from [0,10], use MZ_NO_COMPRESSION, MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc. or a decent default is MZ_DEFAULT_LEVEL */
+/*  If flip is true, the image will be flipped on the Y axis (useful for OpenGL apps). */
+/* On return: */
+/*  Function returns a pointer to the compressed data, or NULL on failure. */
+/*  *pLen_out will be set to the size of the PNG image file. */
+/*  The caller must mz_free() the returned heap block (which will typically be larger than *pLen_out) when it's no longer needed. */
+void *tdefl_write_image_to_png_file_in_memory_ex(const void *pImage, int w, int h, int num_chans, size_t *pLen_out, mz_uint level, mz_bool flip);
+void *tdefl_write_image_to_png_file_in_memory(const void *pImage, int w, int h, int num_chans, size_t *pLen_out);
+
+/* Output stream interface. The compressor uses this interface to write compressed data. It'll typically be called TDEFL_OUT_BUF_SIZE at a time. */
+typedef mz_bool (*tdefl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
+
+/* tdefl_compress_mem_to_output() compresses a block to an output stream. The above helpers use this function internally. */
+mz_bool tdefl_compress_mem_to_output(const void *pBuf, size_t buf_len, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+enum
+{
+    TDEFL_MAX_HUFF_TABLES = 3,
+    TDEFL_MAX_HUFF_SYMBOLS_0 = 288,
+    TDEFL_MAX_HUFF_SYMBOLS_1 = 32,
+    TDEFL_MAX_HUFF_SYMBOLS_2 = 19,
+    TDEFL_LZ_DICT_SIZE = 32768,
+    TDEFL_LZ_DICT_SIZE_MASK = TDEFL_LZ_DICT_SIZE - 1,
+    TDEFL_MIN_MATCH_LEN = 3,
+    TDEFL_MAX_MATCH_LEN = 258
+};
+
+/* TDEFL_OUT_BUF_SIZE MUST be large enough to hold a single entire compressed output block (using static/fixed Huffman codes). */
+#if TDEFL_LESS_MEMORY
+enum
+{
+    TDEFL_LZ_CODE_BUF_SIZE = 24 * 1024,
+    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
+    TDEFL_MAX_HUFF_SYMBOLS = 288,
+    TDEFL_LZ_HASH_BITS = 12,
+    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
+    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
+    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
+};
+#else
+enum
+{
+    TDEFL_LZ_CODE_BUF_SIZE = 64 * 1024,
+    TDEFL_OUT_BUF_SIZE = (TDEFL_LZ_CODE_BUF_SIZE * 13) / 10,
+    TDEFL_MAX_HUFF_SYMBOLS = 288,
+    TDEFL_LZ_HASH_BITS = 15,
+    TDEFL_LEVEL1_HASH_SIZE_MASK = 4095,
+    TDEFL_LZ_HASH_SHIFT = (TDEFL_LZ_HASH_BITS + 2) / 3,
+    TDEFL_LZ_HASH_SIZE = 1 << TDEFL_LZ_HASH_BITS
+};
+#endif
+
+/* The low-level tdefl functions below may be used directly if the above helper functions aren't flexible enough. The low-level functions don't make any heap allocations, unlike the above helper functions. */
+typedef enum
+{
+    TDEFL_STATUS_BAD_PARAM = -2,
+    TDEFL_STATUS_PUT_BUF_FAILED = -1,
+    TDEFL_STATUS_OKAY = 0,
+    TDEFL_STATUS_DONE = 1
+} tdefl_status;
+
+/* Must map to MZ_NO_FLUSH, MZ_SYNC_FLUSH, etc. enums */
+typedef enum
+{
+    TDEFL_NO_FLUSH = 0,
+    TDEFL_SYNC_FLUSH = 2,
+    TDEFL_FULL_FLUSH = 3,
+    TDEFL_FINISH = 4
+} tdefl_flush;
+
+/* tdefl's compression state structure. */
+typedef struct
+{
+    tdefl_put_buf_func_ptr m_pPut_buf_func;
+    void *m_pPut_buf_user;
+    mz_uint m_flags, m_max_probes[2];
+    int m_greedy_parsing;
+    mz_uint m_adler32, m_lookahead_pos, m_lookahead_size, m_dict_size;
+    mz_uint8 *m_pLZ_code_buf, *m_pLZ_flags, *m_pOutput_buf, *m_pOutput_buf_end;
+    mz_uint m_num_flags_left, m_total_lz_bytes, m_lz_code_buf_dict_pos, m_bits_in, m_bit_buffer;
+    mz_uint m_saved_match_dist, m_saved_match_len, m_saved_lit, m_output_flush_ofs, m_output_flush_remaining, m_finished, m_block_index, m_wants_to_finish;
+    tdefl_status m_prev_return_status;
+    const void *m_pIn_buf;
+    void *m_pOut_buf;
+    size_t *m_pIn_buf_size, *m_pOut_buf_size;
+    tdefl_flush m_flush;
+    const mz_uint8 *m_pSrc;
+    size_t m_src_buf_left, m_out_buf_ofs;
+    mz_uint8 m_dict[TDEFL_LZ_DICT_SIZE + TDEFL_MAX_MATCH_LEN - 1];
+    mz_uint16 m_huff_count[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+    mz_uint16 m_huff_codes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+    mz_uint8 m_huff_code_sizes[TDEFL_MAX_HUFF_TABLES][TDEFL_MAX_HUFF_SYMBOLS];
+    mz_uint8 m_lz_code_buf[TDEFL_LZ_CODE_BUF_SIZE];
+    mz_uint16 m_next[TDEFL_LZ_DICT_SIZE];
+    mz_uint16 m_hash[TDEFL_LZ_HASH_SIZE];
+    mz_uint8 m_output_buf[TDEFL_OUT_BUF_SIZE];
+} tdefl_compressor;
+
+/* Initializes the compressor. */
+/* There is no corresponding deinit() function because the tdefl API's do not dynamically allocate memory. */
+/* pBut_buf_func: If NULL, output data will be supplied to the specified callback. In this case, the user should call the tdefl_compress_buffer() API for compression. */
+/* If pBut_buf_func is NULL the user should always call the tdefl_compress() API. */
+/* flags: See the above enums (TDEFL_HUFFMAN_ONLY, TDEFL_WRITE_ZLIB_HEADER, etc.) */
+tdefl_status tdefl_init(tdefl_compressor *d, tdefl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+/* Compresses a block of data, consuming as much of the specified input buffer as possible, and writing as much compressed data to the specified output buffer as possible. */
+tdefl_status tdefl_compress(tdefl_compressor *d, const void *pIn_buf, size_t *pIn_buf_size, void *pOut_buf, size_t *pOut_buf_size, tdefl_flush flush);
+
+/* tdefl_compress_buffer() is only usable when the tdefl_init() is called with a non-NULL tdefl_put_buf_func_ptr. */
+/* tdefl_compress_buffer() always consumes the entire input buffer. */
+tdefl_status tdefl_compress_buffer(tdefl_compressor *d, const void *pIn_buf, size_t in_buf_size, tdefl_flush flush);
+
+tdefl_status tdefl_get_prev_return_status(tdefl_compressor *d);
+mz_uint32 tdefl_get_adler32(tdefl_compressor *d);
+
+/* Create tdefl_compress() flags given zlib-style compression parameters. */
+/* level may range from [0,10] (where 10 is absolute max compression, but may be much slower on some files) */
+/* window_bits may be -15 (raw deflate) or 15 (zlib) */
+/* strategy may be either MZ_DEFAULT_STRATEGY, MZ_FILTERED, MZ_HUFFMAN_ONLY, MZ_RLE, or MZ_FIXED */
+mz_uint tdefl_create_comp_flags_from_zip_params(int level, int window_bits, int strategy);
+
+/* Allocate the tdefl_compressor structure in C so that */
+/* non-C language bindings to tdefl_ API don't need to worry about */
+/* structure size and allocation mechanism. */
+tdefl_compressor *tdefl_compressor_alloc();
+void tdefl_compressor_free(tdefl_compressor *pComp);
+
+#ifdef __cplusplus
+}
+#endif
+#pragma once
+
+/* ------------------- Low-level Decompression API Definitions */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+/* Decompression flags used by tinfl_decompress(). */
+/* TINFL_FLAG_PARSE_ZLIB_HEADER: If set, the input has a valid zlib header and ends with an adler32 checksum (it's a valid zlib stream). Otherwise, the input is a raw deflate stream. */
+/* TINFL_FLAG_HAS_MORE_INPUT: If set, there are more input bytes available beyond the end of the supplied input buffer. If clear, the input buffer contains all remaining input. */
+/* TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF: If set, the output buffer is large enough to hold the entire decompressed stream. If clear, the output buffer is at least the size of the dictionary (typically 32KB). */
+/* TINFL_FLAG_COMPUTE_ADLER32: Force adler-32 checksum computation of the decompressed bytes. */
+enum
+{
+    TINFL_FLAG_PARSE_ZLIB_HEADER = 1,
+    TINFL_FLAG_HAS_MORE_INPUT = 2,
+    TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF = 4,
+    TINFL_FLAG_COMPUTE_ADLER32 = 8
+};
+
+/* High level decompression functions: */
+/* tinfl_decompress_mem_to_heap() decompresses a block in memory to a heap block allocated via malloc(). */
+/* On entry: */
+/*  pSrc_buf, src_buf_len: Pointer and size of the Deflate or zlib source data to decompress. */
+/* On return: */
+/*  Function returns a pointer to the decompressed data, or NULL on failure. */
+/*  *pOut_len will be set to the decompressed data's size, which could be larger than src_buf_len on uncompressible data. */
+/*  The caller must call mz_free() on the returned block when it's no longer needed. */
+void *tinfl_decompress_mem_to_heap(const void *pSrc_buf, size_t src_buf_len, size_t *pOut_len, int flags);
+
+/* tinfl_decompress_mem_to_mem() decompresses a block in memory to another block in memory. */
+/* Returns TINFL_DECOMPRESS_MEM_TO_MEM_FAILED on failure, or the number of bytes written on success. */
+#define TINFL_DECOMPRESS_MEM_TO_MEM_FAILED ((size_t)(-1))
+size_t tinfl_decompress_mem_to_mem(void *pOut_buf, size_t out_buf_len, const void *pSrc_buf, size_t src_buf_len, int flags);
+
+/* tinfl_decompress_mem_to_callback() decompresses a block in memory to an internal 32KB buffer, and a user provided callback function will be called to flush the buffer. */
+/* Returns 1 on success or 0 on failure. */
+typedef int (*tinfl_put_buf_func_ptr)(const void *pBuf, int len, void *pUser);
+int tinfl_decompress_mem_to_callback(const void *pIn_buf, size_t *pIn_buf_size, tinfl_put_buf_func_ptr pPut_buf_func, void *pPut_buf_user, int flags);
+
+struct tinfl_decompressor_tag;
+typedef struct tinfl_decompressor_tag tinfl_decompressor;
+
+/* Allocate the tinfl_decompressor structure in C so that */
+/* non-C language bindings to tinfl_ API don't need to worry about */
+/* structure size and allocation mechanism. */
+
+tinfl_decompressor *tinfl_decompressor_alloc();
+void tinfl_decompressor_free(tinfl_decompressor *pDecomp);
+
+/* Max size of LZ dictionary. */
+#define TINFL_LZ_DICT_SIZE 32768
+
+/* Return status. */
+typedef enum
+{
+    /* This flags indicates the inflator needs 1 or more input bytes to make forward progress, but the caller is indicating that no more are available. The compressed data */
+    /* is probably corrupted. If you call the inflator again with more bytes it'll try to continue processing the input but this is a BAD sign (either the data is corrupted or you called it incorrectly). */
+    /* If you call it again with no input you'll just get TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS again. */
+    TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS = -4,
+
+    /* This flag indicates that one or more of the input parameters was obviously bogus. (You can try calling it again, but if you get this error the calling code is wrong.) */
+    TINFL_STATUS_BAD_PARAM = -3,
+
+    /* This flags indicate the inflator is finished but the adler32 check of the uncompressed data didn't match. If you call it again it'll return TINFL_STATUS_DONE. */
+    TINFL_STATUS_ADLER32_MISMATCH = -2,
+
+    /* This flags indicate the inflator has somehow failed (bad code, corrupted input, etc.). If you call it again without resetting via tinfl_init() it it'll just keep on returning the same status failure code. */
+    TINFL_STATUS_FAILED = -1,
+
+    /* Any status code less than TINFL_STATUS_DONE must indicate a failure. */
+
+    /* This flag indicates the inflator has returned every byte of uncompressed data that it can, has consumed every byte that it needed, has successfully reached the end of the deflate stream, and */
+    /* if zlib headers and adler32 checking enabled that it has successfully checked the uncompressed data's adler32. If you call it again you'll just get TINFL_STATUS_DONE over and over again. */
+    TINFL_STATUS_DONE = 0,
+
+    /* This flag indicates the inflator MUST have more input data (even 1 byte) before it can make any more forward progress, or you need to clear the TINFL_FLAG_HAS_MORE_INPUT */
+    /* flag on the next call if you don't have any more source data. If the source data was somehow corrupted it's also possible (but unlikely) for the inflator to keep on demanding input to */
+    /* proceed, so be sure to properly set the TINFL_FLAG_HAS_MORE_INPUT flag. */
+    TINFL_STATUS_NEEDS_MORE_INPUT = 1,
+
+    /* This flag indicates the inflator definitely has 1 or more bytes of uncompressed data available, but it cannot write this data into the output buffer. */
+    /* Note if the source compressed data was corrupted it's possible for the inflator to return a lot of uncompressed data to the caller. I've been assuming you know how much uncompressed data to expect */
+    /* (either exact or worst case) and will stop calling the inflator and fail after receiving too much. In pure streaming scenarios where you have no idea how many bytes to expect this may not be possible */
+    /* so I may need to add some code to address this. */
+    TINFL_STATUS_HAS_MORE_OUTPUT = 2
+} tinfl_status;
+
+/* Initializes the decompressor to its initial state. */
+#define tinfl_init(r)     \
+    do                    \
+    {                     \
+        (r)->m_state = 0; \
+    }                     \
+    MZ_MACRO_END
+#define tinfl_get_adler32(r) (r)->m_check_adler32
+
+/* Main low-level decompressor coroutine function. This is the only function actually needed for decompression. All the other functions are just high-level helpers for improved usability. */
+/* This is a universal API, i.e. it can be used as a building block to build any desired higher level decompression API. In the limit case, it can be called once per every byte input or output. */
+tinfl_status tinfl_decompress(tinfl_decompressor *r, const mz_uint8 *pIn_buf_next, size_t *pIn_buf_size, mz_uint8 *pOut_buf_start, mz_uint8 *pOut_buf_next, size_t *pOut_buf_size, const mz_uint32 decomp_flags);
+
+/* Internal/private bits follow. */
+enum
+{
+    TINFL_MAX_HUFF_TABLES = 3,
+    TINFL_MAX_HUFF_SYMBOLS_0 = 288,
+    TINFL_MAX_HUFF_SYMBOLS_1 = 32,
+    TINFL_MAX_HUFF_SYMBOLS_2 = 19,
+    TINFL_FAST_LOOKUP_BITS = 10,
+    TINFL_FAST_LOOKUP_SIZE = 1 << TINFL_FAST_LOOKUP_BITS
+};
+
+typedef struct
+{
+    mz_uint8 m_code_size[TINFL_MAX_HUFF_SYMBOLS_0];
+    mz_int16 m_look_up[TINFL_FAST_LOOKUP_SIZE], m_tree[TINFL_MAX_HUFF_SYMBOLS_0 * 2];
+} tinfl_huff_table;
+
+#if MINIZ_HAS_64BIT_REGISTERS
+#define TINFL_USE_64BIT_BITBUF 1
+#endif
+
+#if TINFL_USE_64BIT_BITBUF
+typedef mz_uint64 tinfl_bit_buf_t;
+#define TINFL_BITBUF_SIZE (64)
+#else
+typedef mz_uint32 tinfl_bit_buf_t;
+#define TINFL_BITBUF_SIZE (32)
+#endif
+
+struct tinfl_decompressor_tag
+{
+    mz_uint32 m_state, m_num_bits, m_zhdr0, m_zhdr1, m_z_adler32, m_final, m_type, m_check_adler32, m_dist, m_counter, m_num_extra, m_table_sizes[TINFL_MAX_HUFF_TABLES];
+    tinfl_bit_buf_t m_bit_buf;
+    size_t m_dist_from_out_buf_start;
+    tinfl_huff_table m_tables[TINFL_MAX_HUFF_TABLES];
+    mz_uint8 m_raw_header[4], m_len_codes[TINFL_MAX_HUFF_SYMBOLS_0 + TINFL_MAX_HUFF_SYMBOLS_1 + 137];
+};
+
+#ifdef __cplusplus
+}
+#endif
+
+#pragma once
+
+
+/* ------------------- ZIP archive reading/writing */
+
+#ifndef MINIZ_NO_ARCHIVE_APIS
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+enum
+{
+    /* Note: These enums can be reduced as needed to save memory or stack space - they are pretty conservative. */
+    MZ_ZIP_MAX_IO_BUF_SIZE = 64 * 1024,
+    MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE = 512,
+    MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE = 512
+};
+
+typedef struct
+{
+    /* Central directory file index. */
+    mz_uint32 m_file_index;
+
+    /* Byte offset of this entry in the archive's central directory. Note we currently only support up to UINT_MAX or less bytes in the central dir. */
+    mz_uint64 m_central_dir_ofs;
+
+    /* These fields are copied directly from the zip's central dir. */
+    mz_uint16 m_version_made_by;
+    mz_uint16 m_version_needed;
+    mz_uint16 m_bit_flag;
+    mz_uint16 m_method;
+
+#ifndef MINIZ_NO_TIME
+    MZ_TIME_T m_time;
+#endif
+
+    /* CRC-32 of uncompressed data. */
+    mz_uint32 m_crc32;
+
+    /* File's compressed size. */
+    mz_uint64 m_comp_size;
+
+    /* File's uncompressed size. Note, I've seen some old archives where directory entries had 512 bytes for their uncompressed sizes, but when you try to unpack them you actually get 0 bytes. */
+    mz_uint64 m_uncomp_size;
+
+    /* Zip internal and external file attributes. */
+    mz_uint16 m_internal_attr;
+    mz_uint32 m_external_attr;
+
+    /* Entry's local header file offset in bytes. */
+    mz_uint64 m_local_header_ofs;
+
+    /* Size of comment in bytes. */
+    mz_uint32 m_comment_size;
+
+    /* MZ_TRUE if the entry appears to be a directory. */
+    mz_bool m_is_directory;
+
+    /* MZ_TRUE if the entry uses encryption/strong encryption (which miniz_zip doesn't support) */
+    mz_bool m_is_encrypted;
+
+    /* MZ_TRUE if the file is not encrypted, a patch file, and if it uses a compression method we support. */
+    mz_bool m_is_supported;
+
+    /* Filename. If string ends in '/' it's a subdirectory entry. */
+    /* Guaranteed to be zero terminated, may be truncated to fit. */
+    char m_filename[MZ_ZIP_MAX_ARCHIVE_FILENAME_SIZE];
+
+    /* Comment field. */
+    /* Guaranteed to be zero terminated, may be truncated to fit. */
+    char m_comment[MZ_ZIP_MAX_ARCHIVE_FILE_COMMENT_SIZE];
+
+} mz_zip_archive_file_stat;
+
+typedef size_t (*mz_file_read_func)(void *pOpaque, mz_uint64 file_ofs, void *pBuf, size_t n);
+typedef size_t (*mz_file_write_func)(void *pOpaque, mz_uint64 file_ofs, const void *pBuf, size_t n);
+typedef mz_bool (*mz_file_needs_keepalive)(void *pOpaque);
+
+struct mz_zip_internal_state_tag;
+typedef struct mz_zip_internal_state_tag mz_zip_internal_state;
+
+typedef enum
+{
+    MZ_ZIP_MODE_INVALID = 0,
+    MZ_ZIP_MODE_READING = 1,
+    MZ_ZIP_MODE_WRITING = 2,
+    MZ_ZIP_MODE_WRITING_HAS_BEEN_FINALIZED = 3
+} mz_zip_mode;
+
+typedef enum
+{
+    MZ_ZIP_FLAG_CASE_SENSITIVE = 0x0100,
+    MZ_ZIP_FLAG_IGNORE_PATH = 0x0200,
+    MZ_ZIP_FLAG_COMPRESSED_DATA = 0x0400,
+    MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY = 0x0800,
+    MZ_ZIP_FLAG_VALIDATE_LOCATE_FILE_FLAG = 0x1000, /* if enabled, mz_zip_reader_locate_file() will be called on each file as its validated to ensure the func finds the file in the central dir (intended for testing) */
+    MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY = 0x2000,     /* validate the local headers, but don't decompress the entire file and check the crc32 */
+    MZ_ZIP_FLAG_WRITE_ZIP64 = 0x4000,               /* use the zip64 file format, instead of the original zip file format */
+    MZ_ZIP_FLAG_WRITE_ALLOW_READING = 0x8000,
+    MZ_ZIP_FLAG_ASCII_FILENAME = 0x10000
+} mz_zip_flags;
+
+typedef enum
+{
+    MZ_ZIP_TYPE_INVALID = 0,
+    MZ_ZIP_TYPE_USER,
+    MZ_ZIP_TYPE_MEMORY,
+    MZ_ZIP_TYPE_HEAP,
+    MZ_ZIP_TYPE_FILE,
+    MZ_ZIP_TYPE_CFILE,
+    MZ_ZIP_TOTAL_TYPES
+} mz_zip_type;
+
+/* miniz error codes. Be sure to update mz_zip_get_error_string() if you add or modify this enum. */
+typedef enum
+{
+    MZ_ZIP_NO_ERROR = 0,
+    MZ_ZIP_UNDEFINED_ERROR,
+    MZ_ZIP_TOO_MANY_FILES,
+    MZ_ZIP_FILE_TOO_LARGE,
+    MZ_ZIP_UNSUPPORTED_METHOD,
+    MZ_ZIP_UNSUPPORTED_ENCRYPTION,
+    MZ_ZIP_UNSUPPORTED_FEATURE,
+    MZ_ZIP_FAILED_FINDING_CENTRAL_DIR,
+    MZ_ZIP_NOT_AN_ARCHIVE,
+    MZ_ZIP_INVALID_HEADER_OR_CORRUPTED,
+    MZ_ZIP_UNSUPPORTED_MULTIDISK,
+    MZ_ZIP_DECOMPRESSION_FAILED,
+    MZ_ZIP_COMPRESSION_FAILED,
+    MZ_ZIP_UNEXPECTED_DECOMPRESSED_SIZE,
+    MZ_ZIP_CRC_CHECK_FAILED,
+    MZ_ZIP_UNSUPPORTED_CDIR_SIZE,
+    MZ_ZIP_ALLOC_FAILED,
+    MZ_ZIP_FILE_OPEN_FAILED,
+    MZ_ZIP_FILE_CREATE_FAILED,
+    MZ_ZIP_FILE_WRITE_FAILED,
+    MZ_ZIP_FILE_READ_FAILED,
+    MZ_ZIP_FILE_CLOSE_FAILED,
+    MZ_ZIP_FILE_SEEK_FAILED,
+    MZ_ZIP_FILE_STAT_FAILED,
+    MZ_ZIP_INVALID_PARAMETER,
+    MZ_ZIP_INVALID_FILENAME,
+    MZ_ZIP_BUF_TOO_SMALL,
+    MZ_ZIP_INTERNAL_ERROR,
+    MZ_ZIP_FILE_NOT_FOUND,
+    MZ_ZIP_ARCHIVE_TOO_LARGE,
+    MZ_ZIP_VALIDATION_FAILED,
+    MZ_ZIP_WRITE_CALLBACK_FAILED,
+    MZ_ZIP_TOTAL_ERRORS
+} mz_zip_error;
+
+typedef struct
+{
+    mz_uint64 m_archive_size;
+    mz_uint64 m_central_directory_file_ofs;
+
+    /* We only support up to UINT32_MAX files in zip64 mode. */
+    mz_uint32 m_total_files;
+    mz_zip_mode m_zip_mode;
+    mz_zip_type m_zip_type;
+    mz_zip_error m_last_error;
+
+    mz_uint64 m_file_offset_alignment;
+
+    mz_alloc_func m_pAlloc;
+    mz_free_func m_pFree;
+    mz_realloc_func m_pRealloc;
+    void *m_pAlloc_opaque;
+
+    mz_file_read_func m_pRead;
+    mz_file_write_func m_pWrite;
+       mz_file_needs_keepalive m_pNeeds_keepalive;
+    void *m_pIO_opaque;
+
+    mz_zip_internal_state *m_pState;
+
+} mz_zip_archive;
+
+/* -------- ZIP reading */
+
+/* Inits a ZIP archive reader. */
+/* These functions read and validate the archive's central directory. */
+mz_bool mz_zip_reader_init(mz_zip_archive *pZip, mz_uint64 size, mz_uint flags);
+
+mz_bool mz_zip_reader_init_mem(mz_zip_archive *pZip, const void *pMem, size_t size, mz_uint flags);
+
+#ifndef MINIZ_NO_STDIO
+/* Read a archive from a disk file. */
+/* file_start_ofs is the file offset where the archive actually begins, or 0. */
+/* actual_archive_size is the true total size of the archive, which may be smaller than the file's actual size on disk. If zero the entire file is treated as the archive. */
+mz_bool mz_zip_reader_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint32 flags);
+mz_bool mz_zip_reader_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags, mz_uint64 file_start_ofs, mz_uint64 archive_size);
+
+/* Read an archive from an already opened FILE, beginning at the current file position. */
+/* The archive is assumed to be archive_size bytes long. If archive_size is < 0, then the entire rest of the file is assumed to contain the archive. */
+/* The FILE will NOT be closed when mz_zip_reader_end() is called. */
+mz_bool mz_zip_reader_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint64 archive_size, mz_uint flags);
+#endif
+
+/* Ends archive reading, freeing all allocations, and closing the input archive file if mz_zip_reader_init_file() was used. */
+mz_bool mz_zip_reader_end(mz_zip_archive *pZip);
+
+/* -------- ZIP reading or writing */
+
+/* Clears a mz_zip_archive struct to all zeros. */
+/* Important: This must be done before passing the struct to any mz_zip functions. */
+void mz_zip_zero_struct(mz_zip_archive *pZip);
+
+mz_zip_mode mz_zip_get_mode(mz_zip_archive *pZip);
+mz_zip_type mz_zip_get_type(mz_zip_archive *pZip);
+
+/* Returns the total number of files in the archive. */
+mz_uint mz_zip_reader_get_num_files(mz_zip_archive *pZip);
+
+mz_uint64 mz_zip_get_archive_size(mz_zip_archive *pZip);
+mz_uint64 mz_zip_get_archive_file_start_offset(mz_zip_archive *pZip);
+MZ_FILE *mz_zip_get_cfile(mz_zip_archive *pZip);
+
+/* Reads n bytes of raw archive data, starting at file offset file_ofs, to pBuf. */
+size_t mz_zip_read_archive_data(mz_zip_archive *pZip, mz_uint64 file_ofs, void *pBuf, size_t n);
+
+/* Attempts to locates a file in the archive's central directory. */
+/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
+/* Returns -1 if the file cannot be found. */
+int mz_zip_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
+/* Returns MZ_FALSE if the file cannot be found. */
+mz_bool mz_zip_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *pIndex);
+
+/* All mz_zip funcs set the m_last_error field in the mz_zip_archive struct. These functions retrieve/manipulate this field. */
+/* Note that the m_last_error functionality is not thread safe. */
+mz_zip_error mz_zip_set_last_error(mz_zip_archive *pZip, mz_zip_error err_num);
+mz_zip_error mz_zip_peek_last_error(mz_zip_archive *pZip);
+mz_zip_error mz_zip_clear_last_error(mz_zip_archive *pZip);
+mz_zip_error mz_zip_get_last_error(mz_zip_archive *pZip);
+const char *mz_zip_get_error_string(mz_zip_error mz_err);
+
+/* MZ_TRUE if the archive file entry is a directory entry. */
+mz_bool mz_zip_reader_is_file_a_directory(mz_zip_archive *pZip, mz_uint file_index);
+
+/* MZ_TRUE if the file is encrypted/strong encrypted. */
+mz_bool mz_zip_reader_is_file_encrypted(mz_zip_archive *pZip, mz_uint file_index);
+
+/* MZ_TRUE if the compression method is supported, and the file is not encrypted, and the file is not a compressed patch file. */
+mz_bool mz_zip_reader_is_file_supported(mz_zip_archive *pZip, mz_uint file_index);
+
+/* Retrieves the filename of an archive file entry. */
+/* Returns the number of bytes written to pFilename, or if filename_buf_size is 0 this function returns the number of bytes needed to fully store the filename. */
+mz_uint mz_zip_reader_get_filename(mz_zip_archive *pZip, mz_uint file_index, char *pFilename, mz_uint filename_buf_size);
+
+/* Attempts to locates a file in the archive's central directory. */
+/* Valid flags: MZ_ZIP_FLAG_CASE_SENSITIVE, MZ_ZIP_FLAG_IGNORE_PATH */
+/* Returns -1 if the file cannot be found. */
+int mz_zip_reader_locate_file(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags);
+int mz_zip_reader_locate_file_v2(mz_zip_archive *pZip, const char *pName, const char *pComment, mz_uint flags, mz_uint32 *file_index);
+
+/* Returns detailed information about an archive file entry. */
+mz_bool mz_zip_reader_file_stat(mz_zip_archive *pZip, mz_uint file_index, mz_zip_archive_file_stat *pStat);
+
+/* MZ_TRUE if the file is in zip64 format. */
+/* A file is considered zip64 if it contained a zip64 end of central directory marker, or if it contained any zip64 extended file information fields in the central directory. */
+mz_bool mz_zip_is_zip64(mz_zip_archive *pZip);
+
+/* Returns the total central directory size in bytes. */
+/* The current max supported size is <= MZ_UINT32_MAX. */
+size_t mz_zip_get_central_dir_size(mz_zip_archive *pZip);
+
+/* Extracts a archive file to a memory buffer using no memory allocation. */
+/* There must be at least enough room on the stack to store the inflator's state (~34KB or so). */
+mz_bool mz_zip_reader_extract_to_mem_no_alloc(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
+mz_bool mz_zip_reader_extract_file_to_mem_no_alloc(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags, void *pUser_read_buf, size_t user_read_buf_size);
+
+/* Extracts a archive file to a memory buffer. */
+mz_bool mz_zip_reader_extract_to_mem(mz_zip_archive *pZip, mz_uint file_index, void *pBuf, size_t buf_size, mz_uint flags);
+mz_bool mz_zip_reader_extract_file_to_mem(mz_zip_archive *pZip, const char *pFilename, void *pBuf, size_t buf_size, mz_uint flags);
+
+/* Extracts a archive file to a dynamically allocated heap buffer. */
+/* The memory will be allocated via the mz_zip_archive's alloc/realloc functions. */
+/* Returns NULL and sets the last error on failure. */
+void *mz_zip_reader_extract_to_heap(mz_zip_archive *pZip, mz_uint file_index, size_t *pSize, mz_uint flags);
+void *mz_zip_reader_extract_file_to_heap(mz_zip_archive *pZip, const char *pFilename, size_t *pSize, mz_uint flags);
+
+/* Extracts a archive file using a callback function to output the file's data. */
+mz_bool mz_zip_reader_extract_to_callback(mz_zip_archive *pZip, mz_uint file_index, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
+mz_bool mz_zip_reader_extract_file_to_callback(mz_zip_archive *pZip, const char *pFilename, mz_file_write_func pCallback, void *pOpaque, mz_uint flags);
+
+#ifndef MINIZ_NO_STDIO
+/* Extracts a archive file to a disk file and sets its last accessed and modified times. */
+/* This function only extracts files, not archive directory records. */
+mz_bool mz_zip_reader_extract_to_file(mz_zip_archive *pZip, mz_uint file_index, const char *pDst_filename, mz_uint flags);
+mz_bool mz_zip_reader_extract_file_to_file(mz_zip_archive *pZip, const char *pArchive_filename, const char *pDst_filename, mz_uint flags);
+
+/* Extracts a archive file starting at the current position in the destination FILE stream. */
+mz_bool mz_zip_reader_extract_to_cfile(mz_zip_archive *pZip, mz_uint file_index, MZ_FILE *File, mz_uint flags);
+mz_bool mz_zip_reader_extract_file_to_cfile(mz_zip_archive *pZip, const char *pArchive_filename, MZ_FILE *pFile, mz_uint flags);
+#endif
+
+#if 0
+/* TODO */
+       typedef void *mz_zip_streaming_extract_state_ptr;
+       mz_zip_streaming_extract_state_ptr mz_zip_streaming_extract_begin(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
+       uint64_t mz_zip_streaming_extract_get_size(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+       uint64_t mz_zip_streaming_extract_get_cur_ofs(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+       mz_bool mz_zip_streaming_extract_seek(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, uint64_t new_ofs);
+       size_t mz_zip_streaming_extract_read(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState, void *pBuf, size_t buf_size);
+       mz_bool mz_zip_streaming_extract_end(mz_zip_archive *pZip, mz_zip_streaming_extract_state_ptr pState);
+#endif
+
+/* This function compares the archive's local headers, the optional local zip64 extended information block, and the optional descriptor following the compressed data vs. the data in the central directory. */
+/* It also validates that each file can be successfully uncompressed unless the MZ_ZIP_FLAG_VALIDATE_HEADERS_ONLY is specified. */
+mz_bool mz_zip_validate_file(mz_zip_archive *pZip, mz_uint file_index, mz_uint flags);
+
+/* Validates an entire archive by calling mz_zip_validate_file() on each file. */
+mz_bool mz_zip_validate_archive(mz_zip_archive *pZip, mz_uint flags);
+
+/* Misc utils/helpers, valid for ZIP reading or writing */
+mz_bool mz_zip_validate_mem_archive(const void *pMem, size_t size, mz_uint flags, mz_zip_error *pErr);
+mz_bool mz_zip_validate_file_archive(const char *pFilename, mz_uint flags, mz_zip_error *pErr);
+
+/* Universal end function - calls either mz_zip_reader_end() or mz_zip_writer_end(). */
+mz_bool mz_zip_end(mz_zip_archive *pZip);
+
+/* -------- ZIP writing */
+
+#ifndef MINIZ_NO_ARCHIVE_WRITING_APIS
+
+/* Inits a ZIP archive writer. */
+mz_bool mz_zip_writer_init(mz_zip_archive *pZip, mz_uint64 existing_size);
+mz_bool mz_zip_writer_init_v2(mz_zip_archive *pZip, mz_uint64 existing_size, mz_uint flags);
+mz_bool mz_zip_writer_init_heap(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size);
+mz_bool mz_zip_writer_init_heap_v2(mz_zip_archive *pZip, size_t size_to_reserve_at_beginning, size_t initial_allocation_size, mz_uint flags);
+
+#ifndef MINIZ_NO_STDIO
+mz_bool mz_zip_writer_init_file(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning);
+mz_bool mz_zip_writer_init_file_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint64 size_to_reserve_at_beginning, mz_uint flags);
+mz_bool mz_zip_writer_init_cfile(mz_zip_archive *pZip, MZ_FILE *pFile, mz_uint flags);
+#endif
+
+/* Converts a ZIP archive reader object into a writer object, to allow efficient in-place file appends to occur on an existing archive. */
+/* For archives opened using mz_zip_reader_init_file, pFilename must be the archive's filename so it can be reopened for writing. If the file can't be reopened, mz_zip_reader_end() will be called. */
+/* For archives opened using mz_zip_reader_init_mem, the memory block must be growable using the realloc callback (which defaults to realloc unless you've overridden it). */
+/* Finally, for archives opened using mz_zip_reader_init, the mz_zip_archive's user provided m_pWrite function cannot be NULL. */
+/* Note: In-place archive modification is not recommended unless you know what you're doing, because if execution stops or something goes wrong before */
+/* the archive is finalized the file's central directory will be hosed. */
+mz_bool mz_zip_writer_init_from_reader(mz_zip_archive *pZip, const char *pFilename);
+mz_bool mz_zip_writer_init_from_reader_v2(mz_zip_archive *pZip, const char *pFilename, mz_uint flags);
+
+/* Adds the contents of a memory buffer to an archive. These functions record the current local time into the archive. */
+/* To add a directory entry, call this method with an archive name ending in a forwardslash with an empty buffer. */
+/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
+mz_bool mz_zip_writer_add_mem(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, mz_uint level_and_flags);
+
+/* Like mz_zip_writer_add_mem(), except you can specify a file comment field, and optionally supply the function with already compressed data. */
+/* uncomp_size/uncomp_crc32 are only used if the MZ_ZIP_FLAG_COMPRESSED_DATA flag is specified. */
+mz_bool mz_zip_writer_add_mem_ex(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
+                                 mz_uint64 uncomp_size, mz_uint32 uncomp_crc32);
+
+mz_bool mz_zip_writer_add_mem_ex_v2(mz_zip_archive *pZip, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags,
+                                    mz_uint64 uncomp_size, mz_uint32 uncomp_crc32, MZ_TIME_T *last_modified, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
+                                    const char *user_extra_data_central, mz_uint user_extra_data_central_len);
+
+#ifndef MINIZ_NO_STDIO
+/* Adds the contents of a disk file to an archive. This function also records the disk file's modified time into the archive. */
+/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
+mz_bool mz_zip_writer_add_file(mz_zip_archive *pZip, const char *pArchive_name, const char *pSrc_filename, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
+
+/* Like mz_zip_writer_add_file(), except the file data is read from the specified FILE stream. */
+mz_bool mz_zip_writer_add_cfile(mz_zip_archive *pZip, const char *pArchive_name, MZ_FILE *pSrc_file, mz_uint64 size_to_add,
+                                const MZ_TIME_T *pFile_time, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, const char *user_extra_data_local, mz_uint user_extra_data_local_len,
+                                const char *user_extra_data_central, mz_uint user_extra_data_central_len);
+#endif
+
+/* Adds a file to an archive by fully cloning the data from another archive. */
+/* This function fully clones the source file's compressed data (no recompression), along with its full filename, extra data (it may add or modify the zip64 local header extra data field), and the optional descriptor following the compressed data. */
+mz_bool mz_zip_writer_add_from_zip_reader(mz_zip_archive *pZip, mz_zip_archive *pSource_zip, mz_uint src_file_index);
+
+/* Finalizes the archive by writing the central directory records followed by the end of central directory record. */
+/* After an archive is finalized, the only valid call on the mz_zip_archive struct is mz_zip_writer_end(). */
+/* An archive must be manually finalized by calling this function for it to be valid. */
+mz_bool mz_zip_writer_finalize_archive(mz_zip_archive *pZip);
+
+/* Finalizes a heap archive, returning a poiner to the heap block and its size. */
+/* The heap block will be allocated using the mz_zip_archive's alloc/realloc callbacks. */
+mz_bool mz_zip_writer_finalize_heap_archive(mz_zip_archive *pZip, void **ppBuf, size_t *pSize);
+
+/* Ends archive writing, freeing all allocations, and closing the output file if mz_zip_writer_init_file() was used. */
+/* Note for the archive to be valid, it *must* have been finalized before ending (this function will not do it for you). */
+mz_bool mz_zip_writer_end(mz_zip_archive *pZip);
+
+/* -------- Misc. high-level helper functions: */
+
+/* mz_zip_add_mem_to_archive_file_in_place() efficiently (but not atomically) appends a memory blob to a ZIP archive. */
+/* Note this is NOT a fully safe operation. If it crashes or dies in some way your archive can be left in a screwed up state (without a central directory). */
+/* level_and_flags - compression level (0-10, see MZ_BEST_SPEED, MZ_BEST_COMPRESSION, etc.) logically OR'd with zero or more mz_zip_flags, or just set to MZ_DEFAULT_COMPRESSION. */
+/* TODO: Perhaps add an option to leave the existing central dir in place in case the add dies? We could then truncate the file (so the old central dir would be at the end) if something goes wrong. */
+mz_bool mz_zip_add_mem_to_archive_file_in_place(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags);
+mz_bool mz_zip_add_mem_to_archive_file_in_place_v2(const char *pZip_filename, const char *pArchive_name, const void *pBuf, size_t buf_size, const void *pComment, mz_uint16 comment_size, mz_uint level_and_flags, mz_zip_error *pErr);
+
+/* Reads a single file from an archive into a heap block. */
+/* If pComment is not NULL, only the file with the specified comment will be extracted. */
+/* Returns NULL on failure. */
+void *mz_zip_extract_archive_file_to_heap(const char *pZip_filename, const char *pArchive_name, size_t *pSize, mz_uint flags);
+void *mz_zip_extract_archive_file_to_heap_v2(const char *pZip_filename, const char *pArchive_name, const char *pComment, size_t *pSize, mz_uint flags, mz_zip_error *pErr);
+
+#endif /* #ifndef MINIZ_NO_ARCHIVE_WRITING_APIS */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MINIZ_NO_ARCHIVE_APIS */
diff --git a/core/deps/pbf/pbf.hpp b/core/deps/pbf/pbf.hpp
new file mode 100644 (file)
index 0000000..f73b4f4
--- /dev/null
@@ -0,0 +1,238 @@
+#ifndef __PBF_HPP__
+#define __PBF_HPP__
+
+/*
+ * Some parts are from upb - a minimalist implementation of protocol buffers.
+ *
+ * Copyright (c) 2008-2011 Google Inc.  See LICENSE for details.
+ * Author: Josh Haberman <jhaberman@gmail.com>
+ */
+
+#include <cstdint>
+#include <stdexcept>
+#include <string>
+#include <cstring>
+#include <cassert>
+
+#undef LIKELY
+#undef UNLIKELY
+
+#if defined(__GNUC__) && __GNUC__ >= 4
+#define LIKELY(x)   (__builtin_expect((x), 1))
+#define UNLIKELY(x) (__builtin_expect((x), 0))
+#else
+#define LIKELY(x)   (x)
+#define UNLIKELY(x) (x)
+#endif
+
+namespace protobuf {
+
+#define FORCEINLINE inline __attribute__((always_inline))
+#define NOINLINE __attribute__((noinline))
+#define PBF_INLINE FORCEINLINE
+
+class message {
+    typedef const char * value_type;
+    value_type data_;
+    value_type end_;
+public:
+    uint64_t value;
+    uint32_t tag;
+
+    PBF_INLINE message(value_type data, std::size_t length);
+    PBF_INLINE message();
+
+    PBF_INLINE bool next();
+    PBF_INLINE uint64_t varint();
+    PBF_INLINE uint64_t varint2();
+    PBF_INLINE int64_t svarint();
+    PBF_INLINE std::string string();
+    PBF_INLINE float float32();
+    PBF_INLINE double float64();
+    PBF_INLINE int64_t int64();
+    PBF_INLINE bool boolean();
+    PBF_INLINE void skip();
+    PBF_INLINE void skipValue(uint64_t val);
+    PBF_INLINE void skipBytes(uint64_t bytes);
+    PBF_INLINE value_type getData();
+    PBF_INLINE value_type getEnd();
+    PBF_INLINE message getMessage();
+    PBF_INLINE operator bool() const;
+};
+
+message::message(value_type data, std::size_t length)
+    : data_(data),
+      end_(data + length)
+{
+}
+    
+message::message() {
+    data_ = nullptr;
+    end_ = nullptr;
+}
+
+bool message::next()
+{
+    if (data_ < end_) {
+        value = varint();
+        tag = static_cast<uint32_t>(value >> 3);
+        return true;
+    }
+    return false;
+}
+
+
+uint64_t message::varint()
+{
+    int8_t byte = static_cast<int8_t>(0x80);
+    uint64_t result = 0;
+    int bitpos;
+    for (bitpos = 0; bitpos < 70 && (byte & 0x80); bitpos += 7) {
+        if (data_ >= end_) {
+            throw std::runtime_error("unterminated varint, unexpected end of buffer");
+        }
+        result |= ((uint64_t)(byte = *data_) & 0x7F) << bitpos;
+        data_++;
+    }
+    if (bitpos == 70 && (byte & 0x80)) {
+        throw std::runtime_error("unterminated varint (too long)");
+    }
+
+    return result;
+}
+
+static const int8_t kMaxVarintLength64 = 10;
+
+uint64_t message::varint2() {
+  const int8_t* begin = reinterpret_cast<const int8_t*>(data_);
+  const int8_t* iend = reinterpret_cast<const int8_t*>(end_);
+  const int8_t* p = begin;
+  uint64_t val = 0;
+
+  if (LIKELY(iend - begin >= kMaxVarintLength64)) {  // fast path
+    int64_t b;
+    do {
+      b = *p++; val  = static_cast<uint64_t>((b & 0x7f)     ); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) <<  7); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 14); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 21); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 28); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 35); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 42); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 49); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 56); if (b >= 0) break;
+      b = *p++; val |= static_cast<uint64_t>((b & 0x7f) << 63); if (b >= 0) break;
+      throw std::invalid_argument("Invalid varint value");  // too big
+    } while (false);
+  } else {
+    int shift = 0;
+    while (p != iend && *p < 0) {
+      val |= static_cast<uint64_t>(*p++ & 0x7f) << shift;
+      shift += 7;
+    }
+    if (p == iend) throw std::invalid_argument("Invalid varint value");
+    val |= static_cast<uint64_t>(*p++) << shift;
+  }
+  data_ = reinterpret_cast<value_type>(p);
+  return val;
+}
+
+int64_t message::svarint()
+{
+    uint64_t n = varint();
+    return (n >> 1) ^ -static_cast<int64_t>((n & 1));
+}
+
+std::string message::string()
+{
+    uint64_t len = varint();
+    value_type string = static_cast<value_type>(data_);
+    skipBytes(len);
+    return std::string(string, len);
+}
+
+float message::float32()
+{
+    skipBytes(4);
+    float result;
+    std::memcpy(&result, data_ - 4, 4);
+    return result;
+}
+double message::float64()
+{
+    skipBytes(8);
+    double result;
+    std::memcpy(&result, data_ - 8, 8);
+    return result;
+}
+
+int64_t message::int64()
+{
+    return (int64_t)varint();
+}
+
+bool message::boolean()
+{
+    skipBytes(1);
+    return *(bool *)(data_ - 1);
+}
+
+void message::skip()
+{
+    skipValue(value);
+}
+
+void message::skipValue(uint64_t val)
+{
+    switch (val & 0x7) {
+        case 0: // varint
+            varint();
+            break;
+        case 1: // 64 bit
+            skipBytes(8);
+            break;
+        case 2: // string/message
+            skipBytes(varint());
+            break;
+        case 5: // 32 bit
+            skipBytes(4);
+            break;
+        default:
+            char msg[80];
+            snprintf(msg, 80, "cannot skip unknown type %lld", (unsigned long long)(val & 0x7));
+            throw std::runtime_error(msg);
+    }
+}
+
+void message::skipBytes(uint64_t bytes)
+{
+    data_ += bytes;
+    if (data_ > end_) {
+        throw std::runtime_error("unexpected end of buffer");
+    }
+}
+
+message::value_type message::getData()
+{
+  return data_;
+}
+
+message::value_type message::getEnd()
+{
+  return end_;
+}
+    
+message message::getMessage() {
+    uint32_t bytes = static_cast<uint32_t>(varint());
+    value_type pos = data_;
+    skipBytes(bytes);
+    return message(pos, bytes);
+}
+    
+message::operator bool() const {
+    return data_ < end_;
+}
+
+}
+
+#endif // __PBF_HPP__
diff --git a/core/deps/rapidjson/allocators.h b/core/deps/rapidjson/allocators.h
new file mode 100644 (file)
index 0000000..98affe0
--- /dev/null
@@ -0,0 +1,271 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ALLOCATORS_H_
+#define RAPIDJSON_ALLOCATORS_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Allocator
+
+/*! \class rapidjson::Allocator
+    \brief Concept for allocating, resizing and freeing memory block.
+    
+    Note that Malloc() and Realloc() are non-static but Free() is static.
+    
+    So if an allocator need to support Free(), it needs to put its pointer in 
+    the header of memory block.
+
+\code
+concept Allocator {
+    static const bool kNeedFree;    //!< Whether this allocator needs to call Free().
+
+    // Allocate a memory block.
+    // \param size of the memory block in bytes.
+    // \returns pointer to the memory block.
+    void* Malloc(size_t size);
+
+    // Resize a memory block.
+    // \param originalPtr The pointer to current memory block. Null pointer is permitted.
+    // \param originalSize The current size in bytes. (Design issue: since some allocator may not book-keep this, explicitly pass to it can save memory.)
+    // \param newSize the new size in bytes.
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize);
+
+    // Free a memory block.
+    // \param pointer to the memory block. Null pointer is permitted.
+    static void Free(void *ptr);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// CrtAllocator
+
+//! C-runtime library allocator.
+/*! This class is just wrapper for standard C library memory routines.
+    \note implements Allocator concept
+*/
+class CrtAllocator {
+public:
+    static const bool kNeedFree = true;
+    void* Malloc(size_t size) { 
+        if (size) //  behavior of malloc(0) is implementation defined.
+            return std::malloc(size);
+        else
+            return NULL; // standardize to returning NULL.
+    }
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        (void)originalSize;
+        if (newSize == 0) {
+            std::free(originalPtr);
+            return NULL;
+        }
+        return std::realloc(originalPtr, newSize);
+    }
+    static void Free(void *ptr) { std::free(ptr); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// MemoryPoolAllocator
+
+//! Default memory allocator used by the parser and DOM.
+/*! This allocator allocate memory blocks from pre-allocated memory chunks. 
+
+    It does not free memory blocks. And Realloc() only allocate new memory.
+
+    The memory chunks are allocated by BaseAllocator, which is CrtAllocator by default.
+
+    User may also supply a buffer as the first chunk.
+
+    If the user-buffer is full then additional chunks are allocated by BaseAllocator.
+
+    The user-buffer is not deallocated by this allocator.
+
+    \tparam BaseAllocator the allocator type for allocating memory chunks. Default is CrtAllocator.
+    \note implements Allocator concept
+*/
+template <typename BaseAllocator = CrtAllocator>
+class MemoryPoolAllocator {
+public:
+    static const bool kNeedFree = false;    //!< Tell users that no need to call Free() with this allocator. (concept Allocator)
+
+    //! Constructor with chunkSize.
+    /*! \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) : 
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(0), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+    }
+
+    //! Constructor with user-supplied buffer.
+    /*! The user buffer will be used firstly. When it is full, memory pool allocates new chunk with chunk size.
+
+        The user buffer will not be deallocated when this allocator is destructed.
+
+        \param buffer User supplied buffer.
+        \param size Size of the buffer in bytes. It must at least larger than sizeof(ChunkHeader).
+        \param chunkSize The size of memory chunk. The default is kDefaultChunkSize.
+        \param baseAllocator The allocator for allocating memory chunks.
+    */
+    MemoryPoolAllocator(void *buffer, size_t size, size_t chunkSize = kDefaultChunkCapacity, BaseAllocator* baseAllocator = 0) :
+        chunkHead_(0), chunk_capacity_(chunkSize), userBuffer_(buffer), baseAllocator_(baseAllocator), ownBaseAllocator_(0)
+    {
+        RAPIDJSON_ASSERT(buffer != 0);
+        RAPIDJSON_ASSERT(size > sizeof(ChunkHeader));
+        chunkHead_ = reinterpret_cast<ChunkHeader*>(buffer);
+        chunkHead_->capacity = size - sizeof(ChunkHeader);
+        chunkHead_->size = 0;
+        chunkHead_->next = 0;
+    }
+
+    //! Destructor.
+    /*! This deallocates all memory chunks, excluding the user-supplied buffer.
+    */
+    ~MemoryPoolAllocator() {
+        Clear();
+        RAPIDJSON_DELETE(ownBaseAllocator_);
+    }
+
+    //! Deallocates all memory chunks, excluding the user-supplied buffer.
+    void Clear() {
+        while (chunkHead_ && chunkHead_ != userBuffer_) {
+            ChunkHeader* next = chunkHead_->next;
+            baseAllocator_->Free(chunkHead_);
+            chunkHead_ = next;
+        }
+        if (chunkHead_ && chunkHead_ == userBuffer_)
+            chunkHead_->size = 0; // Clear user buffer
+    }
+
+    //! Computes the total capacity of allocated memory chunks.
+    /*! \return total capacity in bytes.
+    */
+    size_t Capacity() const {
+        size_t capacity = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            capacity += c->capacity;
+        return capacity;
+    }
+
+    //! Computes the memory blocks allocated.
+    /*! \return total used bytes.
+    */
+    size_t Size() const {
+        size_t size = 0;
+        for (ChunkHeader* c = chunkHead_; c != 0; c = c->next)
+            size += c->size;
+        return size;
+    }
+
+    //! Allocates a memory block. (concept Allocator)
+    void* Malloc(size_t size) {
+        if (!size)
+            return NULL;
+
+        size = RAPIDJSON_ALIGN(size);
+        if (chunkHead_ == 0 || chunkHead_->size + size > chunkHead_->capacity)
+            if (!AddChunk(chunk_capacity_ > size ? chunk_capacity_ : size))
+                return NULL;
+
+        void *buffer = reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size;
+        chunkHead_->size += size;
+        return buffer;
+    }
+
+    //! Resizes a memory block (concept Allocator)
+    void* Realloc(void* originalPtr, size_t originalSize, size_t newSize) {
+        if (originalPtr == 0)
+            return Malloc(newSize);
+
+        if (newSize == 0)
+            return NULL;
+
+        originalSize = RAPIDJSON_ALIGN(originalSize);
+        newSize = RAPIDJSON_ALIGN(newSize);
+
+        // Do not shrink if new size is smaller than original
+        if (originalSize >= newSize)
+            return originalPtr;
+
+        // Simply expand it if it is the last allocation and there is sufficient space
+        if (originalPtr == reinterpret_cast<char *>(chunkHead_) + RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + chunkHead_->size - originalSize) {
+            size_t increment = static_cast<size_t>(newSize - originalSize);
+            if (chunkHead_->size + increment <= chunkHead_->capacity) {
+                chunkHead_->size += increment;
+                return originalPtr;
+            }
+        }
+
+        // Realloc process: allocate and copy memory, do not free original buffer.
+        if (void* newBuffer = Malloc(newSize)) {
+            if (originalSize)
+                std::memcpy(newBuffer, originalPtr, originalSize);
+            return newBuffer;
+        }
+        else
+            return NULL;
+    }
+
+    //! Frees a memory block (concept Allocator)
+    static void Free(void *ptr) { (void)ptr; } // Do nothing
+
+private:
+    //! Copy constructor is not permitted.
+    MemoryPoolAllocator(const MemoryPoolAllocator& rhs) /* = delete */;
+    //! Copy assignment operator is not permitted.
+    MemoryPoolAllocator& operator=(const MemoryPoolAllocator& rhs) /* = delete */;
+
+    //! Creates a new chunk.
+    /*! \param capacity Capacity of the chunk in bytes.
+        \return true if success.
+    */
+    bool AddChunk(size_t capacity) {
+        if (!baseAllocator_)
+            ownBaseAllocator_ = baseAllocator_ = RAPIDJSON_NEW(BaseAllocator());
+        if (ChunkHeader* chunk = reinterpret_cast<ChunkHeader*>(baseAllocator_->Malloc(RAPIDJSON_ALIGN(sizeof(ChunkHeader)) + capacity))) {
+            chunk->capacity = capacity;
+            chunk->size = 0;
+            chunk->next = chunkHead_;
+            chunkHead_ =  chunk;
+            return true;
+        }
+        else
+            return false;
+    }
+
+    static const int kDefaultChunkCapacity = 64 * 1024; //!< Default chunk capacity.
+
+    //! Chunk header for perpending to each chunk.
+    /*! Chunks are stored as a singly linked list.
+    */
+    struct ChunkHeader {
+        size_t capacity;    //!< Capacity of the chunk in bytes (excluding the header itself).
+        size_t size;        //!< Current size of allocated memory in bytes.
+        ChunkHeader *next;  //!< Next chunk in the linked list.
+    };
+
+    ChunkHeader *chunkHead_;    //!< Head of the chunk linked-list. Only the head chunk serves allocation.
+    size_t chunk_capacity_;     //!< The minimum capacity of chunk when they are allocated.
+    void *userBuffer_;          //!< User supplied buffer.
+    BaseAllocator* baseAllocator_;  //!< base allocator for allocating memory chunks.
+    BaseAllocator* ownBaseAllocator_;   //!< base allocator created by this object.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/core/deps/rapidjson/document.h b/core/deps/rapidjson/document.h
new file mode 100644 (file)
index 0000000..e3e20df
--- /dev/null
@@ -0,0 +1,2575 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include "reader.h"
+#include "internal/meta.h"
+#include "internal/strfunc.h"
+#include "memorystream.h"
+#include "encodedstream.h"
+#include <new>      // placement new
+#include <limits>
+
+RAPIDJSON_DIAG_PUSH
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#if __GNUC__ >= 6
+RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
+#endif
+#endif // __GNUC__
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+    This class was internal to GenericValue. It used to be a inner struct.
+    But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
+    https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator> 
+struct GenericMember { 
+    GenericValue<Encoding, Allocator> name;     //!< name of member (must be a string)
+    GenericValue<Encoding, Allocator> value;    //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+    \tparam Const Is this a constant iterator?
+    \tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)
+    \tparam Allocator   Allocator type for allocating memory of object, array and string.
+
+    This class implements a Random Access Iterator for GenericMember elements
+    of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
+
+    \note This iterator implementation is mainly intended to avoid implicit
+        conversions from iterator values to \c NULL,
+        e.g. from GenericValue::FindMember.
+
+    \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+        pointer-based implementation, if your platform doesn't provide
+        the C++ <iterator> header.
+
+    \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+    : public std::iterator<std::random_access_iterator_tag
+        , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
+
+    friend class GenericValue<Encoding,Allocator>;
+    template <bool, typename, typename> friend class GenericMemberIterator;
+
+    typedef GenericMember<Encoding,Allocator> PlainType;
+    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+    typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
+
+public:
+    //! Iterator type itself
+    typedef GenericMemberIterator Iterator;
+    //! Constant iterator type
+    typedef GenericMemberIterator<true,Encoding,Allocator>  ConstIterator;
+    //! Non-constant iterator type
+    typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
+
+    //! Pointer to (const) GenericMember
+    typedef typename BaseType::pointer         Pointer;
+    //! Reference to (const) GenericMember
+    typedef typename BaseType::reference       Reference;
+    //! Signed integer type (e.g. \c ptrdiff_t)
+    typedef typename BaseType::difference_type DifferenceType;
+
+    //! Default constructor (singular value)
+    /*! Creates an iterator pointing to no element.
+        \note All operations, except for comparisons, are undefined on such values.
+     */
+    GenericMemberIterator() : ptr_() {}
+
+    //! Iterator conversions to more const
+    /*!
+        \param it (Non-const) iterator to copy from
+
+        Allows the creation of an iterator from another GenericMemberIterator
+        that is "less const".  Especially, creating a non-constant iterator
+        from a constant iterator are disabled:
+        \li const -> non-const (not ok)
+        \li const -> const (ok)
+        \li non-const -> const (ok)
+        \li non-const -> non-const (ok)
+
+        \note If the \c Const template parameter is already \c false, this
+            constructor effectively defines a regular copy-constructor.
+            Otherwise, the copy constructor is implicitly defined.
+    */
+    GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
+    Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
+
+    //! @name stepping
+    //@{
+    Iterator& operator++(){ ++ptr_; return *this; }
+    Iterator& operator--(){ --ptr_; return *this; }
+    Iterator  operator++(int){ Iterator old(*this); ++ptr_; return old; }
+    Iterator  operator--(int){ Iterator old(*this); --ptr_; return old; }
+    //@}
+
+    //! @name increment/decrement
+    //@{
+    Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
+    Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
+
+    Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
+    Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
+    //@}
+
+    //! @name relations
+    //@{
+    bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+    bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+    bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+    bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+    bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
+    bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
+    //@}
+
+    //! @name dereference
+    //@{
+    Reference operator*() const { return *ptr_; }
+    Pointer   operator->() const { return ptr_; }
+    Reference operator[](DifferenceType n) const { return ptr_[n]; }
+    //@}
+
+    //! Distance
+    DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
+
+private:
+    //! Internal constructor from plain pointer
+    explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+    Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false,Encoding,Allocator> {
+    //! use plain pointer as iterator type
+    typedef GenericMember<Encoding,Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true,Encoding,Allocator> {
+    //! use plain const pointer as iterator type
+    typedef const GenericMember<Encoding,Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+    \tparam CharType character type of the string
+
+    This helper class is used to automatically infer constant string
+    references for string literals, especially from \c const \b (!)
+    character arrays.
+
+    The main use is for creating JSON string values without copying the
+    source string via an \ref Allocator.  This requires that the referenced
+    string pointers have a sufficient lifetime, which exceeds the lifetime
+    of the associated GenericValue.
+
+    \b Example
+    \code
+    Value v("foo");   // ok, no need to copy & calculate length
+    const char foo[] = "foo";
+    v.SetString(foo); // ok
+
+    const char* bar = foo;
+    // Value x(bar); // not ok, can't rely on bar's lifetime
+    Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+    Value y(StringRef(bar, 3));  // ok, explicitly pass length
+    \endcode
+
+    \see StringRef, GenericValue::SetString
+*/
+template<typename CharType>
+struct GenericStringRef {
+    typedef CharType Ch; //!< character type of the string
+
+    //! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
+    /*!
+        This constructor implicitly creates a constant string reference from
+        a \c const character array.  It has better performance than
+        \ref StringRef(const CharType*) by inferring the string \ref length
+        from the array length, and also supports strings containing null
+        characters.
+
+        \tparam N length of the string, automatically inferred
+
+        \param str Constant character array, lifetime assumed to be longer
+            than the use of the string in e.g. a GenericValue
+
+        \post \ref s == str
+
+        \note Constant complexity.
+        \note There is a hidden, private overload to disallow references to
+            non-const character arrays to be created via this constructor.
+            By this, e.g. function-scope arrays used to be filled via
+            \c snprintf are excluded from consideration.
+            In such cases, the referenced string should be \b copied to the
+            GenericValue instead.
+     */
+#endif
+    template<SizeType N>
+    GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+        : s(str), length(N-1) {}
+
+    //! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
+    /*!
+        This constructor can be used to \b explicitly  create a reference to
+        a constant string pointer.
+
+        \see StringRef(const CharType*)
+
+        \param str Constant character pointer, lifetime assumed to be longer
+            than the use of the string in e.g. a GenericValue
+
+        \post \ref s == str
+
+        \note There is a hidden, private overload to disallow references to
+            non-const character arrays to be created via this constructor.
+            By this, e.g. function-scope arrays used to be filled via
+            \c snprintf are excluded from consideration.
+            In such cases, the referenced string should be \b copied to the
+            GenericValue instead.
+     */
+#endif
+    explicit GenericStringRef(const CharType* str)
+        : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
+
+    //! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
+    /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+        \param len length of the string, excluding the trailing NULL terminator
+
+        \post \ref s == str && \ref length == len
+        \note Constant complexity.
+     */
+#endif
+    GenericStringRef(const CharType* str, SizeType len)
+        : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
+
+    GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
+
+    GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; }
+
+    //! implicit conversion to plain CharType pointer
+    operator const Ch *() const { return s; }
+
+    const Ch* const s; //!< plain CharType pointer
+    const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
+
+private:
+    //! Disallow construction from non-const array
+    template<SizeType N>
+    GenericStringRef(CharType (&str)[N]) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal".  This function
+    can be used to avoid copying a character string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+    \tparam CharType Character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+
+    \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+    return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal".  This function
+    can be used to avoid copying a character string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+
+    This version has better performance with supplied length, and also
+    supports string containing null characters.
+
+    \tparam CharType character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \param length The length of source string.
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
+    return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+    This function can be used to avoid copying a string to be referenced as a
+    value in a JSON GenericValue object, if the string's lifetime is known
+    to be valid long enough.
+
+    \tparam CharType character type of the string
+    \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
+    \return GenericStringRef string reference object
+    \relatesalso GenericStringRef
+    \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template<typename CharType>
+inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
+    return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
+    : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived classes
+template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// TypeHelper
+
+namespace internal {
+
+template <typename ValueType, typename T>
+struct TypeHelper {};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, bool> {
+    static bool Is(const ValueType& v) { return v.IsBool(); }
+    static bool Get(const ValueType& v) { return v.GetBool(); }
+    static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
+    static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, int> {
+    static bool Is(const ValueType& v) { return v.IsInt(); }
+    static int Get(const ValueType& v) { return v.GetInt(); }
+    static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
+    static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, unsigned> {
+    static bool Is(const ValueType& v) { return v.IsUint(); }
+    static unsigned Get(const ValueType& v) { return v.GetUint(); }
+    static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
+    static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, int64_t> {
+    static bool Is(const ValueType& v) { return v.IsInt64(); }
+    static int64_t Get(const ValueType& v) { return v.GetInt64(); }
+    static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
+    static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, uint64_t> {
+    static bool Is(const ValueType& v) { return v.IsUint64(); }
+    static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
+    static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
+    static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, double> {
+    static bool Is(const ValueType& v) { return v.IsDouble(); }
+    static double Get(const ValueType& v) { return v.GetDouble(); }
+    static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
+    static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, float> {
+    static bool Is(const ValueType& v) { return v.IsFloat(); }
+    static float Get(const ValueType& v) { return v.GetFloat(); }
+    static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
+    static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, const typename ValueType::Ch*> {
+    typedef const typename ValueType::Ch* StringType;
+    static bool Is(const ValueType& v) { return v.IsString(); }
+    static StringType Get(const ValueType& v) { return v.GetString(); }
+    static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
+    static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+
+#if RAPIDJSON_HAS_STDSTRING
+template<typename ValueType> 
+struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
+    typedef std::basic_string<typename ValueType::Ch> StringType;
+    static bool Is(const ValueType& v) { return v.IsString(); }
+    static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }
+    static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
+};
+#endif
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, typename ValueType::Array> {
+    typedef typename ValueType::Array ArrayType;
+    static bool Is(const ValueType& v) { return v.IsArray(); }
+    static ArrayType Get(ValueType& v) { return v.GetArray(); }
+    static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
+    static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, typename ValueType::ConstArray> {
+    typedef typename ValueType::ConstArray ArrayType;
+    static bool Is(const ValueType& v) { return v.IsArray(); }
+    static ArrayType Get(const ValueType& v) { return v.GetArray(); }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, typename ValueType::Object> {
+    typedef typename ValueType::Object ObjectType;
+    static bool Is(const ValueType& v) { return v.IsObject(); }
+    static ObjectType Get(ValueType& v) { return v.GetObject(); }
+    static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
+    static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
+};
+
+template<typename ValueType> 
+struct TypeHelper<ValueType, typename ValueType::ConstObject> {
+    typedef typename ValueType::ConstObject ObjectType;
+    static bool Is(const ValueType& v) { return v.IsObject(); }
+    static ObjectType Get(const ValueType& v) { return v.GetObject(); }
+};
+
+} // namespace internal
+
+// Forward declarations
+template <bool, typename> class GenericArray;
+template <bool, typename> class GenericObject;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+    A JSON value can be one of 7 types. This class is a variant type supporting
+    these types.
+
+    Use the Value if UTF8 and default allocator
+
+    \tparam Encoding    Encoding of the value. (Even non-string values need to have the same encoding in a document)
+    \tparam Allocator   Allocator type for allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> > 
+class GenericValue {
+public:
+    //! Name-value pair in an object.
+    typedef GenericMember<Encoding, Allocator> Member;
+    typedef Encoding EncodingType;                  //!< Encoding type from template parameter.
+    typedef Allocator AllocatorType;                //!< Allocator type from template parameter.
+    typedef typename Encoding::Ch Ch;               //!< Character type derived from Encoding.
+    typedef GenericStringRef<Ch> StringRefType;     //!< Reference to a constant string
+    typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator;  //!< Member iterator for iterating in object.
+    typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator;  //!< Constant member iterator for iterating in object.
+    typedef GenericValue* ValueIterator;            //!< Value iterator for iterating in array.
+    typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
+    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of itself.
+    typedef GenericArray<false, ValueType> Array;
+    typedef GenericArray<true, ValueType> ConstArray;
+    typedef GenericObject<false, ValueType> Object;
+    typedef GenericObject<true, ValueType> ConstObject;
+
+    //!@name Constructors and destructor.
+    //@{
+
+    //! Default constructor creates a null value.
+    GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move constructor in C++11
+    GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
+        rhs.data_.f.flags = kNullFlag; // give up contents
+    }
+#endif
+
+private:
+    //! Copy constructor is not permitted.
+    GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Moving from a GenericDocument is not permitted.
+    template <typename StackAllocator>
+    GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+
+    //! Move assignment from a GenericDocument is not permitted.
+    template <typename StackAllocator>
+    GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
+#endif
+
+public:
+
+    //! Constructor with JSON value type.
+    /*! This creates a Value of specified type with default content.
+        \param type Type of the value.
+        \note Default content for number is zero.
+    */
+    explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
+        static const uint16_t defaultFlags[7] = {
+            kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
+            kNumberAnyFlag
+        };
+        RAPIDJSON_ASSERT(type <= kNumberType);
+        data_.f.flags = defaultFlags[type];
+
+        // Use ShortString to store empty string.
+        if (type == kStringType)
+            data_.ss.SetLength(0);
+    }
+
+    //! Explicit copy constructor (with allocator)
+    /*! Creates a copy of a Value by using the given Allocator
+        \tparam SourceAllocator allocator of \c rhs
+        \param rhs Value to copy from (read-only)
+        \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
+        \see CopyFrom()
+    */
+    template< typename SourceAllocator >
+    GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
+
+    //! Constructor for boolean value.
+    /*! \param b Boolean value
+        \note This constructor is limited to \em real boolean values and rejects
+            implicitly converted types like arbitrary pointers.  Use an explicit cast
+            to \c bool, if you want to construct a boolean JSON value in such cases.
+     */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+    template <typename T>
+    explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT  // See #472
+#else
+    explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+        : data_() {
+            // safe-guard against failing SFINAE
+            RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
+            data_.f.flags = b ? kTrueFlag : kFalseFlag;
+    }
+
+    //! Constructor for int value.
+    explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
+        data_.n.i64 = i;
+        data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
+    }
+
+    //! Constructor for unsigned value.
+    explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
+        data_.n.u64 = u; 
+        data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
+    }
+
+    //! Constructor for int64_t value.
+    explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
+        data_.n.i64 = i64;
+        data_.f.flags = kNumberInt64Flag;
+        if (i64 >= 0) {
+            data_.f.flags |= kNumberUint64Flag;
+            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+                data_.f.flags |= kUintFlag;
+            if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+                data_.f.flags |= kIntFlag;
+        }
+        else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+            data_.f.flags |= kIntFlag;
+    }
+
+    //! Constructor for uint64_t value.
+    explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
+        data_.n.u64 = u64;
+        data_.f.flags = kNumberUint64Flag;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+            data_.f.flags |= kInt64Flag;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+            data_.f.flags |= kUintFlag;
+        if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+            data_.f.flags |= kIntFlag;
+    }
+
+    //! Constructor for double value.
+    explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
+
+    //! Constructor for constant string (i.e. do not make a copy of string)
+    GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
+
+    //! Constructor for constant string (i.e. do not make a copy of string)
+    explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
+
+    //! Constructor for copy-string (i.e. do make a copy of string)
+    GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
+
+    //! Constructor for copy-string (i.e. do make a copy of string)
+    GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Constructor for copy-string from a string object (i.e. do make a copy of string)
+    /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+     */
+    GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
+#endif
+
+    //! Constructor for Array.
+    /*!
+        \param a An array obtained by \c GetArray().
+        \note \c Array is always pass-by-value.
+        \note the source array is moved into this value and the sourec array becomes empty.
+    */
+    GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
+        a.value_.data_ = Data();
+        a.value_.data_.f.flags = kArrayFlag;
+    }
+
+    //! Constructor for Object.
+    /*!
+        \param o An object obtained by \c GetObject().
+        \note \c Object is always pass-by-value.
+        \note the source object is moved into this value and the sourec object becomes empty.
+    */
+    GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
+        o.value_.data_ = Data();
+        o.value_.data_.f.flags = kObjectFlag;
+    }
+
+    //! Destructor.
+    /*! Need to destruct elements of array, members of object, or copy-string.
+    */
+    ~GenericValue() {
+        if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+            switch(data_.f.flags) {
+            case kArrayFlag:
+                {
+                    GenericValue* e = GetElementsPointer();
+                    for (GenericValue* v = e; v != e + data_.a.size; ++v)
+                        v->~GenericValue();
+                    Allocator::Free(e);
+                }
+                break;
+
+            case kObjectFlag:
+                for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+                    m->~Member();
+                Allocator::Free(GetMembersPointer());
+                break;
+
+            case kCopyStringFlag:
+                Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+                break;
+
+            default:
+                break;  // Do nothing for other types.
+            }
+        }
+    }
+
+    //@}
+
+    //!@name Assignment operators
+    //@{
+
+    //! Assignment with move semantics.
+    /*! \param rhs Source of the assignment. It will become a null value after assignment.
+    */
+    GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+        RAPIDJSON_ASSERT(this != &rhs);
+        this->~GenericValue();
+        RawAssign(rhs);
+        return *this;
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move assignment in C++11
+    GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+        return *this = rhs.Move();
+    }
+#endif
+
+    //! Assignment of constant string reference (no copy)
+    /*! \param str Constant string reference to be assigned
+        \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
+        \see GenericStringRef, operator=(T)
+    */
+    GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+        GenericValue s(str);
+        return *this = s;
+    }
+
+    //! Assignment with primitive types.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param value The value to be assigned.
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref SetString(const Ch*, Allocator&) (for copying) or
+            \ref StringRef() (to explicitly mark the pointer as constant) instead.
+            All other pointer types would implicitly convert to \c bool,
+            use \ref SetBool() instead.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+    operator=(T value) {
+        GenericValue v(value);
+        return *this = v;
+    }
+
+    //! Deep-copy assignment from Value
+    /*! Assigns a \b copy of the Value to the current Value object
+        \tparam SourceAllocator Allocator type of \c rhs
+        \param rhs Value to copy from (read-only)
+        \param allocator Allocator to use for copying
+     */
+    template <typename SourceAllocator>
+    GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
+        RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
+        this->~GenericValue();
+        new (this) GenericValue(rhs, allocator);
+        return *this;
+    }
+
+    //! Exchange the contents of this value with those of other.
+    /*!
+        \param other Another value.
+        \note Constant complexity.
+    */
+    GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+        GenericValue temp;
+        temp.RawAssign(*this);
+        RawAssign(other);
+        other.RawAssign(temp);
+        return *this;
+    }
+
+    //! free-standing swap function helper
+    /*!
+        Helper function to enable support for common swap implementation pattern based on \c std::swap:
+        \code
+        void swap(MyClass& a, MyClass& b) {
+            using std::swap;
+            swap(a.value, b.value);
+            // ...
+        }
+        \endcode
+        \see Swap()
+     */
+    friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+    //! Prepare Value for move semantics
+    /*! \return *this */
+    GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+    //@}
+
+    //!@name Equal-to and not-equal-to operators
+    //@{
+    //! Equal-to operator
+    /*!
+        \note If an object contains duplicated named member, comparing equality with any object is always \c false.
+        \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
+    */
+    template <typename SourceAllocator>
+    bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+        typedef GenericValue<Encoding, SourceAllocator> RhsType;
+        if (GetType() != rhs.GetType())
+            return false;
+
+        switch (GetType()) {
+        case kObjectType: // Warning: O(n^2) inner-loop
+            if (data_.o.size != rhs.data_.o.size)
+                return false;           
+            for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+                typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
+                if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
+                    return false;
+            }
+            return true;
+            
+        case kArrayType:
+            if (data_.a.size != rhs.data_.a.size)
+                return false;
+            for (SizeType i = 0; i < data_.a.size; i++)
+                if ((*this)[i] != rhs[i])
+                    return false;
+            return true;
+
+        case kStringType:
+            return StringEqual(rhs);
+
+        case kNumberType:
+            if (IsDouble() || rhs.IsDouble()) {
+                double a = GetDouble();     // May convert from integer to double.
+                double b = rhs.GetDouble(); // Ditto
+                return a >= b && a <= b;    // Prevent -Wfloat-equal
+            }
+            else
+                return data_.n.u64 == rhs.data_.n.u64;
+
+        default:
+            return true;
+        }
+    }
+
+    //! Equal-to operator with const C-string pointer
+    bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Equal-to operator with string object
+    /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+     */
+    bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
+#endif
+
+    //! Equal-to operator with primitive types
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
+    */
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
+
+    //! Not-equal-to operator
+    /*! \return !(*this == rhs)
+     */
+    template <typename SourceAllocator>
+    bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
+
+    //! Not-equal-to operator with const C-string pointer
+    bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+    //! Not-equal-to operator with arbitrary types
+    /*! \return !(*this == rhs)
+     */
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
+
+    //! Equal-to operator with arbitrary types (symmetric version)
+    /*! \return (rhs == lhs)
+     */
+    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
+
+    //! Not-Equal-to operator with arbitrary types (symmetric version)
+    /*! \return !(rhs == lhs)
+     */
+    template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
+    //@}
+
+    //!@name Type
+    //@{
+
+    Type GetType()  const { return static_cast<Type>(data_.f.flags & kTypeMask); }
+    bool IsNull()   const { return data_.f.flags == kNullFlag; }
+    bool IsFalse()  const { return data_.f.flags == kFalseFlag; }
+    bool IsTrue()   const { return data_.f.flags == kTrueFlag; }
+    bool IsBool()   const { return (data_.f.flags & kBoolFlag) != 0; }
+    bool IsObject() const { return data_.f.flags == kObjectFlag; }
+    bool IsArray()  const { return data_.f.flags == kArrayFlag; }
+    bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
+    bool IsInt()    const { return (data_.f.flags & kIntFlag) != 0; }
+    bool IsUint()   const { return (data_.f.flags & kUintFlag) != 0; }
+    bool IsInt64()  const { return (data_.f.flags & kInt64Flag) != 0; }
+    bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
+    bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
+    bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
+
+    // Checks whether a number can be losslessly converted to a double.
+    bool IsLosslessDouble() const {
+        if (!IsNumber()) return false;
+        if (IsUint64()) {
+            uint64_t u = GetUint64();
+            volatile double d = static_cast<double>(u);
+            return (d >= 0.0)
+                && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
+                && (u == static_cast<uint64_t>(d));
+        }
+        if (IsInt64()) {
+            int64_t i = GetInt64();
+            volatile double d = static_cast<double>(i);
+            return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
+                && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
+                && (i == static_cast<int64_t>(d));
+        }
+        return true; // double, int, uint are always lossless
+    }
+
+    // Checks whether a number is a float (possible lossy).
+    bool IsFloat() const  {
+        if ((data_.f.flags & kDoubleFlag) == 0)
+            return false;
+        double d = GetDouble();
+        return d >= -3.4028234e38 && d <= 3.4028234e38;
+    }
+    // Checks whether a number can be losslessly converted to a float.
+    bool IsLosslessFloat() const {
+        if (!IsNumber()) return false;
+        double a = GetDouble();
+        if (a < static_cast<double>(-std::numeric_limits<float>::max())
+                || a > static_cast<double>(std::numeric_limits<float>::max()))
+            return false;
+        double b = static_cast<double>(static_cast<float>(a));
+        return a >= b && a <= b;    // Prevent -Wfloat-equal
+    }
+
+    //@}
+
+    //!@name Null
+    //@{
+
+    GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
+
+    //@}
+
+    //!@name Bool
+    //@{
+
+    bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
+    //!< Set boolean value
+    /*! \post IsBool() == true */
+    GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
+
+    //@}
+
+    //!@name Object
+    //@{
+
+    //! Set this value as an empty object.
+    /*! \post IsObject() == true */
+    GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
+
+    //! Get the number of members in the object.
+    SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
+
+    //! Check whether the object is empty.
+    bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
+
+    //! Get a value from an object associated with the name.
+    /*! \pre IsObject() == true
+        \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
+        \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
+        Since 0.2, if the name is not correct, it will assert.
+        If user is unsure whether a member exists, user should use HasMember() first.
+        A better approach is to use FindMember().
+        \note Linear time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
+        GenericValue n(StringRef(name));
+        return (*this)[n];
+    }
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+    //! Get a value from an object associated with the name.
+    /*! \pre IsObject() == true
+        \tparam SourceAllocator Allocator of the \c name value
+
+        \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
+        And it can also handle strings with embedded null characters.
+
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator member = FindMember(name);
+        if (member != MemberEnd())
+            return member->value;
+        else {
+            RAPIDJSON_ASSERT(false);    // see above note
+
+            // This will generate -Wexit-time-destructors in clang
+            // static GenericValue NullValue;
+            // return NullValue;
+
+            // Use static buffer and placement-new to prevent destruction
+            static char buffer[sizeof(GenericValue)];
+            return *new (buffer) GenericValue();
+        }
+    }
+    template <typename SourceAllocator>
+    const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Get a value from an object associated with name (string object).
+    GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
+    const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
+#endif
+
+    //! Const member iterator
+    /*! \pre IsObject() == true */
+    ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
+    //! Const \em past-the-end member iterator
+    /*! \pre IsObject() == true */
+    ConstMemberIterator MemberEnd() const   { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
+    //! Member iterator
+    /*! \pre IsObject() == true */
+    MemberIterator MemberBegin()            { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
+    //! \em Past-the-end member iterator
+    /*! \pre IsObject() == true */
+    MemberIterator MemberEnd()              { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
+
+    //! Check whether a member exists in the object.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Check whether a member exists in the object with string object.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
+#endif
+
+    //! Check whether a member exists in the object with GenericValue name.
+    /*!
+        This version is faster because it does not need a StrLen(). It can also handle string with null character.
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Whether a member with that name exists.
+        \note It is better to use FindMember() directly if you need the obtain the value as well.
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
+
+    //! Find member by name.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+
+        \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+            the requested member doesn't exist. For consistency with e.g.
+            \c std::map, this has been changed to MemberEnd() now.
+        \note Linear time complexity.
+    */
+    MemberIterator FindMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return FindMember(n);
+    }
+
+    ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+    //! Find member by name.
+    /*!
+        This version is faster because it does not need a StrLen(). It can also handle string with null character.
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+
+        \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+            the requested member doesn't exist. For consistency with e.g.
+            \c std::map, this has been changed to MemberEnd() now.
+        \note Linear time complexity.
+    */
+    template <typename SourceAllocator>
+    MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(name.IsString());
+        MemberIterator member = MemberBegin();
+        for ( ; member != MemberEnd(); ++member)
+            if (name.StringEqual(member->name))
+                break;
+        return member;
+    }
+    template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Find member by string object name.
+    /*!
+        \param name Member name to be searched.
+        \pre IsObject() == true
+        \return Iterator to member, if it exists.
+            Otherwise returns \ref MemberEnd().
+    */
+    MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }
+    ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }
+#endif
+
+    //! Add a member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value Value of any type.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note The ownership of \c name and \c value will be transferred to this object on success.
+        \pre  IsObject() && name.IsString()
+        \post name.IsNull() && value.IsNull()
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(name.IsString());
+
+        ObjectData& o = data_.o;
+        if (o.size >= o.capacity) {
+            if (o.capacity == 0) {
+                o.capacity = kDefaultObjectCapacity;
+                SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
+            }
+            else {
+                SizeType oldCapacity = o.capacity;
+                o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+                SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
+            }
+        }
+        Member* members = GetMembersPointer();
+        members[o.size].name.RawAssign(name);
+        members[o.size].value.RawAssign(value);
+        o.size++;
+        return *this;
+    }
+
+    //! Add a constant string value as member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Add a string object as member (name-value pair) to the object.
+    /*! \param name A string value as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
+        GenericValue v(value, allocator);
+        return AddMember(name, v, allocator);
+    }
+#endif
+
+    //! Add any primitive value as member (name-value pair) to the object.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param name A string value as name of member.
+        \param value Value of primitive type \c T as value of member
+        \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+            AddMember(StringRefType, StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized Constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    AddMember(GenericValue& name, T value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
+        return AddMember(name, value, allocator);
+    }
+    GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+
+    //! Add a member (name-value pair) to the object.
+    /*! \param name A constant string reference as name of member.
+        \param value Value of any type.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note The ownership of \c value will be transferred to this object on success.
+        \pre  IsObject()
+        \post value.IsNull()
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+
+    //! Add a constant string value as member (name-value pair) to the object.
+    /*! \param name A constant string reference as name of member.
+        \param value constant string reference as value of member.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+        \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
+        \note Amortized Constant time complexity.
+    */
+    GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
+        GenericValue v(value);
+        return AddMember(name, v, allocator);
+    }
+
+    //! Add any primitive value as member (name-value pair) to the object.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param name A constant string reference as name of member.
+        \param value Value of primitive type \c T as value of member
+        \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \pre  IsObject()
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+            AddMember(StringRefType, StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized Constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    AddMember(StringRefType name, T value, Allocator& allocator) {
+        GenericValue n(name);
+        return AddMember(n, value, allocator);
+    }
+
+    //! Remove all members in the object.
+    /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
+        \note Linear time complexity.
+    */
+    void RemoveAllMembers() {
+        RAPIDJSON_ASSERT(IsObject()); 
+        for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+            m->~Member();
+        data_.o.size = 0;
+    }
+
+    //! Remove a member in object by its name.
+    /*! \param name Name of member to be removed.
+        \return Whether the member existed.
+        \note This function may reorder the object members. Use \ref
+            EraseMember(ConstMemberIterator) if you need to preserve the
+            relative order of the remaining members.
+        \note Linear time complexity.
+    */
+    bool RemoveMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return RemoveMember(n);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
+#endif
+
+    template <typename SourceAllocator>
+    bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator m = FindMember(name);
+        if (m != MemberEnd()) {
+            RemoveMember(m);
+            return true;
+        }
+        else
+            return false;
+    }
+
+    //! Remove a member in object by iterator.
+    /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+        \return the new iterator after removal.
+        \note This function may reorder the object members. Use \ref
+            EraseMember(ConstMemberIterator) if you need to preserve the
+            relative order of the remaining members.
+        \note Constant time complexity.
+    */
+    MemberIterator RemoveMember(MemberIterator m) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(data_.o.size > 0);
+        RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+        RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+        MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
+        if (data_.o.size > 1 && m != last)
+            *m = *last; // Move the last one to this place
+        else
+            m->~Member(); // Only one left, just destroy
+        --data_.o.size;
+        return m;
+    }
+
+    //! Remove a member from an object by iterator.
+    /*! \param pos iterator to the member to remove
+        \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+        \return Iterator following the removed element.
+            If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
+        \note This function preserves the relative order of the remaining object
+            members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
+        \note Linear time complexity.
+    */
+    MemberIterator EraseMember(ConstMemberIterator pos) {
+        return EraseMember(pos, pos +1);
+    }
+
+    //! Remove members in the range [first, last) from an object.
+    /*! \param first iterator to the first member to remove
+        \param last  iterator following the last member to remove
+        \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
+        \return Iterator following the last removed element.
+        \note This function preserves the relative order of the remaining object
+            members.
+        \note Linear time complexity.
+    */
+    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
+        RAPIDJSON_ASSERT(IsObject());
+        RAPIDJSON_ASSERT(data_.o.size > 0);
+        RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+        RAPIDJSON_ASSERT(first >= MemberBegin());
+        RAPIDJSON_ASSERT(first <= last);
+        RAPIDJSON_ASSERT(last <= MemberEnd());
+
+        MemberIterator pos = MemberBegin() + (first - MemberBegin());
+        for (MemberIterator itr = pos; itr != last; ++itr)
+            itr->~Member();
+        std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
+        data_.o.size -= static_cast<SizeType>(last - first);
+        return pos;
+    }
+
+    //! Erase a member in object by its name.
+    /*! \param name Name of member to be removed.
+        \return Whether the member existed.
+        \note Linear time complexity.
+    */
+    bool EraseMember(const Ch* name) {
+        GenericValue n(StringRef(name));
+        return EraseMember(n);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
+#endif
+
+    template <typename SourceAllocator>
+    bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
+        MemberIterator m = FindMember(name);
+        if (m != MemberEnd()) {
+            EraseMember(m);
+            return true;
+        }
+        else
+            return false;
+    }
+
+    Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
+    ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
+
+    //@}
+
+    //!@name Array
+    //@{
+
+    //! Set this value as an empty array.
+    /*! \post IsArray == true */
+    GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
+
+    //! Get the number of elements in array.
+    SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
+
+    //! Get the capacity of array.
+    SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
+
+    //! Check whether the array is empty.
+    bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
+
+    //! Remove all elements in the array.
+    /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
+        \note Linear time complexity.
+    */
+    void Clear() {
+        RAPIDJSON_ASSERT(IsArray()); 
+        GenericValue* e = GetElementsPointer();
+        for (GenericValue* v = e; v != e + data_.a.size; ++v)
+            v->~GenericValue();
+        data_.a.size = 0;
+    }
+
+    //! Get an element from array by index.
+    /*! \pre IsArray() == true
+        \param index Zero-based index of element.
+        \see operator[](T*)
+    */
+    GenericValue& operator[](SizeType index) {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(index < data_.a.size);
+        return GetElementsPointer()[index];
+    }
+    const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
+
+    //! Element iterator
+    /*! \pre IsArray() == true */
+    ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
+    //! \em Past-the-end element iterator
+    /*! \pre IsArray() == true */
+    ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
+    //! Constant element iterator
+    /*! \pre IsArray() == true */
+    ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
+    //! Constant \em past-the-end element iterator
+    /*! \pre IsArray() == true */
+    ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
+
+    //! Request the array to have enough capacity to store elements.
+    /*! \param newCapacity  The capacity that the array at least need to have.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \note Linear time complexity.
+    */
+    GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
+        RAPIDJSON_ASSERT(IsArray());
+        if (newCapacity > data_.a.capacity) {
+            SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
+            data_.a.capacity = newCapacity;
+        }
+        return *this;
+    }
+
+    //! Append a GenericValue at the end of the array.
+    /*! \param value        Value to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \post value.IsNull() == true
+        \return The value itself for fluent API.
+        \note The ownership of \c value will be transferred to this array on success.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+        \note Amortized constant time complexity.
+    */
+    GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+        RAPIDJSON_ASSERT(IsArray());
+        if (data_.a.size >= data_.a.capacity)
+            Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
+        GetElementsPointer()[data_.a.size++].RawAssign(value);
+        return *this;
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+        return PushBack(value, allocator);
+    }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+    //! Append a constant string reference at the end of the array.
+    /*! \param value        Constant string reference to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \return The value itself for fluent API.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+        \note Amortized constant time complexity.
+        \see GenericStringRef
+    */
+    GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+        return (*this).template PushBack<StringRefType>(value, allocator);
+    }
+
+    //! Append a primitive value at the end of the array.
+    /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+        \param value Value of primitive type T to be appended.
+        \param allocator    Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
+        \pre IsArray() == true
+        \return The value itself for fluent API.
+        \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
+
+        \note The source type \c T explicitly disallows all pointer types,
+            especially (\c const) \ref Ch*.  This helps avoiding implicitly
+            referencing character strings with insufficient lifetime, use
+            \ref PushBack(GenericValue&, Allocator&) or \ref
+            PushBack(StringRefType, Allocator&).
+            All other pointer types would implicitly convert to \c bool,
+            use an explicit cast instead, if needed.
+        \note Amortized constant time complexity.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
+    PushBack(T value, Allocator& allocator) {
+        GenericValue v(value);
+        return PushBack(v, allocator);
+    }
+
+    //! Remove the last element in the array.
+    /*!
+        \note Constant time complexity.
+    */
+    GenericValue& PopBack() {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(!Empty());
+        GetElementsPointer()[--data_.a.size].~GenericValue();
+        return *this;
+    }
+
+    //! Remove an element of array by iterator.
+    /*!
+        \param pos iterator to the element to remove
+        \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+        \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
+        \note Linear time complexity.
+    */
+    ValueIterator Erase(ConstValueIterator pos) {
+        return Erase(pos, pos + 1);
+    }
+
+    //! Remove elements in the range [first, last) of the array.
+    /*!
+        \param first iterator to the first element to remove
+        \param last  iterator following the last element to remove
+        \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
+        \return Iterator following the last removed element.
+        \note Linear time complexity.
+    */
+    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+        RAPIDJSON_ASSERT(IsArray());
+        RAPIDJSON_ASSERT(data_.a.size > 0);
+        RAPIDJSON_ASSERT(GetElementsPointer() != 0);
+        RAPIDJSON_ASSERT(first >= Begin());
+        RAPIDJSON_ASSERT(first <= last);
+        RAPIDJSON_ASSERT(last <= End());
+        ValueIterator pos = Begin() + (first - Begin());
+        for (ValueIterator itr = pos; itr != last; ++itr)
+            itr->~GenericValue();       
+        std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
+        data_.a.size -= static_cast<SizeType>(last - first);
+        return pos;
+    }
+
+    Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
+    ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
+
+    //@}
+
+    //!@name Number
+    //@{
+
+    int GetInt() const          { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag);   return data_.n.i.i;   }
+    unsigned GetUint() const    { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag);  return data_.n.u.u;   }
+    int64_t GetInt64() const    { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
+    uint64_t GetUint64() const  { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
+
+    //! Get the value as double type.
+    /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
+    */
+    double GetDouble() const {
+        RAPIDJSON_ASSERT(IsNumber());
+        if ((data_.f.flags & kDoubleFlag) != 0)                return data_.n.d;   // exact type, no conversion.
+        if ((data_.f.flags & kIntFlag) != 0)                   return data_.n.i.i; // int -> double
+        if ((data_.f.flags & kUintFlag) != 0)                  return data_.n.u.u; // unsigned -> double
+        if ((data_.f.flags & kInt64Flag) != 0)                 return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
+        RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0);  return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
+    }
+
+    //! Get the value as float type.
+    /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
+    */
+    float GetFloat() const {
+        return static_cast<float>(GetDouble());
+    }
+
+    GenericValue& SetInt(int i)             { this->~GenericValue(); new (this) GenericValue(i);    return *this; }
+    GenericValue& SetUint(unsigned u)       { this->~GenericValue(); new (this) GenericValue(u);    return *this; }
+    GenericValue& SetInt64(int64_t i64)     { this->~GenericValue(); new (this) GenericValue(i64);  return *this; }
+    GenericValue& SetUint64(uint64_t u64)   { this->~GenericValue(); new (this) GenericValue(u64);  return *this; }
+    GenericValue& SetDouble(double d)       { this->~GenericValue(); new (this) GenericValue(d);    return *this; }
+    GenericValue& SetFloat(float f)         { this->~GenericValue(); new (this) GenericValue(f);    return *this; }
+
+    //@}
+
+    //!@name String
+    //@{
+
+    const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
+
+    //! Get the length of string.
+    /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
+    */
+    SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
+
+    //! Set this value as a string without copying source string.
+    /*! This version has better performance with supplied length, and also support string containing null character.
+        \param s source string pointer. 
+        \param length The length of source string, excluding the trailing null terminator.
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() == s && GetStringLength() == length
+        \see SetString(StringRefType)
+    */
+    GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
+
+    //! Set this value as a string without copying source string.
+    /*! \param s source string reference
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() == s && GetStringLength() == s.length
+    */
+    GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
+
+    //! Set this value as a string by copying from source string.
+    /*! This version has better performance with supplied length, and also support string containing null character.
+        \param s source string. 
+        \param length The length of source string, excluding the trailing null terminator.
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+    */
+    GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
+
+    //! Set this value as a string by copying from source string.
+    /*! \param s source string. 
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
+    */
+    GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Set this value as a string by copying from source string.
+    /*! \param s source string.
+        \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
+        \return The value itself for fluent API.
+        \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
+        \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+    */
+    GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
+#endif
+
+    //@}
+
+    //!@name Array
+    //@{
+
+    //! Templated version for checking whether this value is type T.
+    /*!
+        \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
+    */
+    template <typename T>
+    bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
+
+    template <typename T>
+    T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
+
+    template <typename T>
+    T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
+
+    template<typename T>
+    ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
+
+    template<typename T>
+    ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
+
+    //@}
+
+    //! Generate events of this value to a Handler.
+    /*! This function adopts the GoF visitor pattern.
+        Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
+        It can also be used to deep clone this value via GenericDocument, which is also a Handler.
+        \tparam Handler type of handler.
+        \param handler An object implementing concept Handler.
+    */
+    template <typename Handler>
+    bool Accept(Handler& handler) const {
+        switch(GetType()) {
+        case kNullType:     return handler.Null();
+        case kFalseType:    return handler.Bool(false);
+        case kTrueType:     return handler.Bool(true);
+
+        case kObjectType:
+            if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+                return false;
+            for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+                RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
+                if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
+                    return false;
+                if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
+                    return false;
+            }
+            return handler.EndObject(data_.o.size);
+
+        case kArrayType:
+            if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+                return false;
+            for (const GenericValue* v = Begin(); v != End(); ++v)
+                if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
+                    return false;
+            return handler.EndArray(data_.a.size);
+    
+        case kStringType:
+            return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
+    
+        default:
+            RAPIDJSON_ASSERT(GetType() == kNumberType);
+            if (IsDouble())         return handler.Double(data_.n.d);
+            else if (IsInt())       return handler.Int(data_.n.i.i);
+            else if (IsUint())      return handler.Uint(data_.n.u.u);
+            else if (IsInt64())     return handler.Int64(data_.n.i64);
+            else                    return handler.Uint64(data_.n.u64);
+        }
+    }
+
+private:
+    template <typename, typename> friend class GenericValue;
+    template <typename, typename, typename> friend class GenericDocument;
+
+    enum {
+        kBoolFlag       = 0x0008,
+        kNumberFlag     = 0x0010,
+        kIntFlag        = 0x0020,
+        kUintFlag       = 0x0040,
+        kInt64Flag      = 0x0080,
+        kUint64Flag     = 0x0100,
+        kDoubleFlag     = 0x0200,
+        kStringFlag     = 0x0400,
+        kCopyFlag       = 0x0800,
+        kInlineStrFlag  = 0x1000,
+
+        // Initial flags of different types.
+        kNullFlag = kNullType,
+        kTrueFlag = kTrueType | kBoolFlag,
+        kFalseFlag = kFalseType | kBoolFlag,
+        kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+        kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+        kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+        kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+        kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+        kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
+        kConstStringFlag = kStringType | kStringFlag,
+        kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+        kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+        kObjectFlag = kObjectType,
+        kArrayFlag = kArrayType,
+
+        kTypeMask = 0x07
+    };
+
+    static const SizeType kDefaultArrayCapacity = 16;
+    static const SizeType kDefaultObjectCapacity = 16;
+
+    struct Flag {
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
+        char payload[sizeof(SizeType) * 2 + 6];     // 2 x SizeType + lower 48-bit pointer
+#elif RAPIDJSON_64BIT
+        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
+#else
+        char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
+#endif
+        uint16_t flags;
+    };
+
+    struct String {
+        SizeType length;
+        SizeType hashcode;  //!< reserved
+        const Ch* str;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
+    // (excluding the terminating zero) and store a value to determine the length of the contained
+    // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
+    // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
+    // the string terminator as well. For getting the string length back from that value just use
+    // "MaxSize - str[LenPos]".
+    // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
+    // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
+    struct ShortString {
+        enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
+        Ch str[MaxChars];
+
+        inline static bool Usable(SizeType len) { return                       (MaxSize >= len); }
+        inline void     SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize -  len); }
+        inline SizeType GetLength() const       { return  static_cast<SizeType>(MaxSize -  str[LenPos]); }
+    };  // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    // By using proper binary layout, retrieval of different integer types do not need conversions.
+    union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+        struct I {
+            int i;
+            char padding[4];
+        }i;
+        struct U {
+            unsigned u;
+            char padding2[4];
+        }u;
+#else
+        struct I {
+            char padding[4];
+            int i;
+        }i;
+        struct U {
+            char padding2[4];
+            unsigned u;
+        }u;
+#endif
+        int64_t i64;
+        uint64_t u64;
+        double d;
+    };  // 8 bytes
+
+    struct ObjectData {
+        SizeType size;
+        SizeType capacity;
+        Member* members;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    struct ArrayData {
+        SizeType size;
+        SizeType capacity;
+        GenericValue* elements;
+    };  // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+    union Data {
+        String s;
+        ShortString ss;
+        Number n;
+        ObjectData o;
+        ArrayData a;
+        Flag f;
+    };  // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+    RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
+    RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
+    RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
+    RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
+    RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
+    RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
+
+    // Initialize this value as array with initial data, without calling destructor.
+    void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+        data_.f.flags = kArrayFlag;
+        if (count) {
+            GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
+            SetElementsPointer(e);
+            std::memcpy(e, values, count * sizeof(GenericValue));
+        }
+        else
+            SetElementsPointer(0);
+        data_.a.size = data_.a.capacity = count;
+    }
+
+    //! Initialize this value as object with initial data, without calling destructor.
+    void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+        data_.f.flags = kObjectFlag;
+        if (count) {
+            Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+            SetMembersPointer(m);
+            std::memcpy(m, members, count * sizeof(Member));
+        }
+        else
+            SetMembersPointer(0);
+        data_.o.size = data_.o.capacity = count;
+    }
+
+    //! Initialize this value as constant string, without calling destructor.
+    void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+        data_.f.flags = kConstStringFlag;
+        SetStringPointer(s);
+        data_.s.length = s.length;
+    }
+
+    //! Initialize this value as copy string with initial data, without calling destructor.
+    void SetStringRaw(StringRefType s, Allocator& allocator) {
+        Ch* str = 0;
+        if (ShortString::Usable(s.length)) {
+            data_.f.flags = kShortStringFlag;
+            data_.ss.SetLength(s.length);
+            str = data_.ss.str;
+        } else {
+            data_.f.flags = kCopyStringFlag;
+            data_.s.length = s.length;
+            str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
+            SetStringPointer(str);
+        }
+        std::memcpy(str, s, s.length * sizeof(Ch));
+        str[s.length] = '\0';
+    }
+
+    //! Assignment without calling destructor
+    void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+        data_ = rhs.data_;
+        // data_.f.flags = rhs.data_.f.flags;
+        rhs.data_.f.flags = kNullFlag;
+    }
+
+    template <typename SourceAllocator>
+    bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+        RAPIDJSON_ASSERT(IsString());
+        RAPIDJSON_ASSERT(rhs.IsString());
+
+        const SizeType len1 = GetStringLength();
+        const SizeType len2 = rhs.GetStringLength();
+        if(len1 != len2) { return false; }
+
+        const Ch* const str1 = GetString();
+        const Ch* const str2 = rhs.GetString();
+        if(str1 == str2) { return true; } // fast path for constant string
+
+        return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+    }
+
+    Data data_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument 
+
+//! A document for parsing JSON text as DOM.
+/*!
+    \note implements Handler concept
+    \tparam Encoding Encoding for both parsing and string storage.
+    \tparam Allocator Allocator for allocating memory for the DOM
+    \tparam StackAllocator Allocator for allocating memory for stack during parsing.
+    \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor.  To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+public:
+    typedef typename Encoding::Ch Ch;                       //!< Character type derived from Encoding.
+    typedef GenericValue<Encoding, Allocator> ValueType;    //!< Value type of the document.
+    typedef Allocator AllocatorType;                        //!< Allocator type from template parameter.
+
+    //! Constructor
+    /*! Creates an empty document of specified type.
+        \param type             Mandatory type of object to create.
+        \param allocator        Optional allocator for allocating memory.
+        \param stackCapacity    Optional initial capacity of stack in bytes.
+        \param stackAllocator   Optional allocator for allocating memory for stack.
+    */
+    explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
+        GenericValue<Encoding, Allocator>(type),  allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+    {
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+    }
+
+    //! Constructor
+    /*! Creates an empty document which type is Null. 
+        \param allocator        Optional allocator for allocating memory.
+        \param stackCapacity    Optional initial capacity of stack in bytes.
+        \param stackAllocator   Optional allocator for allocating memory for stack.
+    */
+    GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) : 
+        allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
+    {
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move constructor in C++11
+    GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+        : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
+          allocator_(rhs.allocator_),
+          ownAllocator_(rhs.ownAllocator_),
+          stack_(std::move(rhs.stack_)),
+          parseResult_(rhs.parseResult_)
+    {
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.parseResult_ = ParseResult();
+    }
+#endif
+
+    ~GenericDocument() {
+        Destroy();
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move assignment in C++11
+    GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+    {
+        // The cast to ValueType is necessary here, because otherwise it would
+        // attempt to call GenericValue's templated assignment operator.
+        ValueType::operator=(std::forward<ValueType>(rhs));
+
+        // Calling the destructor here would prematurely call stack_'s destructor
+        Destroy();
+
+        allocator_ = rhs.allocator_;
+        ownAllocator_ = rhs.ownAllocator_;
+        stack_ = std::move(rhs.stack_);
+        parseResult_ = rhs.parseResult_;
+
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.parseResult_ = ParseResult();
+
+        return *this;
+    }
+#endif
+
+    //! Exchange the contents of this document with those of another.
+    /*!
+        \param rhs Another document.
+        \note Constant complexity.
+        \see GenericValue::Swap
+    */
+    GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
+        ValueType::Swap(rhs);
+        stack_.Swap(rhs.stack_);
+        internal::Swap(allocator_, rhs.allocator_);
+        internal::Swap(ownAllocator_, rhs.ownAllocator_);
+        internal::Swap(parseResult_, rhs.parseResult_);
+        return *this;
+    }
+
+    //! free-standing swap function helper
+    /*!
+        Helper function to enable support for common swap implementation pattern based on \c std::swap:
+        \code
+        void swap(MyClass& a, MyClass& b) {
+            using std::swap;
+            swap(a.doc, b.doc);
+            // ...
+        }
+        \endcode
+        \see Swap()
+     */
+    friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
+
+    //! Populate this document by a generator which produces SAX events.
+    /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
+        \param g Generator functor which sends SAX events to the parameter.
+        \return The document itself for fluent API.
+    */
+    template <typename Generator>
+    GenericDocument& Populate(Generator& g) {
+        ClearStackOnExit scope(*this);
+        if (g(*this)) {
+            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+        }
+        return *this;
+    }
+
+    //!@name Parse from stream
+    //!@{
+
+    //! Parse JSON text from an input stream (with Encoding conversion)
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \tparam SourceEncoding Encoding of input stream
+        \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
+            stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+        ClearStackOnExit scope(*this);
+        parseResult_ = reader.template Parse<parseFlags>(is, *this);
+        if (parseResult_) {
+            RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
+            ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
+        }
+        return *this;
+    }
+
+    //! Parse JSON text from an input stream
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags, typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        return ParseStream<parseFlags, Encoding, InputStream>(is);
+    }
+
+    //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+    /*! \tparam InputStream Type of input stream, implementing Stream concept
+        \param is Input stream to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <typename InputStream>
+    GenericDocument& ParseStream(InputStream& is) {
+        return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+    }
+    //!@}
+
+    //!@name Parse in-place from mutable string
+    //!@{
+
+    //! Parse JSON text from a mutable string
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \param str Mutable zero-terminated string to be parsed.
+        \return The document itself for fluent API.
+    */
+    template <unsigned parseFlags>
+    GenericDocument& ParseInsitu(Ch* str) {
+        GenericInsituStringStream<Encoding> s(str);
+        return ParseStream<parseFlags | kParseInsituFlag>(s);
+    }
+
+    //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+    /*! \param str Mutable zero-terminated string to be parsed.
+        \return The document itself for fluent API.
+    */
+    GenericDocument& ParseInsitu(Ch* str) {
+        return ParseInsitu<kParseDefaultFlags>(str);
+    }
+    //!@}
+
+    //!@name Parse from read-only string
+    //!@{
+
+    //! Parse JSON text from a read-only string (with Encoding conversion)
+    /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+        \tparam SourceEncoding Transcoding from input Encoding
+        \param str Read-only zero-terminated string to be parsed.
+    */
+    template <unsigned parseFlags, typename SourceEncoding>
+    GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
+        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+        GenericStringStream<SourceEncoding> s(str);
+        return ParseStream<parseFlags, SourceEncoding>(s);
+    }
+
+    //! Parse JSON text from a read-only string
+    /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
+        \param str Read-only zero-terminated string to be parsed.
+    */
+    template <unsigned parseFlags>
+    GenericDocument& Parse(const Ch* str) {
+        return Parse<parseFlags, Encoding>(str);
+    }
+
+    //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+    /*! \param str Read-only zero-terminated string to be parsed.
+    */
+    GenericDocument& Parse(const Ch* str) {
+        return Parse<kParseDefaultFlags>(str);
+    }
+
+    template <unsigned parseFlags, typename SourceEncoding>
+    GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
+        RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+        MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
+        EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
+        ParseStream<parseFlags, SourceEncoding>(is);
+        return *this;
+    }
+
+    template <unsigned parseFlags>
+    GenericDocument& Parse(const Ch* str, size_t length) {
+        return Parse<parseFlags, Encoding>(str, length);
+    }
+    
+    GenericDocument& Parse(const Ch* str, size_t length) {
+        return Parse<kParseDefaultFlags>(str, length);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    template <unsigned parseFlags, typename SourceEncoding>
+    GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {
+        // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)
+        return Parse<parseFlags, SourceEncoding>(str.c_str());
+    }
+
+    template <unsigned parseFlags>
+    GenericDocument& Parse(const std::basic_string<Ch>& str) {
+        return Parse<parseFlags, Encoding>(str.c_str());
+    }
+
+    GenericDocument& Parse(const std::basic_string<Ch>& str) {
+        return Parse<kParseDefaultFlags>(str);
+    }
+#endif // RAPIDJSON_HAS_STDSTRING    
+
+    //!@}
+
+    //!@name Handling parse errors
+    //!@{
+
+    //! Whether a parse error has occured in the last parsing.
+    bool HasParseError() const { return parseResult_.IsError(); }
+
+    //! Get the \ref ParseErrorCode of last parsing.
+    ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+    //! Get the position of last parsing error in input, 0 otherwise.
+    size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+    //! Implicit conversion to get the last parse result
+#ifndef __clang // -Wdocumentation
+    /*! \return \ref ParseResult of the last parse operation
+
+        \code
+          Document doc;
+          ParseResult ok = doc.Parse(json);
+          if (!ok)
+            printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
+        \endcode
+     */
+#endif
+    operator ParseResult() const { return parseResult_; }
+    //!@}
+
+    //! Get the allocator of this document.
+    Allocator& GetAllocator() {
+        RAPIDJSON_ASSERT(allocator_);
+        return *allocator_;
+    }
+
+    //! Get the capacity of stack in bytes.
+    size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+private:
+    // clear stack on any exit from ParseStream, e.g. due to exception
+    struct ClearStackOnExit {
+        explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+        ~ClearStackOnExit() { d_.ClearStack(); }
+    private:
+        ClearStackOnExit(const ClearStackOnExit&);
+        ClearStackOnExit& operator=(const ClearStackOnExit&);
+        GenericDocument& d_;
+    };
+
+    // callers of the following private Handler functions
+    // template <typename,typename,typename> friend class GenericReader; // for parsing
+    template <typename, typename> friend class GenericValue; // for deep copying
+
+public:
+    // Implementation of Handler
+    bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
+    bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
+    bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
+    bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
+
+    bool RawNumber(const Ch* str, SizeType length, bool copy) { 
+        if (copy) 
+            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+        else
+            new (stack_.template Push<ValueType>()) ValueType(str, length);
+        return true;
+    }
+
+    bool String(const Ch* str, SizeType length, bool copy) { 
+        if (copy) 
+            new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
+        else
+            new (stack_.template Push<ValueType>()) ValueType(str, length);
+        return true;
+    }
+
+    bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
+    
+    bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
+
+    bool EndObject(SizeType memberCount) {
+        typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
+        stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
+        return true;
+    }
+
+    bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
+    
+    bool EndArray(SizeType elementCount) {
+        ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+        stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
+        return true;
+    }
+
+private:
+    //! Prohibit copying
+    GenericDocument(const GenericDocument&);
+    //! Prohibit assignment
+    GenericDocument& operator=(const GenericDocument&);
+
+    void ClearStack() {
+        if (Allocator::kNeedFree)
+            while (stack_.GetSize() > 0)    // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
+                (stack_.template Pop<ValueType>(1))->~ValueType();
+        else
+            stack_.Clear();
+        stack_.ShrinkToFit();
+    }
+
+    void Destroy() {
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    static const size_t kDefaultStackCapacity = 1024;
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    internal::Stack<StackAllocator> stack_;
+    ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline
+GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
+{
+    switch (rhs.GetType()) {
+    case kObjectType:
+    case kArrayType: { // perform deep copy via SAX Handler
+            GenericDocument<Encoding,Allocator> d(&allocator);
+            rhs.Accept(d);
+            RawAssign(*d.stack_.template Pop<GenericValue>(1));
+        }
+        break;
+    case kStringType:
+        if (rhs.data_.f.flags == kConstStringFlag) {
+            data_.f.flags = rhs.data_.f.flags;
+            data_  = *reinterpret_cast<const Data*>(&rhs.data_);
+        } else {
+            SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
+        }
+        break;
+    default:
+        data_.f.flags = rhs.data_.f.flags;
+        data_  = *reinterpret_cast<const Data*>(&rhs.data_);
+        break;
+    }
+}
+
+//! Helper class for accessing Value of array type.
+/*!
+    Instance of this helper class is obtained by \c GenericValue::GetArray().
+    In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericArray {
+public:
+    typedef GenericArray<true, ValueT> ConstArray;
+    typedef GenericArray<false, ValueT> Array;
+    typedef ValueT PlainType;
+    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+    typedef ValueType* ValueIterator;  // This may be const or non-const iterator
+    typedef const ValueT* ConstValueIterator;
+    typedef typename ValueType::AllocatorType AllocatorType;
+    typedef typename ValueType::StringRefType StringRefType;
+
+    template <typename, typename>
+    friend class GenericValue;
+
+    GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
+    GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
+    ~GenericArray() {}
+
+    SizeType Size() const { return value_.Size(); }
+    SizeType Capacity() const { return value_.Capacity(); }
+    bool Empty() const { return value_.Empty(); }
+    void Clear() const { value_.Clear(); }
+    ValueType& operator[](SizeType index) const {  return value_[index]; }
+    ValueIterator Begin() const { return value_.Begin(); }
+    ValueIterator End() const { return value_.End(); }
+    GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
+    GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
+    GenericArray PopBack() const { value_.PopBack(); return *this; }
+    ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
+    ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+    ValueIterator begin() const { return value_.Begin(); }
+    ValueIterator end() const { return value_.End(); }
+#endif
+
+private:
+    GenericArray();
+    GenericArray(ValueType& value) : value_(value) {}
+    ValueType& value_;
+};
+
+//! Helper class for accessing Value of object type.
+/*!
+    Instance of this helper class is obtained by \c GenericValue::GetObject().
+    In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericObject {
+public:
+    typedef GenericObject<true, ValueT> ConstObject;
+    typedef GenericObject<false, ValueT> Object;
+    typedef ValueT PlainType;
+    typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
+    typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator;  // This may be const or non-const iterator
+    typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
+    typedef typename ValueType::AllocatorType AllocatorType;
+    typedef typename ValueType::StringRefType StringRefType;
+    typedef typename ValueType::EncodingType EncodingType;
+    typedef typename ValueType::Ch Ch;
+
+    template <typename, typename>
+    friend class GenericValue;
+
+    GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
+    GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
+    ~GenericObject() {}
+
+    SizeType MemberCount() const { return value_.MemberCount(); }
+    bool ObjectEmpty() const { return value_.ObjectEmpty(); }
+    template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
+    template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
+#if RAPIDJSON_HAS_STDSTRING
+    ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
+#endif
+    MemberIterator MemberBegin() const { return value_.MemberBegin(); }
+    MemberIterator MemberEnd() const { return value_.MemberEnd(); }
+    bool HasMember(const Ch* name) const { return value_.HasMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+    bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
+#endif
+    template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
+    MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }
+    template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+    MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
+#endif
+    GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#if RAPIDJSON_HAS_STDSTRING
+    GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#endif
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
+    void RemoveAllMembers() { return value_.RemoveAllMembers(); }
+    bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+    bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
+#endif
+    template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
+    MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
+    MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
+    MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
+    bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+    bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
+#endif
+    template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+    MemberIterator begin() const { return value_.MemberBegin(); }
+    MemberIterator end() const { return value_.MemberEnd(); }
+#endif
+
+private:
+    GenericObject();
+    GenericObject(ValueType& value) : value_(value) {}
+    ValueType& value_;
+};
+
+RAPIDJSON_NAMESPACE_END
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/core/deps/rapidjson/encodedstream.h b/core/deps/rapidjson/encodedstream.h
new file mode 100644 (file)
index 0000000..1450683
--- /dev/null
@@ -0,0 +1,299 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODEDSTREAM_H_
+#define RAPIDJSON_ENCODEDSTREAM_H_
+
+#include "stream.h"
+#include "memorystream.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Input byte stream wrapper with a statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam InputByteStream Type of input byte stream. For example, FileReadStream.
+*/
+template <typename Encoding, typename InputByteStream>
+class EncodedInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedInputStream(InputByteStream& is) : is_(is) { 
+        current_ = Encoding::TakeBOM(is_);
+    }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = Encoding::Take(is_); return c; }
+    size_t Tell() const { return is_.Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedInputStream(const EncodedInputStream&);
+    EncodedInputStream& operator=(const EncodedInputStream&);
+
+    InputByteStream& is_;
+    Ch current_;
+};
+
+//! Specialized for UTF8 MemoryStream.
+template <>
+class EncodedInputStream<UTF8<>, MemoryStream> {
+public:
+    typedef UTF8<>::Ch Ch;
+
+    EncodedInputStream(MemoryStream& is) : is_(is) {
+        if (static_cast<unsigned char>(is_.Peek()) == 0xEFu) is_.Take();
+        if (static_cast<unsigned char>(is_.Peek()) == 0xBBu) is_.Take();
+        if (static_cast<unsigned char>(is_.Peek()) == 0xBFu) is_.Take();
+    }
+    Ch Peek() const { return is_.Peek(); }
+    Ch Take() { return is_.Take(); }
+    size_t Tell() const { return is_.Tell(); }
+
+    // Not implemented
+    void Put(Ch) {}
+    void Flush() {} 
+    Ch* PutBegin() { return 0; }
+    size_t PutEnd(Ch*) { return 0; }
+
+    MemoryStream& is_;
+
+private:
+    EncodedInputStream(const EncodedInputStream&);
+    EncodedInputStream& operator=(const EncodedInputStream&);
+};
+
+//! Output byte stream wrapper with statically bound encoding.
+/*!
+    \tparam Encoding The interpretation of encoding of the stream. Either UTF8, UTF16LE, UTF16BE, UTF32LE, UTF32BE.
+    \tparam OutputByteStream Type of input byte stream. For example, FileWriteStream.
+*/
+template <typename Encoding, typename OutputByteStream>
+class EncodedOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef typename Encoding::Ch Ch;
+
+    EncodedOutputStream(OutputByteStream& os, bool putBOM = true) : os_(os) { 
+        if (putBOM)
+            Encoding::PutBOM(os_);
+    }
+
+    void Put(Ch c) { Encoding::Put(os_, c);  }
+    void Flush() { os_.Flush(); }
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false);  return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    EncodedOutputStream(const EncodedOutputStream&);
+    EncodedOutputStream& operator=(const EncodedOutputStream&);
+
+    OutputByteStream& os_;
+};
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+//! Input stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for reading.
+    \tparam InputByteStream type of input byte stream to be wrapped.
+*/
+template <typename CharType, typename InputByteStream>
+class AutoUTFInputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param is input stream to be wrapped.
+        \param type UTF encoding type if it is not detected from the stream.
+    */
+    AutoUTFInputStream(InputByteStream& is, UTFType type = kUTF8) : is_(&is), type_(type), hasBOM_(false) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);        
+        DetectType();
+        static const TakeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Take) };
+        takeFunc_ = f[type_];
+        current_ = takeFunc_(*is_);
+    }
+
+    UTFType GetType() const { return type_; }
+    bool HasBOM() const { return hasBOM_; }
+
+    Ch Peek() const { return current_; }
+    Ch Take() { Ch c = current_; current_ = takeFunc_(*is_); return c; }
+    size_t Tell() const { return is_->Tell(); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFInputStream(const AutoUTFInputStream&);
+    AutoUTFInputStream& operator=(const AutoUTFInputStream&);
+
+    // Detect encoding type with BOM or RFC 4627
+    void DetectType() {
+        // BOM (Byte Order Mark):
+        // 00 00 FE FF  UTF-32BE
+        // FF FE 00 00  UTF-32LE
+        // FE FF        UTF-16BE
+        // FF FE        UTF-16LE
+        // EF BB BF     UTF-8
+
+        const unsigned char* c = reinterpret_cast<const unsigned char *>(is_->Peek4());
+        if (!c)
+            return;
+
+        unsigned bom = static_cast<unsigned>(c[0] | (c[1] << 8) | (c[2] << 16) | (c[3] << 24));
+        hasBOM_ = false;
+        if (bom == 0xFFFE0000)                  { type_ = kUTF32BE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if (bom == 0x0000FEFF)             { type_ = kUTF32LE; hasBOM_ = true; is_->Take(); is_->Take(); is_->Take(); is_->Take(); }
+        else if ((bom & 0xFFFF) == 0xFFFE)      { type_ = kUTF16BE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFF) == 0xFEFF)      { type_ = kUTF16LE; hasBOM_ = true; is_->Take(); is_->Take();                           }
+        else if ((bom & 0xFFFFFF) == 0xBFBBEF)  { type_ = kUTF8;    hasBOM_ = true; is_->Take(); is_->Take(); is_->Take();              }
+
+        // RFC 4627: Section 3
+        // "Since the first two characters of a JSON text will always be ASCII
+        // characters [RFC0020], it is possible to determine whether an octet
+        // stream is UTF-8, UTF-16 (BE or LE), or UTF-32 (BE or LE) by looking
+        // at the pattern of nulls in the first four octets."
+        // 00 00 00 xx  UTF-32BE
+        // 00 xx 00 xx  UTF-16BE
+        // xx 00 00 00  UTF-32LE
+        // xx 00 xx 00  UTF-16LE
+        // xx xx xx xx  UTF-8
+
+        if (!hasBOM_) {
+            unsigned pattern = (c[0] ? 1 : 0) | (c[1] ? 2 : 0) | (c[2] ? 4 : 0) | (c[3] ? 8 : 0);
+            switch (pattern) {
+            case 0x08: type_ = kUTF32BE; break;
+            case 0x0A: type_ = kUTF16BE; break;
+            case 0x01: type_ = kUTF32LE; break;
+            case 0x05: type_ = kUTF16LE; break;
+            case 0x0F: type_ = kUTF8;    break;
+            default: break; // Use type defined by user.
+            }
+        }
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+    }
+
+    typedef Ch (*TakeFunc)(InputByteStream& is);
+    InputByteStream* is_;
+    UTFType type_;
+    Ch current_;
+    TakeFunc takeFunc_;
+    bool hasBOM_;
+};
+
+//! Output stream wrapper with dynamically bound encoding and automatic encoding detection.
+/*!
+    \tparam CharType Type of character for writing.
+    \tparam OutputByteStream type of output byte stream to be wrapped.
+*/
+template <typename CharType, typename OutputByteStream>
+class AutoUTFOutputStream {
+    RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+public:
+    typedef CharType Ch;
+
+    //! Constructor.
+    /*!
+        \param os output stream to be wrapped.
+        \param type UTF encoding type.
+        \param putBOM Whether to write BOM at the beginning of the stream.
+    */
+    AutoUTFOutputStream(OutputByteStream& os, UTFType type, bool putBOM) : os_(&os), type_(type) {
+        RAPIDJSON_ASSERT(type >= kUTF8 && type <= kUTF32BE);
+
+        // Runtime check whether the size of character type is sufficient. It only perform checks with assertion.
+        if (type_ == kUTF16LE || type_ == kUTF16BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 2);
+        if (type_ == kUTF32LE || type_ == kUTF32BE) RAPIDJSON_ASSERT(sizeof(Ch) >= 4);
+
+        static const PutFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Put) };
+        putFunc_ = f[type_];
+
+        if (putBOM)
+            PutBOM();
+    }
+
+    UTFType GetType() const { return type_; }
+
+    void Put(Ch c) { putFunc_(*os_, c); }
+    void Flush() { os_->Flush(); } 
+
+    // Not implemented
+    Ch Peek() const { RAPIDJSON_ASSERT(false); return 0;}
+    Ch Take() { RAPIDJSON_ASSERT(false); return 0;}
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    AutoUTFOutputStream(const AutoUTFOutputStream&);
+    AutoUTFOutputStream& operator=(const AutoUTFOutputStream&);
+
+    void PutBOM() { 
+        typedef void (*PutBOMFunc)(OutputByteStream&);
+        static const PutBOMFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(PutBOM) };
+        f[type_](*os_);
+    }
+
+    typedef void (*PutFunc)(OutputByteStream&, Ch);
+
+    OutputByteStream* os_;
+    UTFType type_;
+    PutFunc putFunc_;
+};
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/core/deps/rapidjson/encodings.h b/core/deps/rapidjson/encodings.h
new file mode 100644 (file)
index 0000000..baa7c2b
--- /dev/null
@@ -0,0 +1,716 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ENCODINGS_H_
+#define RAPIDJSON_ENCODINGS_H_
+
+#include "rapidjson.h"
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4244) // conversion from 'type1' to 'type2', possible loss of data
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+#elif defined(__GNUC__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(overflow)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Encoding
+
+/*! \class rapidjson::Encoding
+    \brief Concept for encoding of Unicode characters.
+
+\code
+concept Encoding {
+    typename Ch;    //! Type of character. A "character" is actually a code unit in unicode's definition.
+
+    enum { supportUnicode = 1 }; // or 0 if not supporting unicode
+
+    //! \brief Encode a Unicode codepoint to an output stream.
+    //! \param os Output stream.
+    //! \param codepoint An unicode codepoint, ranging from 0x0 to 0x10FFFF inclusively.
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint);
+
+    //! \brief Decode a Unicode codepoint from an input stream.
+    //! \param is Input stream.
+    //! \param codepoint Output of the unicode codepoint.
+    //! \return true if a valid codepoint can be decoded from the stream.
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint);
+
+    //! \brief Validate one Unicode codepoint from an encoded stream.
+    //! \param is Input stream to obtain codepoint.
+    //! \param os Output for copying one codepoint.
+    //! \return true if it is valid.
+    //! \note This function just validating and copying the codepoint without actually decode it.
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os);
+
+    // The following functions are deal with byte streams.
+
+    //! Take a character from input byte stream, skip BOM if exist.
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is);
+
+    //! Take a character from input byte stream.
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is);
+
+    //! Put BOM to output byte stream.
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os);
+
+    //! Put a character to output byte stream.
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c);
+};
+\endcode
+*/
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF8
+
+//! UTF-8 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-8
+    http://tools.ietf.org/html/rfc3629
+    \tparam CharType Code unit for storing 8-bit UTF-8 data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct UTF8 {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        if (codepoint <= 0x7F) 
+            os.Put(static_cast<Ch>(codepoint & 0xFF));
+        else if (codepoint <= 0x7FF) {
+            os.Put(static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+        }
+        else if (codepoint <= 0xFFFF) {
+            os.Put(static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            os.Put(static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            os.Put(static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        if (codepoint <= 0x7F) 
+            PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+        else if (codepoint <= 0x7FF) {
+            PutUnsafe(os, static_cast<Ch>(0xC0 | ((codepoint >> 6) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint & 0x3F))));
+        }
+        else if (codepoint <= 0xFFFF) {
+            PutUnsafe(os, static_cast<Ch>(0xE0 | ((codepoint >> 12) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            PutUnsafe(os, static_cast<Ch>(0xF0 | ((codepoint >> 18) & 0xFF)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 12) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | ((codepoint >> 6) & 0x3F)));
+            PutUnsafe(os, static_cast<Ch>(0x80 | (codepoint & 0x3F)));
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+#define COPY() c = is.Take(); *codepoint = (*codepoint << 6) | (static_cast<unsigned char>(c) & 0x3Fu)
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+        typename InputStream::Ch c = is.Take();
+        if (!(c & 0x80)) {
+            *codepoint = static_cast<unsigned char>(c);
+            return true;
+        }
+
+        unsigned char type = GetRange(static_cast<unsigned char>(c));
+        if (type >= 32) {
+            *codepoint = 0;
+        } else {
+            *codepoint = (0xFF >> type) & static_cast<unsigned char>(c);
+        }
+        bool result = true;
+        switch (type) {
+        case 2: TAIL(); return result;
+        case 3: TAIL(); TAIL(); return result;
+        case 4: COPY(); TRANS(0x50); TAIL(); return result;
+        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+        case 6: TAIL(); TAIL(); TAIL(); return result;
+        case 10: COPY(); TRANS(0x20); TAIL(); return result;
+        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+        default: return false;
+        }
+#undef COPY
+#undef TRANS
+#undef TAIL
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+#define COPY() os.Put(c = is.Take())
+#define TRANS(mask) result &= ((GetRange(static_cast<unsigned char>(c)) & mask) != 0)
+#define TAIL() COPY(); TRANS(0x70)
+        Ch c;
+        COPY();
+        if (!(c & 0x80))
+            return true;
+
+        bool result = true;
+        switch (GetRange(static_cast<unsigned char>(c))) {
+        case 2: TAIL(); return result;
+        case 3: TAIL(); TAIL(); return result;
+        case 4: COPY(); TRANS(0x50); TAIL(); return result;
+        case 5: COPY(); TRANS(0x10); TAIL(); TAIL(); return result;
+        case 6: TAIL(); TAIL(); TAIL(); return result;
+        case 10: COPY(); TRANS(0x20); TAIL(); return result;
+        case 11: COPY(); TRANS(0x60); TAIL(); TAIL(); return result;
+        default: return false;
+        }
+#undef COPY
+#undef TRANS
+#undef TAIL
+    }
+
+    static unsigned char GetRange(unsigned char c) {
+        // Referring to DFA of http://bjoern.hoehrmann.de/utf-8/decoder/dfa/
+        // With new mapping 1 -> 0x10, 7 -> 0x20, 9 -> 0x40, such that AND operation can test multiple types.
+        static const unsigned char type[] = {
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,  0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+            0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,
+            0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,
+            8,8,2,2,2,2,2,2,2,2,2,2,2,2,2,2,  2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,
+            10,3,3,3,3,3,3,3,3,3,3,3,3,4,3,3, 11,6,6,6,5,8,8,8,8,8,8,8,8,8,8,8,
+        };
+        return type[c];
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        typename InputByteStream::Ch c = Take(is);
+        if (static_cast<unsigned char>(c) != 0xEFu) return c;
+        c = is.Take();
+        if (static_cast<unsigned char>(c) != 0xBBu) return c;
+        c = is.Take();
+        if (static_cast<unsigned char>(c) != 0xBFu) return c;
+        c = is.Take();
+        return c;
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return static_cast<Ch>(is.Take());
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xEFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xBBu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xBFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF16
+
+//! UTF-16 encoding.
+/*! http://en.wikipedia.org/wiki/UTF-16
+    http://tools.ietf.org/html/rfc2781
+    \tparam CharType Type for storing 16-bit UTF-16 data. Default is wchar_t. C++11 may use char16_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF16LE and UTF16BE, which handle endianness.
+*/
+template<typename CharType = wchar_t>
+struct UTF16 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 2);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        if (codepoint <= 0xFFFF) {
+            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+            os.Put(static_cast<typename OutputStream::Ch>(codepoint));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            unsigned v = codepoint - 0x10000;
+            os.Put(static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+            os.Put((v & 0x3FF) | 0xDC00);
+        }
+    }
+
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        if (codepoint <= 0xFFFF) {
+            RAPIDJSON_ASSERT(codepoint < 0xD800 || codepoint > 0xDFFF); // Code point itself cannot be surrogate pair 
+            PutUnsafe(os, static_cast<typename OutputStream::Ch>(codepoint));
+        }
+        else {
+            RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+            unsigned v = codepoint - 0x10000;
+            PutUnsafe(os, static_cast<typename OutputStream::Ch>((v >> 10) | 0xD800));
+            PutUnsafe(os, (v & 0x3FF) | 0xDC00);
+        }
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        typename InputStream::Ch c = is.Take();
+        if (c < 0xD800 || c > 0xDFFF) {
+            *codepoint = static_cast<unsigned>(c);
+            return true;
+        }
+        else if (c <= 0xDBFF) {
+            *codepoint = (static_cast<unsigned>(c) & 0x3FF) << 10;
+            c = is.Take();
+            *codepoint |= (static_cast<unsigned>(c) & 0x3FF);
+            *codepoint += 0x10000;
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 2);
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 2);
+        typename InputStream::Ch c;
+        os.Put(static_cast<typename OutputStream::Ch>(c = is.Take()));
+        if (c < 0xD800 || c > 0xDFFF)
+            return true;
+        else if (c <= 0xDBFF) {
+            os.Put(c = is.Take());
+            return c >= 0xDC00 && c <= 0xDFFF;
+        }
+        return false;
+    }
+};
+
+//! UTF-16 little endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16LE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<uint8_t>(is.Take());
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+    }
+};
+
+//! UTF-16 big endian encoding.
+template<typename CharType = wchar_t>
+struct UTF16BE : UTF16<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint16_t>(c) == 0xFEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<uint8_t>(is.Take());
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>((static_cast<unsigned>(c) >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(static_cast<unsigned>(c) & 0xFFu));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// UTF32
+
+//! UTF-32 encoding. 
+/*! http://en.wikipedia.org/wiki/UTF-32
+    \tparam CharType Type for storing 32-bit UTF-32 data. Default is unsigned. C++11 may use char32_t instead.
+    \note implements Encoding concept
+
+    \note For in-memory access, no need to concern endianness. The code units and code points are represented by CPU's endianness.
+    For streaming, use UTF32LE and UTF32BE, which handle endianness.
+*/
+template<typename CharType = unsigned>
+struct UTF32 {
+    typedef CharType Ch;
+    RAPIDJSON_STATIC_ASSERT(sizeof(Ch) >= 4);
+
+    enum { supportUnicode = 1 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+        os.Put(codepoint);
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputStream::Ch) >= 4);
+        RAPIDJSON_ASSERT(codepoint <= 0x10FFFF);
+        PutUnsafe(os, codepoint);
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c = is.Take();
+        *codepoint = c;
+        return c <= 0x10FFFF;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputStream::Ch) >= 4);
+        Ch c;
+        os.Put(c = is.Take());
+        return c <= 0x10FFFF;
+    }
+};
+
+//! UTF-32 little endian enocoding.
+template<typename CharType = unsigned>
+struct UTF32LE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c;
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<uint8_t>(is.Take());
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+    }
+};
+
+//! UTF-32 big endian encoding.
+template<typename CharType = unsigned>
+struct UTF32BE : UTF32<CharType> {
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        CharType c = Take(is);
+        return static_cast<uint32_t>(c) == 0x0000FEFFu ? Take(is) : c; 
+    }
+
+    template <typename InputByteStream>
+    static CharType Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        unsigned c = static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 24;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 16;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take())) << 8;
+        c |= static_cast<unsigned>(static_cast<uint8_t>(is.Take()));
+        return static_cast<CharType>(c);
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0x00u));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFEu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(0xFFu));
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, CharType c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 24) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 16) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>((c >> 8) & 0xFFu));
+        os.Put(static_cast<typename OutputByteStream::Ch>(c & 0xFFu));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ASCII
+
+//! ASCII encoding.
+/*! http://en.wikipedia.org/wiki/ASCII
+    \tparam CharType Code unit for storing 7-bit ASCII data. Default is char.
+    \note implements Encoding concept
+*/
+template<typename CharType = char>
+struct ASCII {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 0 };
+
+    template<typename OutputStream>
+    static void Encode(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_ASSERT(codepoint <= 0x7F);
+        os.Put(static_cast<Ch>(codepoint & 0xFF));
+    }
+
+    template<typename OutputStream>
+    static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        RAPIDJSON_ASSERT(codepoint <= 0x7F);
+        PutUnsafe(os, static_cast<Ch>(codepoint & 0xFF));
+    }
+
+    template <typename InputStream>
+    static bool Decode(InputStream& is, unsigned* codepoint) {
+        uint8_t c = static_cast<uint8_t>(is.Take());
+        *codepoint = c;
+        return c <= 0X7F;
+    }
+
+    template <typename InputStream, typename OutputStream>
+    static bool Validate(InputStream& is, OutputStream& os) {
+        uint8_t c = static_cast<uint8_t>(is.Take());
+        os.Put(static_cast<typename OutputStream::Ch>(c));
+        return c <= 0x7F;
+    }
+
+    template <typename InputByteStream>
+    static CharType TakeBOM(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        uint8_t c = static_cast<uint8_t>(Take(is));
+        return static_cast<Ch>(c);
+    }
+
+    template <typename InputByteStream>
+    static Ch Take(InputByteStream& is) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename InputByteStream::Ch) == 1);
+        return static_cast<Ch>(is.Take());
+    }
+
+    template <typename OutputByteStream>
+    static void PutBOM(OutputByteStream& os) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        (void)os;
+    }
+
+    template <typename OutputByteStream>
+    static void Put(OutputByteStream& os, Ch c) {
+        RAPIDJSON_STATIC_ASSERT(sizeof(typename OutputByteStream::Ch) == 1);
+        os.Put(static_cast<typename OutputByteStream::Ch>(c));
+    }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// AutoUTF
+
+//! Runtime-specified UTF encoding type of a stream.
+enum UTFType {
+    kUTF8 = 0,      //!< UTF-8.
+    kUTF16LE = 1,   //!< UTF-16 little endian.
+    kUTF16BE = 2,   //!< UTF-16 big endian.
+    kUTF32LE = 3,   //!< UTF-32 little endian.
+    kUTF32BE = 4    //!< UTF-32 big endian.
+};
+
+//! Dynamically select encoding according to stream's runtime-specified UTF encoding type.
+/*! \note This class can be used with AutoUTFInputtStream and AutoUTFOutputStream, which provides GetType().
+*/
+template<typename CharType>
+struct AutoUTF {
+    typedef CharType Ch;
+
+    enum { supportUnicode = 1 };
+
+#define RAPIDJSON_ENCODINGS_FUNC(x) UTF8<Ch>::x, UTF16LE<Ch>::x, UTF16BE<Ch>::x, UTF32LE<Ch>::x, UTF32BE<Ch>::x
+
+    template<typename OutputStream>
+    RAPIDJSON_FORCEINLINE static void Encode(OutputStream& os, unsigned codepoint) {
+        typedef void (*EncodeFunc)(OutputStream&, unsigned);
+        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Encode) };
+        (*f[os.GetType()])(os, codepoint);
+    }
+
+    template<typename OutputStream>
+    RAPIDJSON_FORCEINLINE static void EncodeUnsafe(OutputStream& os, unsigned codepoint) {
+        typedef void (*EncodeFunc)(OutputStream&, unsigned);
+        static const EncodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(EncodeUnsafe) };
+        (*f[os.GetType()])(os, codepoint);
+    }
+
+    template <typename InputStream>
+    RAPIDJSON_FORCEINLINE static bool Decode(InputStream& is, unsigned* codepoint) {
+        typedef bool (*DecodeFunc)(InputStream&, unsigned*);
+        static const DecodeFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Decode) };
+        return (*f[is.GetType()])(is, codepoint);
+    }
+
+    template <typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        typedef bool (*ValidateFunc)(InputStream&, OutputStream&);
+        static const ValidateFunc f[] = { RAPIDJSON_ENCODINGS_FUNC(Validate) };
+        return (*f[is.GetType()])(is, os);
+    }
+
+#undef RAPIDJSON_ENCODINGS_FUNC
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Transcoder
+
+//! Encoding conversion.
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder {
+    //! Take one Unicode codepoint from source encoding, convert it to target encoding and put it to the output stream.
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+        unsigned codepoint;
+        if (!SourceEncoding::Decode(is, &codepoint))
+            return false;
+        TargetEncoding::Encode(os, codepoint);
+        return true;
+    }
+
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+        unsigned codepoint;
+        if (!SourceEncoding::Decode(is, &codepoint))
+            return false;
+        TargetEncoding::EncodeUnsafe(os, codepoint);
+        return true;
+    }
+
+    //! Validate one Unicode codepoint from an encoded stream.
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        return Transcode(is, os);   // Since source/target encoding is different, must transcode.
+    }
+};
+
+// Forward declaration.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c);
+
+//! Specialization of Transcoder with same source and target encoding.
+template<typename Encoding>
+struct Transcoder<Encoding, Encoding> {
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Transcode(InputStream& is, OutputStream& os) {
+        os.Put(is.Take());  // Just copy one code unit. This semantic is different from primary template class.
+        return true;
+    }
+    
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool TranscodeUnsafe(InputStream& is, OutputStream& os) {
+        PutUnsafe(os, is.Take());  // Just copy one code unit. This semantic is different from primary template class.
+        return true;
+    }
+    
+    template<typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE static bool Validate(InputStream& is, OutputStream& os) {
+        return Encoding::Validate(is, os);  // source/target encoding are the same
+    }
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ENCODINGS_H_
diff --git a/core/deps/rapidjson/error/en.h b/core/deps/rapidjson/error/en.h
new file mode 100644 (file)
index 0000000..2db838b
--- /dev/null
@@ -0,0 +1,74 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_EN_H_
+#define RAPIDJSON_ERROR_EN_H_
+
+#include "error.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(covered-switch-default)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Maps error code of parsing into error message.
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \param parseErrorCode Error code obtained in parsing.
+    \return the error message.
+    \note User can make a copy of this function for localization.
+        Using switch-case is safer for future modification of error codes.
+*/
+inline const RAPIDJSON_ERROR_CHARTYPE* GetParseError_En(ParseErrorCode parseErrorCode) {
+    switch (parseErrorCode) {
+        case kParseErrorNone:                           return RAPIDJSON_ERROR_STRING("No error.");
+
+        case kParseErrorDocumentEmpty:                  return RAPIDJSON_ERROR_STRING("The document is empty.");
+        case kParseErrorDocumentRootNotSingular:        return RAPIDJSON_ERROR_STRING("The document root must not be followed by other values.");
+    
+        case kParseErrorValueInvalid:                   return RAPIDJSON_ERROR_STRING("Invalid value.");
+    
+        case kParseErrorObjectMissName:                 return RAPIDJSON_ERROR_STRING("Missing a name for object member.");
+        case kParseErrorObjectMissColon:                return RAPIDJSON_ERROR_STRING("Missing a colon after a name of object member.");
+        case kParseErrorObjectMissCommaOrCurlyBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or '}' after an object member.");
+    
+        case kParseErrorArrayMissCommaOrSquareBracket:  return RAPIDJSON_ERROR_STRING("Missing a comma or ']' after an array element.");
+
+        case kParseErrorStringUnicodeEscapeInvalidHex:  return RAPIDJSON_ERROR_STRING("Incorrect hex digit after \\u escape in string.");
+        case kParseErrorStringUnicodeSurrogateInvalid:  return RAPIDJSON_ERROR_STRING("The surrogate pair in string is invalid.");
+        case kParseErrorStringEscapeInvalid:            return RAPIDJSON_ERROR_STRING("Invalid escape character in string.");
+        case kParseErrorStringMissQuotationMark:        return RAPIDJSON_ERROR_STRING("Missing a closing quotation mark in string.");
+        case kParseErrorStringInvalidEncoding:          return RAPIDJSON_ERROR_STRING("Invalid encoding in string.");
+
+        case kParseErrorNumberTooBig:                   return RAPIDJSON_ERROR_STRING("Number too big to be stored in double.");
+        case kParseErrorNumberMissFraction:             return RAPIDJSON_ERROR_STRING("Miss fraction part in number.");
+        case kParseErrorNumberMissExponent:             return RAPIDJSON_ERROR_STRING("Miss exponent in number.");
+
+        case kParseErrorTermination:                    return RAPIDJSON_ERROR_STRING("Terminate parsing due to Handler error.");
+        case kParseErrorUnspecificSyntaxError:          return RAPIDJSON_ERROR_STRING("Unspecific syntax error.");
+
+        default:                                        return RAPIDJSON_ERROR_STRING("Unknown error.");
+    }
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_EN_H_
diff --git a/core/deps/rapidjson/error/error.h b/core/deps/rapidjson/error/error.h
new file mode 100644 (file)
index 0000000..95cb31a
--- /dev/null
@@ -0,0 +1,155 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+#include "../rapidjson.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+    The default character type is \c char.
+    On Windows, user can define this macro as \c TCHAR for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+    By default this conversion macro does nothing.
+    On Windows, user can define this macro as \c _T(x) for supporting both
+    unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+    \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+    kParseErrorNone = 0,                        //!< No error.
+
+    kParseErrorDocumentEmpty,                   //!< The document is empty.
+    kParseErrorDocumentRootNotSingular,         //!< The document root must not follow by other values.
+
+    kParseErrorValueInvalid,                    //!< Invalid value.
+
+    kParseErrorObjectMissName,                  //!< Missing a name for object member.
+    kParseErrorObjectMissColon,                 //!< Missing a colon after a name of object member.
+    kParseErrorObjectMissCommaOrCurlyBracket,   //!< Missing a comma or '}' after an object member.
+
+    kParseErrorArrayMissCommaOrSquareBracket,   //!< Missing a comma or ']' after an array element.
+
+    kParseErrorStringUnicodeEscapeInvalidHex,   //!< Incorrect hex digit after \\u escape in string.
+    kParseErrorStringUnicodeSurrogateInvalid,   //!< The surrogate pair in string is invalid.
+    kParseErrorStringEscapeInvalid,             //!< Invalid escape character in string.
+    kParseErrorStringMissQuotationMark,         //!< Missing a closing quotation mark in string.
+    kParseErrorStringInvalidEncoding,           //!< Invalid encoding in string.
+
+    kParseErrorNumberTooBig,                    //!< Number too big to be stored in double.
+    kParseErrorNumberMissFraction,              //!< Miss fraction part in number.
+    kParseErrorNumberMissExponent,              //!< Miss exponent in number.
+
+    kParseErrorTermination,                     //!< Parsing was terminated.
+    kParseErrorUnspecificSyntaxError            //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+    \ingroup RAPIDJSON_ERRORS
+    \code
+        Document doc;
+        ParseResult ok = doc.Parse("[42]");
+        if (!ok) {
+            fprintf(stderr, "JSON parse error: %s (%u)",
+                    GetParseError_En(ok.Code()), ok.Offset());
+            exit(EXIT_FAILURE);
+        }
+    \endcode
+    \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+public:
+    //! Default constructor, no error.
+    ParseResult() : code_(kParseErrorNone), offset_(0) {}
+    //! Constructor to set an error.
+    ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
+
+    //! Get the error code.
+    ParseErrorCode Code() const { return code_; }
+    //! Get the error offset, if \ref IsError(), 0 otherwise.
+    size_t Offset() const { return offset_; }
+
+    //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+    operator bool() const { return !IsError(); }
+    //! Whether the result is an error.
+    bool IsError() const { return code_ != kParseErrorNone; }
+
+    bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+    bool operator==(ParseErrorCode code) const { return code_ == code; }
+    friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
+
+    //! Reset error code.
+    void Clear() { Set(kParseErrorNone); }
+    //! Update error code and offset.
+    void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
+
+private:
+    ParseErrorCode code_;
+    size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+    This is the prototype for \c GetParseError_X(), where \c X is a locale.
+    User can dynamically change locale in runtime, e.g.:
+\code
+    GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+    const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
+\endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_
diff --git a/core/deps/rapidjson/filereadstream.h b/core/deps/rapidjson/filereadstream.h
new file mode 100644 (file)
index 0000000..b56ea13
--- /dev/null
@@ -0,0 +1,99 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEREADSTREAM_H_
+#define RAPIDJSON_FILEREADSTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! File byte stream for input using fread().
+/*!
+    \note implements Stream concept
+*/
+class FileReadStream {
+public:
+    typedef char Ch;    //!< Character type (byte).
+
+    //! Constructor.
+    /*!
+        \param fp File pointer opened for read.
+        \param buffer user-supplied buffer.
+        \param bufferSize size of buffer in bytes. Must >=4 bytes.
+    */
+    FileReadStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferSize_(bufferSize), bufferLast_(0), current_(buffer_), readCount_(0), count_(0), eof_(false) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+        RAPIDJSON_ASSERT(bufferSize >= 4);
+        Read();
+    }
+
+    Ch Peek() const { return *current_; }
+    Ch Take() { Ch c = *current_; Read(); return c; }
+    size_t Tell() const { return count_ + static_cast<size_t>(current_ - buffer_); }
+
+    // Not implemented
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); } 
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return (current_ + 4 <= bufferLast_) ? current_ : 0;
+    }
+
+private:
+    void Read() {
+        if (current_ < bufferLast_)
+            ++current_;
+        else if (!eof_) {
+            count_ += readCount_;
+            readCount_ = fread(buffer_, 1, bufferSize_, fp_);
+            bufferLast_ = buffer_ + readCount_ - 1;
+            current_ = buffer_;
+
+            if (readCount_ < bufferSize_) {
+                buffer_[readCount_] = '\0';
+                ++bufferLast_;
+                eof_ = true;
+            }
+        }
+    }
+
+    std::FILE* fp_;
+    Ch *buffer_;
+    size_t bufferSize_;
+    Ch *bufferLast_;
+    Ch *current_;
+    size_t readCount_;
+    size_t count_;  //!< Number of characters read
+    bool eof_;
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/core/deps/rapidjson/filestream.h b/core/deps/rapidjson/filestream.h
new file mode 100644 (file)
index 0000000..a2e7172
--- /dev/null
@@ -0,0 +1,73 @@
+// Copyright (C) 2011 Milo Yip\r
+//\r
+// Permission is hereby granted, free of charge, to any person obtaining a copy\r
+// of this software and associated documentation files (the "Software"), to deal\r
+// in the Software without restriction, including without limitation the rights\r
+// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell\r
+// copies of the Software, and to permit persons to whom the Software is\r
+// furnished to do so, subject to the following conditions:\r
+//\r
+// The above copyright notice and this permission notice shall be included in\r
+// all copies or substantial portions of the Software.\r
+//\r
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\r
+// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN\r
+// THE SOFTWARE.\r
+\r
+#ifndef RAPIDJSON_FILESTREAM_H_\r
+#define RAPIDJSON_FILESTREAM_H_\r
+\r
+#include "rapidjson.h"\r
+#include <cstdio>\r
+\r
+RAPIDJSON_NAMESPACE_BEGIN\r
+\r
+//! (Deprecated) Wrapper of C file stream for input or output.\r
+/*!\r
+    This simple wrapper does not check the validity of the stream.\r
+    \note implements Stream concept\r
+    \note deprecated: This was only for basic testing in version 0.1, it is found that the performance is very low by using fgetc(). Use FileReadStream instead.\r
+*/\r
+class FileStream {\r
+public:\r
+    typedef char Ch;    //!< Character type. Only support char.\r
+\r
+    FileStream(std::FILE* fp) : fp_(fp), current_('\0'), count_(0) { Read(); }\r
+    char Peek() const { return current_; }\r
+    char Take() { char c = current_; Read(); return c; }\r
+    size_t Tell() const { return count_; }\r
+    void Put(char c) { fputc(c, fp_); }\r
+    void Flush() { fflush(fp_); }\r
+\r
+    // Not implemented\r
+    char* PutBegin() { return 0; }\r
+    size_t PutEnd(char*) { return 0; }\r
+\r
+private:\r
+    // Prohibit copy constructor & assignment operator.\r
+    FileStream(const FileStream&);\r
+    FileStream& operator=(const FileStream&);\r
+\r
+    void Read() {\r
+        RAPIDJSON_ASSERT(fp_ != 0);\r
+        int c = fgetc(fp_);\r
+        if (c != EOF) {\r
+            current_ = (char)c;\r
+            count_++;\r
+        }\r
+        else if (current_ != '\0')\r
+            current_ = '\0';\r
+    }\r
+\r
+    std::FILE* fp_;\r
+    char current_;\r
+    size_t count_;\r
+};\r
+\r
+RAPIDJSON_NAMESPACE_END\r
+\r
+#endif // RAPIDJSON_FILESTREAM_H_\r
diff --git a/core/deps/rapidjson/filewritestream.h b/core/deps/rapidjson/filewritestream.h
new file mode 100644 (file)
index 0000000..6378dd6
--- /dev/null
@@ -0,0 +1,104 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FILEWRITESTREAM_H_
+#define RAPIDJSON_FILEWRITESTREAM_H_
+
+#include "stream.h"
+#include <cstdio>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of C file stream for input using fread().
+/*!
+    \note implements Stream concept
+*/
+class FileWriteStream {
+public:
+    typedef char Ch;    //!< Character type. Only support char.
+
+    FileWriteStream(std::FILE* fp, char* buffer, size_t bufferSize) : fp_(fp), buffer_(buffer), bufferEnd_(buffer + bufferSize), current_(buffer_) { 
+        RAPIDJSON_ASSERT(fp_ != 0);
+    }
+
+    void Put(char c) { 
+        if (current_ >= bufferEnd_)
+            Flush();
+
+        *current_++ = c;
+    }
+
+    void PutN(char c, size_t n) {
+        size_t avail = static_cast<size_t>(bufferEnd_ - current_);
+        while (n > avail) {
+            std::memset(current_, c, avail);
+            current_ += avail;
+            Flush();
+            n -= avail;
+            avail = static_cast<size_t>(bufferEnd_ - current_);
+        }
+
+        if (n > 0) {
+            std::memset(current_, c, n);
+            current_ += n;
+        }
+    }
+
+    void Flush() {
+        if (current_ != buffer_) {
+            size_t result = fwrite(buffer_, 1, static_cast<size_t>(current_ - buffer_), fp_);
+            if (result < static_cast<size_t>(current_ - buffer_)) {
+                // failure deliberately ignored at this time
+                // added to avoid warn_unused_result build errors
+            }
+            current_ = buffer_;
+        }
+    }
+
+    // Not implemented
+    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+    char Take() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    FileWriteStream(const FileWriteStream&);
+    FileWriteStream& operator=(const FileWriteStream&);
+
+    std::FILE* fp_;
+    char *buffer_;
+    char *bufferEnd_;
+    char *current_;
+};
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(FileWriteStream& stream, char c, size_t n) {
+    stream.PutN(c, n);
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_FILESTREAM_H_
diff --git a/core/deps/rapidjson/fwd.h b/core/deps/rapidjson/fwd.h
new file mode 100644 (file)
index 0000000..e8104e8
--- /dev/null
@@ -0,0 +1,151 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_FWD_H_
+#define RAPIDJSON_FWD_H_
+
+#include "rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// encodings.h
+
+template<typename CharType> struct UTF8;
+template<typename CharType> struct UTF16;
+template<typename CharType> struct UTF16BE;
+template<typename CharType> struct UTF16LE;
+template<typename CharType> struct UTF32;
+template<typename CharType> struct UTF32BE;
+template<typename CharType> struct UTF32LE;
+template<typename CharType> struct ASCII;
+template<typename CharType> struct AutoUTF;
+
+template<typename SourceEncoding, typename TargetEncoding>
+struct Transcoder;
+
+// allocators.h
+
+class CrtAllocator;
+
+template <typename BaseAllocator>
+class MemoryPoolAllocator;
+
+// stream.h
+
+template <typename Encoding>
+struct GenericStringStream;
+
+typedef GenericStringStream<UTF8<char> > StringStream;
+
+template <typename Encoding>
+struct GenericInsituStringStream;
+
+typedef GenericInsituStringStream<UTF8<char> > InsituStringStream;
+
+// stringbuffer.h
+
+template <typename Encoding, typename Allocator>
+class GenericStringBuffer;
+
+typedef GenericStringBuffer<UTF8<char>, CrtAllocator> StringBuffer;
+
+// filereadstream.h
+
+class FileReadStream;
+
+// filewritestream.h
+
+class FileWriteStream;
+
+// memorybuffer.h
+
+template <typename Allocator>
+struct GenericMemoryBuffer;
+
+typedef GenericMemoryBuffer<CrtAllocator> MemoryBuffer;
+
+// memorystream.h
+
+struct MemoryStream;
+
+// reader.h
+
+template<typename Encoding, typename Derived>
+struct BaseReaderHandler;
+
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator>
+class GenericReader;
+
+typedef GenericReader<UTF8<char>, UTF8<char>, CrtAllocator> Reader;
+
+// writer.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class Writer;
+
+// prettywriter.h
+
+template<typename OutputStream, typename SourceEncoding, typename TargetEncoding, typename StackAllocator, unsigned writeFlags>
+class PrettyWriter;
+
+// document.h
+
+template <typename Encoding, typename Allocator> 
+struct GenericMember;
+
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator;
+
+template<typename CharType>
+struct GenericStringRef;
+
+template <typename Encoding, typename Allocator> 
+class GenericValue;
+
+typedef GenericValue<UTF8<char>, MemoryPoolAllocator<CrtAllocator> > Value;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+typedef GenericDocument<UTF8<char>, MemoryPoolAllocator<CrtAllocator>, CrtAllocator> Document;
+
+// pointer.h
+
+template <typename ValueType, typename Allocator>
+class GenericPointer;
+
+typedef GenericPointer<Value, CrtAllocator> Pointer;
+
+// schema.h
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider;
+
+template <typename ValueT, typename Allocator>
+class GenericSchemaDocument;
+
+typedef GenericSchemaDocument<Value, CrtAllocator> SchemaDocument;
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+template <
+    typename SchemaDocumentType,
+    typename OutputHandler,
+    typename StateAllocator>
+class GenericSchemaValidator;
+
+typedef GenericSchemaValidator<SchemaDocument, BaseReaderHandler<UTF8<char>, void>, CrtAllocator> SchemaValidator;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSONFWD_H_
diff --git a/core/deps/rapidjson/internal/biginteger.h b/core/deps/rapidjson/internal/biginteger.h
new file mode 100644 (file)
index 0000000..9d3e88c
--- /dev/null
@@ -0,0 +1,290 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+public:
+    typedef uint64_t Type;
+
+    BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+        std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+    }
+
+    explicit BigInteger(uint64_t u) : count_(1) {
+        digits_[0] = u;
+    }
+
+    BigInteger(const char* decimals, size_t length) : count_(1) {
+        RAPIDJSON_ASSERT(length > 0);
+        digits_[0] = 0;
+        size_t i = 0;
+        const size_t kMaxDigitPerIteration = 19;  // 2^64 = 18446744073709551616 > 10^19
+        while (length >= kMaxDigitPerIteration) {
+            AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+            length -= kMaxDigitPerIteration;
+            i += kMaxDigitPerIteration;
+        }
+
+        if (length > 0)
+            AppendDecimal64(decimals + i, decimals + i + length);
+    }
+    
+    BigInteger& operator=(const BigInteger &rhs)
+    {
+        if (this != &rhs) {
+            count_ = rhs.count_;
+            std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+        }
+        return *this;
+    }
+    
+    BigInteger& operator=(uint64_t u) {
+        digits_[0] = u;            
+        count_ = 1;
+        return *this;
+    }
+
+    BigInteger& operator+=(uint64_t u) {
+        Type backup = digits_[0];
+        digits_[0] += u;
+        for (size_t i = 0; i < count_ - 1; i++) {
+            if (digits_[i] >= backup)
+                return *this; // no carry
+            backup = digits_[i + 1];
+            digits_[i + 1] += 1;
+        }
+
+        // Last carry
+        if (digits_[count_ - 1] < backup)
+            PushBack(1);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint64_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            uint64_t hi;
+            digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+            k = hi;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator*=(uint32_t u) {
+        if (u == 0) return *this = 0;
+        if (u == 1) return *this;
+        if (*this == 1) return *this = u;
+
+        uint64_t k = 0;
+        for (size_t i = 0; i < count_; i++) {
+            const uint64_t c = digits_[i] >> 32;
+            const uint64_t d = digits_[i] & 0xFFFFFFFF;
+            const uint64_t uc = u * c;
+            const uint64_t ud = u * d;
+            const uint64_t p0 = ud + k;
+            const uint64_t p1 = uc + (p0 >> 32);
+            digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+            k = p1 >> 32;
+        }
+        
+        if (k > 0)
+            PushBack(k);
+
+        return *this;
+    }
+
+    BigInteger& operator<<=(size_t shift) {
+        if (IsZero() || shift == 0) return *this;
+
+        size_t offset = shift / kTypeBit;
+        size_t interShift = shift % kTypeBit;
+        RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+        if (interShift == 0) {
+            std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
+            count_ += offset;
+        }
+        else {
+            digits_[count_] = 0;
+            for (size_t i = count_; i > 0; i--)
+                digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
+            digits_[offset] = digits_[0] << interShift;
+            count_ += offset;
+            if (digits_[count_])
+                count_++;
+        }
+
+        std::memset(digits_, 0, offset * sizeof(Type));
+
+        return *this;
+    }
+
+    bool operator==(const BigInteger& rhs) const {
+        return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+    }
+
+    bool operator==(const Type rhs) const {
+        return count_ == 1 && digits_[0] == rhs;
+    }
+
+    BigInteger& MultiplyPow5(unsigned exp) {
+        static const uint32_t kPow5[12] = {
+            5,
+            5 * 5,
+            5 * 5 * 5,
+            5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+            5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
+        };
+        if (exp == 0) return *this;
+        for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+        for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
+        if (exp > 0)                 *this *= kPow5[exp - 1];
+        return *this;
+    }
+
+    // Compute absolute difference of this and rhs.
+    // Assume this != rhs
+    bool Difference(const BigInteger& rhs, BigInteger* out) const {
+        int cmp = Compare(rhs);
+        RAPIDJSON_ASSERT(cmp != 0);
+        const BigInteger *a, *b;  // Makes a > b
+        bool ret;
+        if (cmp < 0) { a = &rhs; b = this; ret = true; }
+        else         { a = this; b = &rhs; ret = false; }
+
+        Type borrow = 0;
+        for (size_t i = 0; i < a->count_; i++) {
+            Type d = a->digits_[i] - borrow;
+            if (i < b->count_)
+                d -= b->digits_[i];
+            borrow = (d > a->digits_[i]) ? 1 : 0;
+            out->digits_[i] = d;
+            if (d != 0)
+                out->count_ = i + 1;
+        }
+
+        return ret;
+    }
+
+    int Compare(const BigInteger& rhs) const {
+        if (count_ != rhs.count_)
+            return count_ < rhs.count_ ? -1 : 1;
+
+        for (size_t i = count_; i-- > 0;)
+            if (digits_[i] != rhs.digits_[i])
+                return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+        return 0;
+    }
+
+    size_t GetCount() const { return count_; }
+    Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
+    bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+private:
+    void AppendDecimal64(const char* begin, const char* end) {
+        uint64_t u = ParseUint64(begin, end);
+        if (IsZero())
+            *this = u;
+        else {
+            unsigned exp = static_cast<unsigned>(end - begin);
+            (MultiplyPow5(exp) <<= exp) += u;   // *this = *this * 10^exp + u
+        }
+    }
+
+    void PushBack(Type digit) {
+        RAPIDJSON_ASSERT(count_ < kCapacity);
+        digits_[count_++] = digit;
+    }
+
+    static uint64_t ParseUint64(const char* begin, const char* end) {
+        uint64_t r = 0;
+        for (const char* p = begin; p != end; ++p) {
+            RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+            r = r * 10u + static_cast<unsigned>(*p - '0');
+        }
+        return r;
+    }
+
+    // Assume a * b + k < 2^128
+    static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t low = _umul128(a, b, outHigh) + k;
+        if (low < k)
+            (*outHigh)++;
+        return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+        p += k;
+        *outHigh = static_cast<uint64_t>(p >> 64);
+        return static_cast<uint64_t>(p);
+#else
+        const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
+        uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+        x1 += (x0 >> 32); // can't give carry
+        x1 += x2;
+        if (x1 < x2)
+            x3 += (static_cast<uint64_t>(1) << 32);
+        uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+        uint64_t hi = x3 + (x1 >> 32);
+
+        lo += k;
+        if (lo < k)
+            hi++;
+        *outHigh = hi;
+        return lo;
+#endif
+    }
+
+    static const size_t kBitCount = 3328;  // 64bit * 54 > 10^1000
+    static const size_t kCapacity = kBitCount / sizeof(Type);
+    static const size_t kTypeBit = sizeof(Type) * 8;
+
+    Type digits_[kCapacity];
+    size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/core/deps/rapidjson/internal/diyfp.h b/core/deps/rapidjson/internal/diyfp.h
new file mode 100644 (file)
index 0000000..c9fefdc
--- /dev/null
@@ -0,0 +1,258 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "../rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+struct DiyFp {
+    DiyFp() : f(), e() {}
+
+    DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+    explicit DiyFp(double d) {
+        union {
+            double d;
+            uint64_t u64;
+        } u = { d };
+
+        int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+        uint64_t significand = (u.u64 & kDpSignificandMask);
+        if (biased_e != 0) {
+            f = significand + kDpHiddenBit;
+            e = biased_e - kDpExponentBias;
+        } 
+        else {
+            f = significand;
+            e = kDpMinExponent + 1;
+        }
+    }
+
+    DiyFp operator-(const DiyFp& rhs) const {
+        return DiyFp(f - rhs.f, e);
+    }
+
+    DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        uint64_t h;
+        uint64_t l = _umul128(f, rhs.f, &h);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
+        __extension__ typedef unsigned __int128 uint128;
+        uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+        uint64_t h = static_cast<uint64_t>(p >> 64);
+        uint64_t l = static_cast<uint64_t>(p);
+        if (l & (uint64_t(1) << 63)) // rounding
+            h++;
+        return DiyFp(h, e + rhs.e + 64);
+#else
+        const uint64_t M32 = 0xFFFFFFFF;
+        const uint64_t a = f >> 32;
+        const uint64_t b = f & M32;
+        const uint64_t c = rhs.f >> 32;
+        const uint64_t d = rhs.f & M32;
+        const uint64_t ac = a * c;
+        const uint64_t bc = b * c;
+        const uint64_t ad = a * d;
+        const uint64_t bd = b * d;
+        uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+        tmp += 1U << 31;  /// mult_round
+        return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+    }
+
+    DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+        unsigned long index;
+        _BitScanReverse64(&index, f);
+        return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+        int s = __builtin_clzll(f);
+        return DiyFp(f << s, e - s);
+#else
+        DiyFp res = *this;
+        while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        return res;
+#endif
+    }
+
+    DiyFp NormalizeBoundary() const {
+        DiyFp res = *this;
+        while (!(res.f & (kDpHiddenBit << 1))) {
+            res.f <<= 1;
+            res.e--;
+        }
+        res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+        res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+        return res;
+    }
+
+    void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+        DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+        DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
+        mi.f <<= mi.e - pl.e;
+        mi.e = pl.e;
+        *plus = pl;
+        *minus = mi;
+    }
+
+    double ToDouble() const {
+        union {
+            double d;
+            uint64_t u64;
+        }u;
+        const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 : 
+            static_cast<uint64_t>(e + kDpExponentBias);
+        u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+        return u.d;
+    }
+
+    static const int kDiySignificandSize = 64;
+    static const int kDpSignificandSize = 52;
+    static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+    static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+    static const int kDpMinExponent = -kDpExponentBias;
+    static const int kDpDenormalExponent = -kDpExponentBias + 1;
+    static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    uint64_t f;
+    int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+    // 10^-348, 10^-340, ..., 10^340
+    static const uint64_t kCachedPowers_F[] = {
+        RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+        RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+        RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+        RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+        RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+        RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+        RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+        RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+        RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+        RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+        RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+        RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+        RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+        RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+        RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+        RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+        RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+        RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+        RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+        RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+        RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+        RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+        RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+        RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+        RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+        RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+        RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+        RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+        RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+        RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+        RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+        RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+        RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+        RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+        RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+        RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+        RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+        RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+        RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+        RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+        RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+        RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+        RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+        RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
+    };
+    static const int16_t kCachedPowers_E[] = {
+        -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007,  -980,
+        -954,  -927,  -901,  -874,  -847,  -821,  -794,  -768,  -741,  -715,
+        -688,  -661,  -635,  -608,  -582,  -555,  -529,  -502,  -475,  -449,
+        -422,  -396,  -369,  -343,  -316,  -289,  -263,  -236,  -210,  -183,
+        -157,  -130,  -103,   -77,   -50,   -24,     3,    30,    56,    83,
+        109,   136,   162,   189,   216,   242,   269,   295,   322,   348,
+        375,   402,   428,   455,   481,   508,   534,   561,   588,   614,
+        641,   667,   694,   720,   747,   774,   800,   827,   853,   880,
+        907,   933,   960,   986,  1013,  1039,  1066
+    };
+    return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+    
+inline DiyFp GetCachedPower(int e, int* K) {
+
+    //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+    double dk = (-61 - e) * 0.30102999566398114 + 347;  // dk must be positive, so can do ceiling in positive
+    int k = static_cast<int>(dk);
+    if (dk - k > 0.0)
+        k++;
+
+    unsigned index = static_cast<unsigned>((k >> 3) + 1);
+    *K = -(-348 + static_cast<int>(index << 3));    // decimal exponent no need lookup table
+
+    return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int *outExp) {
+     unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
+     *outExp = -348 + static_cast<int>(index) * 8;
+     return GetCachedPowerByIndex(index);
+ }
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_
diff --git a/core/deps/rapidjson/internal/dtoa.h b/core/deps/rapidjson/internal/dtoa.h
new file mode 100644 (file)
index 0000000..8d6350e
--- /dev/null
@@ -0,0 +1,245 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
+// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
+// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DTOA_
+#define RAPIDJSON_DTOA_
+
+#include "itoa.h" // GetDigitsLut()
+#include "diyfp.h"
+#include "ieee754.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124
+#endif
+
+inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) {
+    while (rest < wp_w && delta - rest >= ten_kappa &&
+           (rest + ten_kappa < wp_w ||  /// closer
+            wp_w - rest > rest + ten_kappa - wp_w)) {
+        buffer[len - 1]--;
+        rest += ten_kappa;
+    }
+}
+
+inline unsigned CountDecimalDigit32(uint32_t n) {
+    // Simple pure C++ implementation was faster than __builtin_clz version in this situation.
+    if (n < 10) return 1;
+    if (n < 100) return 2;
+    if (n < 1000) return 3;
+    if (n < 10000) return 4;
+    if (n < 100000) return 5;
+    if (n < 1000000) return 6;
+    if (n < 10000000) return 7;
+    if (n < 100000000) return 8;
+    // Will not reach 10 digits in DigitGen()
+    //if (n < 1000000000) return 9;
+    //return 10;
+    return 9;
+}
+
+inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) {
+    static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 };
+    const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
+    const DiyFp wp_w = Mp - W;
+    uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
+    uint64_t p2 = Mp.f & (one.f - 1);
+    unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
+    *len = 0;
+
+    while (kappa > 0) {
+        uint32_t d = 0;
+        switch (kappa) {
+            case  9: d = p1 /  100000000; p1 %=  100000000; break;
+            case  8: d = p1 /   10000000; p1 %=   10000000; break;
+            case  7: d = p1 /    1000000; p1 %=    1000000; break;
+            case  6: d = p1 /     100000; p1 %=     100000; break;
+            case  5: d = p1 /      10000; p1 %=      10000; break;
+            case  4: d = p1 /       1000; p1 %=       1000; break;
+            case  3: d = p1 /        100; p1 %=        100; break;
+            case  2: d = p1 /         10; p1 %=         10; break;
+            case  1: d = p1;              p1 =           0; break;
+            default:;
+        }
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
+        kappa--;
+        uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
+        if (tmp <= delta) {
+            *K += kappa;
+            GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f);
+            return;
+        }
+    }
+
+    // kappa = 0
+    for (;;) {
+        p2 *= 10;
+        delta *= 10;
+        char d = static_cast<char>(p2 >> -one.e);
+        if (d || *len)
+            buffer[(*len)++] = static_cast<char>('0' + d);
+        p2 &= one.f - 1;
+        kappa--;
+        if (p2 < delta) {
+            *K += kappa;
+            int index = -static_cast<int>(kappa);
+            GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0));
+            return;
+        }
+    }
+}
+
+inline void Grisu2(double value, char* buffer, int* length, int* K) {
+    const DiyFp v(value);
+    DiyFp w_m, w_p;
+    v.NormalizedBoundaries(&w_m, &w_p);
+
+    const DiyFp c_mk = GetCachedPower(w_p.e, K);
+    const DiyFp W = v.Normalize() * c_mk;
+    DiyFp Wp = w_p * c_mk;
+    DiyFp Wm = w_m * c_mk;
+    Wm.f++;
+    Wp.f--;
+    DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K);
+}
+
+inline char* WriteExponent(int K, char* buffer) {
+    if (K < 0) {
+        *buffer++ = '-';
+        K = -K;
+    }
+
+    if (K >= 100) {
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100));
+        K %= 100;
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else if (K >= 10) {
+        const char* d = GetDigitsLut() + K * 2;
+        *buffer++ = d[0];
+        *buffer++ = d[1];
+    }
+    else
+        *buffer++ = static_cast<char>('0' + static_cast<char>(K));
+
+    return buffer;
+}
+
+inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) {
+    const int kk = length + k;  // 10^(kk-1) <= v < 10^kk
+
+    if (0 <= k && kk <= 21) {
+        // 1234e7 -> 12340000000
+        for (int i = length; i < kk; i++)
+            buffer[i] = '0';
+        buffer[kk] = '.';
+        buffer[kk + 1] = '0';
+        return &buffer[kk + 2];
+    }
+    else if (0 < kk && kk <= 21) {
+        // 1234e-2 -> 12.34
+        std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk));
+        buffer[kk] = '.';
+        if (0 > k + maxDecimalPlaces) {
+            // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1
+            // Remove extra trailing zeros (at least one) after truncation.
+            for (int i = kk + maxDecimalPlaces; i > kk + 1; i--)
+                if (buffer[i] != '0')
+                    return &buffer[i + 1];
+            return &buffer[kk + 2]; // Reserve one zero
+        }
+        else
+            return &buffer[length + 1];
+    }
+    else if (-6 < kk && kk <= 0) {
+        // 1234e-6 -> 0.001234
+        const int offset = 2 - kk;
+        std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length));
+        buffer[0] = '0';
+        buffer[1] = '.';
+        for (int i = 2; i < offset; i++)
+            buffer[i] = '0';
+        if (length - kk > maxDecimalPlaces) {
+            // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1
+            // Remove extra trailing zeros (at least one) after truncation.
+            for (int i = maxDecimalPlaces + 1; i > 2; i--)
+                if (buffer[i] != '0')
+                    return &buffer[i + 1];
+            return &buffer[3]; // Reserve one zero
+        }
+        else
+            return &buffer[length + offset];
+    }
+    else if (kk < -maxDecimalPlaces) {
+        // Truncate to zero
+        buffer[0] = '0';
+        buffer[1] = '.';
+        buffer[2] = '0';
+        return &buffer[3];
+    }
+    else if (length == 1) {
+        // 1e30
+        buffer[1] = 'e';
+        return WriteExponent(kk - 1, &buffer[2]);
+    }
+    else {
+        // 1234e30 -> 1.234e33
+        std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1));
+        buffer[1] = '.';
+        buffer[length + 1] = 'e';
+        return WriteExponent(kk - 1, &buffer[0 + length + 2]);
+    }
+}
+
+inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) {
+    RAPIDJSON_ASSERT(maxDecimalPlaces >= 1);
+    Double d(value);
+    if (d.IsZero()) {
+        if (d.Sign())
+            *buffer++ = '-';     // -0.0, Issue #289
+        buffer[0] = '0';
+        buffer[1] = '.';
+        buffer[2] = '0';
+        return &buffer[3];
+    }
+    else {
+        if (value < 0) {
+            *buffer++ = '-';
+            value = -value;
+        }
+        int length, K;
+        Grisu2(value, buffer, &length, &K);
+        return Prettify(buffer, length, K, maxDecimalPlaces);
+    }
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DTOA_
diff --git a/core/deps/rapidjson/internal/ieee754.h b/core/deps/rapidjson/internal/ieee754.h
new file mode 100644 (file)
index 0000000..82bb0b9
--- /dev/null
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+public:
+    Double() {}
+    Double(double d) : d_(d) {}
+    Double(uint64_t u) : u_(u) {}
+
+    double Value() const { return d_; }
+    uint64_t Uint64Value() const { return u_; }
+
+    double NextPositiveDouble() const {
+        RAPIDJSON_ASSERT(!Sign());
+        return Double(u_ + 1).Value();
+    }
+
+    bool Sign() const { return (u_ & kSignMask) != 0; }
+    uint64_t Significand() const { return u_ & kSignificandMask; }
+    int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
+
+    bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
+    bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
+    bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
+    bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
+    bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+    uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
+    int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
+    uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
+
+    static unsigned EffectiveSignificandSize(int order) {
+        if (order >= -1021)
+            return 53;
+        else if (order <= -1074)
+            return 0;
+        else
+            return static_cast<unsigned>(order) + 1074;
+    }
+
+private:
+    static const int kSignificandSize = 52;
+    static const int kExponentBias = 0x3FF;
+    static const int kDenormalExponent = 1 - kExponentBias;
+    static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+    static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+    static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+    static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+    union {
+        double d_;
+        uint64_t u_;
+    };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_
diff --git a/core/deps/rapidjson/internal/itoa.h b/core/deps/rapidjson/internal/itoa.h
new file mode 100644 (file)
index 0000000..01a4e7e
--- /dev/null
@@ -0,0 +1,304 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+    static const char cDigitsLut[200] = {
+        '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
+        '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
+        '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
+        '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
+        '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
+        '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
+        '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
+        '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
+        '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
+        '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
+    };
+    return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+    const char* cDigitsLut = GetDigitsLut();
+
+    if (value < 10000) {
+        const uint32_t d1 = (value / 100) << 1;
+        const uint32_t d2 = (value % 100) << 1;
+        
+        if (value >= 1000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 100)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 10)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+    }
+    else if (value < 100000000) {
+        // value = bbbbcccc
+        const uint32_t b = value / 10000;
+        const uint32_t c = value % 10000;
+        
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+        
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+        
+        if (value >= 10000000)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= 1000000)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= 100000)
+            *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    else {
+        // value = aabbbbcccc in decimal
+        
+        const uint32_t a = value / 100000000; // 1 to 42
+        value %= 100000000;
+        
+        if (a >= 10) {
+            const unsigned i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+        const uint32_t b = value / 10000; // 0 to 9999
+        const uint32_t c = value % 10000; // 0 to 9999
+        
+        const uint32_t d1 = (b / 100) << 1;
+        const uint32_t d2 = (b % 100) << 1;
+        
+        const uint32_t d3 = (c / 100) << 1;
+        const uint32_t d4 = (c % 100) << 1;
+        
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+    }
+    return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+    uint32_t u = static_cast<uint32_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+    const char* cDigitsLut = GetDigitsLut();
+    const uint64_t  kTen8 = 100000000;
+    const uint64_t  kTen9 = kTen8 * 10;
+    const uint64_t kTen10 = kTen8 * 100;
+    const uint64_t kTen11 = kTen8 * 1000;
+    const uint64_t kTen12 = kTen8 * 10000;
+    const uint64_t kTen13 = kTen8 * 100000;
+    const uint64_t kTen14 = kTen8 * 1000000;
+    const uint64_t kTen15 = kTen8 * 10000000;
+    const uint64_t kTen16 = kTen8 * kTen8;
+    
+    if (value < kTen8) {
+        uint32_t v = static_cast<uint32_t>(value);
+        if (v < 10000) {
+            const uint32_t d1 = (v / 100) << 1;
+            const uint32_t d2 = (v % 100) << 1;
+            
+            if (v >= 1000)
+                *buffer++ = cDigitsLut[d1];
+            if (v >= 100)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (v >= 10)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+        }
+        else {
+            // value = bbbbcccc
+            const uint32_t b = v / 10000;
+            const uint32_t c = v % 10000;
+            
+            const uint32_t d1 = (b / 100) << 1;
+            const uint32_t d2 = (b % 100) << 1;
+            
+            const uint32_t d3 = (c / 100) << 1;
+            const uint32_t d4 = (c % 100) << 1;
+            
+            if (value >= 10000000)
+                *buffer++ = cDigitsLut[d1];
+            if (value >= 1000000)
+                *buffer++ = cDigitsLut[d1 + 1];
+            if (value >= 100000)
+                *buffer++ = cDigitsLut[d2];
+            *buffer++ = cDigitsLut[d2 + 1];
+            
+            *buffer++ = cDigitsLut[d3];
+            *buffer++ = cDigitsLut[d3 + 1];
+            *buffer++ = cDigitsLut[d4];
+            *buffer++ = cDigitsLut[d4 + 1];
+        }
+    }
+    else if (value < kTen16) {
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+        
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+        
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+        
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+        
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+        
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+
+        if (value >= kTen15)
+            *buffer++ = cDigitsLut[d1];
+        if (value >= kTen14)
+            *buffer++ = cDigitsLut[d1 + 1];
+        if (value >= kTen13)
+            *buffer++ = cDigitsLut[d2];
+        if (value >= kTen12)
+            *buffer++ = cDigitsLut[d2 + 1];
+        if (value >= kTen11)
+            *buffer++ = cDigitsLut[d3];
+        if (value >= kTen10)
+            *buffer++ = cDigitsLut[d3 + 1];
+        if (value >= kTen9)
+            *buffer++ = cDigitsLut[d4];
+        if (value >= kTen8)
+            *buffer++ = cDigitsLut[d4 + 1];
+        
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    else {
+        const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+        value %= kTen16;
+        
+        if (a < 10)
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+        else if (a < 100) {
+            const uint32_t i = a << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else if (a < 1000) {
+            *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+            
+            const uint32_t i = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+        }
+        else {
+            const uint32_t i = (a / 100) << 1;
+            const uint32_t j = (a % 100) << 1;
+            *buffer++ = cDigitsLut[i];
+            *buffer++ = cDigitsLut[i + 1];
+            *buffer++ = cDigitsLut[j];
+            *buffer++ = cDigitsLut[j + 1];
+        }
+        
+        const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+        const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+        
+        const uint32_t b0 = v0 / 10000;
+        const uint32_t c0 = v0 % 10000;
+        
+        const uint32_t d1 = (b0 / 100) << 1;
+        const uint32_t d2 = (b0 % 100) << 1;
+        
+        const uint32_t d3 = (c0 / 100) << 1;
+        const uint32_t d4 = (c0 % 100) << 1;
+        
+        const uint32_t b1 = v1 / 10000;
+        const uint32_t c1 = v1 % 10000;
+        
+        const uint32_t d5 = (b1 / 100) << 1;
+        const uint32_t d6 = (b1 % 100) << 1;
+        
+        const uint32_t d7 = (c1 / 100) << 1;
+        const uint32_t d8 = (c1 % 100) << 1;
+        
+        *buffer++ = cDigitsLut[d1];
+        *buffer++ = cDigitsLut[d1 + 1];
+        *buffer++ = cDigitsLut[d2];
+        *buffer++ = cDigitsLut[d2 + 1];
+        *buffer++ = cDigitsLut[d3];
+        *buffer++ = cDigitsLut[d3 + 1];
+        *buffer++ = cDigitsLut[d4];
+        *buffer++ = cDigitsLut[d4 + 1];
+        *buffer++ = cDigitsLut[d5];
+        *buffer++ = cDigitsLut[d5 + 1];
+        *buffer++ = cDigitsLut[d6];
+        *buffer++ = cDigitsLut[d6 + 1];
+        *buffer++ = cDigitsLut[d7];
+        *buffer++ = cDigitsLut[d7 + 1];
+        *buffer++ = cDigitsLut[d8];
+        *buffer++ = cDigitsLut[d8 + 1];
+    }
+    
+    return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+    uint64_t u = static_cast<uint64_t>(value);
+    if (value < 0) {
+        *buffer++ = '-';
+        u = ~u + 1;
+    }
+
+    return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_
diff --git a/core/deps/rapidjson/internal/meta.h b/core/deps/rapidjson/internal/meta.h
new file mode 100644 (file)
index 0000000..5a9aaa4
--- /dev/null
@@ -0,0 +1,181 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "../rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
+template <typename T> struct Void { typedef void Type; };
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond> struct BoolType {
+    static const bool Value = Cond;
+    typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
+template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
+template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
+template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
+template <> struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
+template <> struct OrExprCond<false, false> : FalseType {};
+
+template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
+template <typename C> struct NotExpr  : SelectIf<C,FalseType,TrueType>::Type {};
+template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2> struct OrExpr  : OrExprCond<C1::Value, C2::Value>::Type {};
+
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T> struct AddConst { typedef const T Type; };
+template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T> struct RemoveConst { typedef T Type; };
+template <typename T> struct RemoveConst<const T> { typedef T Type; };
+
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U> struct IsSame : FalseType {};
+template <typename T> struct IsSame<T, T> : TrueType {};
+
+template <typename T> struct IsConst : FalseType {};
+template <typename T> struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+    : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+              BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T> struct IsPointer : FalseType {};
+template <typename T> struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D> struct IsBaseOf
+    : BoolType< ::std::is_base_of<B,D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template<typename B, typename D> struct IsBaseOfImpl {
+    RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+    RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+    typedef char (&Yes)[1];
+    typedef char (&No) [2];
+
+    template <typename T>
+    static Yes Check(const D*, T);
+    static No  Check(const B*, int);
+
+    struct Host {
+        operator const B*() const;
+        operator const D*();
+    };
+
+    enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D> struct IsBaseOf
+    : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void> struct EnableIfCond  { typedef T Type; };
+template <typename T> struct EnableIfCond<false, T> { /* empty */ };
+
+template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
+template <typename T> struct DisableIfCond<true, T> { /* empty */ };
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T> struct RemoveSfinaeTag;
+template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+    typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
+        < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
+    typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
+        <RAPIDJSON_REMOVEFPTR_(cond), \
+         RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/core/deps/rapidjson/internal/pow10.h b/core/deps/rapidjson/internal/pow10.h
new file mode 100644 (file)
index 0000000..02f475d
--- /dev/null
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "../rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+    \param n non-negative exponent. Must <= 308.
+    \return 10.0^n
+*/
+inline double Pow10(int n) {
+    static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+        1e+0,  
+        1e+1,  1e+2,  1e+3,  1e+4,  1e+5,  1e+6,  1e+7,  1e+8,  1e+9,  1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20, 
+        1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
+        1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
+        1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+        1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
+        1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
+        1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
+        1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
+        1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
+        1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
+        1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
+        1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
+        1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
+        1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
+        1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
+        1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
+    };
+    RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+    return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_
diff --git a/core/deps/rapidjson/internal/regex.h b/core/deps/rapidjson/internal/regex.h
new file mode 100644 (file)
index 0000000..422a524
--- /dev/null
@@ -0,0 +1,701 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
+#define RAPIDJSON_INTERNAL_REGEX_H_
+
+#include "../allocators.h"
+#include "../stream.h"
+#include "stack.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+RAPIDJSON_DIAG_OFF(implicit-fallthrough)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+#ifndef RAPIDJSON_REGEX_VERBOSE
+#define RAPIDJSON_REGEX_VERBOSE 0
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericRegex
+
+static const SizeType kRegexInvalidState = ~SizeType(0);  //!< Represents an invalid index in GenericRegex::State::out, out1
+static const SizeType kRegexInvalidRange = ~SizeType(0);
+
+//! Regular expression engine with subset of ECMAscript grammar.
+/*!
+    Supported regular expression syntax:
+    - \c ab     Concatenation
+    - \c a|b    Alternation
+    - \c a?     Zero or one
+    - \c a*     Zero or more
+    - \c a+     One or more
+    - \c a{3}   Exactly 3 times
+    - \c a{3,}  At least 3 times
+    - \c a{3,5} 3 to 5 times
+    - \c (ab)   Grouping
+    - \c ^a     At the beginning
+    - \c a$     At the end
+    - \c .      Any character
+    - \c [abc]  Character classes
+    - \c [a-c]  Character class range
+    - \c [a-z0-9_] Character class combination
+    - \c [^abc] Negated character classes
+    - \c [^a-c] Negated character class range
+    - \c [\b]   Backspace (U+0008)
+    - \c \\| \\\\ ...  Escape characters
+    - \c \\f Form feed (U+000C)
+    - \c \\n Line feed (U+000A)
+    - \c \\r Carriage return (U+000D)
+    - \c \\t Tab (U+0009)
+    - \c \\v Vertical tab (U+000B)
+
+    \note This is a Thompson NFA engine, implemented with reference to 
+        Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).", 
+        https://swtch.com/~rsc/regexp/regexp1.html 
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericRegex {
+public:
+    typedef typename Encoding::Ch Ch;
+
+    GenericRegex(const Ch* source, Allocator* allocator = 0) : 
+        states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(), 
+        stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
+    {
+        GenericStringStream<Encoding> ss(source);
+        DecodedStream<GenericStringStream<Encoding> > ds(ss);
+        Parse(ds);
+    }
+
+    ~GenericRegex() {
+        Allocator::Free(stateSet_);
+    }
+
+    bool IsValid() const {
+        return root_ != kRegexInvalidState;
+    }
+
+    template <typename InputStream>
+    bool Match(InputStream& is) const {
+        return SearchWithAnchoring(is, true, true);
+    }
+
+    bool Match(const Ch* s) const {
+        GenericStringStream<Encoding> is(s);
+        return Match(is);
+    }
+
+    template <typename InputStream>
+    bool Search(InputStream& is) const {
+        return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
+    }
+
+    bool Search(const Ch* s) const {
+        GenericStringStream<Encoding> is(s);
+        return Search(is);
+    }
+
+private:
+    enum Operator {
+        kZeroOrOne,
+        kZeroOrMore,
+        kOneOrMore,
+        kConcatenation,
+        kAlternation,
+        kLeftParenthesis
+    };
+
+    static const unsigned kAnyCharacterClass = 0xFFFFFFFF;   //!< For '.'
+    static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
+    static const unsigned kRangeNegationFlag = 0x80000000;
+
+    struct Range {
+        unsigned start; // 
+        unsigned end;
+        SizeType next;
+    };
+
+    struct State {
+        SizeType out;     //!< Equals to kInvalid for matching state
+        SizeType out1;    //!< Equals to non-kInvalid for split
+        SizeType rangeStart;
+        unsigned codepoint;
+    };
+
+    struct Frag {
+        Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
+        SizeType start;
+        SizeType out; //!< link-list of all output states
+        SizeType minIndex;
+    };
+
+    template <typename SourceStream>
+    class DecodedStream {
+    public:
+        DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+        unsigned Peek() { return codepoint_; }
+        unsigned Take() {
+            unsigned c = codepoint_;
+            if (c) // No further decoding when '\0'
+                Decode();
+            return c;
+        }
+
+    private:
+        void Decode() {
+            if (!Encoding::Decode(ss_, &codepoint_))
+                codepoint_ = 0;
+        }
+
+        SourceStream& ss_;
+        unsigned codepoint_;
+    };
+
+    State& GetState(SizeType index) {
+        RAPIDJSON_ASSERT(index < stateCount_);
+        return states_.template Bottom<State>()[index];
+    }
+
+    const State& GetState(SizeType index) const {
+        RAPIDJSON_ASSERT(index < stateCount_);
+        return states_.template Bottom<State>()[index];
+    }
+
+    Range& GetRange(SizeType index) {
+        RAPIDJSON_ASSERT(index < rangeCount_);
+        return ranges_.template Bottom<Range>()[index];
+    }
+
+    const Range& GetRange(SizeType index) const {
+        RAPIDJSON_ASSERT(index < rangeCount_);
+        return ranges_.template Bottom<Range>()[index];
+    }
+
+    template <typename InputStream>
+    void Parse(DecodedStream<InputStream>& ds) {
+        Allocator allocator;
+        Stack<Allocator> operandStack(&allocator, 256);     // Frag
+        Stack<Allocator> operatorStack(&allocator, 256);    // Operator
+        Stack<Allocator> atomCountStack(&allocator, 256);   // unsigned (Atom per parenthesis)
+
+        *atomCountStack.template Push<unsigned>() = 0;
+
+        unsigned codepoint;
+        while (ds.Peek() != 0) {
+            switch (codepoint = ds.Take()) {
+                case '^':
+                    anchorBegin_ = true;
+                    break;
+
+                case '$':
+                    anchorEnd_ = true;
+                    break;
+
+                case '|':
+                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
+                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                            return;
+                    *operatorStack.template Push<Operator>() = kAlternation;
+                    *atomCountStack.template Top<unsigned>() = 0;
+                    break;
+
+                case '(':
+                    *operatorStack.template Push<Operator>() = kLeftParenthesis;
+                    *atomCountStack.template Push<unsigned>() = 0;
+                    break;
+
+                case ')':
+                    while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
+                        if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                            return;
+                    if (operatorStack.Empty())
+                        return;
+                    operatorStack.template Pop<Operator>(1);
+                    atomCountStack.template Pop<unsigned>(1);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '?':
+                    if (!Eval(operandStack, kZeroOrOne))
+                        return;
+                    break;
+
+                case '*':
+                    if (!Eval(operandStack, kZeroOrMore))
+                        return;
+                    break;
+
+                case '+':
+                    if (!Eval(operandStack, kOneOrMore))
+                        return;
+                    break;
+
+                case '{':
+                    {
+                        unsigned n, m;
+                        if (!ParseUnsigned(ds, &n))
+                            return;
+
+                        if (ds.Peek() == ',') {
+                            ds.Take();
+                            if (ds.Peek() == '}')
+                                m = kInfinityQuantifier;
+                            else if (!ParseUnsigned(ds, &m) || m < n)
+                                return;
+                        }
+                        else
+                            m = n;
+
+                        if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
+                            return;
+                        ds.Take();
+                    }
+                    break;
+
+                case '.':
+                    PushOperand(operandStack, kAnyCharacterClass);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '[':
+                    {
+                        SizeType range;
+                        if (!ParseRange(ds, &range))
+                            return;
+                        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
+                        GetState(s).rangeStart = range;
+                        *operandStack.template Push<Frag>() = Frag(s, s, s);
+                    }
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+                    break;
+
+                case '\\': // Escape character
+                    if (!CharacterEscape(ds, &codepoint))
+                        return; // Unsupported escape character
+                    // fall through to default
+
+                default: // Pattern character
+                    PushOperand(operandStack, codepoint);
+                    ImplicitConcatenation(atomCountStack, operatorStack);
+            }
+        }
+
+        while (!operatorStack.Empty())
+            if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+                return;
+
+        // Link the operand to matching state.
+        if (operandStack.GetSize() == sizeof(Frag)) {
+            Frag* e = operandStack.template Pop<Frag>(1);
+            Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
+            root_ = e->start;
+
+#if RAPIDJSON_REGEX_VERBOSE
+            printf("root: %d\n", root_);
+            for (SizeType i = 0; i < stateCount_ ; i++) {
+                State& s = GetState(i);
+                printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
+            }
+            printf("\n");
+#endif
+        }
+
+        // Preallocate buffer for SearchWithAnchoring()
+        RAPIDJSON_ASSERT(stateSet_ == 0);
+        if (stateCount_ > 0) {
+            stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
+            state0_.template Reserve<SizeType>(stateCount_);
+            state1_.template Reserve<SizeType>(stateCount_);
+        }
+    }
+
+    SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
+        State* s = states_.template Push<State>();
+        s->out = out;
+        s->out1 = out1;
+        s->codepoint = codepoint;
+        s->rangeStart = kRegexInvalidRange;
+        return stateCount_++;
+    }
+
+    void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
+        SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
+        *operandStack.template Push<Frag>() = Frag(s, s, s);
+    }
+
+    void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
+        if (*atomCountStack.template Top<unsigned>())
+            *operatorStack.template Push<Operator>() = kConcatenation;
+        (*atomCountStack.template Top<unsigned>())++;
+    }
+
+    SizeType Append(SizeType l1, SizeType l2) {
+        SizeType old = l1;
+        while (GetState(l1).out != kRegexInvalidState)
+            l1 = GetState(l1).out;
+        GetState(l1).out = l2;
+        return old;
+    }
+
+    void Patch(SizeType l, SizeType s) {
+        for (SizeType next; l != kRegexInvalidState; l = next) {
+            next = GetState(l).out;
+            GetState(l).out = s;
+        }
+    }
+
+    bool Eval(Stack<Allocator>& operandStack, Operator op) {
+        switch (op) {
+            case kConcatenation:
+                RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
+                {
+                    Frag e2 = *operandStack.template Pop<Frag>(1);
+                    Frag e1 = *operandStack.template Pop<Frag>(1);
+                    Patch(e1.out, e2.start);
+                    *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
+                }
+                return true;
+
+            case kAlternation:
+                if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+                    Frag e2 = *operandStack.template Pop<Frag>(1);
+                    Frag e1 = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(e1.start, e2.start, 0);
+                    *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
+                    return true;
+                }
+                return false;
+
+            case kZeroOrOne:
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
+                    return true;
+                }
+                return false;
+
+            case kZeroOrMore:
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    Patch(e.out, s);
+                    *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
+                    return true;
+                }
+                return false;
+
+            default: 
+                RAPIDJSON_ASSERT(op == kOneOrMore);
+                if (operandStack.GetSize() >= sizeof(Frag)) {
+                    Frag e = *operandStack.template Pop<Frag>(1);
+                    SizeType s = NewState(kRegexInvalidState, e.start, 0);
+                    Patch(e.out, s);
+                    *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
+                    return true;
+                }
+                return false;
+        }
+    }
+
+    bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
+        RAPIDJSON_ASSERT(n <= m);
+        RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
+
+        if (n == 0) {
+            if (m == 0)                             // a{0} not support
+                return false;
+            else if (m == kInfinityQuantifier)
+                Eval(operandStack, kZeroOrMore);    // a{0,} -> a*
+            else {
+                Eval(operandStack, kZeroOrOne);         // a{0,5} -> a?
+                for (unsigned i = 0; i < m - 1; i++)
+                    CloneTopOperand(operandStack);      // a{0,5} -> a? a? a? a? a?
+                for (unsigned i = 0; i < m - 1; i++)
+                    Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
+            }
+            return true;
+        }
+
+        for (unsigned i = 0; i < n - 1; i++)        // a{3} -> a a a
+            CloneTopOperand(operandStack);
+
+        if (m == kInfinityQuantifier)
+            Eval(operandStack, kOneOrMore);         // a{3,} -> a a a+
+        else if (m > n) {
+            CloneTopOperand(operandStack);          // a{3,5} -> a a a a
+            Eval(operandStack, kZeroOrOne);         // a{3,5} -> a a a a?
+            for (unsigned i = n; i < m - 1; i++)
+                CloneTopOperand(operandStack);      // a{3,5} -> a a a a? a?
+            for (unsigned i = n; i < m; i++)
+                Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
+        }
+
+        for (unsigned i = 0; i < n - 1; i++)
+            Eval(operandStack, kConcatenation);     // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
+
+        return true;
+    }
+
+    static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
+
+    void CloneTopOperand(Stack<Allocator>& operandStack) {
+        const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
+        SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
+        State* s = states_.template Push<State>(count);
+        memcpy(s, &GetState(src.minIndex), count * sizeof(State));
+        for (SizeType j = 0; j < count; j++) {
+            if (s[j].out != kRegexInvalidState)
+                s[j].out += count;
+            if (s[j].out1 != kRegexInvalidState)
+                s[j].out1 += count;
+        }
+        *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
+        stateCount_ += count;
+    }
+
+    template <typename InputStream>
+    bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
+        unsigned r = 0;
+        if (ds.Peek() < '0' || ds.Peek() > '9')
+            return false;
+        while (ds.Peek() >= '0' && ds.Peek() <= '9') {
+            if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
+                return false; // overflow
+            r = r * 10 + (ds.Take() - '0');
+        }
+        *u = r;
+        return true;
+    }
+
+    template <typename InputStream>
+    bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
+        bool isBegin = true;
+        bool negate = false;
+        int step = 0;
+        SizeType start = kRegexInvalidRange;
+        SizeType current = kRegexInvalidRange;
+        unsigned codepoint;
+        while ((codepoint = ds.Take()) != 0) {
+            if (isBegin) {
+                isBegin = false;
+                if (codepoint == '^') {
+                    negate = true;
+                    continue;
+                }
+            }
+
+            switch (codepoint) {
+            case ']':
+                if (start == kRegexInvalidRange)
+                    return false;   // Error: nothing inside []
+                if (step == 2) { // Add trailing '-'
+                    SizeType r = NewRange('-');
+                    RAPIDJSON_ASSERT(current != kRegexInvalidRange);
+                    GetRange(current).next = r;
+                }
+                if (negate)
+                    GetRange(start).start |= kRangeNegationFlag;
+                *range = start;
+                return true;
+
+            case '\\':
+                if (ds.Peek() == 'b') {
+                    ds.Take();
+                    codepoint = 0x0008; // Escape backspace character
+                }
+                else if (!CharacterEscape(ds, &codepoint))
+                    return false;
+                // fall through to default
+
+            default:
+                switch (step) {
+                case 1:
+                    if (codepoint == '-') {
+                        step++;
+                        break;
+                    }
+                    // fall through to step 0 for other characters
+
+                case 0:
+                    {
+                        SizeType r = NewRange(codepoint);
+                        if (current != kRegexInvalidRange)
+                            GetRange(current).next = r;
+                        if (start == kRegexInvalidRange)
+                            start = r;
+                        current = r;
+                    }
+                    step = 1;
+                    break;
+
+                default:
+                    RAPIDJSON_ASSERT(step == 2);
+                    GetRange(current).end = codepoint;
+                    step = 0;
+                }
+            }
+        }
+        return false;
+    }
+    
+    SizeType NewRange(unsigned codepoint) {
+        Range* r = ranges_.template Push<Range>();
+        r->start = r->end = codepoint;
+        r->next = kRegexInvalidRange;
+        return rangeCount_++;
+    }
+
+    template <typename InputStream>
+    bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
+        unsigned codepoint;
+        switch (codepoint = ds.Take()) {
+            case '^':
+            case '$':
+            case '|':
+            case '(':
+            case ')':
+            case '?':
+            case '*':
+            case '+':
+            case '.':
+            case '[':
+            case ']':
+            case '{':
+            case '}':
+            case '\\':
+                *escapedCodepoint = codepoint; return true;
+            case 'f': *escapedCodepoint = 0x000C; return true;
+            case 'n': *escapedCodepoint = 0x000A; return true;
+            case 'r': *escapedCodepoint = 0x000D; return true;
+            case 't': *escapedCodepoint = 0x0009; return true;
+            case 'v': *escapedCodepoint = 0x000B; return true;
+            default:
+                return false; // Unsupported escape character
+        }
+    }
+
+    template <typename InputStream>
+    bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
+        RAPIDJSON_ASSERT(IsValid());
+        DecodedStream<InputStream> ds(is);
+
+        state0_.Clear();
+        Stack<Allocator> *current = &state0_, *next = &state1_;
+        const size_t stateSetSize = GetStateSetSize();
+        std::memset(stateSet_, 0, stateSetSize);
+
+        bool matched = AddState(*current, root_);
+        unsigned codepoint;
+        while (!current->Empty() && (codepoint = ds.Take()) != 0) {
+            std::memset(stateSet_, 0, stateSetSize);
+            next->Clear();
+            matched = false;
+            for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
+                const State& sr = GetState(*s);
+                if (sr.codepoint == codepoint ||
+                    sr.codepoint == kAnyCharacterClass || 
+                    (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
+                {
+                    matched = AddState(*next, sr.out) || matched;
+                    if (!anchorEnd && matched)
+                        return true;
+                }
+                if (!anchorBegin)
+                    AddState(*next, root_);
+            }
+            internal::Swap(current, next);
+        }
+
+        return matched;
+    }
+
+    size_t GetStateSetSize() const {
+        return (stateCount_ + 31) / 32 * 4;
+    }
+
+    // Return whether the added states is a match state
+    bool AddState(Stack<Allocator>& l, SizeType index) const {
+        RAPIDJSON_ASSERT(index != kRegexInvalidState);
+
+        const State& s = GetState(index);
+        if (s.out1 != kRegexInvalidState) { // Split
+            bool matched = AddState(l, s.out);
+            return AddState(l, s.out1) || matched;
+        }
+        else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
+            stateSet_[index >> 5] |= (1 << (index & 31));
+            *l.template PushUnsafe<SizeType>() = index;
+        }
+        return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
+    }
+
+    bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
+        bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
+        while (rangeIndex != kRegexInvalidRange) {
+            const Range& r = GetRange(rangeIndex);
+            if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
+                return yes;
+            rangeIndex = r.next;
+        }
+        return !yes;
+    }
+
+    Stack<Allocator> states_;
+    Stack<Allocator> ranges_;
+    SizeType root_;
+    SizeType stateCount_;
+    SizeType rangeCount_;
+
+    static const unsigned kInfinityQuantifier = ~0u;
+
+    // For SearchWithAnchoring()
+    uint32_t* stateSet_;        // allocated by states_.GetAllocator()
+    mutable Stack<Allocator> state0_;
+    mutable Stack<Allocator> state1_;
+    bool anchorBegin_;
+    bool anchorEnd_;
+};
+
+typedef GenericRegex<UTF8<> > Regex;
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/core/deps/rapidjson/internal/stack.h b/core/deps/rapidjson/internal/stack.h
new file mode 100644 (file)
index 0000000..022c9aa
--- /dev/null
@@ -0,0 +1,230 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "../allocators.h"
+#include "swap.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+*/
+template <typename Allocator>
+class Stack {
+public:
+    // Optimization note: Do not allocate memory for stack_ in constructor.
+    // Do it lazily when first Push() -> Expand() -> Resize().
+    Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack(Stack&& rhs)
+        : allocator_(rhs.allocator_),
+          ownAllocator_(rhs.ownAllocator_),
+          stack_(rhs.stack_),
+          stackTop_(rhs.stackTop_),
+          stackEnd_(rhs.stackEnd_),
+          initialCapacity_(rhs.initialCapacity_)
+    {
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+        rhs.stack_ = 0;
+        rhs.stackTop_ = 0;
+        rhs.stackEnd_ = 0;
+        rhs.initialCapacity_ = 0;
+    }
+#endif
+
+    ~Stack() {
+        Destroy();
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    Stack& operator=(Stack&& rhs) {
+        if (&rhs != this)
+        {
+            Destroy();
+
+            allocator_ = rhs.allocator_;
+            ownAllocator_ = rhs.ownAllocator_;
+            stack_ = rhs.stack_;
+            stackTop_ = rhs.stackTop_;
+            stackEnd_ = rhs.stackEnd_;
+            initialCapacity_ = rhs.initialCapacity_;
+
+            rhs.allocator_ = 0;
+            rhs.ownAllocator_ = 0;
+            rhs.stack_ = 0;
+            rhs.stackTop_ = 0;
+            rhs.stackEnd_ = 0;
+            rhs.initialCapacity_ = 0;
+        }
+        return *this;
+    }
+#endif
+
+    void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+        internal::Swap(allocator_, rhs.allocator_);
+        internal::Swap(ownAllocator_, rhs.ownAllocator_);
+        internal::Swap(stack_, rhs.stack_);
+        internal::Swap(stackTop_, rhs.stackTop_);
+        internal::Swap(stackEnd_, rhs.stackEnd_);
+        internal::Swap(initialCapacity_, rhs.initialCapacity_);
+    }
+
+    void Clear() { stackTop_ = stack_; }
+
+    void ShrinkToFit() { 
+        if (Empty()) {
+            // If the stack is empty, completely deallocate the memory.
+            Allocator::Free(stack_);
+            stack_ = 0;
+            stackTop_ = 0;
+            stackEnd_ = 0;
+        }
+        else
+            Resize(GetSize());
+    }
+
+    // Optimization note: try to minimize the size of this function for force inline.
+    // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
+    template<typename T>
+    RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
+         // Expand the stack if needed
+        if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
+            Expand<T>(count);
+    }
+
+    template<typename T>
+    RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+        Reserve<T>(count);
+        return PushUnsafe<T>(count);
+    }
+
+    template<typename T>
+    RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
+        RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
+        T* ret = reinterpret_cast<T*>(stackTop_);
+        stackTop_ += sizeof(T) * count;
+        return ret;
+    }
+
+    template<typename T>
+    T* Pop(size_t count) {
+        RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+        stackTop_ -= count * sizeof(T);
+        return reinterpret_cast<T*>(stackTop_);
+    }
+
+    template<typename T>
+    T* Top() { 
+        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+    }
+
+    template<typename T>
+    const T* Top() const {
+        RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+        return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+    }
+
+    template<typename T>
+    T* End() { return reinterpret_cast<T*>(stackTop_); }
+
+    template<typename T>
+    const T* End() const { return reinterpret_cast<T*>(stackTop_); }
+
+    template<typename T>
+    T* Bottom() { return reinterpret_cast<T*>(stack_); }
+
+    template<typename T>
+    const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
+
+    bool HasAllocator() const {
+        return allocator_ != 0;
+    }
+
+    Allocator& GetAllocator() {
+        RAPIDJSON_ASSERT(allocator_);
+        return *allocator_;
+    }
+
+    bool Empty() const { return stackTop_ == stack_; }
+    size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+    size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+private:
+    template<typename T>
+    void Expand(size_t count) {
+        // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
+        size_t newCapacity;
+        if (stack_ == 0) {
+            if (!allocator_)
+                ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+            newCapacity = initialCapacity_;
+        } else {
+            newCapacity = GetCapacity();
+            newCapacity += (newCapacity + 1) / 2;
+        }
+        size_t newSize = GetSize() + sizeof(T) * count;
+        if (newCapacity < newSize)
+            newCapacity = newSize;
+
+        Resize(newCapacity);
+    }
+
+    void Resize(size_t newCapacity) {
+        const size_t size = GetSize();  // Backup the current size
+        stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
+        stackTop_ = stack_ + size;
+        stackEnd_ = stack_ + newCapacity;
+    }
+
+    void Destroy() {
+        Allocator::Free(stack_);
+        RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+    }
+
+    // Prohibit copy constructor & assignment operator.
+    Stack(const Stack&);
+    Stack& operator=(const Stack&);
+
+    Allocator* allocator_;
+    Allocator* ownAllocator_;
+    char *stack_;
+    char *stackTop_;
+    char *stackEnd_;
+    size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/core/deps/rapidjson/internal/strfunc.h b/core/deps/rapidjson/internal/strfunc.h
new file mode 100644 (file)
index 0000000..2edfae5
--- /dev/null
@@ -0,0 +1,55 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "../stream.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+    \param s Null-terminated input string.
+    \return Number of characters in the string. 
+    \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+    const Ch* p = s;
+    while (*p) ++p;
+    return SizeType(p - s);
+}
+
+//! Returns number of code points in a encoded string.
+template<typename Encoding>
+bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
+    GenericStringStream<Encoding> is(s);
+    const typename Encoding::Ch* end = s + length;
+    SizeType count = 0;
+    while (is.src_ < end) {
+        unsigned codepoint;
+        if (!Encoding::Decode(is, &codepoint))
+            return false;
+        count++;
+    }
+    *outCount = count;
+    return true;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/core/deps/rapidjson/internal/strtod.h b/core/deps/rapidjson/internal/strtod.h
new file mode 100644 (file)
index 0000000..289c413
--- /dev/null
@@ -0,0 +1,269 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRTOD_
+#define RAPIDJSON_STRTOD_
+
+#include "ieee754.h"
+#include "biginteger.h"
+#include "diyfp.h"
+#include "pow10.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline double FastPath(double significand, int exp) {
+    if (exp < -308)
+        return 0.0;
+    else if (exp >= 0)
+        return significand * internal::Pow10(exp);
+    else
+        return significand / internal::Pow10(-exp);
+}
+
+inline double StrtodNormalPrecision(double d, int p) {
+    if (p < -308) {
+        // Prevent expSum < -308, making Pow10(p) = 0
+        d = FastPath(d, -308);
+        d = FastPath(d, p + 308);
+    }
+    else
+        d = FastPath(d, p);
+    return d;
+}
+
+template <typename T>
+inline T Min3(T a, T b, T c) {
+    T m = a;
+    if (m > b) m = b;
+    if (m > c) m = c;
+    return m;
+}
+
+inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) {
+    const Double db(b);
+    const uint64_t bInt = db.IntegerSignificand();
+    const int bExp = db.IntegerExponent();
+    const int hExp = bExp - 1;
+
+    int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0;
+
+    // Adjust for decimal exponent
+    if (dExp >= 0) {
+        dS_Exp2 += dExp;
+        dS_Exp5 += dExp;
+    }
+    else {
+        bS_Exp2 -= dExp;
+        bS_Exp5 -= dExp;
+        hS_Exp2 -= dExp;
+        hS_Exp5 -= dExp;
+    }
+
+    // Adjust for binary exponent
+    if (bExp >= 0)
+        bS_Exp2 += bExp;
+    else {
+        dS_Exp2 -= bExp;
+        hS_Exp2 -= bExp;
+    }
+
+    // Adjust for half ulp exponent
+    if (hExp >= 0)
+        hS_Exp2 += hExp;
+    else {
+        dS_Exp2 -= hExp;
+        bS_Exp2 -= hExp;
+    }
+
+    // Remove common power of two factor from all three scaled values
+    int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2);
+    dS_Exp2 -= common_Exp2;
+    bS_Exp2 -= common_Exp2;
+    hS_Exp2 -= common_Exp2;
+
+    BigInteger dS = d;
+    dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2);
+
+    BigInteger bS(bInt);
+    bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2);
+
+    BigInteger hS(1);
+    hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2);
+
+    BigInteger delta(0);
+    dS.Difference(bS, &delta);
+
+    return delta.Compare(hS);
+}
+
+inline bool StrtodFast(double d, int p, double* result) {
+    // Use fast path for string-to-double conversion if possible
+    // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/
+    if (p > 22  && p < 22 + 16) {
+        // Fast Path Cases In Disguise
+        d *= internal::Pow10(p - 22);
+        p = 22;
+    }
+
+    if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1
+        *result = FastPath(d, p);
+        return true;
+    }
+    else
+        return false;
+}
+
+// Compute an approximation and see if it is within 1/2 ULP
+inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) {
+    uint64_t significand = 0;
+    size_t i = 0;   // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999    
+    for (; i < length; i++) {
+        if (significand  >  RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+            (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5'))
+            break;
+        significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0');
+    }
+    
+    if (i < length && decimals[i] >= '5') // Rounding
+        significand++;
+
+    size_t remaining = length - i;
+    const unsigned kUlpShift = 3;
+    const unsigned kUlp = 1 << kUlpShift;
+    int64_t error = (remaining == 0) ? 0 : kUlp / 2;
+
+    DiyFp v(significand, 0);
+    v = v.Normalize();
+    error <<= -v.e;
+
+    const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp;
+
+    int actualExp;
+    DiyFp cachedPower = GetCachedPower10(dExp, &actualExp);
+    if (actualExp != dExp) {
+        static const DiyFp kPow10[] = {
+            DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60),  // 10^1
+            DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57),  // 10^2
+            DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54),  // 10^3
+            DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50),  // 10^4
+            DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47),  // 10^5
+            DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44),  // 10^6
+            DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40)   // 10^7
+        };
+        int  adjustment = dExp - actualExp - 1;
+        RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7);
+        v = v * kPow10[adjustment];
+        if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit
+            error += kUlp / 2;
+    }
+
+    v = v * cachedPower;
+
+    error += kUlp + (error == 0 ? 0 : 1);
+
+    const int oldExp = v.e;
+    v = v.Normalize();
+    error <<= oldExp - v.e;
+
+    const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e);
+    unsigned precisionSize = 64 - effectiveSignificandSize;
+    if (precisionSize + kUlpShift >= 64) {
+        unsigned scaleExp = (precisionSize + kUlpShift) - 63;
+        v.f >>= scaleExp;
+        v.e += scaleExp; 
+        error = (error >> scaleExp) + 1 + static_cast<int>(kUlp);
+        precisionSize -= scaleExp;
+    }
+
+    DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize));
+    const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp;
+    const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp;
+    if (precisionBits >= halfWay + static_cast<unsigned>(error)) {
+        rounded.f++;
+        if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340)
+            rounded.f >>= 1;
+            rounded.e++;
+        }
+    }
+
+    *result = rounded.ToDouble();
+
+    return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error);
+}
+
+inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+    const BigInteger dInt(decimals, length);
+    const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp;
+    Double a(approx);
+    int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp);
+    if (cmp < 0)
+        return a.Value();  // within half ULP
+    else if (cmp == 0) {
+        // Round towards even
+        if (a.Significand() & 1)
+            return a.NextPositiveDouble();
+        else
+            return a.Value();
+    }
+    else // adjustment
+        return a.NextPositiveDouble();
+}
+
+inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) {
+    RAPIDJSON_ASSERT(d >= 0.0);
+    RAPIDJSON_ASSERT(length >= 1);
+
+    double result;
+    if (StrtodFast(d, p, &result))
+        return result;
+
+    // Trim leading zeros
+    while (*decimals == '0' && length > 1) {
+        length--;
+        decimals++;
+        decimalPosition--;
+    }
+
+    // Trim trailing zeros
+    while (decimals[length - 1] == '0' && length > 1) {
+        length--;
+        decimalPosition--;
+        exp++;
+    }
+
+    // Trim right-most digits
+    const int kMaxDecimalDigit = 780;
+    if (static_cast<int>(length) > kMaxDecimalDigit) {
+        int delta = (static_cast<int>(length) - kMaxDecimalDigit);
+        exp += delta;
+        decimalPosition -= static_cast<unsigned>(delta);
+        length = kMaxDecimalDigit;
+    }
+
+    // If too small, underflow to zero
+    if (int(length) + exp < -324)
+        return 0.0;
+
+    if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result))
+        return result;
+
+    // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison
+    return StrtodBigInteger(result, decimals, length, decimalPosition, exp);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STRTOD_
diff --git a/core/deps/rapidjson/internal/swap.h b/core/deps/rapidjson/internal/swap.h
new file mode 100644 (file)
index 0000000..666e49f
--- /dev/null
@@ -0,0 +1,46 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_INTERNAL_SWAP_H_
+#define RAPIDJSON_INTERNAL_SWAP_H_
+
+#include "../rapidjson.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom swap() to avoid dependency on C++ <algorithm> header
+/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
+    \note This has the same semantics as std::swap().
+*/
+template <typename T>
+inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
+    T tmp = a;
+        a = b;
+        b = tmp;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_SWAP_H_
diff --git a/core/deps/rapidjson/istreamwrapper.h b/core/deps/rapidjson/istreamwrapper.h
new file mode 100644 (file)
index 0000000..f5fe289
--- /dev/null
@@ -0,0 +1,115 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_ISTREAMWRAPPER_H_
+#define RAPIDJSON_ISTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4351) // new behavior: elements of array 'array' will be default initialized
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_istream into RapidJSON's Stream concept.
+/*!
+    The classes can be wrapped including but not limited to:
+
+    - \c std::istringstream
+    - \c std::stringstream
+    - \c std::wistringstream
+    - \c std::wstringstream
+    - \c std::ifstream
+    - \c std::fstream
+    - \c std::wifstream
+    - \c std::wfstream
+
+    \tparam StreamType Class derived from \c std::basic_istream.
+*/
+   
+template <typename StreamType>
+class BasicIStreamWrapper {
+public:
+    typedef typename StreamType::char_type Ch;
+    BasicIStreamWrapper(StreamType& stream) : stream_(stream), count_(), peekBuffer_() {}
+
+    Ch Peek() const { 
+        typename StreamType::int_type c = stream_.peek();
+        return RAPIDJSON_LIKELY(c != StreamType::traits_type::eof()) ? static_cast<Ch>(c) : '\0';
+    }
+
+    Ch Take() { 
+        typename StreamType::int_type c = stream_.get();
+        if (RAPIDJSON_LIKELY(c != StreamType::traits_type::eof())) {
+            count_++;
+            return static_cast<Ch>(c);
+        }
+        else
+            return '\0';
+    }
+
+    // tellg() may return -1 when failed. So we count by ourself.
+    size_t Tell() const { return count_; }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        RAPIDJSON_ASSERT(sizeof(Ch) == 1); // Only usable for byte stream.
+        int i;
+        bool hasError = false;
+        for (i = 0; i < 4; ++i) {
+            typename StreamType::int_type c = stream_.get();
+            if (c == StreamType::traits_type::eof()) {
+                hasError = true;
+                stream_.clear();
+                break;
+            }
+            peekBuffer_[i] = static_cast<Ch>(c);
+        }
+        for (--i; i >= 0; --i)
+            stream_.putback(peekBuffer_[i]);
+        return !hasError ? peekBuffer_ : 0;
+    }
+
+private:
+    BasicIStreamWrapper(const BasicIStreamWrapper&);
+    BasicIStreamWrapper& operator=(const BasicIStreamWrapper&);
+
+    StreamType& stream_;
+    size_t count_;  //!< Number of characters read. Note:
+    mutable Ch peekBuffer_[4];
+};
+
+typedef BasicIStreamWrapper<std::istream> IStreamWrapper;
+typedef BasicIStreamWrapper<std::wistream> WIStreamWrapper;
+
+#if defined(__clang__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ISTREAMWRAPPER_H_
diff --git a/core/deps/rapidjson/memorybuffer.h b/core/deps/rapidjson/memorybuffer.h
new file mode 100644 (file)
index 0000000..39bee1d
--- /dev/null
@@ -0,0 +1,70 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
+
+    It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
+
+    Differences between MemoryBuffer and StringBuffer:
+    1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer. 
+    2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+    \tparam Allocator type for allocating memory buffer.
+    \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+    typedef char Ch; // byte
+
+    GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+    void Flush() {}
+
+    void Clear() { stack_.Clear(); }
+    void ShrinkToFit() { stack_.ShrinkToFit(); }
+    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+    const Ch* GetBuffer() const {
+        return stack_.template Bottom<Ch>();
+    }
+
+    size_t GetSize() const { return stack_.GetSize(); }
+
+    static const size_t kDefaultCapacity = 256;
+    mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+    std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/core/deps/rapidjson/memorystream.h b/core/deps/rapidjson/memorystream.h
new file mode 100644 (file)
index 0000000..1d71d8a
--- /dev/null
@@ -0,0 +1,71 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_MEMORYSTREAM_H_
+#define RAPIDJSON_MEMORYSTREAM_H_
+
+#include "stream.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(unreachable-code)
+RAPIDJSON_DIAG_OFF(missing-noreturn)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory input byte stream.
+/*!
+    This class is mainly for being wrapped by EncodedInputStream or AutoUTFInputStream.
+
+    It is similar to FileReadBuffer but the source is an in-memory buffer instead of a file.
+
+    Differences between MemoryStream and StringStream:
+    1. StringStream has encoding but MemoryStream is a byte stream.
+    2. MemoryStream needs size of the source buffer and the buffer don't need to be null terminated. StringStream assume null-terminated string as source.
+    3. MemoryStream supports Peek4() for encoding detection. StringStream is specified with an encoding so it should not have Peek4().
+    \note implements Stream concept
+*/
+struct MemoryStream {
+    typedef char Ch; // byte
+
+    MemoryStream(const Ch *src, size_t size) : src_(src), begin_(src), end_(src + size), size_(size) {}
+
+    Ch Peek() const { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_; }
+    Ch Take() { return RAPIDJSON_UNLIKELY(src_ == end_) ? '\0' : *src_++; }
+    size_t Tell() const { return static_cast<size_t>(src_ - begin_); }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    // For encoding detection only.
+    const Ch* Peek4() const {
+        return Tell() + 4 <= size_ ? src_ : 0;
+    }
+
+    const Ch* src_;     //!< Current read position.
+    const Ch* begin_;   //!< Original head of the string.
+    const Ch* end_;     //!< End of stream.
+    size_t size_;       //!< Size of the stream.
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/core/deps/rapidjson/msinttypes/inttypes.h b/core/deps/rapidjson/msinttypes/inttypes.h
new file mode 100644 (file)
index 0000000..1811128
--- /dev/null
@@ -0,0 +1,316 @@
+// ISO C9x  compliant inttypes.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. Neither the name of the product nor the names of its contributors may
+//      be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) 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.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by 
+// THL A29 Limited ("Tencent Modifications"). 
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_INTTYPES_H_ // [
+#define _MSC_INTTYPES_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#include "stdint.h"
+
+// miloyip: VC supports inttypes.h since VC2013
+#if _MSC_VER >= 1800
+#include <inttypes.h>
+#else
+
+// 7.8 Format conversion of integer types
+
+typedef struct {
+   intmax_t quot;
+   intmax_t rem;
+} imaxdiv_t;
+
+// 7.8.1 Macros for format specifiers
+
+#if !defined(__cplusplus) || defined(__STDC_FORMAT_MACROS) // [   See footnote 185 at page 198
+
+// The fprintf macros for signed integers are:
+#define PRId8       "d"
+#define PRIi8       "i"
+#define PRIdLEAST8  "d"
+#define PRIiLEAST8  "i"
+#define PRIdFAST8   "d"
+#define PRIiFAST8   "i"
+
+#define PRId16       "hd"
+#define PRIi16       "hi"
+#define PRIdLEAST16  "hd"
+#define PRIiLEAST16  "hi"
+#define PRIdFAST16   "hd"
+#define PRIiFAST16   "hi"
+
+#define PRId32       "I32d"
+#define PRIi32       "I32i"
+#define PRIdLEAST32  "I32d"
+#define PRIiLEAST32  "I32i"
+#define PRIdFAST32   "I32d"
+#define PRIiFAST32   "I32i"
+
+#define PRId64       "I64d"
+#define PRIi64       "I64i"
+#define PRIdLEAST64  "I64d"
+#define PRIiLEAST64  "I64i"
+#define PRIdFAST64   "I64d"
+#define PRIiFAST64   "I64i"
+
+#define PRIdMAX     "I64d"
+#define PRIiMAX     "I64i"
+
+#define PRIdPTR     "Id"
+#define PRIiPTR     "Ii"
+
+// The fprintf macros for unsigned integers are:
+#define PRIo8       "o"
+#define PRIu8       "u"
+#define PRIx8       "x"
+#define PRIX8       "X"
+#define PRIoLEAST8  "o"
+#define PRIuLEAST8  "u"
+#define PRIxLEAST8  "x"
+#define PRIXLEAST8  "X"
+#define PRIoFAST8   "o"
+#define PRIuFAST8   "u"
+#define PRIxFAST8   "x"
+#define PRIXFAST8   "X"
+
+#define PRIo16       "ho"
+#define PRIu16       "hu"
+#define PRIx16       "hx"
+#define PRIX16       "hX"
+#define PRIoLEAST16  "ho"
+#define PRIuLEAST16  "hu"
+#define PRIxLEAST16  "hx"
+#define PRIXLEAST16  "hX"
+#define PRIoFAST16   "ho"
+#define PRIuFAST16   "hu"
+#define PRIxFAST16   "hx"
+#define PRIXFAST16   "hX"
+
+#define PRIo32       "I32o"
+#define PRIu32       "I32u"
+#define PRIx32       "I32x"
+#define PRIX32       "I32X"
+#define PRIoLEAST32  "I32o"
+#define PRIuLEAST32  "I32u"
+#define PRIxLEAST32  "I32x"
+#define PRIXLEAST32  "I32X"
+#define PRIoFAST32   "I32o"
+#define PRIuFAST32   "I32u"
+#define PRIxFAST32   "I32x"
+#define PRIXFAST32   "I32X"
+
+#define PRIo64       "I64o"
+#define PRIu64       "I64u"
+#define PRIx64       "I64x"
+#define PRIX64       "I64X"
+#define PRIoLEAST64  "I64o"
+#define PRIuLEAST64  "I64u"
+#define PRIxLEAST64  "I64x"
+#define PRIXLEAST64  "I64X"
+#define PRIoFAST64   "I64o"
+#define PRIuFAST64   "I64u"
+#define PRIxFAST64   "I64x"
+#define PRIXFAST64   "I64X"
+
+#define PRIoMAX     "I64o"
+#define PRIuMAX     "I64u"
+#define PRIxMAX     "I64x"
+#define PRIXMAX     "I64X"
+
+#define PRIoPTR     "Io"
+#define PRIuPTR     "Iu"
+#define PRIxPTR     "Ix"
+#define PRIXPTR     "IX"
+
+// The fscanf macros for signed integers are:
+#define SCNd8       "d"
+#define SCNi8       "i"
+#define SCNdLEAST8  "d"
+#define SCNiLEAST8  "i"
+#define SCNdFAST8   "d"
+#define SCNiFAST8   "i"
+
+#define SCNd16       "hd"
+#define SCNi16       "hi"
+#define SCNdLEAST16  "hd"
+#define SCNiLEAST16  "hi"
+#define SCNdFAST16   "hd"
+#define SCNiFAST16   "hi"
+
+#define SCNd32       "ld"
+#define SCNi32       "li"
+#define SCNdLEAST32  "ld"
+#define SCNiLEAST32  "li"
+#define SCNdFAST32   "ld"
+#define SCNiFAST32   "li"
+
+#define SCNd64       "I64d"
+#define SCNi64       "I64i"
+#define SCNdLEAST64  "I64d"
+#define SCNiLEAST64  "I64i"
+#define SCNdFAST64   "I64d"
+#define SCNiFAST64   "I64i"
+
+#define SCNdMAX     "I64d"
+#define SCNiMAX     "I64i"
+
+#ifdef _WIN64 // [
+#  define SCNdPTR     "I64d"
+#  define SCNiPTR     "I64i"
+#else  // _WIN64 ][
+#  define SCNdPTR     "ld"
+#  define SCNiPTR     "li"
+#endif  // _WIN64 ]
+
+// The fscanf macros for unsigned integers are:
+#define SCNo8       "o"
+#define SCNu8       "u"
+#define SCNx8       "x"
+#define SCNX8       "X"
+#define SCNoLEAST8  "o"
+#define SCNuLEAST8  "u"
+#define SCNxLEAST8  "x"
+#define SCNXLEAST8  "X"
+#define SCNoFAST8   "o"
+#define SCNuFAST8   "u"
+#define SCNxFAST8   "x"
+#define SCNXFAST8   "X"
+
+#define SCNo16       "ho"
+#define SCNu16       "hu"
+#define SCNx16       "hx"
+#define SCNX16       "hX"
+#define SCNoLEAST16  "ho"
+#define SCNuLEAST16  "hu"
+#define SCNxLEAST16  "hx"
+#define SCNXLEAST16  "hX"
+#define SCNoFAST16   "ho"
+#define SCNuFAST16   "hu"
+#define SCNxFAST16   "hx"
+#define SCNXFAST16   "hX"
+
+#define SCNo32       "lo"
+#define SCNu32       "lu"
+#define SCNx32       "lx"
+#define SCNX32       "lX"
+#define SCNoLEAST32  "lo"
+#define SCNuLEAST32  "lu"
+#define SCNxLEAST32  "lx"
+#define SCNXLEAST32  "lX"
+#define SCNoFAST32   "lo"
+#define SCNuFAST32   "lu"
+#define SCNxFAST32   "lx"
+#define SCNXFAST32   "lX"
+
+#define SCNo64       "I64o"
+#define SCNu64       "I64u"
+#define SCNx64       "I64x"
+#define SCNX64       "I64X"
+#define SCNoLEAST64  "I64o"
+#define SCNuLEAST64  "I64u"
+#define SCNxLEAST64  "I64x"
+#define SCNXLEAST64  "I64X"
+#define SCNoFAST64   "I64o"
+#define SCNuFAST64   "I64u"
+#define SCNxFAST64   "I64x"
+#define SCNXFAST64   "I64X"
+
+#define SCNoMAX     "I64o"
+#define SCNuMAX     "I64u"
+#define SCNxMAX     "I64x"
+#define SCNXMAX     "I64X"
+
+#ifdef _WIN64 // [
+#  define SCNoPTR     "I64o"
+#  define SCNuPTR     "I64u"
+#  define SCNxPTR     "I64x"
+#  define SCNXPTR     "I64X"
+#else  // _WIN64 ][
+#  define SCNoPTR     "lo"
+#  define SCNuPTR     "lu"
+#  define SCNxPTR     "lx"
+#  define SCNXPTR     "lX"
+#endif  // _WIN64 ]
+
+#endif // __STDC_FORMAT_MACROS ]
+
+// 7.8.2 Functions for greatest-width integer types
+
+// 7.8.2.1 The imaxabs function
+#define imaxabs _abs64
+
+// 7.8.2.2 The imaxdiv function
+
+// This is modified version of div() function from Microsoft's div.c found
+// in %MSVC.NET%\crt\src\div.c
+#ifdef STATIC_IMAXDIV // [
+static
+#else // STATIC_IMAXDIV ][
+_inline
+#endif // STATIC_IMAXDIV ]
+imaxdiv_t __cdecl imaxdiv(intmax_t numer, intmax_t denom)
+{
+   imaxdiv_t result;
+
+   result.quot = numer / denom;
+   result.rem = numer % denom;
+
+   if (numer < 0 && result.rem > 0) {
+      // did division wrong; must fix up
+      ++result.quot;
+      result.rem -= denom;
+   }
+
+   return result;
+}
+
+// 7.8.2.3 The strtoimax and strtoumax functions
+#define strtoimax _strtoi64
+#define strtoumax _strtoui64
+
+// 7.8.2.4 The wcstoimax and wcstoumax functions
+#define wcstoimax _wcstoi64
+#define wcstoumax _wcstoui64
+
+#endif // _MSC_VER >= 1800
+
+#endif // _MSC_INTTYPES_H_ ]
diff --git a/core/deps/rapidjson/msinttypes/stdint.h b/core/deps/rapidjson/msinttypes/stdint.h
new file mode 100644 (file)
index 0000000..3d4477b
--- /dev/null
@@ -0,0 +1,300 @@
+// ISO C9x  compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124 
+// 
+//  Copyright (c) 2006-2013 Alexander Chemeris
+// 
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+// 
+//   1. Redistributions of source code must retain the above copyright notice,
+//      this list of conditions and the following disclaimer.
+// 
+//   2. Redistributions in binary form must reproduce the above copyright
+//      notice, this list of conditions and the following disclaimer in the
+//      documentation and/or other materials provided with the distribution.
+// 
+//   3. Neither the name of the product nor the names of its contributors may
+//      be used to endorse or promote products derived from this software
+//      without specific prior written permission.
+// 
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) 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.
+// 
+///////////////////////////////////////////////////////////////////////////////
+
+// The above software in this distribution may have been modified by 
+// THL A29 Limited ("Tencent Modifications"). 
+// All Tencent Modifications are Copyright (C) 2015 THL A29 Limited.
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+// miloyip: Originally Visual Studio 2010 uses its own stdint.h. However it generates warning with INT64_C(), so change to use this file for vs2010.
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+#undef INT8_C
+#undef INT16_C
+#undef INT32_C
+#undef INT64_C
+#undef UINT8_C
+#undef UINT16_C
+#undef UINT32_C
+#undef UINT64_C
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C //   [
+#  define INTMAX_C   INT64_C
+#endif // INTMAX_C    ]
+#ifndef UINTMAX_C //  [
+#  define UINTMAX_C  UINT64_C
+#endif // UINTMAX_C   ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#else // ] _MSC_VER >= 1700 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we have to wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler would give many errors like this:
+//   error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#if defined(__cplusplus) && !defined(_M_ARM)
+extern "C" {
+#endif
+#  include <wchar.h>
+#if defined(__cplusplus) && !defined(_M_ARM)
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+#  if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+#     define _W64 __w64
+#  else
+#     define _W64
+#  endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+   typedef signed char       int8_t;
+   typedef signed short      int16_t;
+   typedef signed int        int32_t;
+   typedef unsigned char     uint8_t;
+   typedef unsigned short    uint16_t;
+   typedef unsigned int      uint32_t;
+#else
+   typedef signed __int8     int8_t;
+   typedef signed __int16    int16_t;
+   typedef signed __int32    int32_t;
+   typedef unsigned __int8   uint8_t;
+   typedef unsigned __int16  uint16_t;
+   typedef unsigned __int32  uint32_t;
+#endif
+typedef signed __int64       int64_t;
+typedef unsigned __int64     uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t    int_least8_t;
+typedef int16_t   int_least16_t;
+typedef int32_t   int_least32_t;
+typedef int64_t   int_least64_t;
+typedef uint8_t   uint_least8_t;
+typedef uint16_t  uint_least16_t;
+typedef uint32_t  uint_least32_t;
+typedef uint64_t  uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t    int_fast8_t;
+typedef int16_t   int_fast16_t;
+typedef int32_t   int_fast32_t;
+typedef int64_t   int_fast64_t;
+typedef uint8_t   uint_fast8_t;
+typedef uint16_t  uint_fast16_t;
+typedef uint32_t  uint_fast32_t;
+typedef uint64_t  uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+   typedef signed __int64    intptr_t;
+   typedef unsigned __int64  uintptr_t;
+#else // _WIN64 ][
+   typedef _W64 signed int   intptr_t;
+   typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t   intmax_t;
+typedef uint64_t  uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [   See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN     ((int8_t)_I8_MIN)
+#define INT8_MAX     _I8_MAX
+#define INT16_MIN    ((int16_t)_I16_MIN)
+#define INT16_MAX    _I16_MAX
+#define INT32_MIN    ((int32_t)_I32_MIN)
+#define INT32_MAX    _I32_MAX
+#define INT64_MIN    ((int64_t)_I64_MIN)
+#define INT64_MAX    _I64_MAX
+#define UINT8_MAX    _UI8_MAX
+#define UINT16_MAX   _UI16_MAX
+#define UINT32_MAX   _UI32_MAX
+#define UINT64_MAX   _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN    INT8_MIN
+#define INT_LEAST8_MAX    INT8_MAX
+#define INT_LEAST16_MIN   INT16_MIN
+#define INT_LEAST16_MAX   INT16_MAX
+#define INT_LEAST32_MIN   INT32_MIN
+#define INT_LEAST32_MAX   INT32_MAX
+#define INT_LEAST64_MIN   INT64_MIN
+#define INT_LEAST64_MAX   INT64_MAX
+#define UINT_LEAST8_MAX   UINT8_MAX
+#define UINT_LEAST16_MAX  UINT16_MAX
+#define UINT_LEAST32_MAX  UINT32_MAX
+#define UINT_LEAST64_MAX  UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN    INT8_MIN
+#define INT_FAST8_MAX    INT8_MAX
+#define INT_FAST16_MIN   INT16_MIN
+#define INT_FAST16_MAX   INT16_MAX
+#define INT_FAST32_MIN   INT32_MIN
+#define INT_FAST32_MAX   INT32_MAX
+#define INT_FAST64_MIN   INT64_MIN
+#define INT_FAST64_MAX   INT64_MAX
+#define UINT_FAST8_MAX   UINT8_MAX
+#define UINT_FAST16_MAX  UINT16_MAX
+#define UINT_FAST32_MAX  UINT32_MAX
+#define UINT_FAST64_MAX  UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+#  define INTPTR_MIN   INT64_MIN
+#  define INTPTR_MAX   INT64_MAX
+#  define UINTPTR_MAX  UINT64_MAX
+#else // _WIN64 ][
+#  define INTPTR_MIN   INT32_MIN
+#  define INTPTR_MAX   INT32_MAX
+#  define UINTPTR_MAX  UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN   INT64_MIN
+#define INTMAX_MAX   INT64_MAX
+#define UINTMAX_MAX  UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+#  define PTRDIFF_MIN  _I64_MIN
+#  define PTRDIFF_MAX  _I64_MAX
+#else  // _WIN64 ][
+#  define PTRDIFF_MIN  _I32_MIN
+#  define PTRDIFF_MAX  _I32_MAX
+#endif  // _WIN64 ]
+
+#define SIG_ATOMIC_MIN  INT_MIN
+#define SIG_ATOMIC_MAX  INT_MAX
+
+#ifndef SIZE_MAX // [
+#  ifdef _WIN64 // [
+#     define SIZE_MAX  _UI64_MAX
+#  else // _WIN64 ][
+#     define SIZE_MAX  _UI32_MAX
+#  endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+#  define WCHAR_MIN  0
+#endif  // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+#  define WCHAR_MAX  _UI16_MAX
+#endif  // WCHAR_MAX ]
+
+#define WINT_MIN  0
+#define WINT_MAX  _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [   See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val)  val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val)  val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C //   [
+#  define INTMAX_C   INT64_C
+#endif // INTMAX_C    ]
+#ifndef UINTMAX_C //  [
+#  define UINTMAX_C  UINT64_C
+#endif // UINTMAX_C   ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/core/deps/rapidjson/ostreamwrapper.h b/core/deps/rapidjson/ostreamwrapper.h
new file mode 100644 (file)
index 0000000..6f4667c
--- /dev/null
@@ -0,0 +1,81 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_OSTREAMWRAPPER_H_
+#define RAPIDJSON_OSTREAMWRAPPER_H_
+
+#include "stream.h"
+#include <iosfwd>
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Wrapper of \c std::basic_ostream into RapidJSON's Stream concept.
+/*!
+    The classes can be wrapped including but not limited to:
+
+    - \c std::ostringstream
+    - \c std::stringstream
+    - \c std::wpstringstream
+    - \c std::wstringstream
+    - \c std::ifstream
+    - \c std::fstream
+    - \c std::wofstream
+    - \c std::wfstream
+
+    \tparam StreamType Class derived from \c std::basic_ostream.
+*/
+   
+template <typename StreamType>
+class BasicOStreamWrapper {
+public:
+    typedef typename StreamType::char_type Ch;
+    BasicOStreamWrapper(StreamType& stream) : stream_(stream) {}
+
+    void Put(Ch c) {
+        stream_.put(c);
+    }
+
+    void Flush() {
+        stream_.flush();
+    }
+
+    // Not implemented
+    char Peek() const { RAPIDJSON_ASSERT(false); return 0; }
+    char Take() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t Tell() const { RAPIDJSON_ASSERT(false); return 0; }
+    char* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    size_t PutEnd(char*) { RAPIDJSON_ASSERT(false); return 0; }
+
+private:
+    BasicOStreamWrapper(const BasicOStreamWrapper&);
+    BasicOStreamWrapper& operator=(const BasicOStreamWrapper&);
+
+    StreamType& stream_;
+};
+
+typedef BasicOStreamWrapper<std::ostream> OStreamWrapper;
+typedef BasicOStreamWrapper<std::wostream> WOStreamWrapper;
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_OSTREAMWRAPPER_H_
diff --git a/core/deps/rapidjson/pointer.h b/core/deps/rapidjson/pointer.h
new file mode 100644 (file)
index 0000000..0206ac1
--- /dev/null
@@ -0,0 +1,1358 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_POINTER_H_
+#define RAPIDJSON_POINTER_H_
+
+#include "document.h"
+#include "internal/itoa.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+static const SizeType kPointerInvalidIndex = ~SizeType(0);  //!< Represents an invalid index in GenericPointer::Token
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+    \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
+*/
+enum PointerParseErrorCode {
+    kPointerParseErrorNone = 0,                     //!< The parse is successful
+
+    kPointerParseErrorTokenMustBeginWithSolidus,    //!< A token must begin with a '/'
+    kPointerParseErrorInvalidEscape,                //!< Invalid escape
+    kPointerParseErrorInvalidPercentEncoding,       //!< Invalid percent encoding in URI fragment
+    kPointerParseErrorCharacterMustPercentEncode    //!< A character must percent encoded in URI fragment
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericPointer
+
+//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
+/*!
+    This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer" 
+    (https://tools.ietf.org/html/rfc6901).
+
+    A JSON pointer is for identifying a specific value in a JSON document
+    (GenericDocument). It can simplify coding of DOM tree manipulation, because it
+    can access multiple-level depth of DOM tree with single API call.
+
+    After it parses a string representation (e.g. "/foo/0" or URI fragment 
+    representation (e.g. "#/foo/0") into its internal representation (tokens),
+    it can be used to resolve a specific value in multiple documents, or sub-tree 
+    of documents.
+
+    Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
+    Apart from assignment, a Pointer cannot be modified after construction.
+
+    Although Pointer is very convenient, please aware that constructing Pointer
+    involves parsing and dynamic memory allocation. A special constructor with user-
+    supplied tokens eliminates these.
+
+    GenericPointer depends on GenericDocument and GenericValue.
+    
+    \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
+    \tparam Allocator The allocator type for allocating memory for internal representation.
+    
+    \note GenericPointer uses same encoding of ValueType.
+    However, Allocator of GenericPointer is independent of Allocator of Value.
+*/
+template <typename ValueType, typename Allocator = CrtAllocator>
+class GenericPointer {
+public:
+    typedef typename ValueType::EncodingType EncodingType;  //!< Encoding type from Value
+    typedef typename ValueType::Ch Ch;                      //!< Character type from Value
+
+    //! A token is the basic units of internal representation.
+    /*!
+        A JSON pointer string representation "/foo/123" is parsed to two tokens: 
+        "foo" and 123. 123 will be represented in both numeric form and string form.
+        They are resolved according to the actual value type (object or array).
+
+        For token that are not numbers, or the numeric value is out of bound
+        (greater than limits of SizeType), they are only treated as string form
+        (i.e. the token's index will be equal to kPointerInvalidIndex).
+
+        This struct is public so that user can create a Pointer without parsing and 
+        allocation, using a special constructor.
+    */
+    struct Token {
+        const Ch* name;             //!< Name of the token. It has null character at the end but it can contain null character.
+        SizeType length;            //!< Length of the name.
+        SizeType index;             //!< A valid array index, if it is not equal to kPointerInvalidIndex.
+    };
+
+    //!@name Constructors and destructor.
+    //@{
+
+    //! Default constructor.
+    GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+    //! Constructor that parses a string or URI fragment representation.
+    /*!
+        \param source A null-terminated, string or URI fragment representation of JSON pointer.
+        \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+    */
+    explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+        Parse(source, internal::StrLen(source));
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Constructor that parses a string or URI fragment representation.
+    /*!
+        \param source A string or URI fragment representation of JSON pointer.
+        \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+        \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+    */
+    explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+        Parse(source.c_str(), source.size());
+    }
+#endif
+
+    //! Constructor that parses a string or URI fragment representation, with length of the source string.
+    /*!
+        \param source A string or URI fragment representation of JSON pointer.
+        \param length Length of source.
+        \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
+        \note Slightly faster than the overload without length.
+    */
+    GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+        Parse(source, length);
+    }
+
+    //! Constructor with user-supplied tokens.
+    /*!
+        This constructor let user supplies const array of tokens.
+        This prevents the parsing process and eliminates allocation.
+        This is preferred for memory constrained environments.
+
+        \param tokens An constant array of tokens representing the JSON pointer.
+        \param tokenCount Number of tokens.
+
+        \b Example
+        \code
+        #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+        #define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+        static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+        static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+        // Equivalent to static const Pointer p("/foo/123");
+
+        #undef NAME
+        #undef INDEX
+        \endcode
+    */
+    GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
+
+    //! Copy constructor.
+    GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
+        *this = rhs;
+    }
+
+    //! Destructor.
+    ~GenericPointer() {
+        if (nameBuffer_)    // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
+            Allocator::Free(tokens_);
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    //! Assignment operator.
+    GenericPointer& operator=(const GenericPointer& rhs) {
+        if (this != &rhs) {
+            // Do not delete ownAllcator
+            if (nameBuffer_)
+                Allocator::Free(tokens_);
+
+            tokenCount_ = rhs.tokenCount_;
+            parseErrorOffset_ = rhs.parseErrorOffset_;
+            parseErrorCode_ = rhs.parseErrorCode_;
+
+            if (rhs.nameBuffer_)
+                CopyFromRaw(rhs); // Normally parsed tokens.
+            else {
+                tokens_ = rhs.tokens_; // User supplied const tokens.
+                nameBuffer_ = 0;
+            }
+        }
+        return *this;
+    }
+
+    //@}
+
+    //!@name Append token
+    //@{
+
+    //! Append a token and return a new Pointer
+    /*!
+        \param token Token to be appended.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
+        GenericPointer r;
+        r.allocator_ = allocator;
+        Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
+        std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
+        r.tokens_[tokenCount_].name = p;
+        r.tokens_[tokenCount_].length = token.length;
+        r.tokens_[tokenCount_].index = token.index;
+        return r;
+    }
+
+    //! Append a name token with length, and return a new Pointer
+    /*!
+        \param name Name to be appended.
+        \param length Length of name.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
+        Token token = { name, length, kPointerInvalidIndex };
+        return Append(token, allocator);
+    }
+
+    //! Append a name token without length, and return a new Pointer
+    /*!
+        \param name Name (const Ch*) to be appended.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
+    Append(T* name, Allocator* allocator = 0) const {
+        return Append(name, StrLen(name), allocator);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Append a name token, and return a new Pointer
+    /*!
+        \param name Name to be appended.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
+        return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
+    }
+#endif
+
+    //! Append a index token, and return a new Pointer
+    /*!
+        \param index Index to be appended.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
+        char buffer[21];
+        char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
+        SizeType length = static_cast<SizeType>(end - buffer);
+        buffer[length] = '\0';
+
+        if (sizeof(Ch) == 1) {
+            Token token = { reinterpret_cast<Ch*>(buffer), length, index };
+            return Append(token, allocator);
+        }
+        else {
+            Ch name[21];
+            for (size_t i = 0; i <= length; i++)
+                name[i] = buffer[i];
+            Token token = { name, length, index };
+            return Append(token, allocator);
+        }
+    }
+
+    //! Append a token by value, and return a new Pointer
+    /*!
+        \param token token to be appended.
+        \param allocator Allocator for the newly return Pointer.
+        \return A new Pointer with appended token.
+    */
+    GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
+        if (token.IsString())
+            return Append(token.GetString(), token.GetStringLength(), allocator);
+        else {
+            RAPIDJSON_ASSERT(token.IsUint64());
+            RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
+            return Append(static_cast<SizeType>(token.GetUint64()), allocator);
+        }
+    }
+
+    //!@name Handling Parse Error
+    //@{
+
+    //! Check whether this is a valid pointer.
+    bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
+
+    //! Get the parsing error offset in code unit.
+    size_t GetParseErrorOffset() const { return parseErrorOffset_; }
+
+    //! Get the parsing error code.
+    PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
+
+    //@}
+
+    //! Get the allocator of this pointer.
+    Allocator& GetAllocator() { return *allocator_; }
+
+    //!@name Tokens
+    //@{
+
+    //! Get the token array (const version only).
+    const Token* GetTokens() const { return tokens_; }
+
+    //! Get the number of tokens.
+    size_t GetTokenCount() const { return tokenCount_; }
+
+    //@}
+
+    //!@name Equality/inequality operators
+    //@{
+
+    //! Equality operator.
+    /*!
+        \note When any pointers are invalid, always returns false.
+    */
+    bool operator==(const GenericPointer& rhs) const {
+        if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
+            return false;
+
+        for (size_t i = 0; i < tokenCount_; i++) {
+            if (tokens_[i].index != rhs.tokens_[i].index ||
+                tokens_[i].length != rhs.tokens_[i].length || 
+                (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
+            {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    //! Inequality operator.
+    /*!
+        \note When any pointers are invalid, always returns true.
+    */
+    bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
+
+    //@}
+
+    //!@name Stringify
+    //@{
+
+    //! Stringify the pointer into string representation.
+    /*!
+        \tparam OutputStream Type of output stream.
+        \param os The output stream.
+    */
+    template<typename OutputStream>
+    bool Stringify(OutputStream& os) const {
+        return Stringify<false, OutputStream>(os);
+    }
+
+    //! Stringify the pointer into URI fragment representation.
+    /*!
+        \tparam OutputStream Type of output stream.
+        \param os The output stream.
+    */
+    template<typename OutputStream>
+    bool StringifyUriFragment(OutputStream& os) const {
+        return Stringify<true, OutputStream>(os);
+    }
+
+    //@}
+
+    //!@name Create value
+    //@{
+
+    //! Create a value in a subtree.
+    /*!
+        If the value is not exist, it creates all parent values and a JSON Null value.
+        So it always succeed and return the newly created or existing value.
+
+        Remind that it may change types of parents according to tokens, so it 
+        potentially removes previously stored values. For example, if a document 
+        was an array, and "/foo" is used to create a value, then the document 
+        will be changed to an object, and all existing array elements are lost.
+
+        \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
+        \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+        \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+        \return The resolved newly created (a JSON Null value), or already exists value.
+    */
+    ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
+        RAPIDJSON_ASSERT(IsValid());
+        ValueType* v = &root;
+        bool exist = true;
+        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+            if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
+                v->PushBack(ValueType().Move(), allocator);
+                v = &((*v)[v->Size() - 1]);
+                exist = false;
+            }
+            else {
+                if (t->index == kPointerInvalidIndex) { // must be object name
+                    if (!v->IsObject())
+                        v->SetObject(); // Change to Object
+                }
+                else { // object name or array index
+                    if (!v->IsArray() && !v->IsObject())
+                        v->SetArray(); // Change to Array
+                }
+
+                if (v->IsArray()) {
+                    if (t->index >= v->Size()) {
+                        v->Reserve(t->index + 1, allocator);
+                        while (t->index >= v->Size())
+                            v->PushBack(ValueType().Move(), allocator);
+                        exist = false;
+                    }
+                    v = &((*v)[t->index]);
+                }
+                else {
+                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+                    if (m == v->MemberEnd()) {
+                        v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
+                        v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
+                        exist = false;
+                    }
+                    else
+                        v = &m->value;
+                }
+            }
+        }
+
+        if (alreadyExist)
+            *alreadyExist = exist;
+
+        return *v;
+    }
+
+    //! Creates a value in a document.
+    /*!
+        \param document A document to be resolved.
+        \param alreadyExist If non-null, it stores whether the resolved value is already exist.
+        \return The resolved newly created, or already exists value.
+    */
+    template <typename stackAllocator>
+    ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
+        return Create(document, document.GetAllocator(), alreadyExist);
+    }
+
+    //@}
+
+    //!@name Query value
+    //@{
+
+    //! Query a value in a subtree.
+    /*!
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
+        \return Pointer to the value if it can be resolved. Otherwise null.
+
+        \note
+        There are only 3 situations when a value cannot be resolved:
+        1. A value in the path is not an array nor object.
+        2. An object value does not contain the token.
+        3. A token is out of range of an array value.
+
+        Use unresolvedTokenIndex to retrieve the token index.
+    */
+    ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+        RAPIDJSON_ASSERT(IsValid());
+        ValueType* v = &root;
+        for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+            switch (v->GetType()) {
+            case kObjectType:
+                {
+                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+                    if (m == v->MemberEnd())
+                        break;
+                    v = &m->value;
+                }
+                continue;
+            case kArrayType:
+                if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+                    break;
+                v = &((*v)[t->index]);
+                continue;
+            default:
+                break;
+            }
+
+            // Error: unresolved token
+            if (unresolvedTokenIndex)
+                *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
+            return 0;
+        }
+        return v;
+    }
+
+    //! Query a const value in a const subtree.
+    /*!
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \return Pointer to the value if it can be resolved. Otherwise null.
+    */
+    const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const { 
+        return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
+    }
+
+    //@}
+
+    //!@name Query a value with default
+    //@{
+
+    //! Query a value in a subtree with default value.
+    /*!
+        Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
+        So that this function always succeed.
+
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \param defaultValue Default value to be cloned if the value was not exists.
+        \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+        \see Create()
+    */
+    ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
+        bool alreadyExist;
+        Value& v = Create(root, allocator, &alreadyExist);
+        return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
+    }
+
+    //! Query a value in a subtree with default null-terminated string.
+    ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
+        bool alreadyExist;
+        Value& v = Create(root, allocator, &alreadyExist);
+        return alreadyExist ? v : v.SetString(defaultValue, allocator);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Query a value in a subtree with default std::basic_string.
+    ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
+        bool alreadyExist;
+        Value& v = Create(root, allocator, &alreadyExist);
+        return alreadyExist ? v : v.SetString(defaultValue, allocator);
+    }
+#endif
+
+    //! Query a value in a subtree with default primitive value.
+    /*!
+        \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+    GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
+        return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
+    }
+
+    //! Query a value in a document with default value.
+    template <typename stackAllocator>
+    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
+        return GetWithDefault(document, defaultValue, document.GetAllocator());
+    }
+
+    //! Query a value in a document with default null-terminated string.
+    template <typename stackAllocator>
+    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
+        return GetWithDefault(document, defaultValue, document.GetAllocator());
+    }
+    
+#if RAPIDJSON_HAS_STDSTRING
+    //! Query a value in a document with default std::basic_string.
+    template <typename stackAllocator>
+    ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
+        return GetWithDefault(document, defaultValue, document.GetAllocator());
+    }
+#endif
+
+    //! Query a value in a document with default primitive value.
+    /*!
+        \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+    */
+    template <typename T, typename stackAllocator>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+    GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
+        return GetWithDefault(document, defaultValue, document.GetAllocator());
+    }
+
+    //@}
+
+    //!@name Set a value
+    //@{
+
+    //! Set a value in a subtree, with move semantics.
+    /*!
+        It creates all parents if they are not exist or types are different to the tokens.
+        So this function always succeeds but potentially remove existing values.
+
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \param value Value to be set.
+        \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+        \see Create()
+    */
+    ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator) = value;
+    }
+
+    //! Set a value in a subtree, with copy semantics.
+    ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator).CopyFrom(value, allocator);
+    }
+
+    //! Set a null-terminated string in a subtree.
+    ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator) = ValueType(value, allocator).Move();
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Set a std::basic_string in a subtree.
+    ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator) = ValueType(value, allocator).Move();
+    }
+#endif
+
+    //! Set a primitive value in a subtree.
+    /*!
+        \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+    */
+    template <typename T>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+    Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator) = ValueType(value).Move();
+    }
+
+    //! Set a value in a document, with move semantics.
+    template <typename stackAllocator>
+    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+        return Create(document) = value;
+    }
+
+    //! Set a value in a document, with copy semantics.
+    template <typename stackAllocator>
+    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
+        return Create(document).CopyFrom(value, document.GetAllocator());
+    }
+
+    //! Set a null-terminated string in a document.
+    template <typename stackAllocator>
+    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
+        return Create(document) = ValueType(value, document.GetAllocator()).Move();
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    //! Sets a std::basic_string in a document.
+    template <typename stackAllocator>
+    ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
+        return Create(document) = ValueType(value, document.GetAllocator()).Move();
+    }
+#endif
+
+    //! Set a primitive value in a document.
+    /*!
+    \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
+    */
+    template <typename T, typename stackAllocator>
+    RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
+        Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
+            return Create(document) = value;
+    }
+
+    //@}
+
+    //!@name Swap a value
+    //@{
+
+    //! Swap a value with a value in a subtree.
+    /*!
+        It creates all parents if they are not exist or types are different to the tokens.
+        So this function always succeeds but potentially remove existing values.
+
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \param value Value to be swapped.
+        \param allocator Allocator for creating the values if the specified value or its parents are not exist.
+        \see Create()
+    */
+    ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
+        return Create(root, allocator).Swap(value);
+    }
+
+    //! Swap a value with a value in a document.
+    template <typename stackAllocator>
+    ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
+        return Create(document).Swap(value);
+    }
+
+    //@}
+
+    //! Erase a value in a subtree.
+    /*!
+        \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
+        \return Whether the resolved value is found and erased.
+
+        \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
+    */
+    bool Erase(ValueType& root) const {
+        RAPIDJSON_ASSERT(IsValid());
+        if (tokenCount_ == 0) // Cannot erase the root
+            return false;
+
+        ValueType* v = &root;
+        const Token* last = tokens_ + (tokenCount_ - 1);
+        for (const Token *t = tokens_; t != last; ++t) {
+            switch (v->GetType()) {
+            case kObjectType:
+                {
+                    typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+                    if (m == v->MemberEnd())
+                        return false;
+                    v = &m->value;
+                }
+                break;
+            case kArrayType:
+                if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+                    return false;
+                v = &((*v)[t->index]);
+                break;
+            default:
+                return false;
+            }
+        }
+
+        switch (v->GetType()) {
+        case kObjectType:
+            return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
+        case kArrayType:
+            if (last->index == kPointerInvalidIndex || last->index >= v->Size())
+                return false;
+            v->Erase(v->Begin() + last->index);
+            return true;
+        default:
+            return false;
+        }
+    }
+
+private:
+    //! Clone the content from rhs to this.
+    /*!
+        \param rhs Source pointer.
+        \param extraToken Extra tokens to be allocated.
+        \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
+        \return Start of non-occupied name buffer, for storing extra names.
+    */
+    Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
+        if (!allocator_) // allocator is independently owned.
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+        size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
+        for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
+            nameBufferSize += t->length;
+
+        tokenCount_ = rhs.tokenCount_ + extraToken;
+        tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
+        nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+        if (rhs.tokenCount_ > 0) {
+            std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
+        }
+        if (nameBufferSize > 0) {
+            std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
+        }
+
+        // Adjust pointers to name buffer
+        std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
+        for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
+            t->name += diff;
+
+        return nameBuffer_ + nameBufferSize;
+    }
+
+    //! Check whether a character should be percent-encoded.
+    /*!
+        According to RFC 3986 2.3 Unreserved Characters.
+        \param c The character (code unit) to be tested.
+    */
+    bool NeedPercentEncode(Ch c) const {
+        return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
+    }
+
+    //! Parse a JSON String or its URI fragment representation into tokens.
+#ifndef __clang__ // -Wdocumentation
+    /*!
+        \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
+        \param length Length of the source string.
+        \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
+    */
+#endif
+    void Parse(const Ch* source, size_t length) {
+        RAPIDJSON_ASSERT(source != NULL);
+        RAPIDJSON_ASSERT(nameBuffer_ == 0);
+        RAPIDJSON_ASSERT(tokens_ == 0);
+
+        // Create own allocator if user did not supply.
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+        // Count number of '/' as tokenCount
+        tokenCount_ = 0;
+        for (const Ch* s = source; s != source + length; s++) 
+            if (*s == '/')
+                tokenCount_++;
+
+        Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
+        Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
+        size_t i = 0;
+
+        // Detect if it is a URI fragment
+        bool uriFragment = false;
+        if (source[i] == '#') {
+            uriFragment = true;
+            i++;
+        }
+
+        if (i != length && source[i] != '/') {
+            parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
+            goto error;
+        }
+
+        while (i < length) {
+            RAPIDJSON_ASSERT(source[i] == '/');
+            i++; // consumes '/'
+
+            token->name = name;
+            bool isNumber = true;
+
+            while (i < length && source[i] != '/') {
+                Ch c = source[i];
+                if (uriFragment) {
+                    // Decoding percent-encoding for URI fragment
+                    if (c == '%') {
+                        PercentDecodeStream is(&source[i], source + length);
+                        GenericInsituStringStream<EncodingType> os(name);
+                        Ch* begin = os.PutBegin();
+                        if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
+                            parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
+                            goto error;
+                        }
+                        size_t len = os.PutEnd(begin);
+                        i += is.Tell() - 1;
+                        if (len == 1)
+                            c = *name;
+                        else {
+                            name += len;
+                            isNumber = false;
+                            i++;
+                            continue;
+                        }
+                    }
+                    else if (NeedPercentEncode(c)) {
+                        parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
+                        goto error;
+                    }
+                }
+
+                i++;
+                
+                // Escaping "~0" -> '~', "~1" -> '/'
+                if (c == '~') {
+                    if (i < length) {
+                        c = source[i];
+                        if (c == '0')       c = '~';
+                        else if (c == '1')  c = '/';
+                        else {
+                            parseErrorCode_ = kPointerParseErrorInvalidEscape;
+                            goto error;
+                        }
+                        i++;
+                    }
+                    else {
+                        parseErrorCode_ = kPointerParseErrorInvalidEscape;
+                        goto error;
+                    }
+                }
+
+                // First check for index: all of characters are digit
+                if (c < '0' || c > '9')
+                    isNumber = false;
+
+                *name++ = c;
+            }
+            token->length = static_cast<SizeType>(name - token->name);
+            if (token->length == 0)
+                isNumber = false;
+            *name++ = '\0'; // Null terminator
+
+            // Second check for index: more than one digit cannot have leading zero
+            if (isNumber && token->length > 1 && token->name[0] == '0')
+                isNumber = false;
+
+            // String to SizeType conversion
+            SizeType n = 0;
+            if (isNumber) {
+                for (size_t j = 0; j < token->length; j++) {
+                    SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
+                    if (m < n) {   // overflow detection
+                        isNumber = false;
+                        break;
+                    }
+                    n = m;
+                }
+            }
+
+            token->index = isNumber ? n : kPointerInvalidIndex;
+            token++;
+        }
+
+        RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
+        parseErrorCode_ = kPointerParseErrorNone;
+        return;
+
+    error:
+        Allocator::Free(tokens_);
+        nameBuffer_ = 0;
+        tokens_ = 0;
+        tokenCount_ = 0;
+        parseErrorOffset_ = i;
+        return;
+    }
+
+    //! Stringify to string or URI fragment representation.
+    /*!
+        \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
+        \tparam OutputStream type of output stream.
+        \param os The output stream.
+    */
+    template<bool uriFragment, typename OutputStream>
+    bool Stringify(OutputStream& os) const {
+        RAPIDJSON_ASSERT(IsValid());
+
+        if (uriFragment)
+            os.Put('#');
+
+        for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
+            os.Put('/');
+            for (size_t j = 0; j < t->length; j++) {
+                Ch c = t->name[j];
+                if (c == '~') {
+                    os.Put('~');
+                    os.Put('0');
+                }
+                else if (c == '/') {
+                    os.Put('~');
+                    os.Put('1');
+                }
+                else if (uriFragment && NeedPercentEncode(c)) { 
+                    // Transcode to UTF8 sequence
+                    GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
+                    PercentEncodeStream<OutputStream> target(os);
+                    if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
+                        return false;
+                    j += source.Tell() - 1;
+                }
+                else
+                    os.Put(c);
+            }
+        }
+        return true;
+    }
+
+    //! A helper stream for decoding a percent-encoded sequence into code unit.
+    /*!
+        This stream decodes %XY triplet into code unit (0-255).
+        If it encounters invalid characters, it sets output code unit as 0 and 
+        mark invalid, and to be checked by IsValid().
+    */
+    class PercentDecodeStream {
+    public:
+        typedef typename ValueType::Ch Ch;
+
+        //! Constructor
+        /*!
+            \param source Start of the stream
+            \param end Past-the-end of the stream.
+        */
+        PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
+
+        Ch Take() {
+            if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
+                valid_ = false;
+                return 0;
+            }
+            src_++;
+            Ch c = 0;
+            for (int j = 0; j < 2; j++) {
+                c = static_cast<Ch>(c << 4);
+                Ch h = *src_;
+                if      (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
+                else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
+                else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
+                else {
+                    valid_ = false;
+                    return 0;
+                }
+                src_++;
+            }
+            return c;
+        }
+
+        size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+        bool IsValid() const { return valid_; }
+
+    private:
+        const Ch* src_;     //!< Current read position.
+        const Ch* head_;    //!< Original head of the string.
+        const Ch* end_;     //!< Past-the-end position.
+        bool valid_;        //!< Whether the parsing is valid.
+    };
+
+    //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
+    template <typename OutputStream>
+    class PercentEncodeStream {
+    public:
+        PercentEncodeStream(OutputStream& os) : os_(os) {}
+        void Put(char c) { // UTF-8 must be byte
+            unsigned char u = static_cast<unsigned char>(c);
+            static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+            os_.Put('%');
+            os_.Put(hexDigits[u >> 4]);
+            os_.Put(hexDigits[u & 15]);
+        }
+    private:
+        OutputStream& os_;
+    };
+
+    Allocator* allocator_;                  //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
+    Allocator* ownAllocator_;               //!< Allocator owned by this Pointer.
+    Ch* nameBuffer_;                        //!< A buffer containing all names in tokens.
+    Token* tokens_;                         //!< A list of tokens.
+    size_t tokenCount_;                     //!< Number of tokens in tokens_.
+    size_t parseErrorOffset_;               //!< Offset in code unit when parsing fail.
+    PointerParseErrorCode parseErrorCode_;  //!< Parsing error code.
+};
+
+//! GenericPointer for Value (UTF-8, default allocator).
+typedef GenericPointer<Value> Pointer;
+
+//!@name Helper functions for GenericPointer
+//@{
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
+    return pointer.Create(root, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
+    return pointer.Create(document);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+    return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T>
+const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
+    return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+    return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+    return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+    return pointer.GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
+    return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
+    return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
+    return pointer.GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+    return pointer.GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
+    return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+    return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
+    return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
+    return pointer.Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+    return pointer.Set(root, value, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
+    return pointer.Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
+SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+    return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
+    return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
+    return pointer.Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
+    return pointer.Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
+    return pointer.Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
+    return pointer.Swap(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
+    return pointer.Swap(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
+    return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
+    return pointer.Erase(root);
+}
+
+template <typename T, typename CharType, size_t N>
+bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
+    return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
+}
+
+//@}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_POINTER_H_
diff --git a/core/deps/rapidjson/prettywriter.h b/core/deps/rapidjson/prettywriter.h
new file mode 100644 (file)
index 0000000..0dcb0fe
--- /dev/null
@@ -0,0 +1,255 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_PRETTYWRITER_H_
+#define RAPIDJSON_PRETTYWRITER_H_
+
+#include "writer.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Combination of PrettyWriter format flags.
+/*! \see PrettyWriter::SetFormatOptions
+ */
+enum PrettyFormatOptions {
+    kFormatDefault = 0,         //!< Default pretty formatting.
+    kFormatSingleLineArray = 1  //!< Format arrays on a single line.
+};
+
+//! Writer with indentation and spacing.
+/*!
+    \tparam OutputStream Type of ouptut os.
+    \tparam SourceEncoding Encoding of source string.
+    \tparam TargetEncoding Encoding of output stream.
+    \tparam StackAllocator Type of allocator for allocating memory of stack.
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class PrettyWriter : public Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator, writeFlags> {
+public:
+    typedef Writer<OutputStream, SourceEncoding, TargetEncoding, StackAllocator> Base;
+    typedef typename Base::Ch Ch;
+
+    //! Constructor
+    /*! \param os Output stream.
+        \param allocator User supplied allocator. If it is null, it will create a private one.
+        \param levelDepth Initial capacity of stack.
+    */
+    explicit PrettyWriter(OutputStream& os, StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
+        Base(os, allocator, levelDepth), indentChar_(' '), indentCharCount_(4), formatOptions_(kFormatDefault) {}
+
+
+    explicit PrettyWriter(StackAllocator* allocator = 0, size_t levelDepth = Base::kDefaultLevelDepth) : 
+        Base(allocator, levelDepth), indentChar_(' '), indentCharCount_(4) {}
+
+    //! Set custom indentation.
+    /*! \param indentChar       Character for indentation. Must be whitespace character (' ', '\\t', '\\n', '\\r').
+        \param indentCharCount  Number of indent characters for each indentation level.
+        \note The default indentation is 4 spaces.
+    */
+    PrettyWriter& SetIndent(Ch indentChar, unsigned indentCharCount) {
+        RAPIDJSON_ASSERT(indentChar == ' ' || indentChar == '\t' || indentChar == '\n' || indentChar == '\r');
+        indentChar_ = indentChar;
+        indentCharCount_ = indentCharCount;
+        return *this;
+    }
+
+    //! Set pretty writer formatting options.
+    /*! \param options Formatting options.
+    */
+    PrettyWriter& SetFormatOptions(PrettyFormatOptions options) {
+        formatOptions_ = options;
+        return *this;
+    }
+
+    /*! @name Implementation of Handler
+        \see Handler
+    */
+    //@{
+
+    bool Null()                 { PrettyPrefix(kNullType);   return Base::WriteNull(); }
+    bool Bool(bool b)           { PrettyPrefix(b ? kTrueType : kFalseType); return Base::WriteBool(b); }
+    bool Int(int i)             { PrettyPrefix(kNumberType); return Base::WriteInt(i); }
+    bool Uint(unsigned u)       { PrettyPrefix(kNumberType); return Base::WriteUint(u); }
+    bool Int64(int64_t i64)     { PrettyPrefix(kNumberType); return Base::WriteInt64(i64); }
+    bool Uint64(uint64_t u64)   { PrettyPrefix(kNumberType); return Base::WriteUint64(u64);  }
+    bool Double(double d)       { PrettyPrefix(kNumberType); return Base::WriteDouble(d); }
+
+    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+        (void)copy;
+        PrettyPrefix(kNumberType);
+        return Base::WriteString(str, length);
+    }
+
+    bool String(const Ch* str, SizeType length, bool copy = false) {
+        (void)copy;
+        PrettyPrefix(kStringType);
+        return Base::WriteString(str, length);
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool String(const std::basic_string<Ch>& str) {
+        return String(str.data(), SizeType(str.size()));
+    }
+#endif
+
+    bool StartObject() {
+        PrettyPrefix(kObjectType);
+        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(false);
+        return Base::WriteStartObject();
+    }
+
+    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool Key(const std::basic_string<Ch>& str) {
+        return Key(str.data(), SizeType(str.size()));
+    }
+#endif
+       
+    bool EndObject(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+        RAPIDJSON_ASSERT(!Base::level_stack_.template Top<typename Base::Level>()->inArray);
+        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+        if (!empty) {
+            Base::os_->Put('\n');
+            WriteIndent();
+        }
+        bool ret = Base::WriteEndObject();
+        (void)ret;
+        RAPIDJSON_ASSERT(ret == true);
+        if (Base::level_stack_.Empty()) // end of json text
+            Base::os_->Flush();
+        return true;
+    }
+
+    bool StartArray() {
+        PrettyPrefix(kArrayType);
+        new (Base::level_stack_.template Push<typename Base::Level>()) typename Base::Level(true);
+        return Base::WriteStartArray();
+    }
+
+    bool EndArray(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(Base::level_stack_.GetSize() >= sizeof(typename Base::Level));
+        RAPIDJSON_ASSERT(Base::level_stack_.template Top<typename Base::Level>()->inArray);
+        bool empty = Base::level_stack_.template Pop<typename Base::Level>(1)->valueCount == 0;
+
+        if (!empty && !(formatOptions_ & kFormatSingleLineArray)) {
+            Base::os_->Put('\n');
+            WriteIndent();
+        }
+        bool ret = Base::WriteEndArray();
+        (void)ret;
+        RAPIDJSON_ASSERT(ret == true);
+        if (Base::level_stack_.Empty()) // end of json text
+            Base::os_->Flush();
+        return true;
+    }
+
+    //@}
+
+    /*! @name Convenience extensions */
+    //@{
+
+    //! Simpler but slower overload.
+    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+    //@}
+
+    //! Write a raw JSON value.
+    /*!
+        For user to write a stringified JSON as a value.
+
+        \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+        \param length Length of the json.
+        \param type Type of the root of json.
+        \note When using PrettyWriter::RawValue(), the result json may not be indented correctly.
+    */
+    bool RawValue(const Ch* json, size_t length, Type type) { PrettyPrefix(type); return Base::WriteRawValue(json, length); }
+
+protected:
+    void PrettyPrefix(Type type) {
+        (void)type;
+        if (Base::level_stack_.GetSize() != 0) { // this value is not at root
+            typename Base::Level* level = Base::level_stack_.template Top<typename Base::Level>();
+
+            if (level->inArray) {
+                if (level->valueCount > 0) {
+                    Base::os_->Put(','); // add comma if it is not the first element in array
+                    if (formatOptions_ & kFormatSingleLineArray)
+                        Base::os_->Put(' ');
+                }
+
+                if (!(formatOptions_ & kFormatSingleLineArray)) {
+                    Base::os_->Put('\n');
+                    WriteIndent();
+                }
+            }
+            else {  // in object
+                if (level->valueCount > 0) {
+                    if (level->valueCount % 2 == 0) {
+                        Base::os_->Put(',');
+                        Base::os_->Put('\n');
+                    }
+                    else {
+                        Base::os_->Put(':');
+                        Base::os_->Put(' ');
+                    }
+                }
+                else
+                    Base::os_->Put('\n');
+
+                if (level->valueCount % 2 == 0)
+                    WriteIndent();
+            }
+            if (!level->inArray && level->valueCount % 2 == 0)
+                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+            level->valueCount++;
+        }
+        else {
+            RAPIDJSON_ASSERT(!Base::hasRoot_);  // Should only has one and only one root.
+            Base::hasRoot_ = true;
+        }
+    }
+
+    void WriteIndent()  {
+        size_t count = (Base::level_stack_.GetSize() / sizeof(typename Base::Level)) * indentCharCount_;
+        PutN(*Base::os_, static_cast<typename TargetEncoding::Ch>(indentChar_), count);
+    }
+
+    Ch indentChar_;
+    unsigned indentCharCount_;
+    PrettyFormatOptions formatOptions_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    PrettyWriter(const PrettyWriter&);
+    PrettyWriter& operator=(const PrettyWriter&);
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/core/deps/rapidjson/rapidjson.h b/core/deps/rapidjson/rapidjson.h
new file mode 100644 (file)
index 0000000..053b2ce
--- /dev/null
@@ -0,0 +1,615 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_RAPIDJSON_H_
+#define RAPIDJSON_RAPIDJSON_H_
+
+/*!\file rapidjson.h
+    \brief common definitions and configuration
+    
+    \see RAPIDJSON_CONFIG
+ */
+
+/*! \defgroup RAPIDJSON_CONFIG RapidJSON configuration
+    \brief Configuration macros for library features
+
+    Some RapidJSON features are configurable to adapt the library to a wide
+    variety of platforms, environments and usage scenarios.  Most of the
+    features can be configured in terms of overriden or predefined
+    preprocessor macros at compile-time.
+
+    Some additional customization is available in the \ref RAPIDJSON_ERRORS APIs.
+
+    \note These macros should be given on the compiler command-line
+          (where applicable)  to avoid inconsistent values when compiling
+          different translation units of a single application.
+ */
+
+#include <cstdlib>  // malloc(), realloc(), free(), size_t
+#include <cstring>  // memset(), memcpy(), memmove(), memcmp()
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_VERSION_STRING
+//
+// ALWAYS synchronize the following 3 macros with corresponding variables in /CMakeLists.txt.
+//
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+// token stringification
+#define RAPIDJSON_STRINGIFY(x) RAPIDJSON_DO_STRINGIFY(x)
+#define RAPIDJSON_DO_STRINGIFY(x) #x
+//!@endcond
+
+/*! \def RAPIDJSON_MAJOR_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Major version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_MINOR_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Minor version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_PATCH_VERSION
+    \ingroup RAPIDJSON_CONFIG
+    \brief Patch version of RapidJSON in integer.
+*/
+/*! \def RAPIDJSON_VERSION_STRING
+    \ingroup RAPIDJSON_CONFIG
+    \brief Version of RapidJSON in "<major>.<minor>.<patch>" string format.
+*/
+#define RAPIDJSON_MAJOR_VERSION 1
+#define RAPIDJSON_MINOR_VERSION 1
+#define RAPIDJSON_PATCH_VERSION 0
+#define RAPIDJSON_VERSION_STRING \
+    RAPIDJSON_STRINGIFY(RAPIDJSON_MAJOR_VERSION.RAPIDJSON_MINOR_VERSION.RAPIDJSON_PATCH_VERSION)
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NAMESPACE_(BEGIN|END)
+/*! \def RAPIDJSON_NAMESPACE
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace
+
+    In order to avoid symbol clashes and/or "One Definition Rule" errors
+    between multiple inclusions of (different versions of) RapidJSON in
+    a single binary, users can customize the name of the main RapidJSON
+    namespace.
+
+    In case of a single nesting level, defining \c RAPIDJSON_NAMESPACE
+    to a custom name (e.g. \c MyRapidJSON) is sufficient.  If multiple
+    levels are needed, both \ref RAPIDJSON_NAMESPACE_BEGIN and \ref
+    RAPIDJSON_NAMESPACE_END need to be defined as well:
+
+    \code
+    // in some .cpp file
+    #define RAPIDJSON_NAMESPACE my::rapidjson
+    #define RAPIDJSON_NAMESPACE_BEGIN namespace my { namespace rapidjson {
+    #define RAPIDJSON_NAMESPACE_END   } }
+    #include "rapidjson/..."
+    \endcode
+
+    \see rapidjson
+ */
+/*! \def RAPIDJSON_NAMESPACE_BEGIN
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace (opening expression)
+    \see RAPIDJSON_NAMESPACE
+*/
+/*! \def RAPIDJSON_NAMESPACE_END
+    \ingroup RAPIDJSON_CONFIG
+    \brief   provide custom rapidjson namespace (closing expression)
+    \see RAPIDJSON_NAMESPACE
+*/
+#ifndef RAPIDJSON_NAMESPACE
+#define RAPIDJSON_NAMESPACE rapidjson
+#endif
+#ifndef RAPIDJSON_NAMESPACE_BEGIN
+#define RAPIDJSON_NAMESPACE_BEGIN namespace RAPIDJSON_NAMESPACE {
+#endif
+#ifndef RAPIDJSON_NAMESPACE_END
+#define RAPIDJSON_NAMESPACE_END }
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_HAS_STDSTRING
+
+#ifndef RAPIDJSON_HAS_STDSTRING
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_HAS_STDSTRING 1 // force generation of documentation
+#else
+#define RAPIDJSON_HAS_STDSTRING 0 // no std::string support by default
+#endif
+/*! \def RAPIDJSON_HAS_STDSTRING
+    \ingroup RAPIDJSON_CONFIG
+    \brief Enable RapidJSON support for \c std::string
+
+    By defining this preprocessor symbol to \c 1, several convenience functions for using
+    \ref rapidjson::GenericValue with \c std::string are enabled, especially
+    for construction and comparison.
+
+    \hideinitializer
+*/
+#endif // !defined(RAPIDJSON_HAS_STDSTRING)
+
+#if RAPIDJSON_HAS_STDSTRING
+#include <string>
+#endif // RAPIDJSON_HAS_STDSTRING
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_INT64DEFINE
+
+/*! \def RAPIDJSON_NO_INT64DEFINE
+    \ingroup RAPIDJSON_CONFIG
+    \brief Use external 64-bit integer types.
+
+    RapidJSON requires the 64-bit integer types \c int64_t and  \c uint64_t types
+    to be available at global scope.
+
+    If users have their own definition, define RAPIDJSON_NO_INT64DEFINE to
+    prevent RapidJSON from defining its own types.
+*/
+#ifndef RAPIDJSON_NO_INT64DEFINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && (_MSC_VER < 1800)     // Visual Studio 2013
+#include "msinttypes/stdint.h"
+#include "msinttypes/inttypes.h"
+#else
+// Other compilers should have this.
+#include <stdint.h>
+#include <inttypes.h>
+#endif
+//!@endcond
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_INT64DEFINE
+#endif
+#endif // RAPIDJSON_NO_INT64TYPEDEF
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_FORCEINLINE
+
+#ifndef RAPIDJSON_FORCEINLINE
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#if defined(_MSC_VER) && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __forceinline
+#elif defined(__GNUC__) && __GNUC__ >= 4 && defined(NDEBUG)
+#define RAPIDJSON_FORCEINLINE __attribute__((always_inline))
+#else
+#define RAPIDJSON_FORCEINLINE
+#endif
+//!@endcond
+#endif // RAPIDJSON_FORCEINLINE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ENDIAN
+#define RAPIDJSON_LITTLEENDIAN  0   //!< Little endian machine
+#define RAPIDJSON_BIGENDIAN     1   //!< Big endian machine
+
+//! Endianness of the machine.
+/*!
+    \def RAPIDJSON_ENDIAN
+    \ingroup RAPIDJSON_CONFIG
+
+    GCC 4.6 provided macro for detecting endianness of the target machine. But other
+    compilers may not have this. User can define RAPIDJSON_ENDIAN to either
+    \ref RAPIDJSON_LITTLEENDIAN or \ref RAPIDJSON_BIGENDIAN.
+
+    Default detection implemented with reference to
+    \li https://gcc.gnu.org/onlinedocs/gcc-4.6.0/cpp/Common-Predefined-Macros.html
+    \li http://www.boost.org/doc/libs/1_42_0/boost/detail/endian.hpp
+*/
+#ifndef RAPIDJSON_ENDIAN
+// Detect with GCC 4.6's macro
+#  ifdef __BYTE_ORDER__
+#    if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
+#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#    elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
+#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#    else
+#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+#    endif // __BYTE_ORDER__
+// Detect with GLIBC's endian.h
+#  elif defined(__GLIBC__)
+#    include <endian.h>
+#    if (__BYTE_ORDER == __LITTLE_ENDIAN)
+#      define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#    elif (__BYTE_ORDER == __BIG_ENDIAN)
+#      define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#    else
+#      error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.
+#   endif // __GLIBC__
+// Detect with _LITTLE_ENDIAN and _BIG_ENDIAN macro
+#  elif defined(_LITTLE_ENDIAN) && !defined(_BIG_ENDIAN)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(_BIG_ENDIAN) && !defined(_LITTLE_ENDIAN)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+// Detect with architecture macros
+#  elif defined(__sparc) || defined(__sparc__) || defined(_POWER) || defined(__powerpc__) || defined(__ppc__) || defined(__hpux) || defined(__hppa) || defined(_MIPSEB) || defined(_POWER) || defined(__s390__)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_BIGENDIAN
+#  elif defined(__i386__) || defined(__alpha__) || defined(__ia64) || defined(__ia64__) || defined(_M_IX86) || defined(_M_IA64) || defined(_M_ALPHA) || defined(__amd64) || defined(__amd64__) || defined(_M_AMD64) || defined(__x86_64) || defined(__x86_64__) || defined(_M_X64) || defined(__bfin__)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(_MSC_VER) && defined(_M_ARM)
+#    define RAPIDJSON_ENDIAN RAPIDJSON_LITTLEENDIAN
+#  elif defined(RAPIDJSON_DOXYGEN_RUNNING)
+#    define RAPIDJSON_ENDIAN
+#  else
+#    error Unknown machine endianess detected. User needs to define RAPIDJSON_ENDIAN.   
+#  endif
+#endif // RAPIDJSON_ENDIAN
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_64BIT
+
+//! Whether using 64-bit architecture
+#ifndef RAPIDJSON_64BIT
+#if defined(__LP64__) || (defined(__x86_64__) && defined(__ILP32__)) || defined(_WIN64) || defined(__EMSCRIPTEN__)
+#define RAPIDJSON_64BIT 1
+#else
+#define RAPIDJSON_64BIT 0
+#endif
+#endif // RAPIDJSON_64BIT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ALIGN
+
+//! Data alignment of the machine.
+/*! \ingroup RAPIDJSON_CONFIG
+    \param x pointer to align
+
+    Some machines require strict data alignment. Currently the default uses 4 bytes
+    alignment on 32-bit platforms and 8 bytes alignment for 64-bit platforms.
+    User can customize by defining the RAPIDJSON_ALIGN function macro.
+*/
+#ifndef RAPIDJSON_ALIGN
+#if RAPIDJSON_64BIT == 1
+#define RAPIDJSON_ALIGN(x) (((x) + static_cast<uint64_t>(7u)) & ~static_cast<uint64_t>(7u))
+#else
+#define RAPIDJSON_ALIGN(x) (((x) + 3u) & ~3u)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_UINT64_C2
+
+//! Construct a 64-bit literal by a pair of 32-bit integer.
+/*!
+    64-bit literal with or without ULL suffix is prone to compiler warnings.
+    UINT64_C() is C macro which cause compilation problems.
+    Use this macro to define 64-bit constants by a pair of 32-bit integer.
+*/
+#ifndef RAPIDJSON_UINT64_C2
+#define RAPIDJSON_UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+//! Use only lower 48-bit address for some pointers.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+
+    This optimization uses the fact that current X86-64 architecture only implement lower 48-bit virtual address.
+    The higher 16-bit can be used for storing other data.
+    \c GenericValue uses this optimization to reduce its size form 24 bytes to 16 bytes in 64-bit architecture.
+*/
+#ifndef RAPIDJSON_48BITPOINTER_OPTIMIZATION
+#if defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 1
+#else
+#define RAPIDJSON_48BITPOINTER_OPTIMIZATION 0
+#endif
+#endif // RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION == 1
+#if RAPIDJSON_64BIT != 1
+#error RAPIDJSON_48BITPOINTER_OPTIMIZATION can only be set to 1 when RAPIDJSON_64BIT=1
+#endif
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = reinterpret_cast<type *>((reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0xFFFF0000, 0x00000000))) | reinterpret_cast<uintptr_t>(reinterpret_cast<const void*>(x))))
+#define RAPIDJSON_GETPOINTER(type, p) (reinterpret_cast<type *>(reinterpret_cast<uintptr_t>(p) & static_cast<uintptr_t>(RAPIDJSON_UINT64_C2(0x0000FFFF, 0xFFFFFFFF))))
+#else
+#define RAPIDJSON_SETPOINTER(type, p, x) (p = (x))
+#define RAPIDJSON_GETPOINTER(type, p) (p)
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_SSE2/RAPIDJSON_SSE42/RAPIDJSON_SIMD
+
+/*! \def RAPIDJSON_SIMD
+    \ingroup RAPIDJSON_CONFIG
+    \brief Enable SSE2/SSE4.2 optimization.
+
+    RapidJSON supports optimized implementations for some parsing operations
+    based on the SSE2 or SSE4.2 SIMD extensions on modern Intel-compatible
+    processors.
+
+    To enable these optimizations, two different symbols can be defined;
+    \code
+    // Enable SSE2 optimization.
+    #define RAPIDJSON_SSE2
+
+    // Enable SSE4.2 optimization.
+    #define RAPIDJSON_SSE42
+    \endcode
+
+    \c RAPIDJSON_SSE42 takes precedence, if both are defined.
+
+    If any of these symbols is defined, RapidJSON defines the macro
+    \c RAPIDJSON_SIMD to indicate the availability of the optimized code.
+*/
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42) \
+    || defined(RAPIDJSON_DOXYGEN_RUNNING)
+#define RAPIDJSON_SIMD
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_NO_SIZETYPEDEFINE
+
+#ifndef RAPIDJSON_NO_SIZETYPEDEFINE
+/*! \def RAPIDJSON_NO_SIZETYPEDEFINE
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-provided \c SizeType definition.
+
+    In order to avoid using 32-bit size types for indexing strings and arrays,
+    define this preprocessor symbol and provide the type rapidjson::SizeType
+    before including RapidJSON:
+    \code
+    #define RAPIDJSON_NO_SIZETYPEDEFINE
+    namespace rapidjson { typedef ::std::size_t SizeType; }
+    #include "rapidjson/..."
+    \endcode
+
+    \see rapidjson::SizeType
+*/
+#ifdef RAPIDJSON_DOXYGEN_RUNNING
+#define RAPIDJSON_NO_SIZETYPEDEFINE
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+//! Size type (for string lengths, array sizes, etc.)
+/*! RapidJSON uses 32-bit array/string indices even on 64-bit platforms,
+    instead of using \c size_t. Users may override the SizeType by defining
+    \ref RAPIDJSON_NO_SIZETYPEDEFINE.
+*/
+typedef unsigned SizeType;
+RAPIDJSON_NAMESPACE_END
+#endif
+
+// always import std::size_t to rapidjson namespace
+RAPIDJSON_NAMESPACE_BEGIN
+using std::size_t;
+RAPIDJSON_NAMESPACE_END
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ASSERT
+
+//! Assertion.
+/*! \ingroup RAPIDJSON_CONFIG
+    By default, rapidjson uses C \c assert() for internal assertions.
+    User can override it by defining RAPIDJSON_ASSERT(x) macro.
+
+    \note Parsing errors are handled and can be customized by the
+          \ref RAPIDJSON_ERRORS APIs.
+*/
+#ifndef RAPIDJSON_ASSERT
+#include <cassert>
+#define RAPIDJSON_ASSERT(x) assert(x)
+#endif // RAPIDJSON_ASSERT
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_STATIC_ASSERT
+
+// Adopt from boost
+#ifndef RAPIDJSON_STATIC_ASSERT
+#ifndef __clang__
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#endif
+RAPIDJSON_NAMESPACE_BEGIN
+template <bool x> struct STATIC_ASSERTION_FAILURE;
+template <> struct STATIC_ASSERTION_FAILURE<true> { enum { value = 1 }; };
+template<int x> struct StaticAssertTest {};
+RAPIDJSON_NAMESPACE_END
+
+#define RAPIDJSON_JOIN(X, Y) RAPIDJSON_DO_JOIN(X, Y)
+#define RAPIDJSON_DO_JOIN(X, Y) RAPIDJSON_DO_JOIN2(X, Y)
+#define RAPIDJSON_DO_JOIN2(X, Y) X##Y
+
+#if defined(__GNUC__)
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE __attribute__((unused))
+#else
+#define RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE 
+#endif
+#ifndef __clang__
+//!@endcond
+#endif
+
+/*! \def RAPIDJSON_STATIC_ASSERT
+    \brief (Internal) macro to check for conditions at compile-time
+    \param x compile-time condition
+    \hideinitializer
+ */
+#define RAPIDJSON_STATIC_ASSERT(x) \
+    typedef ::RAPIDJSON_NAMESPACE::StaticAssertTest< \
+      sizeof(::RAPIDJSON_NAMESPACE::STATIC_ASSERTION_FAILURE<bool(x) >)> \
+    RAPIDJSON_JOIN(StaticAssertTypedef, __LINE__) RAPIDJSON_STATIC_ASSERT_UNUSED_ATTRIBUTE
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_LIKELY, RAPIDJSON_UNLIKELY
+
+//! Compiler branching hint for expression with high probability to be true.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+    \param x Boolean expression likely to be true.
+*/
+#ifndef RAPIDJSON_LIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_LIKELY(x) __builtin_expect(!!(x), 1)
+#else
+#define RAPIDJSON_LIKELY(x) (x)
+#endif
+#endif
+
+//! Compiler branching hint for expression with low probability to be true.
+/*!
+    \ingroup RAPIDJSON_CONFIG
+    \param x Boolean expression unlikely to be true.
+*/
+#ifndef RAPIDJSON_UNLIKELY
+#if defined(__GNUC__) || defined(__clang__)
+#define RAPIDJSON_UNLIKELY(x) __builtin_expect(!!(x), 0)
+#else
+#define RAPIDJSON_UNLIKELY(x) (x)
+#endif
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Helpers
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+
+#define RAPIDJSON_MULTILINEMACRO_BEGIN do {  
+#define RAPIDJSON_MULTILINEMACRO_END \
+} while((void)0, 0)
+
+// adopted from Boost
+#define RAPIDJSON_VERSION_CODE(x,y,z) \
+  (((x)*100000) + ((y)*100) + (z))
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_DIAG_PUSH/POP, RAPIDJSON_DIAG_OFF
+
+#if defined(__GNUC__)
+#define RAPIDJSON_GNUC \
+    RAPIDJSON_VERSION_CODE(__GNUC__,__GNUC_MINOR__,__GNUC_PATCHLEVEL__)
+#endif
+
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,2,0))
+
+#define RAPIDJSON_PRAGMA(x) _Pragma(RAPIDJSON_STRINGIFY(x))
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(GCC diagnostic x)
+#define RAPIDJSON_DIAG_OFF(x) \
+    RAPIDJSON_DIAG_PRAGMA(ignored RAPIDJSON_STRINGIFY(RAPIDJSON_JOIN(-W,x)))
+
+// push/pop support in Clang and GCC>=4.6
+#if defined(__clang__) || (defined(RAPIDJSON_GNUC) && RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0))
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)
+#else // GCC >= 4.2, < 4.6
+#define RAPIDJSON_DIAG_PUSH /* ignored */
+#define RAPIDJSON_DIAG_POP /* ignored */
+#endif
+
+#elif defined(_MSC_VER)
+
+// pragma (MSVC specific)
+#define RAPIDJSON_PRAGMA(x) __pragma(x)
+#define RAPIDJSON_DIAG_PRAGMA(x) RAPIDJSON_PRAGMA(warning(x))
+
+#define RAPIDJSON_DIAG_OFF(x) RAPIDJSON_DIAG_PRAGMA(disable: x)
+#define RAPIDJSON_DIAG_PUSH RAPIDJSON_DIAG_PRAGMA(push)
+#define RAPIDJSON_DIAG_POP  RAPIDJSON_DIAG_PRAGMA(pop)
+
+#else
+
+#define RAPIDJSON_DIAG_OFF(x) /* ignored */
+#define RAPIDJSON_DIAG_PUSH   /* ignored */
+#define RAPIDJSON_DIAG_POP    /* ignored */
+
+#endif // RAPIDJSON_DIAG_*
+
+///////////////////////////////////////////////////////////////////////////////
+// C++11 features
+
+#ifndef RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#if defined(__clang__)
+#if __has_feature(cxx_rvalue_references) && \
+    (defined(_LIBCPP_VERSION) || defined(__GLIBCXX__) && __GLIBCXX__ >= 20080306)
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+      (defined(_MSC_VER) && _MSC_VER >= 1600)
+
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 1
+#else
+#define RAPIDJSON_HAS_CXX11_RVALUE_REFS 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+#ifndef RAPIDJSON_HAS_CXX11_NOEXCEPT
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT __has_feature(cxx_noexcept)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,6,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__))
+//    (defined(_MSC_VER) && _MSC_VER >= ????) // not yet supported
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 1
+#else
+#define RAPIDJSON_HAS_CXX11_NOEXCEPT 0
+#endif
+#endif
+#if RAPIDJSON_HAS_CXX11_NOEXCEPT
+#define RAPIDJSON_NOEXCEPT noexcept
+#else
+#define RAPIDJSON_NOEXCEPT /* noexcept */
+#endif // RAPIDJSON_HAS_CXX11_NOEXCEPT
+
+// no automatic detection, yet
+#ifndef RAPIDJSON_HAS_CXX11_TYPETRAITS
+#define RAPIDJSON_HAS_CXX11_TYPETRAITS 0
+#endif
+
+#ifndef RAPIDJSON_HAS_CXX11_RANGE_FOR
+#if defined(__clang__)
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR __has_feature(cxx_range_for)
+#elif (defined(RAPIDJSON_GNUC) && (RAPIDJSON_GNUC >= RAPIDJSON_VERSION_CODE(4,3,0)) && defined(__GXX_EXPERIMENTAL_CXX0X__)) || \
+      (defined(_MSC_VER) && _MSC_VER >= 1700)
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 1
+#else
+#define RAPIDJSON_HAS_CXX11_RANGE_FOR 0
+#endif
+#endif // RAPIDJSON_HAS_CXX11_RANGE_FOR
+
+//!@endcond
+
+///////////////////////////////////////////////////////////////////////////////
+// new/delete
+
+#ifndef RAPIDJSON_NEW
+///! customization point for global \c new
+#define RAPIDJSON_NEW(x) new x
+#endif
+#ifndef RAPIDJSON_DELETE
+///! customization point for global \c delete
+#define RAPIDJSON_DELETE(x) delete x
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// Type
+
+/*! \namespace rapidjson
+    \brief main RapidJSON namespace
+    \see RAPIDJSON_NAMESPACE
+*/
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Type of JSON value
+enum Type {
+    kNullType = 0,      //!< null
+    kFalseType = 1,     //!< false
+    kTrueType = 2,      //!< true
+    kObjectType = 3,    //!< object
+    kArrayType = 4,     //!< array 
+    kStringType = 5,    //!< string
+    kNumberType = 6     //!< number
+};
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/core/deps/rapidjson/reader.h b/core/deps/rapidjson/reader.h
new file mode 100644 (file)
index 0000000..19f8849
--- /dev/null
@@ -0,0 +1,1879 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+#include "allocators.h"
+#include "stream.h"
+#include "encodedstream.h"
+#include "internal/meta.h"
+#include "internal/stack.h"
+#include "internal/strtod.h"
+#include <limits>
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127)  // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702)  // unreachable code
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(old-style-cast)
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch-enum)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define RAPIDJSON_NOTHING /* deliberately empty */
+#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
+    RAPIDJSON_MULTILINEMACRO_BEGIN \
+    if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
+    RAPIDJSON_MULTILINEMACRO_END
+#endif
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
+    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
+//!@endcond
+
+/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
+    \ingroup RAPIDJSON_ERRORS
+    \brief Macro to indicate a parse error.
+    \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+    \param offset  position of the error in JSON input (\c size_t)
+
+    This macros can be used as a customization point for the internal
+    error handling mechanism of RapidJSON.
+
+    A common usage model is to throw an exception instead of requiring the
+    caller to explicitly check the \ref rapidjson::GenericReader::Parse's
+    return value:
+
+    \code
+    #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
+       throw ParseException(parseErrorCode, #parseErrorCode, offset)
+
+    #include <stdexcept>               // std::runtime_error
+    #include "rapidjson/error/error.h" // rapidjson::ParseResult
+
+    struct ParseException : std::runtime_error, rapidjson::ParseResult {
+      ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
+        : std::runtime_error(msg), ParseResult(code, offset) {}
+    };
+
+    #include "rapidjson/reader.h"
+    \endcode
+
+    \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
+ */
+#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
+#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
+    RAPIDJSON_MULTILINEMACRO_BEGIN \
+    RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
+    SetParseError(parseErrorCode, offset); \
+    RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+/*! \def RAPIDJSON_PARSE_ERROR
+    \ingroup RAPIDJSON_ERRORS
+    \brief (Internal) macro to indicate and handle a parse error.
+    \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+    \param offset  position of the error in JSON input (\c size_t)
+
+    Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
+
+    \see RAPIDJSON_PARSE_ERROR_NORETURN
+    \hideinitializer
+ */
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
+    RAPIDJSON_MULTILINEMACRO_BEGIN \
+    RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
+    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
+    RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+#include "error/error.h" // ParseErrorCode, ParseResult
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-defined kParseDefaultFlags definition.
+
+    User can define this as any \c ParseFlag combinations.
+*/
+#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
+#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
+#endif
+
+//! Combination of parseFlags
+/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
+ */
+enum ParseFlag {
+    kParseNoFlags = 0,              //!< No flags are set.
+    kParseInsituFlag = 1,           //!< In-situ(destructive) parsing.
+    kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
+    kParseIterativeFlag = 4,        //!< Iterative(constant complexity in terms of function call stack size) parsing.
+    kParseStopWhenDoneFlag = 8,     //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
+    kParseFullPrecisionFlag = 16,   //!< Parse number in full precision (but slower).
+    kParseCommentsFlag = 32,        //!< Allow one-line (//) and multi-line (/**/) comments.
+    kParseNumbersAsStringsFlag = 64,    //!< Parse all numbers (ints/doubles) as strings.
+    kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
+    kParseNanAndInfFlag = 256,      //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
+    kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS  //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+    \brief Concept for receiving events from GenericReader upon parsing.
+    The functions return true if no error occurs. If they return false,
+    the event publisher should terminate the process.
+\code
+concept Handler {
+    typename Ch;
+
+    bool Null();
+    bool Bool(bool b);
+    bool Int(int i);
+    bool Uint(unsigned i);
+    bool Int64(int64_t i);
+    bool Uint64(uint64_t i);
+    bool Double(double d);
+    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
+    bool RawNumber(const Ch* str, SizeType length, bool copy);
+    bool String(const Ch* str, SizeType length, bool copy);
+    bool StartObject();
+    bool Key(const Ch* str, SizeType length, bool copy);
+    bool EndObject(SizeType memberCount);
+    bool StartArray();
+    bool EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+    \note implements Handler concept
+*/
+template<typename Encoding = UTF8<>, typename Derived = void>
+struct BaseReaderHandler {
+    typedef typename Encoding::Ch Ch;
+
+    typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
+
+    bool Default() { return true; }
+    bool Null() { return static_cast<Override&>(*this).Default(); }
+    bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
+    bool Int(int) { return static_cast<Override&>(*this).Default(); }
+    bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
+    bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
+    bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
+    bool Double(double) { return static_cast<Override&>(*this).Default(); }
+    /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
+    bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+    bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
+    bool StartObject() { return static_cast<Override&>(*this).Default(); }
+    bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
+    bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
+    bool StartArray() { return static_cast<Override&>(*this).Default(); }
+    bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamLocalCopy
+
+namespace internal {
+
+template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
+class StreamLocalCopy;
+
+//! Do copy optimization.
+template<typename Stream>
+class StreamLocalCopy<Stream, 1> {
+public:
+    StreamLocalCopy(Stream& original) : s(original), original_(original) {}
+    ~StreamLocalCopy() { original_ = s; }
+
+    Stream s;
+
+private:
+    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+
+    Stream& original_;
+};
+
+//! Keep reference.
+template<typename Stream>
+class StreamLocalCopy<Stream, 0> {
+public:
+    StreamLocalCopy(Stream& original) : s(original) {}
+
+    Stream& s;
+
+private:
+    StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param is A input stream for skipping white spaces.
+    \note This function has SSE2/SSE4.2 specialization.
+*/
+template<typename InputStream>
+void SkipWhitespace(InputStream& is) {
+    internal::StreamLocalCopy<InputStream> copy(is);
+    InputStream& s(copy.s);
+
+    typename InputStream::Ch c;
+    while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
+        s.Take();
+}
+
+inline const char* SkipWhitespace(const char* p, const char* end) {
+    while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+        ++p;
+    return p;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+    // Fast return for single non-whitespace
+    if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+        ++p;
+    else
+        return p;
+
+    // 16-byte align to the next boundary
+    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+    while (p != nextAligned)
+        if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+            ++p;
+        else
+            return p;
+
+    // The rest of string using SIMD
+    static const char whitespace[16] = " \n\r\t";
+    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
+
+    for (;; p += 16) {
+        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+        const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+        if (r != 0) {   // some of characters is non-whitespace
+#ifdef _MSC_VER         // Find the index of first non-whitespace
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            return p + offset;
+#else
+            return p + __builtin_ffs(r) - 1;
+#endif
+        }
+    }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+    // Fast return for single non-whitespace
+    if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+        ++p;
+    else
+        return p;
+
+    // The middle of string using SIMD
+    static const char whitespace[16] = " \n\r\t";
+    const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
+
+    for (; p <= end - 16; p += 16) {
+        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
+        const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
+        if (r != 0) {   // some of characters is non-whitespace
+#ifdef _MSC_VER         // Find the index of first non-whitespace
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            return p + offset;
+#else
+            return p + __builtin_ffs(r) - 1;
+#endif
+        }
+    }
+
+    return SkipWhitespace(p, end);
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
+inline const char *SkipWhitespace_SIMD(const char* p) {
+    // Fast return for single non-whitespace
+    if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+        ++p;
+    else
+        return p;
+
+    // 16-byte align to the next boundary
+    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+    while (p != nextAligned)
+        if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+            ++p;
+        else
+            return p;
+
+    // The rest of string
+    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+    static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
+    #undef C16
+
+    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
+    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
+    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
+    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
+
+    for (;; p += 16) {
+        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+        __m128i x = _mm_cmpeq_epi8(s, w0);
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+        if (r != 0) {   // some of characters may be non-whitespace
+#ifdef _MSC_VER         // Find the index of first non-whitespace
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            return p + offset;
+#else
+            return p + __builtin_ffs(r) - 1;
+#endif
+        }
+    }
+}
+
+inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
+    // Fast return for single non-whitespace
+    if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+        ++p;
+    else
+        return p;
+
+    // The rest of string
+    #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+    static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
+    #undef C16
+
+    const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
+    const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
+    const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
+    const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
+
+    for (; p <= end - 16; p += 16) {
+        const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
+        __m128i x = _mm_cmpeq_epi8(s, w0);
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+        x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+        unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+        if (r != 0) {   // some of characters may be non-whitespace
+#ifdef _MSC_VER         // Find the index of first non-whitespace
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            return p + offset;
+#else
+            return p + __builtin_ffs(r) - 1;
+#endif
+        }
+    }
+
+    return SkipWhitespace(p, end);
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template<> inline void SkipWhitespace(InsituStringStream& is) {
+    is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
+}
+
+//! Template function specialization for StringStream
+template<> inline void SkipWhitespace(StringStream& is) {
+    is.src_ = SkipWhitespace_SIMD(is.src_);
+}
+
+template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
+    is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously to an
+    object implementing Handler concept.
+
+    It needs to allocate a stack for storing a single decoded string during
+    non-destructive parsing.
+
+    For in-situ parsing, the decoded string is directly written to the source
+    text string, no temporary buffer is required.
+
+    A GenericReader object can be reused for parsing multiple JSON text.
+
+    \tparam SourceEncoding Encoding of the input stream.
+    \tparam TargetEncoding Encoding of the parse output.
+    \tparam StackAllocator Allocator type for stack.
+*/
+template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
+class GenericReader {
+public:
+    typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
+
+    //! Constructor.
+    /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
+        \param stackCapacity stack capacity in bytes for storing a single decoded string.  (Only use for non-destructive parsing)
+    */
+    GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
+
+    //! Parse JSON text.
+    /*! \tparam parseFlags Combination of \ref ParseFlag.
+        \tparam InputStream Type of input stream, implementing Stream concept.
+        \tparam Handler Type of handler, implementing Handler concept.
+        \param is Input stream to be parsed.
+        \param handler The handler to receive events.
+        \return Whether the parsing is successful.
+    */
+    template <unsigned parseFlags, typename InputStream, typename Handler>
+    ParseResult Parse(InputStream& is, Handler& handler) {
+        if (parseFlags & kParseIterativeFlag)
+            return IterativeParse<parseFlags>(is, handler);
+
+        parseResult_.Clear();
+
+        ClearStackOnExit scope(*this);
+
+        SkipWhitespaceAndComments<parseFlags>(is);
+        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+        if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
+            RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+        }
+        else {
+            ParseValue<parseFlags>(is, handler);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+            if (!(parseFlags & kParseStopWhenDoneFlag)) {
+                SkipWhitespaceAndComments<parseFlags>(is);
+                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+                if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
+                    RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
+                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+                }
+            }
+        }
+
+        return parseResult_;
+    }
+
+    //! Parse JSON text (with \ref kParseDefaultFlags)
+    /*! \tparam InputStream Type of input stream, implementing Stream concept
+        \tparam Handler Type of handler, implementing Handler concept.
+        \param is Input stream to be parsed.
+        \param handler The handler to receive events.
+        \return Whether the parsing is successful.
+    */
+    template <typename InputStream, typename Handler>
+    ParseResult Parse(InputStream& is, Handler& handler) {
+        return Parse<kParseDefaultFlags>(is, handler);
+    }
+
+    //! Whether a parse error has occured in the last parsing.
+    bool HasParseError() const { return parseResult_.IsError(); }
+
+    //! Get the \ref ParseErrorCode of last parsing.
+    ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
+
+    //! Get the position of last parsing error in input, 0 otherwise.
+    size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+protected:
+    void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    GenericReader(const GenericReader&);
+    GenericReader& operator=(const GenericReader&);
+
+    void ClearStack() { stack_.Clear(); }
+
+    // clear stack on any exit from ParseStream, e.g. due to exception
+    struct ClearStackOnExit {
+        explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
+        ~ClearStackOnExit() { r_.ClearStack(); }
+    private:
+        GenericReader& r_;
+        ClearStackOnExit(const ClearStackOnExit&);
+        ClearStackOnExit& operator=(const ClearStackOnExit&);
+    };
+
+    template<unsigned parseFlags, typename InputStream>
+    void SkipWhitespaceAndComments(InputStream& is) {
+        SkipWhitespace(is);
+
+        if (parseFlags & kParseCommentsFlag) {
+            while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
+                if (Consume(is, '*')) {
+                    while (true) {
+                        if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
+                            RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+                        else if (Consume(is, '*')) {
+                            if (Consume(is, '/'))
+                                break;
+                        }
+                        else
+                            is.Take();
+                    }
+                }
+                else if (RAPIDJSON_LIKELY(Consume(is, '/')))
+                    while (is.Peek() != '\0' && is.Take() != '\n');
+                else
+                    RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+
+                SkipWhitespace(is);
+            }
+        }
+    }
+
+    // Parse object: { string : value, ... }
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseObject(InputStream& is, Handler& handler) {
+        RAPIDJSON_ASSERT(is.Peek() == '{');
+        is.Take();  // Skip '{'
+
+        if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+        SkipWhitespaceAndComments<parseFlags>(is);
+        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+        if (Consume(is, '}')) {
+            if (RAPIDJSON_UNLIKELY(!handler.EndObject(0)))  // empty object
+                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+            return;
+        }
+
+        for (SizeType memberCount = 0;;) {
+            if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
+                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+
+            ParseString<parseFlags>(is, handler, true);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            SkipWhitespaceAndComments<parseFlags>(is);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
+                RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+            SkipWhitespaceAndComments<parseFlags>(is);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            ParseValue<parseFlags>(is, handler);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            SkipWhitespaceAndComments<parseFlags>(is);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            ++memberCount;
+
+            switch (is.Peek()) {
+                case ',':
+                    is.Take();
+                    SkipWhitespaceAndComments<parseFlags>(is);
+                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+                    break;
+                case '}':
+                    is.Take();
+                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+                    return;
+                default:
+                    RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
+            }
+
+            if (parseFlags & kParseTrailingCommasFlag) {
+                if (is.Peek() == '}') {
+                    if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+                    is.Take();
+                    return;
+                }
+            }
+        }
+    }
+
+    // Parse array: [ value, ... ]
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseArray(InputStream& is, Handler& handler) {
+        RAPIDJSON_ASSERT(is.Peek() == '[');
+        is.Take();  // Skip '['
+
+        if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+        SkipWhitespaceAndComments<parseFlags>(is);
+        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+        if (Consume(is, ']')) {
+            if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
+                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+            return;
+        }
+
+        for (SizeType elementCount = 0;;) {
+            ParseValue<parseFlags>(is, handler);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            ++elementCount;
+            SkipWhitespaceAndComments<parseFlags>(is);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+            if (Consume(is, ',')) {
+                SkipWhitespaceAndComments<parseFlags>(is);
+                RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            }
+            else if (Consume(is, ']')) {
+                if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+                    RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+                return;
+            }
+            else
+                RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
+
+            if (parseFlags & kParseTrailingCommasFlag) {
+                if (is.Peek() == ']') {
+                    if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+                        RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+                    is.Take();
+                    return;
+                }
+            }
+        }
+    }
+
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseNull(InputStream& is, Handler& handler) {
+        RAPIDJSON_ASSERT(is.Peek() == 'n');
+        is.Take();
+
+        if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
+            if (RAPIDJSON_UNLIKELY(!handler.Null()))
+                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+        }
+        else
+            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+    }
+
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseTrue(InputStream& is, Handler& handler) {
+        RAPIDJSON_ASSERT(is.Peek() == 't');
+        is.Take();
+
+        if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
+            if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
+                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+        }
+        else
+            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+    }
+
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseFalse(InputStream& is, Handler& handler) {
+        RAPIDJSON_ASSERT(is.Peek() == 'f');
+        is.Take();
+
+        if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
+            if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
+                RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+        }
+        else
+            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+    }
+
+    template<typename InputStream>
+    RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
+        if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
+            is.Take();
+            return true;
+        }
+        else
+            return false;
+    }
+
+    // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
+    template<typename InputStream>
+    unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
+        unsigned codepoint = 0;
+        for (int i = 0; i < 4; i++) {
+            Ch c = is.Peek();
+            codepoint <<= 4;
+            codepoint += static_cast<unsigned>(c);
+            if (c >= '0' && c <= '9')
+                codepoint -= '0';
+            else if (c >= 'A' && c <= 'F')
+                codepoint -= 'A' - 10;
+            else if (c >= 'a' && c <= 'f')
+                codepoint -= 'a' - 10;
+            else {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
+                RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
+            }
+            is.Take();
+        }
+        return codepoint;
+    }
+
+    template <typename CharType>
+    class StackStream {
+    public:
+        typedef CharType Ch;
+
+        StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
+        RAPIDJSON_FORCEINLINE void Put(Ch c) {
+            *stack_.template Push<Ch>() = c;
+            ++length_;
+        }
+
+        RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
+            length_ += count;
+            return stack_.template Push<Ch>(count);
+        }
+
+        size_t Length() const { return length_; }
+
+        Ch* Pop() {
+            return stack_.template Pop<Ch>(length_);
+        }
+
+    private:
+        StackStream(const StackStream&);
+        StackStream& operator=(const StackStream&);
+
+        internal::Stack<StackAllocator>& stack_;
+        SizeType length_;
+    };
+
+    // Parse string and generate String event. Different code paths for kParseInsituFlag.
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
+        internal::StreamLocalCopy<InputStream> copy(is);
+        InputStream& s(copy.s);
+
+        RAPIDJSON_ASSERT(s.Peek() == '\"');
+        s.Take();  // Skip '\"'
+
+        bool success = false;
+        if (parseFlags & kParseInsituFlag) {
+            typename InputStream::Ch *head = s.PutBegin();
+            ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            size_t length = s.PutEnd(head) - 1;
+            RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+            const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
+            success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
+        }
+        else {
+            StackStream<typename TargetEncoding::Ch> stackStream(stack_);
+            ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+            SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
+            const typename TargetEncoding::Ch* const str = stackStream.Pop();
+            success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
+        }
+        if (RAPIDJSON_UNLIKELY(!success))
+            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+    }
+
+    // Parse string to an output is
+    // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
+    template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
+    RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+        static const char escape[256] = {
+            Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
+            Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
+            0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
+            0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
+        };
+#undef Z16
+//!@endcond
+
+        for (;;) {
+            // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
+            if (!(parseFlags & kParseValidateEncodingFlag))
+                ScanCopyUnescapedString(is, os);
+
+            Ch c = is.Peek();
+            if (RAPIDJSON_UNLIKELY(c == '\\')) {    // Escape
+                size_t escapeOffset = is.Tell();    // For invalid escaping, report the inital '\\' as error offset
+                is.Take();
+                Ch e = is.Peek();
+                if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
+                    is.Take();
+                    os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
+                }
+                else if (RAPIDJSON_LIKELY(e == 'u')) {    // Unicode
+                    is.Take();
+                    unsigned codepoint = ParseHex4(is, escapeOffset);
+                    RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+                    if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
+                        // Handle UTF-16 surrogate pair
+                        if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
+                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+                        unsigned codepoint2 = ParseHex4(is, escapeOffset);
+                        RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+                        if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+                            RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
+                        codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
+                    }
+                    TEncoding::Encode(os, codepoint);
+                }
+                else
+                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
+            }
+            else if (RAPIDJSON_UNLIKELY(c == '"')) {    // Closing double quote
+                is.Take();
+                os.Put('\0');   // null-terminate the string
+                return;
+            }
+            else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
+                if (c == '\0')
+                    RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
+                else
+                    RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+            }
+            else {
+                size_t offset = is.Tell();
+                if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
+                    !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
+                    !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
+                    RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
+            }
+        }
+    }
+
+    template<typename InputStream, typename OutputStream>
+    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
+            // Do nothing for generic version
+    }
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+    // StringStream -> StackStream<char>
+    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
+        const char* p = is.src_;
+
+        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+        while (p != nextAligned)
+            if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+                is.src_ = p;
+                return;
+            }
+            else
+                os.Put(*p++);
+
+        // The rest of string using SIMD
+        static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+        static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+        static const char space[16]  = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+        for (;; p += 16) {
+            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+            const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+            const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
+                SizeType length;
+    #ifdef _MSC_VER         // Find the index of first escaped
+                unsigned long offset;
+                _BitScanForward(&offset, r);
+                length = offset;
+    #else
+                length = static_cast<SizeType>(__builtin_ffs(r) - 1);
+    #endif
+                char* q = reinterpret_cast<char*>(os.Push(length));
+                for (size_t i = 0; i < length; i++)
+                    q[i] = p[i];
+
+                p += length;
+                break;
+            }
+            _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
+        }
+
+        is.src_ = p;
+    }
+
+    // InsituStringStream -> InsituStringStream
+    static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
+        RAPIDJSON_ASSERT(&is == &os);
+        (void)os;
+
+        if (is.src_ == is.dst_) {
+            SkipUnescapedString(is);
+            return;
+        }
+
+        char* p = is.src_;
+        char *q = is.dst_;
+
+        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+        while (p != nextAligned)
+            if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+                is.src_ = p;
+                is.dst_ = q;
+                return;
+            }
+            else
+                *q++ = *p++;
+
+        // The rest of string using SIMD
+        static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+        static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+        static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+        for (;; p += 16, q += 16) {
+            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+            const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+            const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
+                size_t length;
+#ifdef _MSC_VER         // Find the index of first escaped
+                unsigned long offset;
+                _BitScanForward(&offset, r);
+                length = offset;
+#else
+                length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+                for (const char* pend = p + length; p != pend; )
+                    *q++ = *p++;
+                break;
+            }
+            _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
+        }
+
+        is.src_ = p;
+        is.dst_ = q;
+    }
+
+    // When read/write pointers are the same for insitu stream, just skip unescaped characters
+    static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
+        RAPIDJSON_ASSERT(is.src_ == is.dst_);
+        char* p = is.src_;
+
+        // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
+        const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+        for (; p != nextAligned; p++)
+            if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+                is.src_ = is.dst_ = p;
+                return;
+            }
+
+        // The rest of string using SIMD
+        static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+        static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+        static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+        const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+        const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+        const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+        for (;; p += 16) {
+            const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+            const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+            const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+            const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+            const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+            unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+            if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
+                size_t length;
+#ifdef _MSC_VER         // Find the index of first escaped
+                unsigned long offset;
+                _BitScanForward(&offset, r);
+                length = offset;
+#else
+                length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+                p += length;
+                break;
+            }
+        }
+
+        is.src_ = is.dst_ = p;
+    }
+#endif
+
+    template<typename InputStream, bool backup, bool pushOnTake>
+    class NumberStream;
+
+    template<typename InputStream>
+    class NumberStream<InputStream, false, false> {
+    public:
+        typedef typename InputStream::Ch Ch;
+
+        NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader;  }
+        ~NumberStream() {}
+
+        RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+        RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
+        RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
+                 RAPIDJSON_FORCEINLINE void Push(char) {}
+
+        size_t Tell() { return is.Tell(); }
+        size_t Length() { return 0; }
+        const char* Pop() { return 0; }
+
+    protected:
+        NumberStream& operator=(const NumberStream&);
+
+        InputStream& is;
+    };
+
+    template<typename InputStream>
+    class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
+        typedef NumberStream<InputStream, false, false> Base;
+    public:
+        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
+        ~NumberStream() {}
+
+        RAPIDJSON_FORCEINLINE Ch TakePush() {
+            stackStream.Put(static_cast<char>(Base::is.Peek()));
+            return Base::is.Take();
+        }
+
+        RAPIDJSON_FORCEINLINE void Push(char c) {
+            stackStream.Put(c);
+        }
+
+        size_t Length() { return stackStream.Length(); }
+
+        const char* Pop() {
+            stackStream.Put('\0');
+            return stackStream.Pop();
+        }
+
+    private:
+        StackStream<char> stackStream;
+    };
+
+    template<typename InputStream>
+    class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
+        typedef NumberStream<InputStream, true, false> Base;
+    public:
+        NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
+        ~NumberStream() {}
+
+        RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
+    };
+
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseNumber(InputStream& is, Handler& handler) {
+        internal::StreamLocalCopy<InputStream> copy(is);
+        NumberStream<InputStream,
+            ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
+                ((parseFlags & kParseInsituFlag) == 0) :
+                ((parseFlags & kParseFullPrecisionFlag) != 0),
+            (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
+                (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
+
+        size_t startOffset = s.Tell();
+        double d = 0.0;
+        bool useNanOrInf = false;
+
+        // Parse minus
+        bool minus = Consume(s, '-');
+
+        // Parse int: zero / ( digit1-9 *DIGIT )
+        unsigned i = 0;
+        uint64_t i64 = 0;
+        bool use64bit = false;
+        int significandDigit = 0;
+        if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
+            i = 0;
+            s.TakePush();
+        }
+        else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
+            i = static_cast<unsigned>(s.TakePush() - '0');
+
+            if (minus)
+                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                    if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
+                        if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
+                            i64 = i;
+                            use64bit = true;
+                            break;
+                        }
+                    }
+                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+                    significandDigit++;
+                }
+            else
+                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                    if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
+                        if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
+                            i64 = i;
+                            use64bit = true;
+                            break;
+                        }
+                    }
+                    i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+                    significandDigit++;
+                }
+        }
+        // Parse NaN or Infinity here
+        else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
+            useNanOrInf = true;
+            if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
+                d = std::numeric_limits<double>::quiet_NaN();
+            }
+            else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
+                d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
+                if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
+                                                            && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))
+                    RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+            }
+            else
+                RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+        }
+        else
+            RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+
+        // Parse 64bit int
+        bool useDouble = false;
+        if (use64bit) {
+            if (minus)
+                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                     if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
+                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
+                            d = static_cast<double>(i64);
+                            useDouble = true;
+                            break;
+                        }
+                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+                    significandDigit++;
+                }
+            else
+                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                    if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
+                        if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
+                            d = static_cast<double>(i64);
+                            useDouble = true;
+                            break;
+                        }
+                    i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+                    significandDigit++;
+                }
+        }
+
+        // Force double for big integer
+        if (useDouble) {
+            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
+                    RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+                d = d * 10 + (s.TakePush() - '0');
+            }
+        }
+
+        // Parse frac = decimal-point 1*DIGIT
+        int expFrac = 0;
+        size_t decimalPosition;
+        if (Consume(s, '.')) {
+            decimalPosition = s.Length();
+
+            if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
+                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
+
+            if (!useDouble) {
+#if RAPIDJSON_64BIT
+                // Use i64 to store significand in 64-bit architecture
+                if (!use64bit)
+                    i64 = i;
+
+                while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                    if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
+                        break;
+                    else {
+                        i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+                        --expFrac;
+                        if (i64 != 0)
+                            significandDigit++;
+                    }
+                }
+
+                d = static_cast<double>(i64);
+#else
+                // Use double to store significand in 32-bit architecture
+                d = static_cast<double>(use64bit ? i64 : i);
+#endif
+                useDouble = true;
+            }
+
+            while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                if (significandDigit < 17) {
+                    d = d * 10.0 + (s.TakePush() - '0');
+                    --expFrac;
+                    if (RAPIDJSON_LIKELY(d > 0.0))
+                        significandDigit++;
+                }
+                else
+                    s.TakePush();
+            }
+        }
+        else
+            decimalPosition = s.Length(); // decimal position at the end of integer.
+
+        // Parse exp = e [ minus / plus ] 1*DIGIT
+        int exp = 0;
+        if (Consume(s, 'e') || Consume(s, 'E')) {
+            if (!useDouble) {
+                d = static_cast<double>(use64bit ? i64 : i);
+                useDouble = true;
+            }
+
+            bool expMinus = false;
+            if (Consume(s, '+'))
+                ;
+            else if (Consume(s, '-'))
+                expMinus = true;
+
+            if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                exp = static_cast<int>(s.Take() - '0');
+                if (expMinus) {
+                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                        exp = exp * 10 + static_cast<int>(s.Take() - '0');
+                        if (exp >= 214748364) {                         // Issue #313: prevent overflow exponent
+                            while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9'))  // Consume the rest of exponent
+                                s.Take();
+                        }
+                    }
+                }
+                else {  // positive exp
+                    int maxExp = 308 - expFrac;
+                    while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+                        exp = exp * 10 + static_cast<int>(s.Take() - '0');
+                        if (RAPIDJSON_UNLIKELY(exp > maxExp))
+                            RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+                    }
+                }
+            }
+            else
+                RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
+
+            if (expMinus)
+                exp = -exp;
+        }
+
+        // Finish parsing, call event according to the type of number.
+        bool cont = true;
+
+        if (parseFlags & kParseNumbersAsStringsFlag) {
+            if (parseFlags & kParseInsituFlag) {
+                s.Pop();  // Pop stack no matter if it will be used or not.
+                typename InputStream::Ch* head = is.PutBegin();
+                const size_t length = s.Tell() - startOffset;
+                RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+                // unable to insert the \0 character here, it will erase the comma after this number
+                const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
+                cont = handler.RawNumber(str, SizeType(length), false);
+            }
+            else {
+                SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
+                StringStream srcStream(s.Pop());
+                StackStream<typename TargetEncoding::Ch> dstStream(stack_);
+                while (numCharsToCopy--) {
+                    Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
+                }
+                dstStream.Put('\0');
+                const typename TargetEncoding::Ch* str = dstStream.Pop();
+                const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
+                cont = handler.RawNumber(str, SizeType(length), true);
+            }
+        }
+        else {
+           size_t length = s.Length();
+           const char* decimal = s.Pop();  // Pop stack no matter if it will be used or not.
+
+           if (useDouble) {
+               int p = exp + expFrac;
+               if (parseFlags & kParseFullPrecisionFlag)
+                   d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
+               else
+                   d = internal::StrtodNormalPrecision(d, p);
+
+               cont = handler.Double(minus ? -d : d);
+           }
+           else if (useNanOrInf) {
+               cont = handler.Double(d);
+           }
+           else {
+               if (use64bit) {
+                   if (minus)
+                       cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
+                   else
+                       cont = handler.Uint64(i64);
+               }
+               else {
+                   if (minus)
+                       cont = handler.Int(static_cast<int32_t>(~i + 1));
+                   else
+                       cont = handler.Uint(i);
+               }
+           }
+        }
+        if (RAPIDJSON_UNLIKELY(!cont))
+            RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
+    }
+
+    // Parse any JSON value
+    template<unsigned parseFlags, typename InputStream, typename Handler>
+    void ParseValue(InputStream& is, Handler& handler) {
+        switch (is.Peek()) {
+            case 'n': ParseNull  <parseFlags>(is, handler); break;
+            case 't': ParseTrue  <parseFlags>(is, handler); break;
+            case 'f': ParseFalse <parseFlags>(is, handler); break;
+            case '"': ParseString<parseFlags>(is, handler); break;
+            case '{': ParseObject<parseFlags>(is, handler); break;
+            case '[': ParseArray <parseFlags>(is, handler); break;
+            default :
+                      ParseNumber<parseFlags>(is, handler);
+                      break;
+
+        }
+    }
+
+    // Iterative Parsing
+
+    // States
+    enum IterativeParsingState {
+        IterativeParsingStartState = 0,
+        IterativeParsingFinishState,
+        IterativeParsingErrorState,
+
+        // Object states
+        IterativeParsingObjectInitialState,
+        IterativeParsingMemberKeyState,
+        IterativeParsingKeyValueDelimiterState,
+        IterativeParsingMemberValueState,
+        IterativeParsingMemberDelimiterState,
+        IterativeParsingObjectFinishState,
+
+        // Array states
+        IterativeParsingArrayInitialState,
+        IterativeParsingElementState,
+        IterativeParsingElementDelimiterState,
+        IterativeParsingArrayFinishState,
+
+        // Single value state
+        IterativeParsingValueState
+    };
+
+    enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
+
+    // Tokens
+    enum Token {
+        LeftBracketToken = 0,
+        RightBracketToken,
+
+        LeftCurlyBracketToken,
+        RightCurlyBracketToken,
+
+        CommaToken,
+        ColonToken,
+
+        StringToken,
+        FalseToken,
+        TrueToken,
+        NullToken,
+        NumberToken,
+
+        kTokenCount
+    };
+
+    RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define N NumberToken
+#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
+        // Maps from ASCII to Token
+        static const unsigned char tokenMap[256] = {
+            N16, // 00~0F
+            N16, // 10~1F
+            N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
+            N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
+            N16, // 40~4F
+            N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
+            N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
+            N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
+            N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
+        };
+#undef N
+#undef N16
+//!@endcond
+
+        if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
+            return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
+        else
+            return NumberToken;
+    }
+
+    RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
+        // current state x one lookahead token -> new state
+        static const char G[cIterativeParsingStateCount][kTokenCount] = {
+            // Start
+            {
+                IterativeParsingArrayInitialState,  // Left bracket
+                IterativeParsingErrorState,         // Right bracket
+                IterativeParsingObjectInitialState, // Left curly bracket
+                IterativeParsingErrorState,         // Right curly bracket
+                IterativeParsingErrorState,         // Comma
+                IterativeParsingErrorState,         // Colon
+                IterativeParsingValueState,         // String
+                IterativeParsingValueState,         // False
+                IterativeParsingValueState,         // True
+                IterativeParsingValueState,         // Null
+                IterativeParsingValueState          // Number
+            },
+            // Finish(sink state)
+            {
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState
+            },
+            // Error(sink state)
+            {
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState
+            },
+            // ObjectInitial
+            {
+                IterativeParsingErrorState,         // Left bracket
+                IterativeParsingErrorState,         // Right bracket
+                IterativeParsingErrorState,         // Left curly bracket
+                IterativeParsingObjectFinishState,  // Right curly bracket
+                IterativeParsingErrorState,         // Comma
+                IterativeParsingErrorState,         // Colon
+                IterativeParsingMemberKeyState,     // String
+                IterativeParsingErrorState,         // False
+                IterativeParsingErrorState,         // True
+                IterativeParsingErrorState,         // Null
+                IterativeParsingErrorState          // Number
+            },
+            // MemberKey
+            {
+                IterativeParsingErrorState,             // Left bracket
+                IterativeParsingErrorState,             // Right bracket
+                IterativeParsingErrorState,             // Left curly bracket
+                IterativeParsingErrorState,             // Right curly bracket
+                IterativeParsingErrorState,             // Comma
+                IterativeParsingKeyValueDelimiterState, // Colon
+                IterativeParsingErrorState,             // String
+                IterativeParsingErrorState,             // False
+                IterativeParsingErrorState,             // True
+                IterativeParsingErrorState,             // Null
+                IterativeParsingErrorState              // Number
+            },
+            // KeyValueDelimiter
+            {
+                IterativeParsingArrayInitialState,      // Left bracket(push MemberValue state)
+                IterativeParsingErrorState,             // Right bracket
+                IterativeParsingObjectInitialState,     // Left curly bracket(push MemberValue state)
+                IterativeParsingErrorState,             // Right curly bracket
+                IterativeParsingErrorState,             // Comma
+                IterativeParsingErrorState,             // Colon
+                IterativeParsingMemberValueState,       // String
+                IterativeParsingMemberValueState,       // False
+                IterativeParsingMemberValueState,       // True
+                IterativeParsingMemberValueState,       // Null
+                IterativeParsingMemberValueState        // Number
+            },
+            // MemberValue
+            {
+                IterativeParsingErrorState,             // Left bracket
+                IterativeParsingErrorState,             // Right bracket
+                IterativeParsingErrorState,             // Left curly bracket
+                IterativeParsingObjectFinishState,      // Right curly bracket
+                IterativeParsingMemberDelimiterState,   // Comma
+                IterativeParsingErrorState,             // Colon
+                IterativeParsingErrorState,             // String
+                IterativeParsingErrorState,             // False
+                IterativeParsingErrorState,             // True
+                IterativeParsingErrorState,             // Null
+                IterativeParsingErrorState              // Number
+            },
+            // MemberDelimiter
+            {
+                IterativeParsingErrorState,         // Left bracket
+                IterativeParsingErrorState,         // Right bracket
+                IterativeParsingErrorState,         // Left curly bracket
+                IterativeParsingObjectFinishState,  // Right curly bracket
+                IterativeParsingErrorState,         // Comma
+                IterativeParsingErrorState,         // Colon
+                IterativeParsingMemberKeyState,     // String
+                IterativeParsingErrorState,         // False
+                IterativeParsingErrorState,         // True
+                IterativeParsingErrorState,         // Null
+                IterativeParsingErrorState          // Number
+            },
+            // ObjectFinish(sink state)
+            {
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState
+            },
+            // ArrayInitial
+            {
+                IterativeParsingArrayInitialState,      // Left bracket(push Element state)
+                IterativeParsingArrayFinishState,       // Right bracket
+                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)
+                IterativeParsingErrorState,             // Right curly bracket
+                IterativeParsingErrorState,             // Comma
+                IterativeParsingErrorState,             // Colon
+                IterativeParsingElementState,           // String
+                IterativeParsingElementState,           // False
+                IterativeParsingElementState,           // True
+                IterativeParsingElementState,           // Null
+                IterativeParsingElementState            // Number
+            },
+            // Element
+            {
+                IterativeParsingErrorState,             // Left bracket
+                IterativeParsingArrayFinishState,       // Right bracket
+                IterativeParsingErrorState,             // Left curly bracket
+                IterativeParsingErrorState,             // Right curly bracket
+                IterativeParsingElementDelimiterState,  // Comma
+                IterativeParsingErrorState,             // Colon
+                IterativeParsingErrorState,             // String
+                IterativeParsingErrorState,             // False
+                IterativeParsingErrorState,             // True
+                IterativeParsingErrorState,             // Null
+                IterativeParsingErrorState              // Number
+            },
+            // ElementDelimiter
+            {
+                IterativeParsingArrayInitialState,      // Left bracket(push Element state)
+                IterativeParsingArrayFinishState,       // Right bracket
+                IterativeParsingObjectInitialState,     // Left curly bracket(push Element state)
+                IterativeParsingErrorState,             // Right curly bracket
+                IterativeParsingErrorState,             // Comma
+                IterativeParsingErrorState,             // Colon
+                IterativeParsingElementState,           // String
+                IterativeParsingElementState,           // False
+                IterativeParsingElementState,           // True
+                IterativeParsingElementState,           // Null
+                IterativeParsingElementState            // Number
+            },
+            // ArrayFinish(sink state)
+            {
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState
+            },
+            // Single Value (sink state)
+            {
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
+                IterativeParsingErrorState
+            }
+        }; // End of G
+
+        return static_cast<IterativeParsingState>(G[state][token]);
+    }
+
+    // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
+    // May return a new state on state pop.
+    template <unsigned parseFlags, typename InputStream, typename Handler>
+    RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
+        (void)token;
+
+        switch (dst) {
+        case IterativeParsingErrorState:
+            return dst;
+
+        case IterativeParsingObjectInitialState:
+        case IterativeParsingArrayInitialState:
+        {
+            // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
+            // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
+            IterativeParsingState n = src;
+            if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
+                n = IterativeParsingElementState;
+            else if (src == IterativeParsingKeyValueDelimiterState)
+                n = IterativeParsingMemberValueState;
+            // Push current state.
+            *stack_.template Push<SizeType>(1) = n;
+            // Initialize and push the member/element count.
+            *stack_.template Push<SizeType>(1) = 0;
+            // Call handler
+            bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
+            // On handler short circuits the parsing.
+            if (!hr) {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+                return IterativeParsingErrorState;
+            }
+            else {
+                is.Take();
+                return dst;
+            }
+        }
+
+        case IterativeParsingMemberKeyState:
+            ParseString<parseFlags>(is, handler, true);
+            if (HasParseError())
+                return IterativeParsingErrorState;
+            else
+                return dst;
+
+        case IterativeParsingKeyValueDelimiterState:
+            RAPIDJSON_ASSERT(token == ColonToken);
+            is.Take();
+            return dst;
+
+        case IterativeParsingMemberValueState:
+            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+            ParseValue<parseFlags>(is, handler);
+            if (HasParseError()) {
+                return IterativeParsingErrorState;
+            }
+            return dst;
+
+        case IterativeParsingElementState:
+            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+            ParseValue<parseFlags>(is, handler);
+            if (HasParseError()) {
+                return IterativeParsingErrorState;
+            }
+            return dst;
+
+        case IterativeParsingMemberDelimiterState:
+        case IterativeParsingElementDelimiterState:
+            is.Take();
+            // Update member/element count.
+            *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+            return dst;
+
+        case IterativeParsingObjectFinishState:
+        {
+            // Transit from delimiter is only allowed when trailing commas are enabled
+            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());
+                return IterativeParsingErrorState;
+            }
+            // Get member count.
+            SizeType c = *stack_.template Pop<SizeType>(1);
+            // If the object is not empty, count the last member.
+            if (src == IterativeParsingMemberValueState)
+                ++c;
+            // Restore the state.
+            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+            // Transit to Finish state if this is the topmost scope.
+            if (n == IterativeParsingStartState)
+                n = IterativeParsingFinishState;
+            // Call handler
+            bool hr = handler.EndObject(c);
+            // On handler short circuits the parsing.
+            if (!hr) {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+                return IterativeParsingErrorState;
+            }
+            else {
+                is.Take();
+                return n;
+            }
+        }
+
+        case IterativeParsingArrayFinishState:
+        {
+            // Transit from delimiter is only allowed when trailing commas are enabled
+            if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());
+                return IterativeParsingErrorState;
+            }
+            // Get element count.
+            SizeType c = *stack_.template Pop<SizeType>(1);
+            // If the array is not empty, count the last element.
+            if (src == IterativeParsingElementState)
+                ++c;
+            // Restore the state.
+            IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
+            // Transit to Finish state if this is the topmost scope.
+            if (n == IterativeParsingStartState)
+                n = IterativeParsingFinishState;
+            // Call handler
+            bool hr = handler.EndArray(c);
+            // On handler short circuits the parsing.
+            if (!hr) {
+                RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+                return IterativeParsingErrorState;
+            }
+            else {
+                is.Take();
+                return n;
+            }
+        }
+
+        default:
+            // This branch is for IterativeParsingValueState actually.
+            // Use `default:` rather than
+            // `case IterativeParsingValueState:` is for code coverage.
+
+            // The IterativeParsingStartState is not enumerated in this switch-case.
+            // It is impossible for that case. And it can be caught by following assertion.
+
+            // The IterativeParsingFinishState is not enumerated in this switch-case either.
+            // It is a "derivative" state which cannot triggered from Predict() directly.
+            // Therefore it cannot happen here. And it can be caught by following assertion.
+            RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
+
+            // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
+            ParseValue<parseFlags>(is, handler);
+            if (HasParseError()) {
+                return IterativeParsingErrorState;
+            }
+            return IterativeParsingFinishState;
+        }
+    }
+
+    template <typename InputStream>
+    void HandleError(IterativeParsingState src, InputStream& is) {
+        if (HasParseError()) {
+            // Error flag has been set.
+            return;
+        }
+
+        switch (src) {
+        case IterativeParsingStartState:            RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
+        case IterativeParsingFinishState:           RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
+        case IterativeParsingObjectInitialState:
+        case IterativeParsingMemberDelimiterState:  RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
+        case IterativeParsingMemberKeyState:        RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
+        case IterativeParsingMemberValueState:      RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
+        case IterativeParsingKeyValueDelimiterState:
+        case IterativeParsingArrayInitialState:
+        case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
+        default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
+        }
+    }
+
+    template <unsigned parseFlags, typename InputStream, typename Handler>
+    ParseResult IterativeParse(InputStream& is, Handler& handler) {
+        parseResult_.Clear();
+        ClearStackOnExit scope(*this);
+        IterativeParsingState state = IterativeParsingStartState;
+
+        SkipWhitespaceAndComments<parseFlags>(is);
+        RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+        while (is.Peek() != '\0') {
+            Token t = Tokenize(is.Peek());
+            IterativeParsingState n = Predict(state, t);
+            IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
+
+            if (d == IterativeParsingErrorState) {
+                HandleError(state, is);
+                break;
+            }
+
+            state = d;
+
+            // Do not further consume streams if a root JSON has been parsed.
+            if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
+                break;
+
+            SkipWhitespaceAndComments<parseFlags>(is);
+            RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+        }
+
+        // Handle the end of file.
+        if (state != IterativeParsingFinishState)
+            HandleError(state, is);
+
+        return parseResult_;
+    }
+
+    static const size_t kDefaultStackCapacity = 256;    //!< Default stack capacity in bytes for storing a single decoded string.
+    internal::Stack<StackAllocator> stack_;  //!< A stack for storing decoded string temporarily during non-destructive parsing.
+    ParseResult parseResult_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/core/deps/rapidjson/schema.h b/core/deps/rapidjson/schema.h
new file mode 100644 (file)
index 0000000..b182aa2
--- /dev/null
@@ -0,0 +1,2006 @@
+// Tencent is pleased to support the open source community by making RapidJSON available->
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License-> You may obtain a copy of the License at
+//
+// http://opensource->org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied-> See the License for the 
+// specific language governing permissions and limitations under the License->
+
+#ifndef RAPIDJSON_SCHEMA_H_
+#define RAPIDJSON_SCHEMA_H_
+
+#include "document.h"
+#include "pointer.h"
+#include <cmath> // abs, floor
+
+#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
+#endif
+
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+#include "internal/regex.h"
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+#include <regex>
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
+#define RAPIDJSON_SCHEMA_HAS_REGEX 1
+#else
+#define RAPIDJSON_SCHEMA_HAS_REGEX 0
+#endif
+
+#ifndef RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#endif
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#include "stringbuffer.h"
+#endif
+
+RAPIDJSON_DIAG_PUSH
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(weak-vtables)
+RAPIDJSON_DIAG_OFF(exit-time-destructors)
+RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
+RAPIDJSON_DIAG_OFF(variadic-macros)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Verbose Utilities
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+
+namespace internal {
+
+inline void PrintInvalidKeyword(const char* keyword) {
+    printf("Fail keyword: %s\n", keyword);
+}
+
+inline void PrintInvalidKeyword(const wchar_t* keyword) {
+    wprintf(L"Fail keyword: %ls\n", keyword);
+}
+
+inline void PrintInvalidDocument(const char* document) {
+    printf("Fail document: %s\n\n", document);
+}
+
+inline void PrintInvalidDocument(const wchar_t* document) {
+    wprintf(L"Fail document: %ls\n\n", document);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
+    printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
+}
+
+inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
+    wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
+}
+
+} // namespace internal
+
+#endif // RAPIDJSON_SCHEMA_VERBOSE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_INVALID_KEYWORD_RETURN
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
+#else
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
+#endif
+
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+    context.invalidKeyword = keyword.GetString();\
+    RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
+    return false;\
+RAPIDJSON_MULTILINEMACRO_END
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <typename ValueType, typename Allocator>
+class GenericSchemaDocument;
+
+namespace internal {
+
+template <typename SchemaDocumentType>
+class Schema;
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaValidator
+
+class ISchemaValidator {
+public:
+    virtual ~ISchemaValidator() {}
+    virtual bool IsValid() const = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaStateFactory
+
+template <typename SchemaType>
+class ISchemaStateFactory {
+public:
+    virtual ~ISchemaStateFactory() {}
+    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+    virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
+    virtual void* CreateHasher() = 0;
+    virtual uint64_t GetHashCode(void* hasher) = 0;
+    virtual void DestroryHasher(void* hasher) = 0;
+    virtual void* MallocState(size_t size) = 0;
+    virtual void FreeState(void* p) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Hasher
+
+// For comparison of compound value
+template<typename Encoding, typename Allocator>
+class Hasher {
+public:
+    typedef typename Encoding::Ch Ch;
+
+    Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
+
+    bool Null() { return WriteType(kNullType); }
+    bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
+    bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+    bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+    bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
+    bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
+    bool Double(double d) { 
+        Number n; 
+        if (d < 0) n.u.i = static_cast<int64_t>(d);
+        else       n.u.u = static_cast<uint64_t>(d); 
+        n.d = d;
+        return WriteNumber(n);
+    }
+
+    bool RawNumber(const Ch* str, SizeType len, bool) {
+        WriteBuffer(kNumberType, str, len * sizeof(Ch));
+        return true;
+    }
+
+    bool String(const Ch* str, SizeType len, bool) {
+        WriteBuffer(kStringType, str, len * sizeof(Ch));
+        return true;
+    }
+
+    bool StartObject() { return true; }
+    bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
+    bool EndObject(SizeType memberCount) { 
+        uint64_t h = Hash(0, kObjectType);
+        uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
+        for (SizeType i = 0; i < memberCount; i++)
+            h ^= Hash(kv[i * 2], kv[i * 2 + 1]);  // Use xor to achieve member order insensitive
+        *stack_.template Push<uint64_t>() = h;
+        return true;
+    }
+    
+    bool StartArray() { return true; }
+    bool EndArray(SizeType elementCount) { 
+        uint64_t h = Hash(0, kArrayType);
+        uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
+        for (SizeType i = 0; i < elementCount; i++)
+            h = Hash(h, e[i]); // Use hash to achieve element order sensitive
+        *stack_.template Push<uint64_t>() = h;
+        return true;
+    }
+
+    bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
+
+    uint64_t GetHashCode() const {
+        RAPIDJSON_ASSERT(IsValid());
+        return *stack_.template Top<uint64_t>();
+    }
+
+private:
+    static const size_t kDefaultSize = 256;
+    struct Number {
+        union U {
+            uint64_t u;
+            int64_t i;
+        }u;
+        double d;
+    };
+
+    bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
+    
+    bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
+    
+    bool WriteBuffer(Type type, const void* data, size_t len) {
+        // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
+        uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
+        const unsigned char* d = static_cast<const unsigned char*>(data);
+        for (size_t i = 0; i < len; i++)
+            h = Hash(h, d[i]);
+        *stack_.template Push<uint64_t>() = h;
+        return true;
+    }
+
+    static uint64_t Hash(uint64_t h, uint64_t d) {
+        static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
+        h ^= d;
+        h *= kPrime;
+        return h;
+    }
+
+    Stack<Allocator> stack_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidationContext
+
+template <typename SchemaDocumentType>
+struct SchemaValidationContext {
+    typedef Schema<SchemaDocumentType> SchemaType;
+    typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
+    typedef typename SchemaType::ValueType ValueType;
+    typedef typename ValueType::Ch Ch;
+
+    enum PatternValidatorType {
+        kPatternValidatorOnly,
+        kPatternValidatorWithProperty,
+        kPatternValidatorWithAdditionalProperty
+    };
+
+    SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
+        factory(f),
+        schema(s),
+        valueSchema(),
+        invalidKeyword(),
+        hasher(),
+        arrayElementHashCodes(),
+        validators(),
+        validatorCount(),
+        patternPropertiesValidators(),
+        patternPropertiesValidatorCount(),
+        patternPropertiesSchemas(),
+        patternPropertiesSchemaCount(),
+        valuePatternValidatorType(kPatternValidatorOnly),
+        propertyExist(),
+        inArray(false),
+        valueUniqueness(false),
+        arrayUniqueness(false)
+    {
+    }
+
+    ~SchemaValidationContext() {
+        if (hasher)
+            factory.DestroryHasher(hasher);
+        if (validators) {
+            for (SizeType i = 0; i < validatorCount; i++)
+                factory.DestroySchemaValidator(validators[i]);
+            factory.FreeState(validators);
+        }
+        if (patternPropertiesValidators) {
+            for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
+                factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+            factory.FreeState(patternPropertiesValidators);
+        }
+        if (patternPropertiesSchemas)
+            factory.FreeState(patternPropertiesSchemas);
+        if (propertyExist)
+            factory.FreeState(propertyExist);
+    }
+
+    SchemaValidatorFactoryType& factory;
+    const SchemaType* schema;
+    const SchemaType* valueSchema;
+    const Ch* invalidKeyword;
+    void* hasher; // Only validator access
+    void* arrayElementHashCodes; // Only validator access this
+    ISchemaValidator** validators;
+    SizeType validatorCount;
+    ISchemaValidator** patternPropertiesValidators;
+    SizeType patternPropertiesValidatorCount;
+    const SchemaType** patternPropertiesSchemas;
+    SizeType patternPropertiesSchemaCount;
+    PatternValidatorType valuePatternValidatorType;
+    PatternValidatorType objectPatternValidatorType;
+    SizeType arrayElementIndex;
+    bool* propertyExist;
+    bool inArray;
+    bool valueUniqueness;
+    bool arrayUniqueness;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Schema
+
+template <typename SchemaDocumentType>
+class Schema {
+public:
+    typedef typename SchemaDocumentType::ValueType ValueType;
+    typedef typename SchemaDocumentType::AllocatorType AllocatorType;
+    typedef typename SchemaDocumentType::PointerType PointerType;
+    typedef typename ValueType::EncodingType EncodingType;
+    typedef typename EncodingType::Ch Ch;
+    typedef SchemaValidationContext<SchemaDocumentType> Context;
+    typedef Schema<SchemaDocumentType> SchemaType;
+    typedef GenericValue<EncodingType, AllocatorType> SValue;
+    friend class GenericSchemaDocument<ValueType, AllocatorType>;
+
+    Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
+        allocator_(allocator),
+        enum_(),
+        enumCount_(),
+        not_(),
+        type_((1 << kTotalSchemaType) - 1), // typeless
+        validatorCount_(),
+        properties_(),
+        additionalPropertiesSchema_(),
+        patternProperties_(),
+        patternPropertyCount_(),
+        propertyCount_(),
+        minProperties_(),
+        maxProperties_(SizeType(~0)),
+        additionalProperties_(true),
+        hasDependencies_(),
+        hasRequired_(),
+        hasSchemaDependencies_(),
+        additionalItemsSchema_(),
+        itemsList_(),
+        itemsTuple_(),
+        itemsTupleCount_(),
+        minItems_(),
+        maxItems_(SizeType(~0)),
+        additionalItems_(true),
+        uniqueItems_(false),
+        pattern_(),
+        minLength_(0),
+        maxLength_(~SizeType(0)),
+        exclusiveMinimum_(false),
+        exclusiveMaximum_(false)
+    {
+        typedef typename SchemaDocumentType::ValueType ValueType;
+        typedef typename ValueType::ConstValueIterator ConstValueIterator;
+        typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
+
+        if (!value.IsObject())
+            return;
+
+        if (const ValueType* v = GetMember(value, GetTypeString())) {
+            type_ = 0;
+            if (v->IsString())
+                AddType(*v);
+            else if (v->IsArray())
+                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
+                    AddType(*itr);
+        }
+
+        if (const ValueType* v = GetMember(value, GetEnumString()))
+            if (v->IsArray() && v->Size() > 0) {
+                enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
+                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
+                    typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
+                    char buffer[256 + 24];
+                    MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
+                    EnumHasherType h(&hasherAllocator, 256);
+                    itr->Accept(h);
+                    enum_[enumCount_++] = h.GetHashCode();
+                }
+            }
+
+        if (schemaDocument) {
+            AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
+            AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
+            AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
+        }
+
+        if (const ValueType* v = GetMember(value, GetNotString())) {
+            schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
+            notValidatorIndex_ = validatorCount_;
+            validatorCount_++;
+        }
+
+        // Object
+
+        const ValueType* properties = GetMember(value, GetPropertiesString());
+        const ValueType* required = GetMember(value, GetRequiredString());
+        const ValueType* dependencies = GetMember(value, GetDependenciesString());
+        {
+            // Gather properties from properties/required/dependencies
+            SValue allProperties(kArrayType);
+
+            if (properties && properties->IsObject())
+                for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
+                    AddUniqueElement(allProperties, itr->name);
+            
+            if (required && required->IsArray())
+                for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+                    if (itr->IsString())
+                        AddUniqueElement(allProperties, *itr);
+
+            if (dependencies && dependencies->IsObject())
+                for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+                    AddUniqueElement(allProperties, itr->name);
+                    if (itr->value.IsArray())
+                        for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
+                            if (i->IsString())
+                                AddUniqueElement(allProperties, *i);
+                }
+
+            if (allProperties.Size() > 0) {
+                propertyCount_ = allProperties.Size();
+                properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
+                for (SizeType i = 0; i < propertyCount_; i++) {
+                    new (&properties_[i]) Property();
+                    properties_[i].name = allProperties[i];
+                    properties_[i].schema = GetTypeless();
+                }
+            }
+        }
+
+        if (properties && properties->IsObject()) {
+            PointerType q = p.Append(GetPropertiesString(), allocator_);
+            for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
+                SizeType index;
+                if (FindPropertyIndex(itr->name, &index))
+                    schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
+            }
+        }
+
+        if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
+            PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
+            patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
+            patternPropertyCount_ = 0;
+
+            for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
+                new (&patternProperties_[patternPropertyCount_]) PatternProperty();
+                patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
+                schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
+                patternPropertyCount_++;
+            }
+        }
+
+        if (required && required->IsArray())
+            for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
+                if (itr->IsString()) {
+                    SizeType index;
+                    if (FindPropertyIndex(*itr, &index)) {
+                        properties_[index].required = true;
+                        hasRequired_ = true;
+                    }
+                }
+
+        if (dependencies && dependencies->IsObject()) {
+            PointerType q = p.Append(GetDependenciesString(), allocator_);
+            hasDependencies_ = true;
+            for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
+                SizeType sourceIndex;
+                if (FindPropertyIndex(itr->name, &sourceIndex)) {
+                    if (itr->value.IsArray()) {
+                        properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
+                        std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
+                        for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
+                            SizeType targetIndex;
+                            if (FindPropertyIndex(*targetItr, &targetIndex))
+                                properties_[sourceIndex].dependencies[targetIndex] = true;
+                        }
+                    }
+                    else if (itr->value.IsObject()) {
+                        hasSchemaDependencies_ = true;
+                        schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
+                        properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
+                        validatorCount_++;
+                    }
+                }
+            }
+        }
+
+        if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
+            if (v->IsBool())
+                additionalProperties_ = v->GetBool();
+            else if (v->IsObject())
+                schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
+        }
+
+        AssignIfExist(minProperties_, value, GetMinPropertiesString());
+        AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
+
+        // Array
+        if (const ValueType* v = GetMember(value, GetItemsString())) {
+            PointerType q = p.Append(GetItemsString(), allocator_);
+            if (v->IsObject()) // List validation
+                schemaDocument->CreateSchema(&itemsList_, q, *v, document);
+            else if (v->IsArray()) { // Tuple validation
+                itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
+                SizeType index = 0;
+                for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
+                    schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
+            }
+        }
+
+        AssignIfExist(minItems_, value, GetMinItemsString());
+        AssignIfExist(maxItems_, value, GetMaxItemsString());
+
+        if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
+            if (v->IsBool())
+                additionalItems_ = v->GetBool();
+            else if (v->IsObject())
+                schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
+        }
+
+        AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
+
+        // String
+        AssignIfExist(minLength_, value, GetMinLengthString());
+        AssignIfExist(maxLength_, value, GetMaxLengthString());
+
+        if (const ValueType* v = GetMember(value, GetPatternString()))
+            pattern_ = CreatePattern(*v);
+
+        // Number
+        if (const ValueType* v = GetMember(value, GetMinimumString()))
+            if (v->IsNumber())
+                minimum_.CopyFrom(*v, *allocator_);
+
+        if (const ValueType* v = GetMember(value, GetMaximumString()))
+            if (v->IsNumber())
+                maximum_.CopyFrom(*v, *allocator_);
+
+        AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
+        AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
+
+        if (const ValueType* v = GetMember(value, GetMultipleOfString()))
+            if (v->IsNumber() && v->GetDouble() > 0.0)
+                multipleOf_.CopyFrom(*v, *allocator_);
+    }
+
+    ~Schema() {
+        if (allocator_) {
+            allocator_->Free(enum_);
+        }
+        if (properties_) {
+            for (SizeType i = 0; i < propertyCount_; i++)
+                properties_[i].~Property();
+            AllocatorType::Free(properties_);
+        }
+        if (patternProperties_) {
+            for (SizeType i = 0; i < patternPropertyCount_; i++)
+                patternProperties_[i].~PatternProperty();
+            AllocatorType::Free(patternProperties_);
+        }
+        AllocatorType::Free(itemsTuple_);
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+        if (pattern_) {
+            pattern_->~RegexType();
+            allocator_->Free(pattern_);
+        }
+#endif
+    }
+
+    bool BeginValue(Context& context) const {
+        if (context.inArray) {
+            if (uniqueItems_)
+                context.valueUniqueness = true;
+
+            if (itemsList_)
+                context.valueSchema = itemsList_;
+            else if (itemsTuple_) {
+                if (context.arrayElementIndex < itemsTupleCount_)
+                    context.valueSchema = itemsTuple_[context.arrayElementIndex];
+                else if (additionalItemsSchema_)
+                    context.valueSchema = additionalItemsSchema_;
+                else if (additionalItems_)
+                    context.valueSchema = GetTypeless();
+                else
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+            }
+            else
+                context.valueSchema = GetTypeless();
+
+            context.arrayElementIndex++;
+        }
+        return true;
+    }
+
+    RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+        if (context.patternPropertiesValidatorCount > 0) {
+            bool otherValid = false;
+            SizeType count = context.patternPropertiesValidatorCount;
+            if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
+                otherValid = context.patternPropertiesValidators[--count]->IsValid();
+
+            bool patternValid = true;
+            for (SizeType i = 0; i < count; i++)
+                if (!context.patternPropertiesValidators[i]->IsValid()) {
+                    patternValid = false;
+                    break;
+                }
+
+            if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
+                if (!patternValid)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+            }
+            else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
+                if (!patternValid || !otherValid)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+            }
+            else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
+                RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+        }
+
+        if (enum_) {
+            const uint64_t h = context.factory.GetHashCode(context.hasher);
+            for (SizeType i = 0; i < enumCount_; i++)
+                if (enum_[i] == h)
+                    goto foundEnum;
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+            foundEnum:;
+        }
+
+        if (allOf_.schemas)
+            for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+                if (!context.validators[i]->IsValid())
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
+        
+        if (anyOf_.schemas) {
+            for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+                if (context.validators[i]->IsValid())
+                    goto foundAny;
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
+            foundAny:;
+        }
+
+        if (oneOf_.schemas) {
+            bool oneValid = false;
+            for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+                if (context.validators[i]->IsValid()) {
+                    if (oneValid)
+                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+                    else
+                        oneValid = true;
+                }
+            if (!oneValid)
+                RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+        }
+
+        if (not_ && context.validators[notValidatorIndex_]->IsValid())
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+
+        return true;
+    }
+
+    bool Null(Context& context) const { 
+        if (!(type_ & (1 << kNullSchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+        return CreateParallelValidator(context);
+    }
+    
+    bool Bool(Context& context, bool) const { 
+        if (!(type_ & (1 << kBooleanSchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+        return CreateParallelValidator(context);
+    }
+
+    bool Int(Context& context, int i) const {
+        if (!CheckInt(context, i))
+            return false;
+        return CreateParallelValidator(context);
+    }
+
+    bool Uint(Context& context, unsigned u) const {
+        if (!CheckUint(context, u))
+            return false;
+        return CreateParallelValidator(context);
+    }
+
+    bool Int64(Context& context, int64_t i) const {
+        if (!CheckInt(context, i))
+            return false;
+        return CreateParallelValidator(context);
+    }
+
+    bool Uint64(Context& context, uint64_t u) const {
+        if (!CheckUint(context, u))
+            return false;
+        return CreateParallelValidator(context);
+    }
+
+    bool Double(Context& context, double d) const {
+        if (!(type_ & (1 << kNumberSchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
+            return false;
+
+        if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
+            return false;
+        
+        if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
+            return false;
+        
+        return CreateParallelValidator(context);
+    }
+    
+    bool String(Context& context, const Ch* str, SizeType length, bool) const {
+        if (!(type_ & (1 << kStringSchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
+            SizeType count;
+            if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
+                if (count < minLength_)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
+                if (count > maxLength_)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+            }
+        }
+
+        if (pattern_ && !IsPatternMatch(pattern_, str, length))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+
+        return CreateParallelValidator(context);
+    }
+
+    bool StartObject(Context& context) const { 
+        if (!(type_ & (1 << kObjectSchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        if (hasDependencies_ || hasRequired_) {
+            context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
+            std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
+        }
+
+        if (patternProperties_) { // pre-allocate schema array
+            SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
+            context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
+            context.patternPropertiesSchemaCount = 0;
+            std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
+        }
+
+        return CreateParallelValidator(context);
+    }
+    
+    bool Key(Context& context, const Ch* str, SizeType len, bool) const {
+        if (patternProperties_) {
+            context.patternPropertiesSchemaCount = 0;
+            for (SizeType i = 0; i < patternPropertyCount_; i++)
+                if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
+                    context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
+        }
+
+        SizeType index;
+        if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
+            if (context.patternPropertiesSchemaCount > 0) {
+                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
+                context.valueSchema = GetTypeless();
+                context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
+            }
+            else
+                context.valueSchema = properties_[index].schema;
+
+            if (context.propertyExist)
+                context.propertyExist[index] = true;
+
+            return true;
+        }
+
+        if (additionalPropertiesSchema_) {
+            if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
+                context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
+                context.valueSchema = GetTypeless();
+                context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
+            }
+            else
+                context.valueSchema = additionalPropertiesSchema_;
+            return true;
+        }
+        else if (additionalProperties_) {
+            context.valueSchema = GetTypeless();
+            return true;
+        }
+
+        if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+
+        return true;
+    }
+
+    bool EndObject(Context& context, SizeType memberCount) const {
+        if (hasRequired_)
+            for (SizeType index = 0; index < propertyCount_; index++)
+                if (properties_[index].required)
+                    if (!context.propertyExist[index])
+                        RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+
+        if (memberCount < minProperties_)
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+
+        if (memberCount > maxProperties_)
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+
+        if (hasDependencies_) {
+            for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
+                if (context.propertyExist[sourceIndex]) {
+                    if (properties_[sourceIndex].dependencies) {
+                        for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
+                            if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
+                                RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+                    }
+                    else if (properties_[sourceIndex].dependenciesSchema)
+                        if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
+                            RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+                }
+        }
+
+        return true;
+    }
+
+    bool StartArray(Context& context) const { 
+        if (!(type_ & (1 << kArraySchemaType)))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        context.arrayElementIndex = 0;
+        context.inArray = true;
+
+        return CreateParallelValidator(context);
+    }
+
+    bool EndArray(Context& context, SizeType elementCount) const { 
+        context.inArray = false;
+        
+        if (elementCount < minItems_)
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
+        
+        if (elementCount > maxItems_)
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+
+        return true;
+    }
+
+    // Generate functions for string literal according to Ch
+#define RAPIDJSON_STRING_(name, ...) \
+    static const ValueType& Get##name##String() {\
+        static const Ch s[] = { __VA_ARGS__, '\0' };\
+        static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
+        return v;\
+    }
+
+    RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+    RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
+    RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
+    RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
+    RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
+    RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
+    RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
+    RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
+    RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
+    RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
+    RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
+    RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
+    RAPIDJSON_STRING_(Not, 'n', 'o', 't')
+    RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+    RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
+    RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
+    RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+    RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+    RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+    RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
+    RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
+    RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
+    RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
+    RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
+    RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
+    RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
+    RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
+    RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
+    RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
+    RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
+    RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
+    RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
+    RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
+
+#undef RAPIDJSON_STRING_
+
+private:
+    enum SchemaValueType {
+        kNullSchemaType,
+        kBooleanSchemaType,
+        kObjectSchemaType,
+        kArraySchemaType,
+        kStringSchemaType,
+        kNumberSchemaType,
+        kIntegerSchemaType,
+        kTotalSchemaType
+    };
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+        typedef internal::GenericRegex<EncodingType> RegexType;
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+        typedef std::basic_regex<Ch> RegexType;
+#else
+        typedef char RegexType;
+#endif
+
+    struct SchemaArray {
+        SchemaArray() : schemas(), count() {}
+        ~SchemaArray() { AllocatorType::Free(schemas); }
+        const SchemaType** schemas;
+        SizeType begin; // begin index of context.validators
+        SizeType count;
+    };
+
+    static const SchemaType* GetTypeless() {
+        static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
+        return &typeless;
+    }
+
+    template <typename V1, typename V2>
+    void AddUniqueElement(V1& a, const V2& v) {
+        for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+            if (*itr == v)
+                return;
+        V1 c(v, *allocator_);
+        a.PushBack(c, *allocator_);
+    }
+
+    static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
+        typename ValueType::ConstMemberIterator itr = value.FindMember(name);
+        return itr != value.MemberEnd() ? &(itr->value) : 0;
+    }
+
+    static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
+        if (const ValueType* v = GetMember(value, name))
+            if (v->IsBool())
+                out = v->GetBool();
+    }
+
+    static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
+        if (const ValueType* v = GetMember(value, name))
+            if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
+                out = static_cast<SizeType>(v->GetUint64());
+    }
+
+    void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
+        if (const ValueType* v = GetMember(value, name)) {
+            if (v->IsArray() && v->Size() > 0) {
+                PointerType q = p.Append(name, allocator_);
+                out.count = v->Size();
+                out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
+                memset(out.schemas, 0, sizeof(Schema*)* out.count);
+                for (SizeType i = 0; i < out.count; i++)
+                    schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
+                out.begin = validatorCount_;
+                validatorCount_ += out.count;
+            }
+        }
+    }
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+    template <typename ValueType>
+    RegexType* CreatePattern(const ValueType& value) {
+        if (value.IsString()) {
+            RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
+            if (!r->IsValid()) {
+                r->~RegexType();
+                AllocatorType::Free(r);
+                r = 0;
+            }
+            return r;
+        }
+        return 0;
+    }
+
+    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
+        return pattern->Search(str);
+    }
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+    template <typename ValueType>
+    RegexType* CreatePattern(const ValueType& value) {
+        if (value.IsString())
+            try {
+                return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
+            }
+            catch (const std::regex_error&) {
+            }
+        return 0;
+    }
+
+    static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
+        std::match_results<const Ch*> r;
+        return std::regex_search(str, str + length, r, *pattern);
+    }
+#else
+    template <typename ValueType>
+    RegexType* CreatePattern(const ValueType&) { return 0; }
+
+    static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
+#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
+
+    void AddType(const ValueType& type) {
+        if      (type == GetNullString()   ) type_ |= 1 << kNullSchemaType;
+        else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
+        else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
+        else if (type == GetArrayString()  ) type_ |= 1 << kArraySchemaType;
+        else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
+        else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
+        else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
+    }
+
+    bool CreateParallelValidator(Context& context) const {
+        if (enum_ || context.arrayUniqueness)
+            context.hasher = context.factory.CreateHasher();
+
+        if (validatorCount_) {
+            RAPIDJSON_ASSERT(context.validators == 0);
+            context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
+            context.validatorCount = validatorCount_;
+
+            if (allOf_.schemas)
+                CreateSchemaValidators(context, allOf_);
+
+            if (anyOf_.schemas)
+                CreateSchemaValidators(context, anyOf_);
+            
+            if (oneOf_.schemas)
+                CreateSchemaValidators(context, oneOf_);
+            
+            if (not_)
+                context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
+            
+            if (hasSchemaDependencies_) {
+                for (SizeType i = 0; i < propertyCount_; i++)
+                    if (properties_[i].dependenciesSchema)
+                        context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
+            }
+        }
+
+        return true;
+    }
+
+    void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
+        for (SizeType i = 0; i < schemas.count; i++)
+            context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+    }
+
+    // O(n)
+    bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
+        SizeType len = name.GetStringLength();
+        const Ch* str = name.GetString();
+        for (SizeType index = 0; index < propertyCount_; index++)
+            if (properties_[index].name.GetStringLength() == len && 
+                (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
+            {
+                *outIndex = index;
+                return true;
+            }
+        return false;
+    }
+
+    bool CheckInt(Context& context, int64_t i) const {
+        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        if (!minimum_.IsNull()) {
+            if (minimum_.IsInt64()) {
+                if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+            }
+            else if (minimum_.IsUint64()) {
+                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
+            }
+            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+                return false;
+        }
+
+        if (!maximum_.IsNull()) {
+            if (maximum_.IsInt64()) {
+                if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+            }
+            else if (maximum_.IsUint64())
+                /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
+            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+                return false;
+        }
+
+        if (!multipleOf_.IsNull()) {
+            if (multipleOf_.IsUint64()) {
+                if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+            }
+            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+                return false;
+        }
+
+        return true;
+    }
+
+    bool CheckUint(Context& context, uint64_t i) const {
+        if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+        if (!minimum_.IsNull()) {
+            if (minimum_.IsUint64()) {
+                if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+            }
+            else if (minimum_.IsInt64())
+                /* do nothing */; // i >= 0 > minimum.Getint64()
+            else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+                return false;
+        }
+
+        if (!maximum_.IsNull()) {
+            if (maximum_.IsUint64()) {
+                if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+            }
+            else if (maximum_.IsInt64())
+                RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
+            else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+                return false;
+        }
+
+        if (!multipleOf_.IsNull()) {
+            if (multipleOf_.IsUint64()) {
+                if (i % multipleOf_.GetUint64() != 0)
+                    RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+            }
+            else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+                return false;
+        }
+
+        return true;
+    }
+
+    bool CheckDoubleMinimum(Context& context, double d) const {
+        if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+        return true;
+    }
+
+    bool CheckDoubleMaximum(Context& context, double d) const {
+        if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+        return true;
+    }
+
+    bool CheckDoubleMultipleOf(Context& context, double d) const {
+        double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
+        double q = std::floor(a / b);
+        double r = a - q * b;
+        if (r > 0.0)
+            RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+        return true;
+    }
+
+    struct Property {
+        Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
+        ~Property() { AllocatorType::Free(dependencies); }
+        SValue name;
+        const SchemaType* schema;
+        const SchemaType* dependenciesSchema;
+        SizeType dependenciesValidatorIndex;
+        bool* dependencies;
+        bool required;
+    };
+
+    struct PatternProperty {
+        PatternProperty() : schema(), pattern() {}
+        ~PatternProperty() { 
+            if (pattern) {
+                pattern->~RegexType();
+                AllocatorType::Free(pattern);
+            }
+        }
+        const SchemaType* schema;
+        RegexType* pattern;
+    };
+
+    AllocatorType* allocator_;
+    uint64_t* enum_;
+    SizeType enumCount_;
+    SchemaArray allOf_;
+    SchemaArray anyOf_;
+    SchemaArray oneOf_;
+    const SchemaType* not_;
+    unsigned type_; // bitmask of kSchemaType
+    SizeType validatorCount_;
+    SizeType notValidatorIndex_;
+
+    Property* properties_;
+    const SchemaType* additionalPropertiesSchema_;
+    PatternProperty* patternProperties_;
+    SizeType patternPropertyCount_;
+    SizeType propertyCount_;
+    SizeType minProperties_;
+    SizeType maxProperties_;
+    bool additionalProperties_;
+    bool hasDependencies_;
+    bool hasRequired_;
+    bool hasSchemaDependencies_;
+
+    const SchemaType* additionalItemsSchema_;
+    const SchemaType* itemsList_;
+    const SchemaType** itemsTuple_;
+    SizeType itemsTupleCount_;
+    SizeType minItems_;
+    SizeType maxItems_;
+    bool additionalItems_;
+    bool uniqueItems_;
+
+    RegexType* pattern_;
+    SizeType minLength_;
+    SizeType maxLength_;
+
+    SValue minimum_;
+    SValue maximum_;
+    SValue multipleOf_;
+    bool exclusiveMinimum_;
+    bool exclusiveMaximum_;
+};
+
+template<typename Stack, typename Ch>
+struct TokenHelper {
+    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+        *documentStack.template Push<Ch>() = '/';
+        char buffer[21];
+        size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
+        for (size_t i = 0; i < length; i++)
+            *documentStack.template Push<Ch>() = buffer[i];
+    }
+};
+
+// Partial specialized version for char to prevent buffer copying.
+template <typename Stack>
+struct TokenHelper<Stack, char> {
+    RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
+        if (sizeof(SizeType) == 4) {
+            char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
+            *buffer++ = '/';
+            const char* end = internal::u32toa(index, buffer);
+             documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
+        }
+        else {
+            char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
+            *buffer++ = '/';
+            const char* end = internal::u64toa(index, buffer);
+            documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
+        }
+    }
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// IGenericRemoteSchemaDocumentProvider
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider {
+public:
+    typedef typename SchemaDocumentType::Ch Ch;
+
+    virtual ~IGenericRemoteSchemaDocumentProvider() {}
+    virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaDocument
+
+//! JSON schema document.
+/*!
+    A JSON schema document is a compiled version of a JSON schema.
+    It is basically a tree of internal::Schema.
+
+    \note This is an immutable class (i.e. its instance cannot be modified after construction).
+    \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
+    \tparam Allocator Allocator type for allocating memory of this document.
+*/
+template <typename ValueT, typename Allocator = CrtAllocator>
+class GenericSchemaDocument {
+public:
+    typedef ValueT ValueType;
+    typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
+    typedef Allocator AllocatorType;
+    typedef typename ValueType::EncodingType EncodingType;
+    typedef typename EncodingType::Ch Ch;
+    typedef internal::Schema<GenericSchemaDocument> SchemaType;
+    typedef GenericPointer<ValueType, Allocator> PointerType;
+    friend class internal::Schema<GenericSchemaDocument>;
+    template <typename, typename, typename>
+    friend class GenericSchemaValidator;
+
+    //! Constructor.
+    /*!
+        Compile a JSON document into schema document.
+
+        \param document A JSON document as source.
+        \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
+        \param allocator An optional allocator instance for allocating memory. Can be null.
+    */
+    explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
+        remoteProvider_(remoteProvider),
+        allocator_(allocator),
+        ownAllocator_(),
+        root_(),
+        schemaMap_(allocator, kInitialSchemaMapSize),
+        schemaRef_(allocator, kInitialSchemaRefSize)
+    {
+        if (!allocator_)
+            ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+        // Generate root schema, it will call CreateSchema() to create sub-schemas,
+        // And call AddRefSchema() if there are $ref.
+        CreateSchemaRecursive(&root_, PointerType(), document, document);
+
+        // Resolve $ref
+        while (!schemaRef_.Empty()) {
+            SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
+            if (const SchemaType* s = GetSchema(refEntry->target)) {
+                if (refEntry->schema)
+                    *refEntry->schema = s;
+
+                // Create entry in map if not exist
+                if (!GetSchema(refEntry->source)) {
+                    new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
+                }
+            }
+            refEntry->~SchemaRefEntry();
+        }
+
+        RAPIDJSON_ASSERT(root_ != 0);
+
+        schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
+    }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    //! Move constructor in C++11
+    GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
+        remoteProvider_(rhs.remoteProvider_),
+        allocator_(rhs.allocator_),
+        ownAllocator_(rhs.ownAllocator_),
+        root_(rhs.root_),
+        schemaMap_(std::move(rhs.schemaMap_)),
+        schemaRef_(std::move(rhs.schemaRef_))
+    {
+        rhs.remoteProvider_ = 0;
+        rhs.allocator_ = 0;
+        rhs.ownAllocator_ = 0;
+    }
+#endif
+
+    //! Destructor
+    ~GenericSchemaDocument() {
+        while (!schemaMap_.Empty())
+            schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
+
+        RAPIDJSON_DELETE(ownAllocator_);
+    }
+
+    //! Get the root schema.
+    const SchemaType& GetRoot() const { return *root_; }
+
+private:
+    //! Prohibit copying
+    GenericSchemaDocument(const GenericSchemaDocument&);
+    //! Prohibit assignment
+    GenericSchemaDocument& operator=(const GenericSchemaDocument&);
+
+    struct SchemaRefEntry {
+        SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
+        PointerType source;
+        PointerType target;
+        const SchemaType** schema;
+    };
+
+    struct SchemaEntry {
+        SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
+        ~SchemaEntry() {
+            if (owned) {
+                schema->~SchemaType();
+                Allocator::Free(schema);
+            }
+        }
+        PointerType pointer;
+        SchemaType* schema;
+        bool owned;
+    };
+
+    void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+        if (schema)
+            *schema = SchemaType::GetTypeless();
+
+        if (v.GetType() == kObjectType) {
+            const SchemaType* s = GetSchema(pointer);
+            if (!s)
+                CreateSchema(schema, pointer, v, document);
+
+            for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
+                CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
+        }
+        else if (v.GetType() == kArrayType)
+            for (SizeType i = 0; i < v.Size(); i++)
+                CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
+    }
+
+    void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
+        RAPIDJSON_ASSERT(pointer.IsValid());
+        if (v.IsObject()) {
+            if (!HandleRefSchema(pointer, schema, v, document)) {
+                SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
+                new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
+                if (schema)
+                    *schema = s;
+            }
+        }
+    }
+
+    bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
+        static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
+        static const ValueType kRefValue(kRefString, 4);
+
+        typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
+        if (itr == v.MemberEnd())
+            return false;
+
+        if (itr->value.IsString()) {
+            SizeType len = itr->value.GetStringLength();
+            if (len > 0) {
+                const Ch* s = itr->value.GetString();
+                SizeType i = 0;
+                while (i < len && s[i] != '#') // Find the first #
+                    i++;
+
+                if (i > 0) { // Remote reference, resolve immediately
+                    if (remoteProvider_) {
+                        if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
+                            PointerType pointer(&s[i], len - i, allocator_);
+                            if (pointer.IsValid()) {
+                                if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
+                                    if (schema)
+                                        *schema = sc;
+                                    return true;
+                                }
+                            }
+                        }
+                    }
+                }
+                else if (s[i] == '#') { // Local reference, defer resolution
+                    PointerType pointer(&s[i], len - i, allocator_);
+                    if (pointer.IsValid()) {
+                        if (const ValueType* nv = pointer.Get(document))
+                            if (HandleRefSchema(source, schema, *nv, document))
+                                return true;
+
+                        new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
+                        return true;
+                    }
+                }
+            }
+        }
+        return false;
+    }
+
+    const SchemaType* GetSchema(const PointerType& pointer) const {
+        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+            if (pointer == target->pointer)
+                return target->schema;
+        return 0;
+    }
+
+    PointerType GetPointer(const SchemaType* schema) const {
+        for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
+            if (schema == target->schema)
+                return target->pointer;
+        return PointerType();
+    }
+
+    static const size_t kInitialSchemaMapSize = 64;
+    static const size_t kInitialSchemaRefSize = 64;
+
+    IRemoteSchemaDocumentProviderType* remoteProvider_;
+    Allocator *allocator_;
+    Allocator *ownAllocator_;
+    const SchemaType* root_;                //!< Root schema.
+    internal::Stack<Allocator> schemaMap_;  // Stores created Pointer -> Schemas
+    internal::Stack<Allocator> schemaRef_;  // Stores Pointer from $ref and schema which holds the $ref
+};
+
+//! GenericSchemaDocument using Value type.
+typedef GenericSchemaDocument<Value> SchemaDocument;
+//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaValidator
+
+//! JSON Schema Validator.
+/*!
+    A SAX style JSON schema validator.
+    It uses a \c GenericSchemaDocument to validate SAX events.
+    It delegates the incoming SAX events to an output handler.
+    The default output handler does nothing.
+    It can be reused multiple times by calling \c Reset().
+
+    \tparam SchemaDocumentType Type of schema document.
+    \tparam OutputHandler Type of output handler. Default handler does nothing.
+    \tparam StateAllocator Allocator for storing the internal validation states.
+*/
+template <
+    typename SchemaDocumentType,
+    typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
+    typename StateAllocator = CrtAllocator>
+class GenericSchemaValidator :
+    public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>, 
+    public internal::ISchemaValidator
+{
+public:
+    typedef typename SchemaDocumentType::SchemaType SchemaType;
+    typedef typename SchemaDocumentType::PointerType PointerType;
+    typedef typename SchemaType::EncodingType EncodingType;
+    typedef typename EncodingType::Ch Ch;
+
+    //! Constructor without output handler.
+    /*!
+        \param schemaDocument The schema document to conform to.
+        \param allocator Optional allocator for storing internal validation states.
+        \param schemaStackCapacity Optional initial capacity of schema path stack.
+        \param documentStackCapacity Optional initial capacity of document path stack.
+    */
+    GenericSchemaValidator(
+        const SchemaDocumentType& schemaDocument,
+        StateAllocator* allocator = 0, 
+        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+        size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+        :
+        schemaDocument_(&schemaDocument),
+        root_(schemaDocument.GetRoot()),
+        outputHandler_(GetNullHandler()),
+        stateAllocator_(allocator),
+        ownStateAllocator_(0),
+        schemaStack_(allocator, schemaStackCapacity),
+        documentStack_(allocator, documentStackCapacity),
+        valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+        , depth_(0)
+#endif
+    {
+    }
+
+    //! Constructor with output handler.
+    /*!
+        \param schemaDocument The schema document to conform to.
+        \param allocator Optional allocator for storing internal validation states.
+        \param schemaStackCapacity Optional initial capacity of schema path stack.
+        \param documentStackCapacity Optional initial capacity of document path stack.
+    */
+    GenericSchemaValidator(
+        const SchemaDocumentType& schemaDocument,
+        OutputHandler& outputHandler,
+        StateAllocator* allocator = 0, 
+        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+        size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+        :
+        schemaDocument_(&schemaDocument),
+        root_(schemaDocument.GetRoot()),
+        outputHandler_(outputHandler),
+        stateAllocator_(allocator),
+        ownStateAllocator_(0),
+        schemaStack_(allocator, schemaStackCapacity),
+        documentStack_(allocator, documentStackCapacity),
+        valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+        , depth_(0)
+#endif
+    {
+    }
+
+    //! Destructor.
+    ~GenericSchemaValidator() {
+        Reset();
+        RAPIDJSON_DELETE(ownStateAllocator_);
+    }
+
+    //! Reset the internal states.
+    void Reset() {
+        while (!schemaStack_.Empty())
+            PopSchema();
+        documentStack_.Clear();
+        valid_ = true;
+    }
+
+    //! Checks whether the current state is valid.
+    // Implementation of ISchemaValidator
+    virtual bool IsValid() const { return valid_; }
+
+    //! Gets the JSON pointer pointed to the invalid schema.
+    PointerType GetInvalidSchemaPointer() const {
+        return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
+    }
+
+    //! Gets the keyword of invalid schema.
+    const Ch* GetInvalidSchemaKeyword() const {
+        return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+    }
+
+    //! Gets the JSON pointer pointed to the invalid value.
+    PointerType GetInvalidDocumentPointer() const {
+        return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
+    }
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
+RAPIDJSON_MULTILINEMACRO_BEGIN\
+    *documentStack_.template Push<Ch>() = '\0';\
+    documentStack_.template Pop<Ch>(1);\
+    internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
+RAPIDJSON_MULTILINEMACRO_END
+#else
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
+#endif
+
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
+    if (!valid_) return false; \
+    if (!BeginValue() || !CurrentSchema().method arg1) {\
+        RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
+        return valid_ = false;\
+    }
+
+#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
+    for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
+        if (context->hasher)\
+            static_cast<HasherType*>(context->hasher)->method arg2;\
+        if (context->validators)\
+            for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
+                static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
+        if (context->patternPropertiesValidators)\
+            for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
+                static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
+    }
+
+#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
+    return valid_ = EndValue() && outputHandler_.method arg2
+
+#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
+    RAPIDJSON_SCHEMA_HANDLE_BEGIN_   (method, arg1);\
+    RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
+    RAPIDJSON_SCHEMA_HANDLE_END_     (method, arg2)
+
+    bool Null()             { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null,   (CurrentContext()   ), ( )); }
+    bool Bool(bool b)       { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool,   (CurrentContext(), b), (b)); }
+    bool Int(int i)         { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int,    (CurrentContext(), i), (i)); }
+    bool Uint(unsigned u)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint,   (CurrentContext(), u), (u)); }
+    bool Int64(int64_t i)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64,  (CurrentContext(), i), (i)); }
+    bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
+    bool Double(double d)   { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
+    bool RawNumber(const Ch* str, SizeType length, bool copy)
+                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
+    bool String(const Ch* str, SizeType length, bool copy)
+                                    { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
+
+    bool StartObject() {
+        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
+        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
+        return valid_ = outputHandler_.StartObject();
+    }
+    
+    bool Key(const Ch* str, SizeType len, bool copy) {
+        if (!valid_) return false;
+        AppendToken(str, len);
+        if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
+        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
+        return valid_ = outputHandler_.Key(str, len, copy);
+    }
+    
+    bool EndObject(SizeType memberCount) { 
+        if (!valid_) return false;
+        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
+        if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
+        RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
+    }
+
+    bool StartArray() {
+        RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
+        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
+        return valid_ = outputHandler_.StartArray();
+    }
+    
+    bool EndArray(SizeType elementCount) {
+        if (!valid_) return false;
+        RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
+        if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
+        RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
+    }
+
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
+#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
+#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
+
+    // Implementation of ISchemaStateFactory<SchemaType>
+    virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
+        return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+        depth_ + 1,
+#endif
+        &GetStateAllocator());
+    }
+
+    virtual void DestroySchemaValidator(ISchemaValidator* validator) {
+        GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
+        v->~GenericSchemaValidator();
+        StateAllocator::Free(v);
+    }
+
+    virtual void* CreateHasher() {
+        return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
+    }
+
+    virtual uint64_t GetHashCode(void* hasher) {
+        return static_cast<HasherType*>(hasher)->GetHashCode();
+    }
+
+    virtual void DestroryHasher(void* hasher) {
+        HasherType* h = static_cast<HasherType*>(hasher);
+        h->~HasherType();
+        StateAllocator::Free(h);
+    }
+
+    virtual void* MallocState(size_t size) {
+        return GetStateAllocator().Malloc(size);
+    }
+
+    virtual void FreeState(void* p) {
+        return StateAllocator::Free(p);
+    }
+
+private:
+    typedef typename SchemaType::Context Context;
+    typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
+    typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
+
+    GenericSchemaValidator( 
+        const SchemaDocumentType& schemaDocument,
+        const SchemaType& root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+        unsigned depth,
+#endif
+        StateAllocator* allocator = 0,
+        size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+        size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+        :
+        schemaDocument_(&schemaDocument),
+        root_(root),
+        outputHandler_(GetNullHandler()),
+        stateAllocator_(allocator),
+        ownStateAllocator_(0),
+        schemaStack_(allocator, schemaStackCapacity),
+        documentStack_(allocator, documentStackCapacity),
+        valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+        , depth_(depth)
+#endif
+    {
+    }
+
+    StateAllocator& GetStateAllocator() {
+        if (!stateAllocator_)
+            stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
+        return *stateAllocator_;
+    }
+
+    bool BeginValue() {
+        if (schemaStack_.Empty())
+            PushSchema(root_);
+        else {
+            if (CurrentContext().inArray)
+                internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
+
+            if (!CurrentSchema().BeginValue(CurrentContext()))
+                return false;
+
+            SizeType count = CurrentContext().patternPropertiesSchemaCount;
+            const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
+            typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
+            bool valueUniqueness = CurrentContext().valueUniqueness;
+            if (CurrentContext().valueSchema)
+                PushSchema(*CurrentContext().valueSchema);
+
+            if (count > 0) {
+                CurrentContext().objectPatternValidatorType = patternValidatorType;
+                ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
+                SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
+                va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
+                for (SizeType i = 0; i < count; i++)
+                    va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+            }
+
+            CurrentContext().arrayUniqueness = valueUniqueness;
+        }
+        return true;
+    }
+
+    bool EndValue() {
+        if (!CurrentSchema().EndValue(CurrentContext()))
+            return false;
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+        GenericStringBuffer<EncodingType> sb;
+        schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
+
+        *documentStack_.template Push<Ch>() = '\0';
+        documentStack_.template Pop<Ch>(1);
+        internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
+#endif
+
+        uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
+        
+        PopSchema();
+
+        if (!schemaStack_.Empty()) {
+            Context& context = CurrentContext();
+            if (context.valueUniqueness) {
+                HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
+                if (!a)
+                    CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
+                for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
+                    if (itr->GetUint64() == h)
+                        RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
+                a->PushBack(h, GetStateAllocator());
+            }
+        }
+
+        // Remove the last token of document pointer
+        while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
+            ;
+
+        return true;
+    }
+
+    void AppendToken(const Ch* str, SizeType len) {
+        documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
+        *documentStack_.template PushUnsafe<Ch>() = '/';
+        for (SizeType i = 0; i < len; i++) {
+            if (str[i] == '~') {
+                *documentStack_.template PushUnsafe<Ch>() = '~';
+                *documentStack_.template PushUnsafe<Ch>() = '0';
+            }
+            else if (str[i] == '/') {
+                *documentStack_.template PushUnsafe<Ch>() = '~';
+                *documentStack_.template PushUnsafe<Ch>() = '1';
+            }
+            else
+                *documentStack_.template PushUnsafe<Ch>() = str[i];
+        }
+    }
+
+    RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
+    
+    RAPIDJSON_FORCEINLINE void PopSchema() {
+        Context* c = schemaStack_.template Pop<Context>(1);
+        if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
+            a->~HashCodeArray();
+            StateAllocator::Free(a);
+        }
+        c->~Context();
+    }
+
+    const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
+    Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
+    const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
+
+    static OutputHandler& GetNullHandler() {
+        static OutputHandler nullHandler;
+        return nullHandler;
+    }
+
+    static const size_t kDefaultSchemaStackCapacity = 1024;
+    static const size_t kDefaultDocumentStackCapacity = 256;
+    const SchemaDocumentType* schemaDocument_;
+    const SchemaType& root_;
+    OutputHandler& outputHandler_;
+    StateAllocator* stateAllocator_;
+    StateAllocator* ownStateAllocator_;
+    internal::Stack<StateAllocator> schemaStack_;    //!< stack to store the current path of schema (BaseSchemaType *)
+    internal::Stack<StateAllocator> documentStack_;  //!< stack to store the current path of validating document (Ch)
+    bool valid_;
+#if RAPIDJSON_SCHEMA_VERBOSE
+    unsigned depth_;
+#endif
+};
+
+typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidatingReader
+
+//! A helper class for parsing with validation.
+/*!
+    This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
+
+    \tparam parseFlags Combination of \ref ParseFlag.
+    \tparam InputStream Type of input stream, implementing Stream concept.
+    \tparam SourceEncoding Encoding of the input stream.
+    \tparam SchemaDocumentType Type of schema document.
+    \tparam StackAllocator Allocator type for stack.
+*/
+template <
+    unsigned parseFlags,
+    typename InputStream,
+    typename SourceEncoding,
+    typename SchemaDocumentType = SchemaDocument,
+    typename StackAllocator = CrtAllocator>
+class SchemaValidatingReader {
+public:
+    typedef typename SchemaDocumentType::PointerType PointerType;
+    typedef typename InputStream::Ch Ch;
+
+    //! Constructor
+    /*!
+        \param is Input stream.
+        \param sd Schema document.
+    */
+    SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
+
+    template <typename Handler>
+    bool operator()(Handler& handler) {
+        GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
+        GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
+        parseResult_ = reader.template Parse<parseFlags>(is_, validator);
+
+        isValid_ = validator.IsValid();
+        if (isValid_) {
+            invalidSchemaPointer_ = PointerType();
+            invalidSchemaKeyword_ = 0;
+            invalidDocumentPointer_ = PointerType();
+        }
+        else {
+            invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
+            invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+            invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+        }
+
+        return parseResult_;
+    }
+
+    const ParseResult& GetParseResult() const { return parseResult_; }
+    bool IsValid() const { return isValid_; }
+    const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
+    const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
+    const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
+
+private:
+    InputStream& is_;
+    const SchemaDocumentType& sd_;
+
+    ParseResult parseResult_;
+    PointerType invalidSchemaPointer_;
+    const Ch* invalidSchemaKeyword_;
+    PointerType invalidDocumentPointer_;
+    bool isValid_;
+};
+
+RAPIDJSON_NAMESPACE_END
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_SCHEMA_H_
diff --git a/core/deps/rapidjson/stream.h b/core/deps/rapidjson/stream.h
new file mode 100644 (file)
index 0000000..fef82c2
--- /dev/null
@@ -0,0 +1,179 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#include "rapidjson.h"
+
+#ifndef RAPIDJSON_STREAM_H_
+#define RAPIDJSON_STREAM_H_
+
+#include "encodings.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+//  Stream
+
+/*! \class rapidjson::Stream
+    \brief Concept for reading and writing characters.
+
+    For read-only stream, no need to implement PutBegin(), Put(), Flush() and PutEnd().
+
+    For write-only stream, only need to implement Put() and Flush().
+
+\code
+concept Stream {
+    typename Ch;    //!< Character type of the stream.
+
+    //! Read the current character from stream without moving the read cursor.
+    Ch Peek() const;
+
+    //! Read the current character from stream and moving the read cursor to next character.
+    Ch Take();
+
+    //! Get the current read cursor.
+    //! \return Number of characters read from start.
+    size_t Tell();
+
+    //! Begin writing operation at the current read pointer.
+    //! \return The begin writer pointer.
+    Ch* PutBegin();
+
+    //! Write a character.
+    void Put(Ch c);
+
+    //! Flush the buffer.
+    void Flush();
+
+    //! End the writing operation.
+    //! \param begin The begin write pointer returned by PutBegin().
+    //! \return Number of characters written.
+    size_t PutEnd(Ch* begin);
+}
+\endcode
+*/
+
+//! Provides additional information for stream.
+/*!
+    By using traits pattern, this type provides a default configuration for stream.
+    For custom stream, this type can be specialized for other configuration.
+    See TEST(Reader, CustomStringStream) in readertest.cpp for example.
+*/
+template<typename Stream>
+struct StreamTraits {
+    //! Whether to make local copy of stream for optimization during parsing.
+    /*!
+        By default, for safety, streams do not use local copy optimization.
+        Stream that can be copied fast should specialize this, like StreamTraits<StringStream>.
+    */
+    enum { copyOptimization = 0 };
+};
+
+//! Reserve n characters for writing to a stream.
+template<typename Stream>
+inline void PutReserve(Stream& stream, size_t count) {
+    (void)stream;
+    (void)count;
+}
+
+//! Write character to a stream, presuming buffer is reserved.
+template<typename Stream>
+inline void PutUnsafe(Stream& stream, typename Stream::Ch c) {
+    stream.Put(c);
+}
+
+//! Put N copies of a character to a stream.
+template<typename Stream, typename Ch>
+inline void PutN(Stream& stream, Ch c, size_t n) {
+    PutReserve(stream, n);
+    for (size_t i = 0; i < n; i++)
+        PutUnsafe(stream, c);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// StringStream
+
+//! Read-only string stream.
+/*! \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericStringStream {
+    typedef typename Encoding::Ch Ch;
+
+    GenericStringStream(const Ch *src) : src_(src), head_(src) {}
+
+    Ch Peek() const { return *src_; }
+    Ch Take() { return *src_++; }
+    size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+
+    Ch* PutBegin() { RAPIDJSON_ASSERT(false); return 0; }
+    void Put(Ch) { RAPIDJSON_ASSERT(false); }
+    void Flush() { RAPIDJSON_ASSERT(false); }
+    size_t PutEnd(Ch*) { RAPIDJSON_ASSERT(false); return 0; }
+
+    const Ch* src_;     //!< Current read position.
+    const Ch* head_;    //!< Original head of the string.
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericStringStream<Encoding> > {
+    enum { copyOptimization = 1 };
+};
+
+//! String stream with UTF8 encoding.
+typedef GenericStringStream<UTF8<> > StringStream;
+
+///////////////////////////////////////////////////////////////////////////////
+// InsituStringStream
+
+//! A read-write string stream.
+/*! This string stream is particularly designed for in-situ parsing.
+    \note implements Stream concept
+*/
+template <typename Encoding>
+struct GenericInsituStringStream {
+    typedef typename Encoding::Ch Ch;
+
+    GenericInsituStringStream(Ch *src) : src_(src), dst_(0), head_(src) {}
+
+    // Read
+    Ch Peek() { return *src_; }
+    Ch Take() { return *src_++; }
+    size_t Tell() { return static_cast<size_t>(src_ - head_); }
+
+    // Write
+    void Put(Ch c) { RAPIDJSON_ASSERT(dst_ != 0); *dst_++ = c; }
+
+    Ch* PutBegin() { return dst_ = src_; }
+    size_t PutEnd(Ch* begin) { return static_cast<size_t>(dst_ - begin); }
+    void Flush() {}
+
+    Ch* Push(size_t count) { Ch* begin = dst_; dst_ += count; return begin; }
+    void Pop(size_t count) { dst_ -= count; }
+
+    Ch* src_;
+    Ch* dst_;
+    Ch* head_;
+};
+
+template <typename Encoding>
+struct StreamTraits<GenericInsituStringStream<Encoding> > {
+    enum { copyOptimization = 1 };
+};
+
+//! Insitu string stream with UTF8 encoding.
+typedef GenericInsituStringStream<UTF8<> > InsituStringStream;
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_STREAM_H_
diff --git a/core/deps/rapidjson/stringbuffer.h b/core/deps/rapidjson/stringbuffer.h
new file mode 100644 (file)
index 0000000..78f34d2
--- /dev/null
@@ -0,0 +1,117 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "internal/stack.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++98-compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+    \tparam Encoding Encoding of the stream.
+    \tparam Allocator type for allocating memory buffer.
+    \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+public:
+    typedef typename Encoding::Ch Ch;
+
+    GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+    GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
+    GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+        if (&rhs != this)
+            stack_ = std::move(rhs.stack_);
+        return *this;
+    }
+#endif
+
+    void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+    void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
+    void Flush() {}
+
+    void Clear() { stack_.Clear(); }
+    void ShrinkToFit() {
+        // Push and pop a null terminator. This is safe.
+        *stack_.template Push<Ch>() = '\0';
+        stack_.ShrinkToFit();
+        stack_.template Pop<Ch>(1);
+    }
+
+    void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
+    Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+    Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
+    void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+    const Ch* GetString() const {
+        // Push and pop a null terminator. This is safe.
+        *stack_.template Push<Ch>() = '\0';
+        stack_.template Pop<Ch>(1);
+
+        return stack_.template Bottom<Ch>();
+    }
+
+    size_t GetSize() const { return stack_.GetSize(); }
+
+    static const size_t kDefaultCapacity = 256;
+    mutable internal::Stack<Allocator> stack_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    GenericStringBuffer(const GenericStringBuffer&);
+    GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+template<typename Encoding, typename Allocator>
+inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
+    stream.Reserve(count);
+}
+
+template<typename Encoding, typename Allocator>
+inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
+    stream.PutUnsafe(c);
+}
+
+//! Implement specialized version of PutN() with memset() for better performance.
+template<>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+    std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/core/deps/rapidjson/writer.h b/core/deps/rapidjson/writer.h
new file mode 100644 (file)
index 0000000..94f22dd
--- /dev/null
@@ -0,0 +1,610 @@
+// Tencent is pleased to support the open source community by making RapidJSON available.
+// 
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file except
+// in compliance with the License. You may obtain a copy of the License at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software distributed 
+// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 
+// CONDITIONS OF ANY KIND, either express or implied. See the License for the 
+// specific language governing permissions and limitations under the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include "stream.h"
+#include "internal/stack.h"
+#include "internal/strfunc.h"
+#include "internal/dtoa.h"
+#include "internal/itoa.h"
+#include "stringbuffer.h"
+#include <new>      // placement new
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable-code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// WriteFlag
+
+/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS 
+    \ingroup RAPIDJSON_CONFIG
+    \brief User-defined kWriteDefaultFlags definition.
+
+    User can define this as any \c WriteFlag combinations.
+*/
+#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
+#endif
+
+//! Combination of writeFlags
+enum WriteFlag {
+    kWriteNoFlags = 0,              //!< No flags are set.
+    kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
+    kWriteNanAndInfFlag = 2,        //!< Allow writing of Infinity, -Infinity and NaN.
+    kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS  //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
+};
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+    It generates JSON text by events to an output os.
+
+    User may programmatically calls the functions of a writer to generate JSON text.
+
+    On the other side, a writer can also be passed to objects that generates events, 
+
+    for example Reader::Parse() and Document::Accept().
+
+    \tparam OutputStream Type of output stream.
+    \tparam SourceEncoding Encoding of source string.
+    \tparam TargetEncoding Encoding of output stream.
+    \tparam StackAllocator Type of allocator for allocating memory of stack.
+    \note implements Handler concept
+*/
+template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
+class Writer {
+public:
+    typedef typename SourceEncoding::Ch Ch;
+
+    static const int kDefaultMaxDecimalPlaces = 324;
+
+    //! Constructor
+    /*! \param os Output stream.
+        \param stackAllocator User supplied allocator. If it is null, it will create a private one.
+        \param levelDepth Initial capacity of stack.
+    */
+    explicit
+    Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) : 
+        os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+    explicit
+    Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
+        os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
+
+    //! Reset the writer with a new stream.
+    /*!
+        This function reset the writer with a new stream and default settings,
+        in order to make a Writer object reusable for output multiple JSONs.
+
+        \param os New output stream.
+        \code
+        Writer<OutputStream> writer(os1);
+        writer.StartObject();
+        // ...
+        writer.EndObject();
+
+        writer.Reset(os2);
+        writer.StartObject();
+        // ...
+        writer.EndObject();
+        \endcode
+    */
+    void Reset(OutputStream& os) {
+        os_ = &os;
+        hasRoot_ = false;
+        level_stack_.Clear();
+    }
+
+    //! Checks whether the output is a complete JSON.
+    /*!
+        A complete JSON has a complete root object or array.
+    */
+    bool IsComplete() const {
+        return hasRoot_ && level_stack_.Empty();
+    }
+
+    int GetMaxDecimalPlaces() const {
+        return maxDecimalPlaces_;
+    }
+
+    //! Sets the maximum number of decimal places for double output.
+    /*!
+        This setting truncates the output with specified number of decimal places.
+
+        For example, 
+
+        \code
+        writer.SetMaxDecimalPlaces(3);
+        writer.StartArray();
+        writer.Double(0.12345);                 // "0.123"
+        writer.Double(0.0001);                  // "0.0"
+        writer.Double(1.234567890123456e30);    // "1.234567890123456e30" (do not truncate significand for positive exponent)
+        writer.Double(1.23e-4);                 // "0.0"                  (do truncate significand for negative exponent)
+        writer.EndArray();
+        \endcode
+
+        The default setting does not truncate any decimal places. You can restore to this setting by calling
+        \code
+        writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
+        \endcode
+    */
+    void SetMaxDecimalPlaces(int maxDecimalPlaces) {
+        maxDecimalPlaces_ = maxDecimalPlaces;
+    }
+
+    /*!@name Implementation of Handler
+        \see Handler
+    */
+    //@{
+
+    bool Null()                 { Prefix(kNullType);   return EndValue(WriteNull()); }
+    bool Bool(bool b)           { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
+    bool Int(int i)             { Prefix(kNumberType); return EndValue(WriteInt(i)); }
+    bool Uint(unsigned u)       { Prefix(kNumberType); return EndValue(WriteUint(u)); }
+    bool Int64(int64_t i64)     { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
+    bool Uint64(uint64_t u64)   { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
+
+    //! Writes the given \c double value to the stream
+    /*!
+        \param d The value to be written.
+        \return Whether it is succeed.
+    */
+    bool Double(double d)       { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
+
+    bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+        (void)copy;
+        Prefix(kNumberType);
+        return EndValue(WriteString(str, length));
+    }
+
+    bool String(const Ch* str, SizeType length, bool copy = false) {
+        (void)copy;
+        Prefix(kStringType);
+        return EndValue(WriteString(str, length));
+    }
+
+#if RAPIDJSON_HAS_STDSTRING
+    bool String(const std::basic_string<Ch>& str) {
+        return String(str.data(), SizeType(str.size()));
+    }
+#endif
+
+    bool StartObject() {
+        Prefix(kObjectType);
+        new (level_stack_.template Push<Level>()) Level(false);
+        return WriteStartObject();
+    }
+
+    bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
+
+    bool EndObject(SizeType memberCount = 0) {
+        (void)memberCount;
+        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+        RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+        level_stack_.template Pop<Level>(1);
+        return EndValue(WriteEndObject());
+    }
+
+    bool StartArray() {
+        Prefix(kArrayType);
+        new (level_stack_.template Push<Level>()) Level(true);
+        return WriteStartArray();
+    }
+
+    bool EndArray(SizeType elementCount = 0) {
+        (void)elementCount;
+        RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+        RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+        level_stack_.template Pop<Level>(1);
+        return EndValue(WriteEndArray());
+    }
+    //@}
+
+    /*! @name Convenience extensions */
+    //@{
+
+    //! Simpler but slower overload.
+    bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+    bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+    //@}
+
+    //! Write a raw JSON value.
+    /*!
+        For user to write a stringified JSON as a value.
+
+        \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
+        \param length Length of the json.
+        \param type Type of the root of json.
+    */
+    bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
+
+protected:
+    //! Information for each nested level
+    struct Level {
+        Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+        size_t valueCount;  //!< number of values in this level
+        bool inArray;       //!< true if in array, otherwise in object
+    };
+
+    static const size_t kDefaultLevelDepth = 32;
+
+    bool WriteNull()  {
+        PutReserve(*os_, 4);
+        PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
+    }
+
+    bool WriteBool(bool b)  {
+        if (b) {
+            PutReserve(*os_, 4);
+            PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
+        }
+        else {
+            PutReserve(*os_, 5);
+            PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
+        }
+        return true;
+    }
+
+    bool WriteInt(int i) {
+        char buffer[11];
+        const char* end = internal::i32toa(i, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+        return true;
+    }
+
+    bool WriteUint(unsigned u) {
+        char buffer[10];
+        const char* end = internal::u32toa(u, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+        return true;
+    }
+
+    bool WriteInt64(int64_t i64) {
+        char buffer[21];
+        const char* end = internal::i64toa(i64, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (const char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+        return true;
+    }
+
+    bool WriteUint64(uint64_t u64) {
+        char buffer[20];
+        char* end = internal::u64toa(u64, buffer);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+        return true;
+    }
+
+    bool WriteDouble(double d) {
+        if (internal::Double(d).IsNanOrInf()) {
+            if (!(writeFlags & kWriteNanAndInfFlag))
+                return false;
+            if (internal::Double(d).IsNan()) {
+                PutReserve(*os_, 3);
+                PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+                return true;
+            }
+            if (internal::Double(d).Sign()) {
+                PutReserve(*os_, 9);
+                PutUnsafe(*os_, '-');
+            }
+            else
+                PutReserve(*os_, 8);
+            PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+            PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+            return true;
+        }
+
+        char buffer[25];
+        char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+        PutReserve(*os_, static_cast<size_t>(end - buffer));
+        for (char* p = buffer; p != end; ++p)
+            PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+        return true;
+    }
+
+    bool WriteString(const Ch* str, SizeType length)  {
+        static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
+        static const char escape[256] = {
+#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
+            //0    1    2    3    4    5    6    7    8    9    A    B    C    D    E    F
+            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
+            'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
+              0,   0, '"',   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0, // 20
+            Z16, Z16,                                                                       // 30~4F
+              0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,   0,'\\',   0,   0,   0, // 50
+            Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16                                // 60~FF
+#undef Z16
+        };
+
+        if (TargetEncoding::supportUnicode)
+            PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
+        else
+            PutReserve(*os_, 2 + length * 12);  // "\uxxxx\uyyyy..."
+
+        PutUnsafe(*os_, '\"');
+        GenericStringStream<SourceEncoding> is(str);
+        while (ScanWriteUnescapedString(is, length)) {
+            const Ch c = is.Peek();
+            if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
+                // Unicode escaping
+                unsigned codepoint;
+                if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
+                    return false;
+                PutUnsafe(*os_, '\\');
+                PutUnsafe(*os_, 'u');
+                if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+                    PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(codepoint      ) & 15]);
+                }
+                else {
+                    RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+                    // Surrogate pair
+                    unsigned s = codepoint - 0x010000;
+                    unsigned lead = (s >> 10) + 0xD800;
+                    unsigned trail = (s & 0x3FF) + 0xDC00;
+                    PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(lead      ) & 15]);
+                    PutUnsafe(*os_, '\\');
+                    PutUnsafe(*os_, 'u');
+                    PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail >>  8) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail >>  4) & 15]);
+                    PutUnsafe(*os_, hexDigits[(trail      ) & 15]);                    
+                }
+            }
+            else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)]))  {
+                is.Take();
+                PutUnsafe(*os_, '\\');
+                PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
+                if (escape[static_cast<unsigned char>(c)] == 'u') {
+                    PutUnsafe(*os_, '0');
+                    PutUnsafe(*os_, '0');
+                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
+                    PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
+                }
+            }
+            else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ? 
+                Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
+                Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
+                return false;
+        }
+        PutUnsafe(*os_, '\"');
+        return true;
+    }
+
+    bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
+        return RAPIDJSON_LIKELY(is.Tell() < length);
+    }
+
+    bool WriteStartObject() { os_->Put('{'); return true; }
+    bool WriteEndObject()   { os_->Put('}'); return true; }
+    bool WriteStartArray()  { os_->Put('['); return true; }
+    bool WriteEndArray()    { os_->Put(']'); return true; }
+
+    bool WriteRawValue(const Ch* json, size_t length) {
+        PutReserve(*os_, length);
+        for (size_t i = 0; i < length; i++) {
+            RAPIDJSON_ASSERT(json[i] != '\0');
+            PutUnsafe(*os_, json[i]);
+        }
+        return true;
+    }
+
+    void Prefix(Type type) {
+        (void)type;
+        if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
+            Level* level = level_stack_.template Top<Level>();
+            if (level->valueCount > 0) {
+                if (level->inArray) 
+                    os_->Put(','); // add comma if it is not the first element in array
+                else  // in object
+                    os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+            }
+            if (!level->inArray && level->valueCount % 2 == 0)
+                RAPIDJSON_ASSERT(type == kStringType);  // if it's in object, then even number should be a name
+            level->valueCount++;
+        }
+        else {
+            RAPIDJSON_ASSERT(!hasRoot_);    // Should only has one and only one root.
+            hasRoot_ = true;
+        }
+    }
+
+    // Flush the value if it is the top level one.
+    bool EndValue(bool ret) {
+        if (RAPIDJSON_UNLIKELY(level_stack_.Empty()))   // end of json text
+            os_->Flush();
+        return ret;
+    }
+
+    OutputStream* os_;
+    internal::Stack<StackAllocator> level_stack_;
+    int maxDecimalPlaces_;
+    bool hasRoot_;
+
+private:
+    // Prohibit copy constructor & assignment operator.
+    Writer(const Writer&);
+    Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+    char *buffer = os_->Push(11);
+    const char* end = internal::i32toa(i, buffer);
+    os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+    char *buffer = os_->Push(10);
+    const char* end = internal::u32toa(u, buffer);
+    os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+    char *buffer = os_->Push(21);
+    const char* end = internal::i64toa(i64, buffer);
+    os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+    char *buffer = os_->Push(20);
+    const char* end = internal::u64toa(u, buffer);
+    os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+    return true;
+}
+
+template<>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+    if (internal::Double(d).IsNanOrInf()) {
+        // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
+        if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
+            return false;
+        if (internal::Double(d).IsNan()) {
+            PutReserve(*os_, 3);
+            PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
+            return true;
+        }
+        if (internal::Double(d).Sign()) {
+            PutReserve(*os_, 9);
+            PutUnsafe(*os_, '-');
+        }
+        else
+            PutReserve(*os_, 8);
+        PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
+        PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
+        return true;
+    }
+    
+    char *buffer = os_->Push(25);
+    char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+    os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+    return true;
+}
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+template<>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
+    if (length < 16)
+        return RAPIDJSON_LIKELY(is.Tell() < length);
+
+    if (!RAPIDJSON_LIKELY(is.Tell() < length))
+        return false;
+
+    const char* p = is.src_;
+    const char* end = is.head_ + length;
+    const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+    const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+    if (nextAligned > end)
+        return true;
+
+    while (p != nextAligned)
+        if (*p < 0x20 || *p == '\"' || *p == '\\') {
+            is.src_ = p;
+            return RAPIDJSON_LIKELY(is.Tell() < length);
+        }
+        else
+            os_->PutUnsafe(*p++);
+
+    // The rest of string using SIMD
+    static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
+    static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
+    static const char space[16]  = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
+    const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
+    const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
+    const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
+
+    for (; p != endAligned; p += 16) {
+        const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
+        const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+        const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+        const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+        const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+        unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+        if (RAPIDJSON_UNLIKELY(r != 0)) {   // some of characters is escaped
+            SizeType len;
+#ifdef _MSC_VER         // Find the index of first escaped
+            unsigned long offset;
+            _BitScanForward(&offset, r);
+            len = offset;
+#else
+            len = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+            char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+            for (size_t i = 0; i < len; i++)
+                q[i] = p[i];
+
+            p += len;
+            break;
+        }
+        _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
+    }
+
+    is.src_ = p;
+    return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/core/deps/sdf/sdf.h b/core/deps/sdf/sdf.h
new file mode 100644 (file)
index 0000000..e0368e2
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ Copyright (C) 2014 Mikko Mononen (memon@inside.org)
+ Copyright (C) 2009-2012 Stefan Gustavson (stefan.gustavson@gmail.com)
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+ */
+
+#ifndef SDF_H
+#define SDF_H
+
+// Sweep-and-update Euclidean distance transform of an antialised image for contour textures.
+// Based on edtaa3func.c by Stefan Gustavson.
+//
+// White (255) pixels are treated as object pixels, zero pixels are treated as background.
+// An attempt is made to treat antialiased edges correctly. The input image must have
+// pixels in the range [0,255], and the antialiased image should be a box-filter
+// sampling of the ideal, crisp edge. If the antialias region is more than 1 pixel wide,
+// the result from this transform will be inaccurate.
+// Pixels at image border are not calculated and are set to 0.
+//
+// The output distance field is encoded as bytes, where 0 = radius (outside) and 255 = -radius (inside).
+// Input and output can be the same buffer.
+//   out - Output of the distance transform, one byte per pixel.
+//   outstride - Bytes per row on output image.
+//   radius - The radius of the distance field narrow band in pixels.
+//   img - Input image, one byte per pixel.
+//   width - Width if the image.
+//   height - Height if the image.
+//   stride - Bytes per row on input image.
+int sdfBuildDistanceField(unsigned char* out, int outstride, float radius,
+                          const unsigned char* img, int width, int height, int stride);
+
+// Same as distXform, but does not allocate any memory.
+// The 'temp' array should be enough to fit width * height * sizeof(float) * 3 bytes.
+void sdfBuildDistanceFieldNoAlloc(unsigned char* out, int outstride, float radius,
+                                  const unsigned char* img, int width, int height, int stride,
+                                  unsigned char* temp);
+
+// This function converts the antialiased image where each pixel represents coverage (box-filter
+// sampling of the ideal, crisp edge) to a distance field with narrow band radius of sqrt(2).
+// This is the fastest way to turn antialised image to contour texture. This function is good
+// if you don't need the distance field for effects (i.e. fat outline or dropshadow).
+// Input and output buffers must be different.
+//   out - Output of the distance transform, one byte per pixel.
+//   outstride - Bytes per row on output image.
+//   img - Input image, one byte per pixel.
+//   width - Width if the image.
+//   height - Height if the image.
+//   stride - Bytes per row on input image.
+void sdfCoverageToDistanceField(unsigned char* out, int outstride,
+                                const unsigned char* img, int width, int height, int stride);
+
+#endif //SDF_H
+
+
+#ifdef SDF_IMPLEMENTATION
+
+#include <math.h>
+#include <stdlib.h>
+
+#define SDF_MAX_PASSES 10    // Maximum number of distance transform passes
+#define SDF_SLACK 0.001f     // Controls how much smaller the neighbour value must be to cosnider, too small slack increse iteration count.
+#define SDF_SQRT2 1.4142136f // sqrt(2)
+#define SDF_BIG 1e+37f       // Big value used to initialize the distance field.
+
+static float sdf__clamp01(float x) {
+    return x < 0.0f ? 0.0f : (x > 1.0f ? 1.0f : x);
+}
+
+void sdfCoverageToDistanceField(unsigned char* out, int outstride,
+                                const unsigned char* img, int width, int height, int stride) {
+    int x, y;
+
+    // Zero out borders
+    for (x = 0; x < width; x++)
+        out[x] = 0;
+    for (y = 1; y < height; y++) {
+        out[y * outstride] = 0;
+        out[width - 1 + y * outstride] = 0;
+    }
+    for (x = 0; x < width; x++)
+        out[x + (height - 1) * outstride] = 0;
+
+    for (y = 1; y < height - 1; y++) {
+        for (x = 1; x < width - 1; x++) {
+            int k = x + y * stride;
+            float d, gx, gy, glen, a, a1;
+
+            // Skip flat areas.
+            if (img[k] == 255) {
+                out[x + y * outstride] = 255;
+                continue;
+            }
+            if (img[k] == 0) {
+                // Special handling for cases where full opaque pixels are next to full transparent pixels.
+                // See: https://github.com/memononen/SDF/issues/2
+                int he = img[k - 1] == 255 || img[k + 1] == 255;
+                int ve = img[k - stride] == 255 || img[k + stride] == 255;
+                if (!he && !ve) {
+                    out[x + y * outstride] = 0;
+                    continue;
+                }
+            }
+
+            gx = -(float)img[k - stride - 1] - SDF_SQRT2 * (float)img[k - 1] - (float)img[k + stride - 1] + (float)img[k - stride + 1] + SDF_SQRT2 * (float)img[k + 1] + (float)img[k + stride + 1];
+            gy = -(float)img[k - stride - 1] - SDF_SQRT2 * (float)img[k - stride] - (float)img[k - stride + 1] + (float)img[k + stride - 1] + SDF_SQRT2 * (float)img[k + stride] + (float)img[k + stride + 1];
+            a = (float)img[k] / 255.0f;
+            gx = fabsf(gx);
+            gy = fabsf(gy);
+            if (gx < 0.0001f || gy < 0.000f) {
+                d = (0.5f - a) * SDF_SQRT2;
+            } else {
+                glen = gx * gx + gy * gy;
+                glen = 1.0f / sqrtf(glen);
+                gx *= glen;
+                gy *= glen;
+                if (gx < gy) {
+                    float temp = gx;
+                    gx = gy;
+                    gy = temp;
+                }
+                a1 = 0.5f * gy / gx;
+                if (a < a1) { // 0 <= a < a1
+                    d = 0.5f * (gx + gy) - sqrtf(2.0f * gx * gy * a);
+                } else if (a < (1.0 - a1)) { // a1 <= a <= 1-a1
+                    d = (0.5f - a) * gx;
+                } else { // 1-a1 < a <= 1
+                    d = -0.5f * (gx + gy) + sqrt(2.0f * gx * gy * (1.0f - a));
+                }
+            }
+            d *= 1.0f / SDF_SQRT2;
+            out[x + y * outstride] = (unsigned char)(sdf__clamp01(0.5f - d) * 255.0f);
+        }
+    }
+}
+
+static float sdf__edgedf(float gx, float gy, float a) {
+    float df, a1;
+    if ((gx == 0) || (gy == 0)) {
+        // Either A) gu or gv are zero, or B) both
+        // Linear approximation is A) correct or B) a fair guess
+        df = 0.5f - a;
+    } else {
+        // Everything is symmetric wrt sign and transposition,
+        // so move to first octant (gx>=0, gy>=0, gx>=gy) to
+        // avoid handling all possible edge directions.
+        gx = fabsf(gx);
+        gy = fabsf(gy);
+        if (gx < gy) {
+            float temp = gx;
+            gx = gy;
+            gy = temp;
+        }
+        a1 = 0.5f * gy / gx;
+        if (a < a1) { // 0 <= a < a1
+            df = 0.5f * (gx + gy) - sqrtf(2.0f * gx * gy * a);
+        } else if (a < (1.0 - a1)) { // a1 <= a <= 1-a1
+            df = (0.5f - a) * gx;
+        } else { // 1-a1 < a <= 1
+            df = -0.5f * (gx + gy) + sqrt(2.0f * gx * gy * (1.0f - a));
+        }
+    }
+    return df;
+}
+
+struct SDFpoint {
+    float x, y;
+};
+
+static float sdf__distsqr(struct SDFpoint* a, struct SDFpoint* b) {
+    float dx = b->x - a->x, dy = b->y - a->y;
+    return dx * dx + dy * dy;
+}
+
+void sdfBuildDistanceFieldNoAlloc(unsigned char* out, int outstride, float radius,
+                                  const unsigned char* img, int width, int height, int stride,
+                                  unsigned char* temp) {
+    int i, x, y, pass;
+    float scale;
+    float* tdist = (float*)&temp[0];
+    struct SDFpoint* tpt = (struct SDFpoint*)&temp[width * height * sizeof(float)];
+
+    // Initialize buffers
+    for (i = 0; i < width * height; i++) {
+        tpt[i].x = 0;
+        tpt[i].y = 0;
+        tdist[i] = SDF_BIG;
+    }
+
+    // Calculate position of the anti-aliased pixels and distance to the boundary of the shape.
+    for (y = 1; y < height - 1; y++) {
+        for (x = 1; x < width - 1; x++) {
+            int tk, k = x + y * stride;
+            struct SDFpoint c = {(float)x, (float)y};
+            float d, gx, gy, glen;
+
+            // Skip flat areas.
+            if (img[k] == 255) continue;
+            if (img[k] == 0) {
+                // Special handling for cases where full opaque pixels are next to full transparent pixels.
+                // See: https://github.com/memononen/SDF/issues/2
+                int he = img[k - 1] == 255 || img[k + 1] == 255;
+                int ve = img[k - stride] == 255 || img[k + stride] == 255;
+                if (!he && !ve) continue;
+            }
+
+            // Calculate gradient direction
+            gx = -(float)img[k - stride - 1] - SDF_SQRT2 * (float)img[k - 1] - (float)img[k + stride - 1] + (float)img[k - stride + 1] + SDF_SQRT2 * (float)img[k + 1] + (float)img[k + stride + 1];
+            gy = -(float)img[k - stride - 1] - SDF_SQRT2 * (float)img[k - stride] - (float)img[k - stride + 1] + (float)img[k + stride - 1] + SDF_SQRT2 * (float)img[k + stride] + (float)img[k + stride + 1];
+            if (fabsf(gx) < 0.001f && fabsf(gy) < 0.001f) continue;
+            glen = gx * gx + gy * gy;
+            if (glen > 0.0001f) {
+                glen = 1.0f / sqrtf(glen);
+                gx *= glen;
+                gy *= glen;
+            }
+
+            // Find nearest point on contour.
+            tk = x + y * width;
+            d = sdf__edgedf(gx, gy, (float)img[k] / 255.0f);
+            tpt[tk].x = x + gx * d;
+            tpt[tk].y = y + gy * d;
+            tdist[tk] = sdf__distsqr(&c, &tpt[tk]);
+        }
+    }
+
+    // Calculate distance transform using sweep-and-update.
+    for (pass = 0; pass < SDF_MAX_PASSES; pass++) {
+        int changed = 0;
+
+        // Bottom-left to top-right.
+        for (y = 1; y < height - 1; y++) {
+            for (x = 1; x < width - 1; x++) {
+                int k = x + y * width, kn, ch = 0;
+                struct SDFpoint c = {(float)x, (float)y}, pt;
+                float pd = tdist[k], d;
+                // (-1,-1)
+                kn = k - 1 - width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (0,-1)
+                kn = k - width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (1,-1)
+                kn = k + 1 - width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (-1,0)
+                kn = k - 1;
+                if (tdist[kn] < tdist[k]) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                if (ch) {
+                    tpt[k] = pt;
+                    tdist[k] = pd;
+                    changed++;
+                }
+            }
+        }
+
+        // Top-right to bottom-left.
+        for (y = height - 2; y > 0; y--) {
+            for (x = width - 2; x > 0; x--) {
+                int k = x + y * width, kn, ch = 0;
+                struct SDFpoint c = {(float)x, (float)y}, pt;
+                float pd = tdist[k], d;
+                // (1,0)
+                kn = k + 1;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (-1,1)
+                kn = k - 1 + width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (0,1)
+                kn = k + width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                // (1,1)
+                kn = k + 1 + width;
+                if (tdist[kn] < pd) {
+                    d = sdf__distsqr(&c, &tpt[kn]);
+                    if (d + SDF_SLACK < pd) {
+                        pt = tpt[kn];
+                        pd = d;
+                        ch = 1;
+                    }
+                }
+                if (ch) {
+                    tpt[k] = pt;
+                    tdist[k] = pd;
+                    changed++;
+                }
+            }
+        }
+
+        if (changed == 0) break;
+    }
+
+    // Map to good range.
+    scale = 1.0f / radius;
+    for (y = 0; y < height; y++) {
+        for (x = 0; x < width; x++) {
+            float d = sqrtf(tdist[x + y * width]) * scale;
+            if (img[x + y * stride] > 127) d = -d;
+            out[x + y * outstride] = (unsigned char)(sdf__clamp01(0.5f - d * 0.5f) * 255.0f);
+        }
+    }
+}
+
+int sdfBuildDistanceField(unsigned char* out, int outstride, float radius,
+                          const unsigned char* img, int width, int height, int stride) {
+    unsigned char* temp = (unsigned char*)malloc(width * height * sizeof(float) * 3);
+    if (temp == NULL) return 0;
+    sdfBuildDistanceFieldNoAlloc(out, outstride, radius, img, width, height, stride, temp);
+    free(temp);
+    return 1;
+}
+
+#endif //SDF_IMPLEMENTATION
diff --git a/core/deps/stb/stb_easy_font.h b/core/deps/stb/stb_easy_font.h
new file mode 100644 (file)
index 0000000..514f46d
--- /dev/null
@@ -0,0 +1,265 @@
+// stb_easy_font.h - v0.7 - bitmap font for 3D rendering - public domain
+// Sean Barrett, Feb 2015
+//
+//    Easy-to-deploy,
+//    reasonably compact,
+//    extremely inefficient performance-wise,
+//    crappy-looking,
+//    ASCII-only,
+//    bitmap font for use in 3D APIs.
+//
+// Intended for when you just want to get some text displaying
+// in a 3D app as quickly as possible.
+//
+// Doesn't use any textures, instead builds characters out of quads.
+//
+// DOCUMENTATION:
+//
+//   int stb_easy_font_width(char *text)
+//   int stb_easy_font_height(char *text)
+//
+//      Takes a string and returns the horizontal size and the
+//      vertical size (which can vary if 'text' has newlines).
+//
+//   int stb_easy_font_print(float x, float y,
+//                           char *text, unsigned char color[4],
+//                           void *vertex_buffer, int vbuf_size)
+//
+//      Takes a string (which can contain '\n') and fills out a
+//      vertex buffer with renderable data to draw the string.
+//      Output data assumes increasing x is rightwards, increasing y
+//      is downwards.
+//
+//      The vertex data is divided into quads, i.e. there are four
+//      vertices in the vertex buffer for each quad.
+//
+//      The vertices are stored in an interleaved format:
+//
+//         x:float
+//         y:float
+//         z:float
+//         color:uint8[4]
+//
+//      You can ignore z and color if you get them from elsewhere
+//      This format was chosen in the hopes it would make it
+//      easier for you to reuse existing vertex-buffer-drawing code.
+//
+//      If you pass in NULL for color, it becomes 255,255,255,255.
+//
+//      Returns the number of quads.
+//
+//      If the buffer isn't large enough, it will truncate.
+//      Expect it to use an average of ~270 bytes per character.
+//
+//      If your API doesn't draw quads, build a reusable index
+//      list that allows you to render quads as indexed triangles.
+//
+//   void stb_easy_font_spacing(float spacing)
+//
+//      Use positive values to expand the space between characters,
+//      and small negative values (no smaller than -1.5) to contract
+//      the space between characters.
+//
+//      E.g. spacing = 1 adds one "pixel" of spacing between the
+//      characters. spacing = -1 is reasonable but feels a bit too
+//      compact to me; -0.5 is a reasonable compromise as long as
+//      you're scaling the font up.
+//
+// LICENSE
+//
+//   This software is in the public domain. Where that dedication is not
+//   recognized, you are granted a perpetual, irrevocable license to copy,
+//   distribute, and modify this file as you see fit.
+//
+// VERSION HISTORY
+//
+//   (2016-01-22)  0.7   width() supports multiline text; add height()
+//   (2015-09-13)  0.6   #include <math.h>; updated license
+//   (2015-02-01)  0.5   First release
+
+#if 0
+// SAMPLE CODE:
+//
+//    Here's sample code for old OpenGL; it's a lot more complicated
+//    to make work on modern APIs, and that's your problem.
+//
+void print_string(float x, float y, char *text, float r, float g, float b)
+{
+  static char buffer[99999]; // ~500 chars
+  int num_quads;
+
+  num_quads = stb_easy_font_print(x, y, text, NULL, buffer, sizeof(buffer));
+
+  glColor3f(r,g,b);
+  glEnableClientState(GL_VERTEX_ARRAY);
+  glVertexPointer(2, GL_FLOAT, 16, buffer);
+  glDrawArrays(GL_QUADS, 0, num_quads*4);
+  glDisableClientState(GL_VERTEX_ARRAY);
+}
+#endif
+
+#ifndef INCLUDE_STB_EASY_FONT_H
+#define INCLUDE_STB_EASY_FONT_H
+
+#include <stdlib.h>
+#include <math.h>
+
+int stb_easy_font_print(float x, float y, const char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size);
+
+#ifdef STB_EASY_FONT_IMPLEMENTATION
+
+struct {
+    unsigned char advance;
+    unsigned char h_seg;
+    unsigned char v_seg;
+} stb_easy_font_charinfo[96] = {
+    {  5,  0,  0 },  {  3,  0,  0 },  {  5,  1,  1 },  {  7,  1,  4 },
+    {  7,  3,  7 },  {  7,  6, 12 },  {  7,  8, 19 },  {  4, 16, 21 },
+    {  4, 17, 22 },  {  4, 19, 23 },  { 23, 21, 24 },  { 23, 22, 31 },
+    { 20, 23, 34 },  { 22, 23, 36 },  { 19, 24, 36 },  { 21, 25, 36 },
+    {  6, 25, 39 },  {  6, 27, 43 },  {  6, 28, 45 },  {  6, 30, 49 },
+    {  6, 33, 53 },  {  6, 34, 57 },  {  6, 40, 58 },  {  6, 46, 59 },
+    {  6, 47, 62 },  {  6, 55, 64 },  { 19, 57, 68 },  { 20, 59, 68 },
+    { 21, 61, 69 },  { 22, 66, 69 },  { 21, 68, 69 },  {  7, 73, 69 },
+    {  9, 75, 74 },  {  6, 78, 81 },  {  6, 80, 85 },  {  6, 83, 90 },
+    {  6, 85, 91 },  {  6, 87, 95 },  {  6, 90, 96 },  {  7, 92, 97 },
+    {  6, 96,102 },  {  5, 97,106 },  {  6, 99,107 },  {  6,100,110 },
+    {  6,100,115 },  {  7,101,116 },  {  6,101,121 },  {  6,101,125 },
+    {  6,102,129 },  {  7,103,133 },  {  6,104,140 },  {  6,105,145 },
+    {  7,107,149 },  {  6,108,151 },  {  7,109,155 },  {  7,109,160 },
+    {  7,109,165 },  {  7,118,167 },  {  6,118,172 },  {  4,120,176 },
+    {  6,122,177 },  {  4,122,181 },  { 23,124,182 },  { 22,129,182 },
+    {  4,130,182 },  { 22,131,183 },  {  6,133,187 },  { 22,135,191 },
+    {  6,137,192 },  { 22,139,196 },  {  5,144,197 },  { 22,147,198 },
+    {  6,150,202 },  { 19,151,206 },  { 21,152,207 },  {  6,155,209 },
+    {  3,160,210 },  { 23,160,211 },  { 22,164,216 },  { 22,165,220 },
+    { 22,167,224 },  { 22,169,228 },  { 21,171,232 },  { 21,173,233 },
+    {  5,178,233 },  { 22,179,234 },  { 23,180,238 },  { 23,180,243 },
+    { 23,180,248 },  { 22,189,248 },  { 22,191,252 },  {  5,196,252 },
+    {  3,203,252 },  {  5,203,253 },  { 22,210,253 },  {  0,214,253 },
+};
+
+unsigned char stb_easy_font_hseg[214] = {
+   97,37,69,84,28,51,2,18,10,49,98,41,65,25,81,105,33,9,97,1,97,37,37,36,
+    81,10,98,107,3,100,3,99,58,51,4,99,58,8,73,81,10,50,98,8,73,81,4,10,50,
+    98,8,25,33,65,81,10,50,17,65,97,25,33,25,49,9,65,20,68,1,65,25,49,41,
+    11,105,13,101,76,10,50,10,50,98,11,99,10,98,11,50,99,11,50,11,99,8,57,
+    58,3,99,99,107,10,10,11,10,99,11,5,100,41,65,57,41,65,9,17,81,97,3,107,
+    9,97,1,97,33,25,9,25,41,100,41,26,82,42,98,27,83,42,98,26,51,82,8,41,
+    35,8,10,26,82,114,42,1,114,8,9,73,57,81,41,97,18,8,8,25,26,26,82,26,82,
+    26,82,41,25,33,82,26,49,73,35,90,17,81,41,65,57,41,65,25,81,90,114,20,
+    84,73,57,41,49,25,33,65,81,9,97,1,97,25,33,65,81,57,33,25,41,25,
+};
+
+unsigned char stb_easy_font_vseg[253] = {
+   4,2,8,10,15,8,15,33,8,15,8,73,82,73,57,41,82,10,82,18,66,10,21,29,1,65,
+    27,8,27,9,65,8,10,50,97,74,66,42,10,21,57,41,29,25,14,81,73,57,26,8,8,
+    26,66,3,8,8,15,19,21,90,58,26,18,66,18,105,89,28,74,17,8,73,57,26,21,
+    8,42,41,42,8,28,22,8,8,30,7,8,8,26,66,21,7,8,8,29,7,7,21,8,8,8,59,7,8,
+    8,15,29,8,8,14,7,57,43,10,82,7,7,25,42,25,15,7,25,41,15,21,105,105,29,
+    7,57,57,26,21,105,73,97,89,28,97,7,57,58,26,82,18,57,57,74,8,30,6,8,8,
+    14,3,58,90,58,11,7,74,43,74,15,2,82,2,42,75,42,10,67,57,41,10,7,2,42,
+    74,106,15,2,35,8,8,29,7,8,8,59,35,51,8,8,15,35,30,35,8,8,30,7,8,8,60,
+    36,8,45,7,7,36,8,43,8,44,21,8,8,44,35,8,8,43,23,8,8,43,35,8,8,31,21,15,
+    20,8,8,28,18,58,89,58,26,21,89,73,89,29,20,8,8,30,7,
+};
+
+typedef struct
+{
+   unsigned char c[4];
+} stb_easy_font_color;
+
+int stb_easy_font_draw_segs(float x, float y, unsigned char *segs, int num_segs, int vertical, stb_easy_font_color c, char *vbuf, int vbuf_size, int offset)
+{
+    int i,j;
+    for (i=0; i < num_segs; ++i) {
+        int len = segs[i] & 7;
+        x += (float) ((segs[i] >> 3) & 1);
+        if (len && offset+64 <= vbuf_size) {
+            float y0 = y + (float) (segs[i]>>4);
+            for (j=0; j < 4; ++j) {
+                * (float *) (vbuf+offset+0) = x  + (j==1 || j==2 ? (vertical ? 1 : len) : 0);
+                * (float *) (vbuf+offset+4) = y0 + (    j >= 2   ? (vertical ? len : 1) : 0);
+                * (float *) (vbuf+offset+8) = 0.f;
+                * (stb_easy_font_color *) (vbuf+offset+12) = c;
+                offset += 16;
+            }
+        }
+    }
+    return offset;
+}
+
+float stb_easy_font_spacing_val = 0;
+void stb_easy_font_spacing(float spacing)
+{
+   stb_easy_font_spacing_val = spacing;
+}
+
+int stb_easy_font_print(float x, float y, const char *text, unsigned char color[4], void *vertex_buffer, int vbuf_size)
+{
+    char *vbuf = (char *) vertex_buffer;
+    float start_x = x;
+    int offset = 0;
+
+    stb_easy_font_color c {{ 255,255,255,255 }}; // use structure copying to avoid needing depending on memcpy()
+    if (color) { c.c[0] = color[0]; c.c[1] = color[1]; c.c[2] = color[2]; c.c[3] = color[3]; }
+
+    while (*text && offset < vbuf_size) {
+        if (*text == '\n') {
+            y += 12;
+            x = start_x;
+        } else {
+            unsigned char advance = stb_easy_font_charinfo[*text-32].advance;
+            float y_ch = advance & 16 ? y+1 : y;
+            int h_seg, v_seg, num_h, num_v;
+            h_seg = stb_easy_font_charinfo[*text-32  ].h_seg;
+            v_seg = stb_easy_font_charinfo[*text-32  ].v_seg;
+            num_h = stb_easy_font_charinfo[*text-32+1].h_seg - h_seg;
+            num_v = stb_easy_font_charinfo[*text-32+1].v_seg - v_seg;
+            offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_hseg[h_seg], num_h, 0, c, vbuf, vbuf_size, offset);
+            offset = stb_easy_font_draw_segs(x, y_ch, &stb_easy_font_vseg[v_seg], num_v, 1, c, vbuf, vbuf_size, offset);
+            x += advance & 15;
+            x += stb_easy_font_spacing_val;
+        }
+        ++text;
+    }
+    return (unsigned) offset/64;
+}
+
+int stb_easy_font_width(char *text)
+{
+    float len = 0;
+    float max_len = 0;
+    while (*text) {
+        if (*text == '\n') {
+            if (len > max_len) max_len = len;
+            len = 0;
+        } else {
+            len += stb_easy_font_charinfo[*text-32].advance & 15;
+            len += stb_easy_font_spacing_val;
+        }
+        ++text;
+    }
+    if (len > max_len) max_len = len;
+    return (int) ceil(max_len);
+}
+
+int stb_easy_font_height(char *text)
+{
+    float y = 0;
+    int nonempty_line=0;
+    while (*text) {
+        if (*text == '\n') {
+            y += 12;
+            nonempty_line = 0;
+        } else {
+            nonempty_line = 1;
+        }
+        ++text;
+    }
+    return (int) ceil(y + (nonempty_line ? 12 : 0));
+}
+
+#endif
+
+#endif
diff --git a/core/deps/stb/stb_image.h b/core/deps/stb/stb_image.h
new file mode 100644 (file)
index 0000000..096bc6b
--- /dev/null
@@ -0,0 +1,6755 @@
+/* stb_image - v2.12 - public domain image loader - http://nothings.org/stb_image.h
+                                     no warranty implied; use at your own risk
+
+   Do this:
+      #define STB_IMAGE_IMPLEMENTATION
+   before you include this file in *one* C or C++ file to create the implementation.
+
+   // i.e. it should look like this:
+   #include ...
+   #include ...
+   #include ...
+   #define STB_IMAGE_IMPLEMENTATION
+   #include "stb_image.h"
+
+   You can #define STBI_ASSERT(x) before the #include to avoid using assert.h.
+   And #define STBI_MALLOC, STBI_REALLOC, and STBI_FREE to avoid using malloc,realloc,free
+
+
+   QUICK NOTES:
+      Primarily of interest to game developers and other people who can
+          avoid problematic images and only need the trivial interface
+
+      JPEG baseline & progressive (12 bpc/arithmetic not supported, same as stock IJG lib)
+      PNG 1/2/4/8-bit-per-channel (16 bpc not supported)
+
+      TGA (not sure what subset, if a subset)
+      BMP non-1bpp, non-RLE
+      PSD (composited view only, no extra channels, 8/16 bit-per-channel)
+
+      GIF (*comp always reports as 4-channel)
+      HDR (radiance rgbE format)
+      PIC (Softimage PIC)
+      PNM (PPM and PGM binary only)
+
+      Animated GIF still needs a proper API, but here's one way to do it:
+          http://gist.github.com/urraka/685d9a6340b26b830d49
+
+      - decode from memory or through FILE (define STBI_NO_STDIO to remove code)
+      - decode from arbitrary I/O callbacks
+      - SIMD acceleration on x86/x64 (SSE2) and ARM (NEON)
+
+   Full documentation under "DOCUMENTATION" below.
+
+
+   Revision 2.00 release notes:
+
+      - Progressive JPEG is now supported.
+
+      - PPM and PGM binary formats are now supported, thanks to Ken Miller.
+
+      - x86 platforms now make use of SSE2 SIMD instructions for
+        JPEG decoding, and ARM platforms can use NEON SIMD if requested.
+        This work was done by Fabian "ryg" Giesen. SSE2 is used by
+        default, but NEON must be enabled explicitly; see docs.
+
+        With other JPEG optimizations included in this version, we see
+        2x speedup on a JPEG on an x86 machine, and a 1.5x speedup
+        on a JPEG on an ARM machine, relative to previous versions of this
+        library. The same results will not obtain for all JPGs and for all
+        x86/ARM machines. (Note that progressive JPEGs are significantly
+        slower to decode than regular JPEGs.) This doesn't mean that this
+        is the fastest JPEG decoder in the land; rather, it brings it
+        closer to parity with standard libraries. If you want the fastest
+        decode, look elsewhere. (See "Philosophy" section of docs below.)
+
+        See final bullet items below for more info on SIMD.
+
+      - Added STBI_MALLOC, STBI_REALLOC, and STBI_FREE macros for replacing
+        the memory allocator. Unlike other STBI libraries, these macros don't
+        support a context parameter, so if you need to pass a context in to
+        the allocator, you'll have to store it in a global or a thread-local
+        variable.
+
+      - Split existing STBI_NO_HDR flag into two flags, STBI_NO_HDR and
+        STBI_NO_LINEAR.
+            STBI_NO_HDR:     suppress implementation of .hdr reader format
+            STBI_NO_LINEAR:  suppress high-dynamic-range light-linear float API
+
+      - You can suppress implementation of any of the decoders to reduce
+        your code footprint by #defining one or more of the following
+        symbols before creating the implementation.
+
+            STBI_NO_JPEG
+            STBI_NO_PNG
+            STBI_NO_BMP
+            STBI_NO_PSD
+            STBI_NO_TGA
+            STBI_NO_GIF
+            STBI_NO_HDR
+            STBI_NO_PIC
+            STBI_NO_PNM   (.ppm and .pgm)
+
+      - You can request *only* certain decoders and suppress all other ones
+        (this will be more forward-compatible, as addition of new decoders
+        doesn't require you to disable them explicitly):
+
+            STBI_ONLY_JPEG
+            STBI_ONLY_PNG
+            STBI_ONLY_BMP
+            STBI_ONLY_PSD
+            STBI_ONLY_TGA
+            STBI_ONLY_GIF
+            STBI_ONLY_HDR
+            STBI_ONLY_PIC
+            STBI_ONLY_PNM   (.ppm and .pgm)
+
+         Note that you can define multiples of these, and you will get all
+         of them ("only x" and "only y" is interpreted to mean "only x&y").
+
+       - If you use STBI_NO_PNG (or _ONLY_ without PNG), and you still
+         want the zlib decoder to be available, #define STBI_SUPPORT_ZLIB
+
+      - Compilation of all SIMD code can be suppressed with
+            #define STBI_NO_SIMD
+        It should not be necessary to disable SIMD unless you have issues
+        compiling (e.g. using an x86 compiler which doesn't support SSE
+        intrinsics or that doesn't support the method used to detect
+        SSE2 support at run-time), and even those can be reported as
+        bugs so I can refine the built-in compile-time checking to be
+        smarter.
+
+      - The old STBI_SIMD system which allowed installing a user-defined
+        IDCT etc. has been removed. If you need this, don't upgrade. My
+        assumption is that almost nobody was doing this, and those who
+        were will find the built-in SIMD more satisfactory anyway.
+
+      - RGB values computed for JPEG images are slightly different from
+        previous versions of stb_image. (This is due to using less
+        integer precision in SIMD.) The C code has been adjusted so
+        that the same RGB values will be computed regardless of whether
+        SIMD support is available, so your app should always produce
+        consistent results. But these results are slightly different from
+        previous versions. (Specifically, about 3% of available YCbCr values
+        will compute different RGB results from pre-1.49 versions by +-1;
+        most of the deviating values are one smaller in the G channel.)
+
+      - If you must produce consistent results with previous versions of
+        stb_image, #define STBI_JPEG_OLD and you will get the same results
+        you used to; however, you will not get the SIMD speedups for
+        the YCbCr-to-RGB conversion step (although you should still see
+        significant JPEG speedup from the other changes).
+
+        Please note that STBI_JPEG_OLD is a temporary feature; it will be
+        removed in future versions of the library. It is only intended for
+        near-term back-compatibility use.
+
+
+   Latest revision history:
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) 16-bit PNGS; enable SSE2 in non-gcc x64
+                         RGB-format JPEG; remove white matting in PSD;
+                         allocate large structures on the stack;
+                         correct channel count for PNG & BMP
+      2.10  (2016-01-22) avoid warning introduced in 2.09
+      2.09  (2016-01-16) 16-bit TGA; comments in PNM files; STBI_REALLOC_SIZED
+      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+      2.07  (2015-09-13) partial animated GIF support
+                         limited 16-bit PSD support
+                         minor bugs, code cleanup, and compiler warnings
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+      2.03  (2015-04-12) additional corruption checking
+                         stbi_set_flip_vertically_on_load
+                         fix NEON support; fix mingw support
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPEG, including x86 SSE2 & ARM NEON SIMD
+                         progressive JPEG
+                         PGM/PPM support
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         STBI_NO_*, STBI_ONLY_*
+                         GIF bugfix
+
+   See end of file for full revision history.
+
+
+ ============================    Contributors    =========================
+
+ Image formats                          Extensions, features
+    Sean Barrett (jpeg, png, bmp)          Jetro Lauha (stbi_info)
+    Nicolas Schulz (hdr, psd)              Martin "SpartanJ" Golini (stbi_info)
+    Jonathan Dummer (tga)                  James "moose2000" Brown (iPhone PNG)
+    Jean-Marc Lienher (gif)                Ben "Disch" Wenger (io callbacks)
+    Tom Seddon (pic)                       Omar Cornut (1/2/4-bit PNG)
+    Thatcher Ulrich (psd)                  Nicolas Guillemot (vertical flip)
+    Ken Miller (pgm, ppm)                  Richard Mitton (16-bit PSD)
+    urraka@github (animated gif)           Junggon Kim (PNM comments)
+                                           Daniel Gibson (16-bit TGA)
+
+ Optimizations & bugfixes
+    Fabian "ryg" Giesen
+    Arseny Kapoulkine
+
+ Bug & warning fixes
+    Marc LeBlanc            David Woo          Guillaume George   Martins Mozeiko
+    Christpher Lloyd        Martin Golini      Jerry Jansson      Joseph Thomson
+    Dave Moore              Roy Eltham         Hayaki Saito       Phil Jordan
+    Won Chun                Luke Graham        Johan Duparc       Nathan Reed
+    the Horde3D community   Thomas Ruf         Ronny Chevalier    Nick Verigakis
+    Janez Zemva             John Bartholomew   Michal Cichon      svdijk@github
+    Jonathan Blow           Ken Hamada         Tero Hanninen      Baldur Karlsson
+    Laurent Gomila          Cort Stratton      Sergio Gonzalez    romigrou@github
+    Aruelien Pocheville     Thibault Reuille   Cass Everitt       Matthew Gregan
+    Ryamond Barbiero        Paul Du Bois       Engin Manap        snagar@github
+    Michaelangel007@github  Oriol Ferrer Mesia socks-the-fox
+    Blazej Dariusz Roszkowski
+
+
+LICENSE
+
+This software is dual-licensed to the public domain and under the following
+license: you are granted a perpetual, irrevocable license to copy, modify,
+publish, and distribute this file as you see fit.
+
+*/
+
+#ifndef STBI_INCLUDE_STB_IMAGE_H
+#define STBI_INCLUDE_STB_IMAGE_H
+
+// DOCUMENTATION
+//
+// Limitations:
+//    - no 16-bit-per-channel PNG
+//    - no 12-bit-per-channel JPEG
+//    - no JPEGs with arithmetic coding
+//    - no 1-bit BMP
+//    - GIF always returns *comp=4
+//
+// Basic usage (see HDR discussion below for HDR usage):
+//    int x,y,n;
+//    unsigned char *data = stbi_load(filename, &x, &y, &n, 0);
+//    // ... process data if not NULL ...
+//    // ... x = width, y = height, n = # 8-bit components per pixel ...
+//    // ... replace '0' with '1'..'4' to force that many components per pixel
+//    // ... but 'n' will always be the number that it would have been if you said 0
+//    stbi_image_free(data)
+//
+// Standard parameters:
+//    int *x       -- outputs image width in pixels
+//    int *y       -- outputs image height in pixels
+//    int *comp    -- outputs # of image components in image file
+//    int req_comp -- if non-zero, # of image components requested in result
+//
+// The return value from an image loader is an 'unsigned char *' which points
+// to the pixel data, or NULL on an allocation failure or if the image is
+// corrupt or invalid. The pixel data consists of *y scanlines of *x pixels,
+// with each pixel consisting of N interleaved 8-bit components; the first
+// pixel pointed to is top-left-most in the image. There is no padding between
+// image scanlines or between pixels, regardless of format. The number of
+// components N is 'req_comp' if req_comp is non-zero, or *comp otherwise.
+// If req_comp is non-zero, *comp has the number of components that _would_
+// have been output otherwise. E.g. if you set req_comp to 4, you will always
+// get RGBA output, but you can check *comp to see if it's trivially opaque
+// because e.g. there were only 3 channels in the source image.
+//
+// An output image with N components has the following components interleaved
+// in this order in each pixel:
+//
+//     N=#comp     components
+//       1           grey
+//       2           grey, alpha
+//       3           red, green, blue
+//       4           red, green, blue, alpha
+//
+// If image loading fails for any reason, the return value will be NULL,
+// and *x, *y, *comp will be unchanged. The function stbi_failure_reason()
+// can be queried for an extremely brief, end-user unfriendly explanation
+// of why the load failed. Define STBI_NO_FAILURE_STRINGS to avoid
+// compiling these strings at all, and STBI_FAILURE_USERMSG to get slightly
+// more user-friendly ones.
+//
+// Paletted PNG, BMP, GIF, and PIC images are automatically depalettized.
+//
+// ===========================================================================
+//
+// Philosophy
+//
+// stb libraries are designed with the following priorities:
+//
+//    1. easy to use
+//    2. easy to maintain
+//    3. good performance
+//
+// Sometimes I let "good performance" creep up in priority over "easy to maintain",
+// and for best performance I may provide less-easy-to-use APIs that give higher
+// performance, in addition to the easy to use ones. Nevertheless, it's important
+// to keep in mind that from the standpoint of you, a client of this library,
+// all you care about is #1 and #3, and stb libraries do not emphasize #3 above all.
+//
+// Some secondary priorities arise directly from the first two, some of which
+// make more explicit reasons why performance can't be emphasized.
+//
+//    - Portable ("ease of use")
+//    - Small footprint ("easy to maintain")
+//    - No dependencies ("ease of use")
+//
+// ===========================================================================
+//
+// I/O callbacks
+//
+// I/O callbacks allow you to read from arbitrary sources, like packaged
+// files or some other source. Data read from callbacks are processed
+// through a small internal buffer (currently 128 bytes) to try to reduce
+// overhead.
+//
+// The three functions you must define are "read" (reads some bytes of data),
+// "skip" (skips some bytes of data), "eof" (reports if the stream is at the end).
+//
+// ===========================================================================
+//
+// SIMD support
+//
+// The JPEG decoder will try to automatically use SIMD kernels on x86 when
+// supported by the compiler. For ARM Neon support, you must explicitly
+// request it.
+//
+// (The old do-it-yourself SIMD API is no longer supported in the current
+// code.)
+//
+// On x86, SSE2 will automatically be used when available based on a run-time
+// test; if not, the generic C versions are used as a fall-back. On ARM targets,
+// the typical path is to have separate builds for NEON and non-NEON devices
+// (at least this is true for iOS and Android). Therefore, the NEON support is
+// toggled by a build flag: define STBI_NEON to get NEON loops.
+//
+// The output of the JPEG decoder is slightly different from versions where
+// SIMD support was introduced (that is, for versions before 1.49). The
+// difference is only +-1 in the 8-bit RGB channels, and only on a small
+// fraction of pixels. You can force the pre-1.49 behavior by defining
+// STBI_JPEG_OLD, but this will disable some of the SIMD decoding path
+// and hence cost some performance.
+//
+// If for some reason you do not want to use any of SIMD code, or if
+// you have issues compiling it, you can disable it entirely by
+// defining STBI_NO_SIMD.
+//
+// ===========================================================================
+//
+// HDR image support   (disable by defining STBI_NO_HDR)
+//
+// stb_image now supports loading HDR images in general, and currently
+// the Radiance .HDR file format, although the support is provided
+// generically. You can still load any file through the existing interface;
+// if you attempt to load an HDR file, it will be automatically remapped to
+// LDR, assuming gamma 2.2 and an arbitrary scale factor defaulting to 1;
+// both of these constants can be reconfigured through this interface:
+//
+//     stbi_hdr_to_ldr_gamma(2.2f);
+//     stbi_hdr_to_ldr_scale(1.0f);
+//
+// (note, do not use _inverse_ constants; stbi_image will invert them
+// appropriately).
+//
+// Additionally, there is a new, parallel interface for loading files as
+// (linear) floats to preserve the full dynamic range:
+//
+//    float *data = stbi_loadf(filename, &x, &y, &n, 0);
+//
+// If you load LDR images through this interface, those images will
+// be promoted to floating point values, run through the inverse of
+// constants corresponding to the above:
+//
+//     stbi_ldr_to_hdr_scale(1.0f);
+//     stbi_ldr_to_hdr_gamma(2.2f);
+//
+// Finally, given a filename (or an open file or memory block--see header
+// file for details) containing image data, you can query for the "most
+// appropriate" interface to use (that is, whether the image is HDR or
+// not), using:
+//
+//     stbi_is_hdr(char *filename);
+//
+// ===========================================================================
+//
+// iPhone PNG support:
+//
+// By default we convert iphone-formatted PNGs back to RGB, even though
+// they are internally encoded differently. You can disable this conversion
+// by by calling stbi_convert_iphone_png_to_rgb(0), in which case
+// you will always just get the native iphone "format" through (which
+// is BGR stored in RGB).
+//
+// Call stbi_set_unpremultiply_on_load(1) as well to force a divide per
+// pixel to remove any premultiplied alpha *only* if the image file explicitly
+// says there's premultiplied data (currently only happens in iPhone images,
+// and only if iPhone convert-to-rgb processing is on).
+//
+
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif // STBI_NO_STDIO
+
+#define STBI_VERSION 1
+
+enum
+{
+   STBI_default = 0, // only used for req_comp
+
+   STBI_grey       = 1,
+   STBI_grey_alpha = 2,
+   STBI_rgb        = 3,
+   STBI_rgb_alpha  = 4
+};
+
+typedef unsigned char stbi_uc;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifdef STB_IMAGE_STATIC
+#define STBIDEF static
+#else
+#define STBIDEF extern
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// PRIMARY API - works on images of any type
+//
+
+//
+// load image by filename, open file, or memory buffer
+//
+
+typedef struct
+{
+   int      (*read)  (void *user,char *data,int size);   // fill 'data' with 'size' bytes.  return number of bytes actually read
+   void     (*skip)  (void *user,int n);                 // skip the next 'n' bytes, or 'unget' the last -n bytes if negative
+   int      (*eof)   (void *user);                       // returns nonzero if we are at end of file/data
+} stbi_io_callbacks;
+
+STBIDEF stbi_uc *stbi_load               (char              const *filename,           int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_memory   (stbi_uc           const *buffer, int len   , int *x, int *y, int *comp, int req_comp);
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk  , void *user, int *x, int *y, int *comp, int req_comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF stbi_uc *stbi_load_from_file  (FILE *f,                  int *x, int *y, int *comp, int req_comp);
+// for stbi_load_from_file, file pointer is left pointing immediately after image
+#endif
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF float *stbi_loadf                 (char const *filename,           int *x, int *y, int *comp, int req_comp);
+   STBIDEF float *stbi_loadf_from_memory     (stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp);
+   STBIDEF float *stbi_loadf_from_callbacks  (stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp);
+
+   #ifndef STBI_NO_STDIO
+   STBIDEF float *stbi_loadf_from_file  (FILE *f,                int *x, int *y, int *comp, int req_comp);
+   #endif
+#endif
+
+#ifndef STBI_NO_HDR
+   STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma);
+   STBIDEF void   stbi_hdr_to_ldr_scale(float scale);
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_LINEAR
+   STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma);
+   STBIDEF void   stbi_ldr_to_hdr_scale(float scale);
+#endif // STBI_NO_LINEAR
+
+// stbi_is_hdr is always defined, but always returns false if STBI_NO_HDR
+STBIDEF int    stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user);
+STBIDEF int    stbi_is_hdr_from_memory(stbi_uc const *buffer, int len);
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename);
+STBIDEF int      stbi_is_hdr_from_file(FILE *f);
+#endif // STBI_NO_STDIO
+
+
+// get a VERY brief reason for failure
+// NOT THREADSAFE
+STBIDEF const char *stbi_failure_reason  (void);
+
+// free the loaded image -- this is just free()
+STBIDEF void     stbi_image_free      (void *retval_from_stbi_load);
+
+// get image dimensions & components without fully decoding
+STBIDEF int      stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp);
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_info            (char const *filename,     int *x, int *y, int *comp);
+STBIDEF int      stbi_info_from_file  (FILE *f,                  int *x, int *y, int *comp);
+
+#endif
+
+
+
+// for image formats that explicitly notate that they have premultiplied alpha,
+// we just return the colors as stored in the file. set this flag to force
+// unpremultiplication. results are undefined if the unpremultiply overflow.
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply);
+
+// indicate whether we should process iphone images back to canonical format,
+// or just pass them through "as-is"
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert);
+
+// flip the image vertically, so the first pixel in the output array is the bottom left
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip);
+
+// ZLIB client - used by PNG, available for other purposes
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen);
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header);
+STBIDEF char *stbi_zlib_decode_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(const char *buffer, int len, int *outlen);
+STBIDEF int   stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+//
+//
+////   end header file   /////////////////////////////////////////////////////
+#endif // STBI_INCLUDE_STB_IMAGE_H
+
+#ifdef STB_IMAGE_IMPLEMENTATION
+
+#if defined(STBI_ONLY_JPEG) || defined(STBI_ONLY_PNG) || defined(STBI_ONLY_BMP) \
+  || defined(STBI_ONLY_TGA) || defined(STBI_ONLY_GIF) || defined(STBI_ONLY_PSD) \
+  || defined(STBI_ONLY_HDR) || defined(STBI_ONLY_PIC) || defined(STBI_ONLY_PNM) \
+  || defined(STBI_ONLY_ZLIB)
+   #ifndef STBI_ONLY_JPEG
+   #define STBI_NO_JPEG
+   #endif
+   #ifndef STBI_ONLY_PNG
+   #define STBI_NO_PNG
+   #endif
+   #ifndef STBI_ONLY_BMP
+   #define STBI_NO_BMP
+   #endif
+   #ifndef STBI_ONLY_PSD
+   #define STBI_NO_PSD
+   #endif
+   #ifndef STBI_ONLY_TGA
+   #define STBI_NO_TGA
+   #endif
+   #ifndef STBI_ONLY_GIF
+   #define STBI_NO_GIF
+   #endif
+   #ifndef STBI_ONLY_HDR
+   #define STBI_NO_HDR
+   #endif
+   #ifndef STBI_ONLY_PIC
+   #define STBI_NO_PIC
+   #endif
+   #ifndef STBI_ONLY_PNM
+   #define STBI_NO_PNM
+   #endif
+#endif
+
+#if defined(STBI_NO_PNG) && !defined(STBI_SUPPORT_ZLIB) && !defined(STBI_NO_ZLIB)
+#define STBI_NO_ZLIB
+#endif
+
+
+#include <stdarg.h>
+#include <stddef.h> // ptrdiff_t on osx
+#include <stdlib.h>
+#include <string.h>
+
+#if !defined(STBI_NO_LINEAR) || !defined(STBI_NO_HDR)
+#include <math.h>  // ldexp
+#endif
+
+#ifndef STBI_NO_STDIO
+#include <stdio.h>
+#endif
+
+#ifndef STBI_ASSERT
+#include <assert.h>
+#define STBI_ASSERT(x) assert(x)
+#endif
+
+
+#ifndef _MSC_VER
+   #ifdef __cplusplus
+   #define stbi_inline inline
+   #else
+   #define stbi_inline
+   #endif
+#else
+   #define stbi_inline __forceinline
+#endif
+
+
+#ifdef _MSC_VER
+typedef unsigned short stbi__uint16;
+typedef   signed short stbi__int16;
+typedef unsigned int   stbi__uint32;
+typedef   signed int   stbi__int32;
+#else
+#include <stdint.h>
+typedef uint16_t stbi__uint16;
+typedef int16_t  stbi__int16;
+typedef uint32_t stbi__uint32;
+typedef int32_t  stbi__int32;
+#endif
+
+// should produce compiler error if size is wrong
+typedef unsigned char validate_uint32[sizeof(stbi__uint32)==4 ? 1 : -1];
+
+#ifdef _MSC_VER
+#define STBI_NOTUSED(v)  (void)(v)
+#else
+#define STBI_NOTUSED(v)  (void)sizeof(v)
+#endif
+
+#ifdef _MSC_VER
+#define STBI_HAS_LROTL
+#endif
+
+#ifdef STBI_HAS_LROTL
+   #define stbi_lrot(x,y)  _lrotl(x,y)
+#else
+   #define stbi_lrot(x,y)  (((x) << (y)) | ((x) >> (32 - (y))))
+#endif
+
+#if defined(STBI_MALLOC) && defined(STBI_FREE) && (defined(STBI_REALLOC) || defined(STBI_REALLOC_SIZED))
+// ok
+#elif !defined(STBI_MALLOC) && !defined(STBI_FREE) && !defined(STBI_REALLOC) && !defined(STBI_REALLOC_SIZED)
+// ok
+#else
+#error "Must define all or none of STBI_MALLOC, STBI_FREE, and STBI_REALLOC (or STBI_REALLOC_SIZED)."
+#endif
+
+#ifndef STBI_MALLOC
+#define STBI_MALLOC(sz)           malloc(sz)
+#define STBI_REALLOC(p,newsz)     realloc(p,newsz)
+#define STBI_FREE(p)              free(p)
+#endif
+
+#ifndef STBI_REALLOC_SIZED
+#define STBI_REALLOC_SIZED(p,oldsz,newsz) STBI_REALLOC(p,newsz)
+#endif
+
+// x86/x64 detection
+#if defined(__x86_64__) || defined(_M_X64)
+#define STBI__X64_TARGET
+#elif defined(__i386) || defined(_M_IX86)
+#define STBI__X86_TARGET
+#endif
+
+#if defined(__GNUC__) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET)) && !defined(__SSE2__) && !defined(STBI_NO_SIMD)
+// NOTE: not clear do we actually need this for the 64-bit path?
+// gcc doesn't support sse2 intrinsics unless you compile with -msse2,
+// (but compiling with -msse2 allows the compiler to use SSE2 everywhere;
+// this is just broken and gcc are jerks for not fixing it properly
+// http://www.virtualdub.org/blog/pivot/entry.php?id=363 )
+#define STBI_NO_SIMD
+#endif
+
+#if defined(__MINGW32__) && defined(STBI__X86_TARGET) && !defined(STBI_MINGW_ENABLE_SSE2) && !defined(STBI_NO_SIMD)
+// Note that __MINGW32__ doesn't actually mean 32-bit, so we have to avoid STBI__X64_TARGET
+//
+// 32-bit MinGW wants ESP to be 16-byte aligned, but this is not in the
+// Windows ABI and VC++ as well as Windows DLLs don't maintain that invariant.
+// As a result, enabling SSE2 on 32-bit MinGW is dangerous when not
+// simultaneously enabling "-mstackrealign".
+//
+// See https://github.com/nothings/stb/issues/81 for more information.
+//
+// So default to no SSE2 on 32-bit MinGW. If you've read this far and added
+// -mstackrealign to your build settings, feel free to #define STBI_MINGW_ENABLE_SSE2.
+#define STBI_NO_SIMD
+#endif
+
+#if !defined(STBI_NO_SIMD) && (defined(STBI__X86_TARGET) || defined(STBI__X64_TARGET))
+#define STBI_SSE2
+#include <emmintrin.h>
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1400  // not VC6
+#include <intrin.h> // __cpuid
+static int stbi__cpuid3(void)
+{
+   int info[4];
+   __cpuid(info,1);
+   return info[3];
+}
+#else
+static int stbi__cpuid3(void)
+{
+   int res;
+   __asm {
+      mov  eax,1
+      cpuid
+      mov  res,edx
+   }
+   return res;
+}
+#endif
+
+#define STBI_SIMD_ALIGN(type, name) __declspec(align(16)) type name
+
+static int stbi__sse2_available()
+{
+   int info3 = stbi__cpuid3();
+   return ((info3 >> 26) & 1) != 0;
+}
+#else // assume GCC-style if not VC++
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+
+static int stbi__sse2_available()
+{
+#if defined(__GNUC__) && (__GNUC__ * 100 + __GNUC_MINOR__) >= 408 // GCC 4.8 or later
+   // GCC 4.8+ has a nice way to do this
+   return __builtin_cpu_supports("sse2");
+#else
+   // portable way to do this, preferably without using GCC inline ASM?
+   // just bail for now.
+   return 0;
+#endif
+}
+#endif
+#endif
+
+// ARM NEON
+#if defined(STBI_NO_SIMD) && defined(STBI_NEON)
+#undef STBI_NEON
+#endif
+
+#ifdef STBI_NEON
+#include <arm_neon.h>
+// assume GCC or Clang on ARM targets
+#define STBI_SIMD_ALIGN(type, name) type name __attribute__((aligned(16)))
+#endif
+
+#ifndef STBI_SIMD_ALIGN
+#define STBI_SIMD_ALIGN(type, name) type name
+#endif
+
+///////////////////////////////////////////////
+//
+//  stbi__context struct and start_xxx functions
+
+// stbi__context structure is our basic context used by all images, so it
+// contains all the IO context, plus some basic image information
+typedef struct
+{
+   stbi__uint32 img_x, img_y;
+   int img_n, img_out_n;
+
+   stbi_io_callbacks io;
+   void *io_user_data;
+
+   int read_from_callbacks;
+   int buflen;
+   stbi_uc buffer_start[128];
+
+   stbi_uc *img_buffer, *img_buffer_end;
+   stbi_uc *img_buffer_original, *img_buffer_original_end;
+} stbi__context;
+
+
+static void stbi__refill_buffer(stbi__context *s);
+
+// initialize a memory-decode context
+static void stbi__start_mem(stbi__context *s, stbi_uc const *buffer, int len)
+{
+   s->io.read = NULL;
+   s->read_from_callbacks = 0;
+   s->img_buffer = s->img_buffer_original = (stbi_uc *) buffer;
+   s->img_buffer_end = s->img_buffer_original_end = (stbi_uc *) buffer+len;
+}
+
+// initialize a callback-based context
+static void stbi__start_callbacks(stbi__context *s, stbi_io_callbacks *c, void *user)
+{
+   s->io = *c;
+   s->io_user_data = user;
+   s->buflen = sizeof(s->buffer_start);
+   s->read_from_callbacks = 1;
+   s->img_buffer_original = s->buffer_start;
+   stbi__refill_buffer(s);
+   s->img_buffer_original_end = s->img_buffer_end;
+}
+
+#ifndef STBI_NO_STDIO
+
+static int stbi__stdio_read(void *user, char *data, int size)
+{
+   return (int) fread(data,1,size,(FILE*) user);
+}
+
+static void stbi__stdio_skip(void *user, int n)
+{
+   fseek((FILE*) user, n, SEEK_CUR);
+}
+
+static int stbi__stdio_eof(void *user)
+{
+   return feof((FILE*) user);
+}
+
+static stbi_io_callbacks stbi__stdio_callbacks =
+{
+   stbi__stdio_read,
+   stbi__stdio_skip,
+   stbi__stdio_eof,
+};
+
+static void stbi__start_file(stbi__context *s, FILE *f)
+{
+   stbi__start_callbacks(s, &stbi__stdio_callbacks, (void *) f);
+}
+
+//static void stop_file(stbi__context *s) { }
+
+#endif // !STBI_NO_STDIO
+
+static void stbi__rewind(stbi__context *s)
+{
+   // conceptually rewind SHOULD rewind to the beginning of the stream,
+   // but we just rewind to the beginning of the initial buffer, because
+   // we only use it after doing 'test', which only ever looks at at most 92 bytes
+   s->img_buffer = s->img_buffer_original;
+   s->img_buffer_end = s->img_buffer_original_end;
+}
+
+#ifndef STBI_NO_JPEG
+static int      stbi__jpeg_test(stbi__context *s);
+static stbi_uc *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNG
+static int      stbi__png_test(stbi__context *s);
+static stbi_uc *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__png_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_BMP
+static int      stbi__bmp_test(stbi__context *s);
+static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_TGA
+static int      stbi__tga_test(stbi__context *s);
+static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__tga_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PSD
+static int      stbi__psd_test(stbi__context *s);
+static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__psd_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static int      stbi__hdr_test(stbi__context *s);
+static float   *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PIC
+static int      stbi__pic_test(stbi__context *s);
+static stbi_uc *stbi__pic_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__pic_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_GIF
+static int      stbi__gif_test(stbi__context *s);
+static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__gif_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+#ifndef STBI_NO_PNM
+static int      stbi__pnm_test(stbi__context *s);
+static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp);
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp);
+#endif
+
+// this is not threadsafe
+static const char *stbi__g_failure_reason;
+
+STBIDEF const char *stbi_failure_reason(void)
+{
+   return stbi__g_failure_reason;
+}
+
+static int stbi__err(const char *str)
+{
+   stbi__g_failure_reason = str;
+   return 0;
+}
+
+static void *stbi__malloc(size_t size)
+{
+    return STBI_MALLOC(size);
+}
+
+// stbi__err - error
+// stbi__errpf - error returning pointer to float
+// stbi__errpuc - error returning pointer to unsigned char
+
+#ifdef STBI_NO_FAILURE_STRINGS
+   #define stbi__err(x,y)  0
+#elif defined(STBI_FAILURE_USERMSG)
+   #define stbi__err(x,y)  stbi__err(y)
+#else
+   #define stbi__err(x,y)  stbi__err(x)
+#endif
+
+#define stbi__errpf(x,y)   ((float *)(size_t) (stbi__err(x,y)?NULL:NULL))
+#define stbi__errpuc(x,y)  ((unsigned char *)(size_t) (stbi__err(x,y)?NULL:NULL))
+
+STBIDEF void stbi_image_free(void *retval_from_stbi_load)
+{
+   STBI_FREE(retval_from_stbi_load);
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp);
+#endif
+
+#ifndef STBI_NO_HDR
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp);
+#endif
+
+static int stbi__vertically_flip_on_load = 0;
+
+STBIDEF void stbi_set_flip_vertically_on_load(int flag_true_if_should_flip)
+{
+    stbi__vertically_flip_on_load = flag_true_if_should_flip;
+}
+
+static unsigned char *stbi__load_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_test(s)) return stbi__jpeg_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PNG
+   if (stbi__png_test(s))  return stbi__png_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_test(s))  return stbi__bmp_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_test(s))  return stbi__gif_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_test(s))  return stbi__psd_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_test(s))  return stbi__pic_load(s,x,y,comp,req_comp);
+   #endif
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_test(s))  return stbi__pnm_load(s,x,y,comp,req_comp);
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      float *hdr = stbi__hdr_load(s, x,y,comp,req_comp);
+      return stbi__hdr_to_ldr(hdr, *x, *y, req_comp ? req_comp : *comp);
+   }
+   #endif
+
+   #ifndef STBI_NO_TGA
+   // test tga last because it's a crappy test!
+   if (stbi__tga_test(s))
+      return stbi__tga_load(s,x,y,comp,req_comp);
+   #endif
+
+   return stbi__errpuc("unknown image type", "Image not of any known type, or corrupt");
+}
+
+static unsigned char *stbi__load_flip(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *result = stbi__load_main(s, x, y, comp, req_comp);
+
+   if (stbi__vertically_flip_on_load && result != NULL) {
+      int w = *x, h = *y;
+      int depth = req_comp ? req_comp : *comp;
+      int row,col,z;
+      stbi_uc temp;
+
+      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+      for (row = 0; row < (h>>1); row++) {
+         for (col = 0; col < w; col++) {
+            for (z = 0; z < depth; z++) {
+               temp = result[(row * w + col) * depth + z];
+               result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
+               result[((h - row - 1) * w + col) * depth + z] = temp;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+#ifndef STBI_NO_HDR
+static void stbi__float_postprocess(float *result, int *x, int *y, int *comp, int req_comp)
+{
+   if (stbi__vertically_flip_on_load && result != NULL) {
+      int w = *x, h = *y;
+      int depth = req_comp ? req_comp : *comp;
+      int row,col,z;
+      float temp;
+
+      // @OPTIMIZE: use a bigger temp buffer and memcpy multiple pixels at once
+      for (row = 0; row < (h>>1); row++) {
+         for (col = 0; col < w; col++) {
+            for (z = 0; z < depth; z++) {
+               temp = result[(row * w + col) * depth + z];
+               result[(row * w + col) * depth + z] = result[((h - row - 1) * w + col) * depth + z];
+               result[((h - row - 1) * w + col) * depth + z] = temp;
+            }
+         }
+      }
+   }
+}
+#endif
+
+#ifndef STBI_NO_STDIO
+
+static FILE *stbi__fopen(char const *filename, char const *mode)
+{
+   FILE *f;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+   if (0 != fopen_s(&f, filename, mode))
+      f=0;
+#else
+   f = fopen(filename, mode);
+#endif
+   return f;
+}
+
+
+STBIDEF stbi_uc *stbi_load(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   unsigned char *result;
+   if (!f) return stbi__errpuc("can't fopen", "Unable to open file");
+   result = stbi_load_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF stbi_uc *stbi_load_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *result;
+   stbi__context s;
+   stbi__start_file(&s,f);
+   result = stbi__load_flip(&s,x,y,comp,req_comp);
+   if (result) {
+      // need to 'unget' all the characters in the IO buffer
+      fseek(f, - (int) (s.img_buffer_end - s.img_buffer), SEEK_CUR);
+   }
+   return result;
+}
+#endif //!STBI_NO_STDIO
+
+STBIDEF stbi_uc *stbi_load_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__load_flip(&s,x,y,comp,req_comp);
+}
+
+STBIDEF stbi_uc *stbi_load_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__load_flip(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_LINEAR
+static float *stbi__loadf_main(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char *data;
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_test(s)) {
+      float *hdr_data = stbi__hdr_load(s,x,y,comp,req_comp);
+      if (hdr_data)
+         stbi__float_postprocess(hdr_data,x,y,comp,req_comp);
+      return hdr_data;
+   }
+   #endif
+   data = stbi__load_flip(s, x, y, comp, req_comp);
+   if (data)
+      return stbi__ldr_to_hdr(data, *x, *y, req_comp ? req_comp : *comp);
+   return stbi__errpf("unknown image type", "Image not of any known type, or corrupt");
+}
+
+STBIDEF float *stbi_loadf_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+STBIDEF float *stbi_loadf_from_callbacks(stbi_io_callbacks const *clbk, void *user, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF float *stbi_loadf(char const *filename, int *x, int *y, int *comp, int req_comp)
+{
+   float *result;
+   FILE *f = stbi__fopen(filename, "rb");
+   if (!f) return stbi__errpf("can't fopen", "Unable to open file");
+   result = stbi_loadf_from_file(f,x,y,comp,req_comp);
+   fclose(f);
+   return result;
+}
+
+STBIDEF float *stbi_loadf_from_file(FILE *f, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi__loadf_main(&s,x,y,comp,req_comp);
+}
+#endif // !STBI_NO_STDIO
+
+#endif // !STBI_NO_LINEAR
+
+// these is-hdr-or-not is defined independent of whether STBI_NO_LINEAR is
+// defined, for API simplicity; if STBI_NO_LINEAR is defined, it always
+// reports false!
+
+STBIDEF int stbi_is_hdr_from_memory(stbi_uc const *buffer, int len)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(buffer);
+   STBI_NOTUSED(len);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int      stbi_is_hdr          (char const *filename)
+{
+   FILE *f = stbi__fopen(filename, "rb");
+   int result=0;
+   if (f) {
+      result = stbi_is_hdr_from_file(f);
+      fclose(f);
+   }
+   return result;
+}
+
+STBIDEF int      stbi_is_hdr_from_file(FILE *f)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_file(&s,f);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(f);
+   return 0;
+   #endif
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int      stbi_is_hdr_from_callbacks(stbi_io_callbacks const *clbk, void *user)
+{
+   #ifndef STBI_NO_HDR
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) clbk, user);
+   return stbi__hdr_test(&s);
+   #else
+   STBI_NOTUSED(clbk);
+   STBI_NOTUSED(user);
+   return 0;
+   #endif
+}
+
+#ifndef STBI_NO_LINEAR
+static float stbi__l2h_gamma=2.2f, stbi__l2h_scale=1.0f;
+
+STBIDEF void   stbi_ldr_to_hdr_gamma(float gamma) { stbi__l2h_gamma = gamma; }
+STBIDEF void   stbi_ldr_to_hdr_scale(float scale) { stbi__l2h_scale = scale; }
+#endif
+
+static float stbi__h2l_gamma_i=1.0f/2.2f, stbi__h2l_scale_i=1.0f;
+
+STBIDEF void   stbi_hdr_to_ldr_gamma(float gamma) { stbi__h2l_gamma_i = 1/gamma; }
+STBIDEF void   stbi_hdr_to_ldr_scale(float scale) { stbi__h2l_scale_i = 1/scale; }
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+// Common code used by all image loaders
+//
+
+enum
+{
+   STBI__SCAN_load=0,
+   STBI__SCAN_type,
+   STBI__SCAN_header
+};
+
+static void stbi__refill_buffer(stbi__context *s)
+{
+   int n = (s->io.read)(s->io_user_data,(char*)s->buffer_start,s->buflen);
+   if (n == 0) {
+      // at end of file, treat same as if from memory, but need to handle case
+      // where s->img_buffer isn't pointing to safe memory, e.g. 0-byte file
+      s->read_from_callbacks = 0;
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start+1;
+      *s->img_buffer = 0;
+   } else {
+      s->img_buffer = s->buffer_start;
+      s->img_buffer_end = s->buffer_start + n;
+   }
+}
+
+stbi_inline static stbi_uc stbi__get8(stbi__context *s)
+{
+   if (s->img_buffer < s->img_buffer_end)
+      return *s->img_buffer++;
+   if (s->read_from_callbacks) {
+      stbi__refill_buffer(s);
+      return *s->img_buffer++;
+   }
+   return 0;
+}
+
+stbi_inline static int stbi__at_eof(stbi__context *s)
+{
+   if (s->io.read) {
+      if (!(s->io.eof)(s->io_user_data)) return 0;
+      // if feof() is true, check if buffer = end
+      // special case: we've only got the special 0 character at the end
+      if (s->read_from_callbacks == 0) return 1;
+   }
+
+   return s->img_buffer >= s->img_buffer_end;
+}
+
+static void stbi__skip(stbi__context *s, int n)
+{
+   if (n < 0) {
+      s->img_buffer = s->img_buffer_end;
+      return;
+   }
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         s->img_buffer = s->img_buffer_end;
+         (s->io.skip)(s->io_user_data, n - blen);
+         return;
+      }
+   }
+   s->img_buffer += n;
+}
+
+static int stbi__getn(stbi__context *s, stbi_uc *buffer, int n)
+{
+   if (s->io.read) {
+      int blen = (int) (s->img_buffer_end - s->img_buffer);
+      if (blen < n) {
+         int res, count;
+
+         memcpy(buffer, s->img_buffer, blen);
+
+         count = (s->io.read)(s->io_user_data, (char*) buffer + blen, n - blen);
+         res = (count == (n-blen));
+         s->img_buffer = s->img_buffer_end;
+         return res;
+      }
+   }
+
+   if (s->img_buffer+n <= s->img_buffer_end) {
+      memcpy(buffer, s->img_buffer, n);
+      s->img_buffer += n;
+      return 1;
+   } else
+      return 0;
+}
+
+static int stbi__get16be(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return (z << 8) + stbi__get8(s);
+}
+
+static stbi__uint32 stbi__get32be(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16be(s);
+   return (z << 16) + stbi__get16be(s);
+}
+
+#if defined(STBI_NO_BMP) && defined(STBI_NO_TGA) && defined(STBI_NO_GIF)
+// nothing
+#else
+static int stbi__get16le(stbi__context *s)
+{
+   int z = stbi__get8(s);
+   return z + (stbi__get8(s) << 8);
+}
+#endif
+
+#ifndef STBI_NO_BMP
+static stbi__uint32 stbi__get32le(stbi__context *s)
+{
+   stbi__uint32 z = stbi__get16le(s);
+   return z + (stbi__get16le(s) << 16);
+}
+#endif
+
+#define STBI__BYTECAST(x)  ((stbi_uc) ((x) & 255))  // truncate int to byte without warnings
+
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  generic converter from built-in img_n to req_comp
+//    individual types do this automatically as much as possible (e.g. jpeg
+//    does all cases internally since it needs to colorspace convert anyway,
+//    and it never has alpha, so very few cases ). png can automatically
+//    interleave an alpha=255 channel, but falls back to this for other cases
+//
+//  assume data buffer is malloced, so malloc a new one and free that one
+//  only failure mode is malloc failing
+
+static stbi_uc stbi__compute_y(int r, int g, int b)
+{
+   return (stbi_uc) (((r*77) + (g*150) +  (29*b)) >> 8);
+}
+
+static unsigned char *stbi__convert_format(unsigned char *data, int img_n, int req_comp, unsigned int x, unsigned int y)
+{
+   int i,j;
+   unsigned char *good;
+
+   if (req_comp == img_n) return data;
+   STBI_ASSERT(req_comp >= 1 && req_comp <= 4);
+
+   good = (unsigned char *) stbi__malloc(req_comp * x * y);
+   if (good == NULL) {
+      STBI_FREE(data);
+      return stbi__errpuc("outofmem", "Out of memory");
+   }
+
+   for (j=0; j < (int) y; ++j) {
+      unsigned char *src  = data + j * x * img_n   ;
+      unsigned char *dest = good + j * x * req_comp;
+
+      #define COMBO(a,b)  ((a)*8+(b))
+      #define CASE(a,b)   case COMBO(a,b): for(i=x-1; i >= 0; --i, src += a, dest += b)
+      // convert source image with img_n components to one with req_comp components;
+      // avoid switch per pixel, so use switch per scanline and massive macros
+      switch (COMBO(img_n, req_comp)) {
+          CASE(1,2) { dest[0]=src[0], dest[1]=255; } break;
+          CASE(1,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+          CASE(1,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=255; } break;
+          CASE(2,1) { dest[0]=src[0]; } break;
+          CASE(2,3) { dest[0]=dest[1]=dest[2]=src[0]; } break;
+          CASE(2,4) { dest[0]=dest[1]=dest[2]=src[0], dest[3]=src[1]; } break;
+          CASE(3,4) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2],dest[3]=255; } break;
+          CASE(3,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+          CASE(3,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = 255; } break;
+          CASE(4,1) { dest[0]=stbi__compute_y(src[0],src[1],src[2]); } break;
+          CASE(4,2) { dest[0]=stbi__compute_y(src[0],src[1],src[2]), dest[1] = src[3]; } break;
+          CASE(4,3) { dest[0]=src[0],dest[1]=src[1],dest[2]=src[2]; } break;
+         default: STBI_ASSERT(0);
+      }
+      #undef CASE
+   }
+
+   STBI_FREE(data);
+   return good;
+}
+
+#ifndef STBI_NO_LINEAR
+static float   *stbi__ldr_to_hdr(stbi_uc *data, int x, int y, int comp)
+{
+   int i,k,n;
+   float *output = (float *) stbi__malloc(x * y * comp * sizeof(float));
+   if (output == NULL) { STBI_FREE(data); return stbi__errpf("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         output[i*comp + k] = (float) (pow(data[i*comp+k]/255.0f, stbi__l2h_gamma) * stbi__l2h_scale);
+      }
+      if (k < comp) output[i*comp + k] = data[i*comp+k]/255.0f;
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+#ifndef STBI_NO_HDR
+#define stbi__float2int(x)   ((int) (x))
+static stbi_uc *stbi__hdr_to_ldr(float   *data, int x, int y, int comp)
+{
+   int i,k,n;
+   stbi_uc *output = (stbi_uc *) stbi__malloc(x * y * comp);
+   if (output == NULL) { STBI_FREE(data); return stbi__errpuc("outofmem", "Out of memory"); }
+   // compute number of non-alpha components
+   if (comp & 1) n = comp; else n = comp-1;
+   for (i=0; i < x*y; ++i) {
+      for (k=0; k < n; ++k) {
+         float z = (float) pow(data[i*comp+k]*stbi__h2l_scale_i, stbi__h2l_gamma_i) * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+      if (k < comp) {
+         float z = data[i*comp+k] * 255 + 0.5f;
+         if (z < 0) z = 0;
+         if (z > 255) z = 255;
+         output[i*comp + k] = (stbi_uc) stbi__float2int(z);
+      }
+   }
+   STBI_FREE(data);
+   return output;
+}
+#endif
+
+//////////////////////////////////////////////////////////////////////////////
+//
+//  "baseline" JPEG/JFIF decoder
+//
+//    simple implementation
+//      - doesn't support delayed output of y-dimension
+//      - simple interface (only one output format: 8-bit interleaved RGB)
+//      - doesn't try to recover corrupt jpegs
+//      - doesn't allow partial loading, loading multiple at once
+//      - still fast on x86 (copying globals into locals doesn't help x86)
+//      - allocates lots of intermediate memory (full size of all components)
+//        - non-interleaved case requires this anyway
+//        - allows good upsampling (see next)
+//    high-quality
+//      - upsampled channels are bilinearly interpolated, even across blocks
+//      - quality integer IDCT derived from IJG's 'slow'
+//    performance
+//      - fast huffman; reasonable integer IDCT
+//      - some SIMD kernels for common paths on targets with SSE2/NEON
+//      - uses a lot of intermediate memory, could cache poorly
+
+#ifndef STBI_NO_JPEG
+
+// huffman decoding acceleration
+#define FAST_BITS   9  // larger handles more cases; smaller stomps less cache
+
+typedef struct
+{
+   stbi_uc  fast[1 << FAST_BITS];
+   // weirdly, repacking this into AoS is a 10% speed loss, instead of a win
+   stbi__uint16 code[256];
+   stbi_uc  values[256];
+   stbi_uc  size[257];
+   unsigned int maxcode[18];
+   int    delta[17];   // old 'firstsymbol' - old 'firstcode'
+} stbi__huffman;
+
+typedef struct
+{
+   stbi__context *s;
+   stbi__huffman huff_dc[4];
+   stbi__huffman huff_ac[4];
+   stbi_uc dequant[4][64];
+   stbi__int16 fast_ac[4][1 << FAST_BITS];
+
+// sizes for components, interleaved MCUs
+   int img_h_max, img_v_max;
+   int img_mcu_x, img_mcu_y;
+   int img_mcu_w, img_mcu_h;
+
+// definition of jpeg image component
+   struct
+   {
+      int id;
+      int h,v;
+      int tq;
+      int hd,ha;
+      int dc_pred;
+
+      int x,y,w2,h2;
+      stbi_uc *data;
+      void *raw_data, *raw_coeff;
+      stbi_uc *linebuf;
+      short   *coeff;   // progressive only
+      int      coeff_w, coeff_h; // number of 8x8 coefficient blocks
+   } img_comp[4];
+
+   stbi__uint32   code_buffer; // jpeg entropy-coded buffer
+   int            code_bits;   // number of valid bits
+   unsigned char  marker;      // marker seen while filling entropy buffer
+   int            nomore;      // flag if we saw a marker so must stop
+
+   int            progressive;
+   int            spec_start;
+   int            spec_end;
+   int            succ_high;
+   int            succ_low;
+   int            eob_run;
+   int            rgb;
+
+   int scan_n, order[4];
+   int restart_interval, todo;
+
+// kernels
+   void (*idct_block_kernel)(stbi_uc *out, int out_stride, short data[64]);
+   void (*YCbCr_to_RGB_kernel)(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step);
+   stbi_uc *(*resample_row_hv_2_kernel)(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs);
+} stbi__jpeg;
+
+static int stbi__build_huffman(stbi__huffman *h, int *count)
+{
+   int i,j,k=0,code;
+   // build size list for each symbol (from JPEG spec)
+   for (i=0; i < 16; ++i)
+      for (j=0; j < count[i]; ++j)
+         h->size[k++] = (stbi_uc) (i+1);
+   h->size[k] = 0;
+
+   // compute actual symbols (from jpeg spec)
+   code = 0;
+   k = 0;
+   for(j=1; j <= 16; ++j) {
+      // compute delta to add to code to compute symbol id
+      h->delta[j] = k - code;
+      if (h->size[k] == j) {
+         while (h->size[k] == j)
+            h->code[k++] = (stbi__uint16) (code++);
+         if (code-1 >= (1 << j)) return stbi__err("bad code lengths","Corrupt JPEG");
+      }
+      // compute largest code + 1 for this size, preshifted as needed later
+      h->maxcode[j] = code << (16-j);
+      code <<= 1;
+   }
+   h->maxcode[j] = 0xffffffff;
+
+   // build non-spec acceleration table; 255 is flag for not-accelerated
+   memset(h->fast, 255, 1 << FAST_BITS);
+   for (i=0; i < k; ++i) {
+      int s = h->size[i];
+      if (s <= FAST_BITS) {
+         int c = h->code[i] << (FAST_BITS-s);
+         int m = 1 << (FAST_BITS-s);
+         for (j=0; j < m; ++j) {
+            h->fast[c+j] = (stbi_uc) i;
+         }
+      }
+   }
+   return 1;
+}
+
+// build a table that decodes both magnitude and value of small ACs in
+// one go.
+static void stbi__build_fast_ac(stbi__int16 *fast_ac, stbi__huffman *h)
+{
+   int i;
+   for (i=0; i < (1 << FAST_BITS); ++i) {
+      stbi_uc fast = h->fast[i];
+      fast_ac[i] = 0;
+      if (fast < 255) {
+         int rs = h->values[fast];
+         int run = (rs >> 4) & 15;
+         int magbits = rs & 15;
+         int len = h->size[fast];
+
+         if (magbits && len + magbits <= FAST_BITS) {
+            // magnitude code followed by receive_extend code
+            int k = ((i << len) & ((1 << FAST_BITS) - 1)) >> (FAST_BITS - magbits);
+            int m = 1 << (magbits - 1);
+            if (k < m) k += (-1 << magbits) + 1;
+            // if the result is small enough, we can fit it in fast_ac table
+            if (k >= -128 && k <= 127)
+               fast_ac[i] = (stbi__int16) ((k << 8) + (run << 4) + (len + magbits));
+         }
+      }
+   }
+}
+
+static void stbi__grow_buffer_unsafe(stbi__jpeg *j)
+{
+   do {
+      int b = j->nomore ? 0 : stbi__get8(j->s);
+      if (b == 0xff) {
+         int c = stbi__get8(j->s);
+         if (c != 0) {
+            j->marker = (unsigned char) c;
+            j->nomore = 1;
+            return;
+         }
+      }
+      j->code_buffer |= b << (24 - j->code_bits);
+      j->code_bits += 8;
+   } while (j->code_bits <= 24);
+}
+
+// (1 << n) - 1
+static stbi__uint32 stbi__bmask[17]={0,1,3,7,15,31,63,127,255,511,1023,2047,4095,8191,16383,32767,65535};
+
+// decode a jpeg huffman value from the bitstream
+stbi_inline static int stbi__jpeg_huff_decode(stbi__jpeg *j, stbi__huffman *h)
+{
+   unsigned int temp;
+   int c,k;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   // look at the top FAST_BITS and determine what symbol ID it is,
+   // if the code is <= FAST_BITS
+   c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+   k = h->fast[c];
+   if (k < 255) {
+      int s = h->size[k];
+      if (s > j->code_bits)
+         return -1;
+      j->code_buffer <<= s;
+      j->code_bits -= s;
+      return h->values[k];
+   }
+
+   // naive test is to shift the code_buffer down so k bits are
+   // valid, then test against maxcode. To speed this up, we've
+   // preshifted maxcode left so that it has (16-k) 0s at the
+   // end; in other words, regardless of the number of bits, it
+   // wants to be compared against something shifted to have 16;
+   // that way we don't need to shift inside the loop.
+   temp = j->code_buffer >> 16;
+   for (k=FAST_BITS+1 ; ; ++k)
+      if (temp < h->maxcode[k])
+         break;
+   if (k == 17) {
+      // error! code not found
+      j->code_bits -= 16;
+      return -1;
+   }
+
+   if (k > j->code_bits)
+      return -1;
+
+   // convert the huffman code to the symbol id
+   c = ((j->code_buffer >> (32 - k)) & stbi__bmask[k]) + h->delta[k];
+   STBI_ASSERT((((j->code_buffer) >> (32 - h->size[c])) & stbi__bmask[h->size[c]]) == h->code[c]);
+
+   // convert the id to a symbol
+   j->code_bits -= k;
+   j->code_buffer <<= k;
+   return h->values[c];
+}
+
+// bias[n] = (-1<<n) + 1
+static int const stbi__jbias[16] = {0,-1,-3,-7,-15,-31,-63,-127,-255,-511,-1023,-2047,-4095,-8191,-16383,-32767};
+
+// combined JPEG 'receive' and JPEG 'extend', since baseline
+// always extends everything it receives.
+stbi_inline static int stbi__extend_receive(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   int sgn;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+
+   sgn = (stbi__int32)j->code_buffer >> 31; // sign bit is always in MSB
+   k = stbi_lrot(j->code_buffer, n);
+   STBI_ASSERT(n >= 0 && n < (int) (sizeof(stbi__bmask)/sizeof(*stbi__bmask)));
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k + (stbi__jbias[n] & ~sgn);
+}
+
+// get some unsigned bits
+stbi_inline static int stbi__jpeg_get_bits(stbi__jpeg *j, int n)
+{
+   unsigned int k;
+   if (j->code_bits < n) stbi__grow_buffer_unsafe(j);
+   k = stbi_lrot(j->code_buffer, n);
+   j->code_buffer = k & ~stbi__bmask[n];
+   k &= stbi__bmask[n];
+   j->code_bits -= n;
+   return k;
+}
+
+stbi_inline static int stbi__jpeg_get_bit(stbi__jpeg *j)
+{
+   unsigned int k;
+   if (j->code_bits < 1) stbi__grow_buffer_unsafe(j);
+   k = j->code_buffer;
+   j->code_buffer <<= 1;
+   --j->code_bits;
+   return k & 0x80000000;
+}
+
+// given a value that's at position X in the zigzag stream,
+// where does it appear in the 8x8 matrix coded as row-major?
+static stbi_uc stbi__jpeg_dezigzag[64+15] =
+{
+    0,  1,  8, 16,  9,  2,  3, 10,
+   17, 24, 32, 25, 18, 11,  4,  5,
+   12, 19, 26, 33, 40, 48, 41, 34,
+   27, 20, 13,  6,  7, 14, 21, 28,
+   35, 42, 49, 56, 57, 50, 43, 36,
+   29, 22, 15, 23, 30, 37, 44, 51,
+   58, 59, 52, 45, 38, 31, 39, 46,
+   53, 60, 61, 54, 47, 55, 62, 63,
+   // let corrupt input sample past end
+   63, 63, 63, 63, 63, 63, 63, 63,
+   63, 63, 63, 63, 63, 63, 63
+};
+
+// decode one 64-entry block--
+static int stbi__jpeg_decode_block(stbi__jpeg *j, short data[64], stbi__huffman *hdc, stbi__huffman *hac, stbi__int16 *fac, int b, stbi_uc *dequant)
+{
+   int diff,dc,k;
+   int t;
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+   t = stbi__jpeg_huff_decode(j, hdc);
+   if (t < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+
+   // 0 all the ac values now so we can do it 32-bits at a time
+   memset(data,0,64*sizeof(data[0]));
+
+   diff = t ? stbi__extend_receive(j, t) : 0;
+   dc = j->img_comp[b].dc_pred + diff;
+   j->img_comp[b].dc_pred = dc;
+   data[0] = (short) (dc * dequant[0]);
+
+   // decode AC components, see JPEG spec
+   k = 1;
+   do {
+      unsigned int zig;
+      int c,r,s;
+      if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+      c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+      r = fac[c];
+      if (r) { // fast-AC path
+         k += (r >> 4) & 15; // run
+         s = r & 15; // combined length
+         j->code_buffer <<= s;
+         j->code_bits -= s;
+         // decode into unzigzag'd location
+         zig = stbi__jpeg_dezigzag[k++];
+         data[zig] = (short) ((r >> 8) * dequant[zig]);
+      } else {
+         int rs = stbi__jpeg_huff_decode(j, hac);
+         if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+         s = rs & 15;
+         r = rs >> 4;
+         if (s == 0) {
+            if (rs != 0xf0) break; // end block
+            k += 16;
+         } else {
+            k += r;
+            // decode into unzigzag'd location
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) (stbi__extend_receive(j,s) * dequant[zig]);
+         }
+      }
+   } while (k < 64);
+   return 1;
+}
+
+static int stbi__jpeg_decode_block_prog_dc(stbi__jpeg *j, short data[64], stbi__huffman *hdc, int b)
+{
+   int diff,dc;
+   int t;
+   if (j->spec_end != 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+
+   if (j->succ_high == 0) {
+      // first scan for DC coefficient, must be first
+      memset(data,0,64*sizeof(data[0])); // 0 all the ac values now
+      t = stbi__jpeg_huff_decode(j, hdc);
+      diff = t ? stbi__extend_receive(j, t) : 0;
+
+      dc = j->img_comp[b].dc_pred + diff;
+      j->img_comp[b].dc_pred = dc;
+      data[0] = (short) (dc << j->succ_low);
+   } else {
+      // refinement scan for DC coefficient
+      if (stbi__jpeg_get_bit(j))
+         data[0] += (short) (1 << j->succ_low);
+   }
+   return 1;
+}
+
+// @OPTIMIZE: store non-zigzagged during the decode passes,
+// and only de-zigzag when dequantizing
+static int stbi__jpeg_decode_block_prog_ac(stbi__jpeg *j, short data[64], stbi__huffman *hac, stbi__int16 *fac)
+{
+   int k;
+   if (j->spec_start == 0) return stbi__err("can't merge dc and ac", "Corrupt JPEG");
+
+   if (j->succ_high == 0) {
+      int shift = j->succ_low;
+
+      if (j->eob_run) {
+         --j->eob_run;
+         return 1;
+      }
+
+      k = j->spec_start;
+      do {
+         unsigned int zig;
+         int c,r,s;
+         if (j->code_bits < 16) stbi__grow_buffer_unsafe(j);
+         c = (j->code_buffer >> (32 - FAST_BITS)) & ((1 << FAST_BITS)-1);
+         r = fac[c];
+         if (r) { // fast-AC path
+            k += (r >> 4) & 15; // run
+            s = r & 15; // combined length
+            j->code_buffer <<= s;
+            j->code_bits -= s;
+            zig = stbi__jpeg_dezigzag[k++];
+            data[zig] = (short) ((r >> 8) << shift);
+         } else {
+            int rs = stbi__jpeg_huff_decode(j, hac);
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r);
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  --j->eob_run;
+                  break;
+               }
+               k += 16;
+            } else {
+               k += r;
+               zig = stbi__jpeg_dezigzag[k++];
+               data[zig] = (short) (stbi__extend_receive(j,s) << shift);
+            }
+         }
+      } while (k <= j->spec_end);
+   } else {
+      // refinement scan for these AC coefficients
+
+      short bit = (short) (1 << j->succ_low);
+
+      if (j->eob_run) {
+         --j->eob_run;
+         for (k = j->spec_start; k <= j->spec_end; ++k) {
+            short *p = &data[stbi__jpeg_dezigzag[k]];
+            if (*p != 0)
+               if (stbi__jpeg_get_bit(j))
+                  if ((*p & bit)==0) {
+                     if (*p > 0)
+                        *p += bit;
+                     else
+                        *p -= bit;
+                  }
+         }
+      } else {
+         k = j->spec_start;
+         do {
+            int r,s;
+            int rs = stbi__jpeg_huff_decode(j, hac); // @OPTIMIZE see if we can use the fast path here, advance-by-r is so slow, eh
+            if (rs < 0) return stbi__err("bad huffman code","Corrupt JPEG");
+            s = rs & 15;
+            r = rs >> 4;
+            if (s == 0) {
+               if (r < 15) {
+                  j->eob_run = (1 << r) - 1;
+                  if (r)
+                     j->eob_run += stbi__jpeg_get_bits(j, r);
+                  r = 64; // force end of block
+               } else {
+                  // r=15 s=0 should write 16 0s, so we just do
+                  // a run of 15 0s and then write s (which is 0),
+                  // so we don't have to do anything special here
+               }
+            } else {
+               if (s != 1) return stbi__err("bad huffman code", "Corrupt JPEG");
+               // sign bit
+               if (stbi__jpeg_get_bit(j))
+                  s = bit;
+               else
+                  s = -bit;
+            }
+
+            // advance by r
+            while (k <= j->spec_end) {
+               short *p = &data[stbi__jpeg_dezigzag[k++]];
+               if (*p != 0) {
+                  if (stbi__jpeg_get_bit(j))
+                     if ((*p & bit)==0) {
+                        if (*p > 0)
+                           *p += bit;
+                        else
+                           *p -= bit;
+                     }
+               } else {
+                  if (r == 0) {
+                     *p = (short) s;
+                     break;
+                  }
+                  --r;
+               }
+            }
+         } while (k <= j->spec_end);
+      }
+   }
+   return 1;
+}
+
+// take a -128..127 value and stbi__clamp it and convert to 0..255
+stbi_inline static stbi_uc stbi__clamp(int x)
+{
+   // trick to use a single test to catch both cases
+   if ((unsigned int) x > 255) {
+      if (x < 0) return 0;
+      if (x > 255) return 255;
+   }
+   return (stbi_uc) x;
+}
+
+#define stbi__f2f(x)  ((int) (((x) * 4096 + 0.5)))
+#define stbi__fsh(x)  ((x) << 12)
+
+// derived from jidctint -- DCT_ISLOW
+#define STBI__IDCT_1D(s0,s1,s2,s3,s4,s5,s6,s7) \
+   int t0,t1,t2,t3,p1,p2,p3,p4,p5,x0,x1,x2,x3; \
+   p2 = s2;                                    \
+   p3 = s6;                                    \
+   p1 = (p2+p3) * stbi__f2f(0.5411961f);       \
+   t2 = p1 + p3*stbi__f2f(-1.847759065f);      \
+   t3 = p1 + p2*stbi__f2f( 0.765366865f);      \
+   p2 = s0;                                    \
+   p3 = s4;                                    \
+   t0 = stbi__fsh(p2+p3);                      \
+   t1 = stbi__fsh(p2-p3);                      \
+   x0 = t0+t3;                                 \
+   x3 = t0-t3;                                 \
+   x1 = t1+t2;                                 \
+   x2 = t1-t2;                                 \
+   t0 = s7;                                    \
+   t1 = s5;                                    \
+   t2 = s3;                                    \
+   t3 = s1;                                    \
+   p3 = t0+t2;                                 \
+   p4 = t1+t3;                                 \
+   p1 = t0+t3;                                 \
+   p2 = t1+t2;                                 \
+   p5 = (p3+p4)*stbi__f2f( 1.175875602f);      \
+   t0 = t0*stbi__f2f( 0.298631336f);           \
+   t1 = t1*stbi__f2f( 2.053119869f);           \
+   t2 = t2*stbi__f2f( 3.072711026f);           \
+   t3 = t3*stbi__f2f( 1.501321110f);           \
+   p1 = p5 + p1*stbi__f2f(-0.899976223f);      \
+   p2 = p5 + p2*stbi__f2f(-2.562915447f);      \
+   p3 = p3*stbi__f2f(-1.961570560f);           \
+   p4 = p4*stbi__f2f(-0.390180644f);           \
+   t3 += p1+p4;                                \
+   t2 += p2+p3;                                \
+   t1 += p2+p4;                                \
+   t0 += p1+p3;
+
+static void stbi__idct_block(stbi_uc *out, int out_stride, short data[64])
+{
+   int i,val[64],*v=val;
+   stbi_uc *o;
+   short *d = data;
+
+   // columns
+   for (i=0; i < 8; ++i,++d, ++v) {
+      // if all zeroes, shortcut -- this avoids dequantizing 0s and IDCTing
+      if (d[ 8]==0 && d[16]==0 && d[24]==0 && d[32]==0
+           && d[40]==0 && d[48]==0 && d[56]==0) {
+         //    no shortcut                 0     seconds
+         //    (1|2|3|4|5|6|7)==0          0     seconds
+         //    all separate               -0.047 seconds
+         //    1 && 2|3 && 4|5 && 6|7:    -0.047 seconds
+         int dcterm = d[0] << 2;
+         v[0] = v[8] = v[16] = v[24] = v[32] = v[40] = v[48] = v[56] = dcterm;
+      } else {
+         STBI__IDCT_1D(d[ 0],d[ 8],d[16],d[24],d[32],d[40],d[48],d[56])
+         // constants scaled things up by 1<<12; let's bring them back
+         // down, but keep 2 extra bits of precision
+         x0 += 512; x1 += 512; x2 += 512; x3 += 512;
+         v[ 0] = (x0+t3) >> 10;
+         v[56] = (x0-t3) >> 10;
+         v[ 8] = (x1+t2) >> 10;
+         v[48] = (x1-t2) >> 10;
+         v[16] = (x2+t1) >> 10;
+         v[40] = (x2-t1) >> 10;
+         v[24] = (x3+t0) >> 10;
+         v[32] = (x3-t0) >> 10;
+      }
+   }
+
+   for (i=0, v=val, o=out; i < 8; ++i,v+=8,o+=out_stride) {
+      // no fast case since the first 1D IDCT spread components out
+      STBI__IDCT_1D(v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7])
+      // constants scaled things up by 1<<12, plus we had 1<<2 from first
+      // loop, plus horizontal and vertical each scale by sqrt(8) so together
+      // we've got an extra 1<<3, so 1<<17 total we need to remove.
+      // so we want to round that, which means adding 0.5 * 1<<17,
+      // aka 65536. Also, we'll end up with -128 to 127 that we want
+      // to encode as 0..255 by adding 128, so we'll add that before the shift
+      x0 += 65536 + (128<<17);
+      x1 += 65536 + (128<<17);
+      x2 += 65536 + (128<<17);
+      x3 += 65536 + (128<<17);
+      // tried computing the shifts into temps, or'ing the temps to see
+      // if any were out of range, but that was slower
+      o[0] = stbi__clamp((x0+t3) >> 17);
+      o[7] = stbi__clamp((x0-t3) >> 17);
+      o[1] = stbi__clamp((x1+t2) >> 17);
+      o[6] = stbi__clamp((x1-t2) >> 17);
+      o[2] = stbi__clamp((x2+t1) >> 17);
+      o[5] = stbi__clamp((x2-t1) >> 17);
+      o[3] = stbi__clamp((x3+t0) >> 17);
+      o[4] = stbi__clamp((x3-t0) >> 17);
+   }
+}
+
+#ifdef STBI_SSE2
+// sse2 integer IDCT. not the fastest possible implementation but it
+// produces bit-identical results to the generic C version so it's
+// fully "transparent".
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   // This is constructed to match our regular (generic) integer IDCT exactly.
+   __m128i row0, row1, row2, row3, row4, row5, row6, row7;
+   __m128i tmp;
+
+   // dot product constant: even elems=x, odd elems=y
+   #define dct_const(x,y)  _mm_setr_epi16((x),(y),(x),(y),(x),(y),(x),(y))
+
+   // out(0) = c0[even]*x + c0[odd]*y   (c0, x, y 16-bit, out 32-bit)
+   // out(1) = c1[even]*x + c1[odd]*y
+   #define dct_rot(out0,out1, x,y,c0,c1) \
+      __m128i c0##lo = _mm_unpacklo_epi16((x),(y)); \
+      __m128i c0##hi = _mm_unpackhi_epi16((x),(y)); \
+      __m128i out0##_l = _mm_madd_epi16(c0##lo, c0); \
+      __m128i out0##_h = _mm_madd_epi16(c0##hi, c0); \
+      __m128i out1##_l = _mm_madd_epi16(c0##lo, c1); \
+      __m128i out1##_h = _mm_madd_epi16(c0##hi, c1)
+
+   // out = in << 12  (in 16-bit, out 32-bit)
+   #define dct_widen(out, in) \
+      __m128i out##_l = _mm_srai_epi32(_mm_unpacklo_epi16(_mm_setzero_si128(), (in)), 4); \
+      __m128i out##_h = _mm_srai_epi32(_mm_unpackhi_epi16(_mm_setzero_si128(), (in)), 4)
+
+   // wide add
+   #define dct_wadd(out, a, b) \
+      __m128i out##_l = _mm_add_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_add_epi32(a##_h, b##_h)
+
+   // wide sub
+   #define dct_wsub(out, a, b) \
+      __m128i out##_l = _mm_sub_epi32(a##_l, b##_l); \
+      __m128i out##_h = _mm_sub_epi32(a##_h, b##_h)
+
+   // butterfly a/b, add bias, then shift by "s" and pack
+   #define dct_bfly32o(out0, out1, a,b,bias,s) \
+      { \
+         __m128i abiased_l = _mm_add_epi32(a##_l, bias); \
+         __m128i abiased_h = _mm_add_epi32(a##_h, bias); \
+         dct_wadd(sum, abiased, b); \
+         dct_wsub(dif, abiased, b); \
+         out0 = _mm_packs_epi32(_mm_srai_epi32(sum_l, s), _mm_srai_epi32(sum_h, s)); \
+         out1 = _mm_packs_epi32(_mm_srai_epi32(dif_l, s), _mm_srai_epi32(dif_h, s)); \
+      }
+
+   // 8-bit interleave step (for transposes)
+   #define dct_interleave8(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi8(a, b); \
+      b = _mm_unpackhi_epi8(tmp, b)
+
+   // 16-bit interleave step (for transposes)
+   #define dct_interleave16(a, b) \
+      tmp = a; \
+      a = _mm_unpacklo_epi16(a, b); \
+      b = _mm_unpackhi_epi16(tmp, b)
+
+   #define dct_pass(bias,shift) \
+      { \
+         /* even part */ \
+         dct_rot(t2e,t3e, row2,row6, rot0_0,rot0_1); \
+         __m128i sum04 = _mm_add_epi16(row0, row4); \
+         __m128i dif04 = _mm_sub_epi16(row0, row4); \
+         dct_widen(t0e, sum04); \
+         dct_widen(t1e, dif04); \
+         dct_wadd(x0, t0e, t3e); \
+         dct_wsub(x3, t0e, t3e); \
+         dct_wadd(x1, t1e, t2e); \
+         dct_wsub(x2, t1e, t2e); \
+         /* odd part */ \
+         dct_rot(y0o,y2o, row7,row3, rot2_0,rot2_1); \
+         dct_rot(y1o,y3o, row5,row1, rot3_0,rot3_1); \
+         __m128i sum17 = _mm_add_epi16(row1, row7); \
+         __m128i sum35 = _mm_add_epi16(row3, row5); \
+         dct_rot(y4o,y5o, sum17,sum35, rot1_0,rot1_1); \
+         dct_wadd(x4, y0o, y4o); \
+         dct_wadd(x5, y1o, y5o); \
+         dct_wadd(x6, y2o, y5o); \
+         dct_wadd(x7, y3o, y4o); \
+         dct_bfly32o(row0,row7, x0,x7,bias,shift); \
+         dct_bfly32o(row1,row6, x1,x6,bias,shift); \
+         dct_bfly32o(row2,row5, x2,x5,bias,shift); \
+         dct_bfly32o(row3,row4, x3,x4,bias,shift); \
+      }
+
+   __m128i rot0_0 = dct_const(stbi__f2f(0.5411961f), stbi__f2f(0.5411961f) + stbi__f2f(-1.847759065f));
+   __m128i rot0_1 = dct_const(stbi__f2f(0.5411961f) + stbi__f2f( 0.765366865f), stbi__f2f(0.5411961f));
+   __m128i rot1_0 = dct_const(stbi__f2f(1.175875602f) + stbi__f2f(-0.899976223f), stbi__f2f(1.175875602f));
+   __m128i rot1_1 = dct_const(stbi__f2f(1.175875602f), stbi__f2f(1.175875602f) + stbi__f2f(-2.562915447f));
+   __m128i rot2_0 = dct_const(stbi__f2f(-1.961570560f) + stbi__f2f( 0.298631336f), stbi__f2f(-1.961570560f));
+   __m128i rot2_1 = dct_const(stbi__f2f(-1.961570560f), stbi__f2f(-1.961570560f) + stbi__f2f( 3.072711026f));
+   __m128i rot3_0 = dct_const(stbi__f2f(-0.390180644f) + stbi__f2f( 2.053119869f), stbi__f2f(-0.390180644f));
+   __m128i rot3_1 = dct_const(stbi__f2f(-0.390180644f), stbi__f2f(-0.390180644f) + stbi__f2f( 1.501321110f));
+
+   // rounding biases in column/row passes, see stbi__idct_block for explanation.
+   __m128i bias_0 = _mm_set1_epi32(512);
+   __m128i bias_1 = _mm_set1_epi32(65536 + (128<<17));
+
+   // load
+   row0 = _mm_load_si128((const __m128i *) (data + 0*8));
+   row1 = _mm_load_si128((const __m128i *) (data + 1*8));
+   row2 = _mm_load_si128((const __m128i *) (data + 2*8));
+   row3 = _mm_load_si128((const __m128i *) (data + 3*8));
+   row4 = _mm_load_si128((const __m128i *) (data + 4*8));
+   row5 = _mm_load_si128((const __m128i *) (data + 5*8));
+   row6 = _mm_load_si128((const __m128i *) (data + 6*8));
+   row7 = _mm_load_si128((const __m128i *) (data + 7*8));
+
+   // column pass
+   dct_pass(bias_0, 10);
+
+   {
+      // 16bit 8x8 transpose pass 1
+      dct_interleave16(row0, row4);
+      dct_interleave16(row1, row5);
+      dct_interleave16(row2, row6);
+      dct_interleave16(row3, row7);
+
+      // transpose pass 2
+      dct_interleave16(row0, row2);
+      dct_interleave16(row1, row3);
+      dct_interleave16(row4, row6);
+      dct_interleave16(row5, row7);
+
+      // transpose pass 3
+      dct_interleave16(row0, row1);
+      dct_interleave16(row2, row3);
+      dct_interleave16(row4, row5);
+      dct_interleave16(row6, row7);
+   }
+
+   // row pass
+   dct_pass(bias_1, 17);
+
+   {
+      // pack
+      __m128i p0 = _mm_packus_epi16(row0, row1); // a0a1a2a3...a7b0b1b2b3...b7
+      __m128i p1 = _mm_packus_epi16(row2, row3);
+      __m128i p2 = _mm_packus_epi16(row4, row5);
+      __m128i p3 = _mm_packus_epi16(row6, row7);
+
+      // 8bit 8x8 transpose pass 1
+      dct_interleave8(p0, p2); // a0e0a1e1...
+      dct_interleave8(p1, p3); // c0g0c1g1...
+
+      // transpose pass 2
+      dct_interleave8(p0, p1); // a0c0e0g0...
+      dct_interleave8(p2, p3); // b0d0f0h0...
+
+      // transpose pass 3
+      dct_interleave8(p0, p2); // a0b0c0d0...
+      dct_interleave8(p1, p3); // a4b4c4d4...
+
+      // store
+      _mm_storel_epi64((__m128i *) out, p0); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p0, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p2); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p2, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p1); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p1, 0x4e)); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, p3); out += out_stride;
+      _mm_storel_epi64((__m128i *) out, _mm_shuffle_epi32(p3, 0x4e));
+   }
+
+#undef dct_const
+#undef dct_rot
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_interleave8
+#undef dct_interleave16
+#undef dct_pass
+}
+
+#endif // STBI_SSE2
+
+#ifdef STBI_NEON
+
+// NEON integer IDCT. should produce bit-identical
+// results to the generic C version.
+static void stbi__idct_simd(stbi_uc *out, int out_stride, short data[64])
+{
+   int16x8_t row0, row1, row2, row3, row4, row5, row6, row7;
+
+   int16x4_t rot0_0 = vdup_n_s16(stbi__f2f(0.5411961f));
+   int16x4_t rot0_1 = vdup_n_s16(stbi__f2f(-1.847759065f));
+   int16x4_t rot0_2 = vdup_n_s16(stbi__f2f( 0.765366865f));
+   int16x4_t rot1_0 = vdup_n_s16(stbi__f2f( 1.175875602f));
+   int16x4_t rot1_1 = vdup_n_s16(stbi__f2f(-0.899976223f));
+   int16x4_t rot1_2 = vdup_n_s16(stbi__f2f(-2.562915447f));
+   int16x4_t rot2_0 = vdup_n_s16(stbi__f2f(-1.961570560f));
+   int16x4_t rot2_1 = vdup_n_s16(stbi__f2f(-0.390180644f));
+   int16x4_t rot3_0 = vdup_n_s16(stbi__f2f( 0.298631336f));
+   int16x4_t rot3_1 = vdup_n_s16(stbi__f2f( 2.053119869f));
+   int16x4_t rot3_2 = vdup_n_s16(stbi__f2f( 3.072711026f));
+   int16x4_t rot3_3 = vdup_n_s16(stbi__f2f( 1.501321110f));
+
+#define dct_long_mul(out, inq, coeff) \
+   int32x4_t out##_l = vmull_s16(vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmull_s16(vget_high_s16(inq), coeff)
+
+#define dct_long_mac(out, acc, inq, coeff) \
+   int32x4_t out##_l = vmlal_s16(acc##_l, vget_low_s16(inq), coeff); \
+   int32x4_t out##_h = vmlal_s16(acc##_h, vget_high_s16(inq), coeff)
+
+#define dct_widen(out, inq) \
+   int32x4_t out##_l = vshll_n_s16(vget_low_s16(inq), 12); \
+   int32x4_t out##_h = vshll_n_s16(vget_high_s16(inq), 12)
+
+// wide add
+#define dct_wadd(out, a, b) \
+   int32x4_t out##_l = vaddq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vaddq_s32(a##_h, b##_h)
+
+// wide sub
+#define dct_wsub(out, a, b) \
+   int32x4_t out##_l = vsubq_s32(a##_l, b##_l); \
+   int32x4_t out##_h = vsubq_s32(a##_h, b##_h)
+
+// butterfly a/b, then shift using "shiftop" by "s" and pack
+#define dct_bfly32o(out0,out1, a,b,shiftop,s) \
+   { \
+      dct_wadd(sum, a, b); \
+      dct_wsub(dif, a, b); \
+      out0 = vcombine_s16(shiftop(sum_l, s), shiftop(sum_h, s)); \
+      out1 = vcombine_s16(shiftop(dif_l, s), shiftop(dif_h, s)); \
+   }
+
+#define dct_pass(shiftop, shift) \
+   { \
+      /* even part */ \
+      int16x8_t sum26 = vaddq_s16(row2, row6); \
+      dct_long_mul(p1e, sum26, rot0_0); \
+      dct_long_mac(t2e, p1e, row6, rot0_1); \
+      dct_long_mac(t3e, p1e, row2, rot0_2); \
+      int16x8_t sum04 = vaddq_s16(row0, row4); \
+      int16x8_t dif04 = vsubq_s16(row0, row4); \
+      dct_widen(t0e, sum04); \
+      dct_widen(t1e, dif04); \
+      dct_wadd(x0, t0e, t3e); \
+      dct_wsub(x3, t0e, t3e); \
+      dct_wadd(x1, t1e, t2e); \
+      dct_wsub(x2, t1e, t2e); \
+      /* odd part */ \
+      int16x8_t sum15 = vaddq_s16(row1, row5); \
+      int16x8_t sum17 = vaddq_s16(row1, row7); \
+      int16x8_t sum35 = vaddq_s16(row3, row5); \
+      int16x8_t sum37 = vaddq_s16(row3, row7); \
+      int16x8_t sumodd = vaddq_s16(sum17, sum35); \
+      dct_long_mul(p5o, sumodd, rot1_0); \
+      dct_long_mac(p1o, p5o, sum17, rot1_1); \
+      dct_long_mac(p2o, p5o, sum35, rot1_2); \
+      dct_long_mul(p3o, sum37, rot2_0); \
+      dct_long_mul(p4o, sum15, rot2_1); \
+      dct_wadd(sump13o, p1o, p3o); \
+      dct_wadd(sump24o, p2o, p4o); \
+      dct_wadd(sump23o, p2o, p3o); \
+      dct_wadd(sump14o, p1o, p4o); \
+      dct_long_mac(x4, sump13o, row7, rot3_0); \
+      dct_long_mac(x5, sump24o, row5, rot3_1); \
+      dct_long_mac(x6, sump23o, row3, rot3_2); \
+      dct_long_mac(x7, sump14o, row1, rot3_3); \
+      dct_bfly32o(row0,row7, x0,x7,shiftop,shift); \
+      dct_bfly32o(row1,row6, x1,x6,shiftop,shift); \
+      dct_bfly32o(row2,row5, x2,x5,shiftop,shift); \
+      dct_bfly32o(row3,row4, x3,x4,shiftop,shift); \
+   }
+
+   // load
+   row0 = vld1q_s16(data + 0*8);
+   row1 = vld1q_s16(data + 1*8);
+   row2 = vld1q_s16(data + 2*8);
+   row3 = vld1q_s16(data + 3*8);
+   row4 = vld1q_s16(data + 4*8);
+   row5 = vld1q_s16(data + 5*8);
+   row6 = vld1q_s16(data + 6*8);
+   row7 = vld1q_s16(data + 7*8);
+
+   // add DC bias
+   row0 = vaddq_s16(row0, vsetq_lane_s16(1024, vdupq_n_s16(0), 0));
+
+   // column pass
+   dct_pass(vrshrn_n_s32, 10);
+
+   // 16bit 8x8 transpose
+   {
+// these three map to a single VTRN.16, VTRN.32, and VSWP, respectively.
+// whether compilers actually get this is another story, sadly.
+#define dct_trn16(x, y) { int16x8x2_t t = vtrnq_s16(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn32(x, y) { int32x4x2_t t = vtrnq_s32(vreinterpretq_s32_s16(x), vreinterpretq_s32_s16(y)); x = vreinterpretq_s16_s32(t.val[0]); y = vreinterpretq_s16_s32(t.val[1]); }
+#define dct_trn64(x, y) { int16x8_t x0 = x; int16x8_t y0 = y; x = vcombine_s16(vget_low_s16(x0), vget_low_s16(y0)); y = vcombine_s16(vget_high_s16(x0), vget_high_s16(y0)); }
+
+      // pass 1
+      dct_trn16(row0, row1); // a0b0a2b2a4b4a6b6
+      dct_trn16(row2, row3);
+      dct_trn16(row4, row5);
+      dct_trn16(row6, row7);
+
+      // pass 2
+      dct_trn32(row0, row2); // a0b0c0d0a4b4c4d4
+      dct_trn32(row1, row3);
+      dct_trn32(row4, row6);
+      dct_trn32(row5, row7);
+
+      // pass 3
+      dct_trn64(row0, row4); // a0b0c0d0e0f0g0h0
+      dct_trn64(row1, row5);
+      dct_trn64(row2, row6);
+      dct_trn64(row3, row7);
+
+#undef dct_trn16
+#undef dct_trn32
+#undef dct_trn64
+   }
+
+   // row pass
+   // vrshrn_n_s32 only supports shifts up to 16, we need
+   // 17. so do a non-rounding shift of 16 first then follow
+   // up with a rounding shift by 1.
+   dct_pass(vshrn_n_s32, 16);
+
+   {
+      // pack and round
+      uint8x8_t p0 = vqrshrun_n_s16(row0, 1);
+      uint8x8_t p1 = vqrshrun_n_s16(row1, 1);
+      uint8x8_t p2 = vqrshrun_n_s16(row2, 1);
+      uint8x8_t p3 = vqrshrun_n_s16(row3, 1);
+      uint8x8_t p4 = vqrshrun_n_s16(row4, 1);
+      uint8x8_t p5 = vqrshrun_n_s16(row5, 1);
+      uint8x8_t p6 = vqrshrun_n_s16(row6, 1);
+      uint8x8_t p7 = vqrshrun_n_s16(row7, 1);
+
+      // again, these can translate into one instruction, but often don't.
+#define dct_trn8_8(x, y) { uint8x8x2_t t = vtrn_u8(x, y); x = t.val[0]; y = t.val[1]; }
+#define dct_trn8_16(x, y) { uint16x4x2_t t = vtrn_u16(vreinterpret_u16_u8(x), vreinterpret_u16_u8(y)); x = vreinterpret_u8_u16(t.val[0]); y = vreinterpret_u8_u16(t.val[1]); }
+#define dct_trn8_32(x, y) { uint32x2x2_t t = vtrn_u32(vreinterpret_u32_u8(x), vreinterpret_u32_u8(y)); x = vreinterpret_u8_u32(t.val[0]); y = vreinterpret_u8_u32(t.val[1]); }
+
+      // sadly can't use interleaved stores here since we only write
+      // 8 bytes to each scan line!
+
+      // 8x8 8-bit transpose pass 1
+      dct_trn8_8(p0, p1);
+      dct_trn8_8(p2, p3);
+      dct_trn8_8(p4, p5);
+      dct_trn8_8(p6, p7);
+
+      // pass 2
+      dct_trn8_16(p0, p2);
+      dct_trn8_16(p1, p3);
+      dct_trn8_16(p4, p6);
+      dct_trn8_16(p5, p7);
+
+      // pass 3
+      dct_trn8_32(p0, p4);
+      dct_trn8_32(p1, p5);
+      dct_trn8_32(p2, p6);
+      dct_trn8_32(p3, p7);
+
+      // store
+      vst1_u8(out, p0); out += out_stride;
+      vst1_u8(out, p1); out += out_stride;
+      vst1_u8(out, p2); out += out_stride;
+      vst1_u8(out, p3); out += out_stride;
+      vst1_u8(out, p4); out += out_stride;
+      vst1_u8(out, p5); out += out_stride;
+      vst1_u8(out, p6); out += out_stride;
+      vst1_u8(out, p7);
+
+#undef dct_trn8_8
+#undef dct_trn8_16
+#undef dct_trn8_32
+   }
+
+#undef dct_long_mul
+#undef dct_long_mac
+#undef dct_widen
+#undef dct_wadd
+#undef dct_wsub
+#undef dct_bfly32o
+#undef dct_pass
+}
+
+#endif // STBI_NEON
+
+#define STBI__MARKER_none  0xff
+// if there's a pending marker from the entropy stream, return that
+// otherwise, fetch from the stream and get a marker. if there's no
+// marker, return 0xff, which is never a valid marker value
+static stbi_uc stbi__get_marker(stbi__jpeg *j)
+{
+   stbi_uc x;
+   if (j->marker != STBI__MARKER_none) { x = j->marker; j->marker = STBI__MARKER_none; return x; }
+   x = stbi__get8(j->s);
+   if (x != 0xff) return STBI__MARKER_none;
+   while (x == 0xff)
+      x = stbi__get8(j->s);
+   return x;
+}
+
+// in each scan, we'll have scan_n components, and the order
+// of the components is specified by order[]
+#define STBI__RESTART(x)     ((x) >= 0xd0 && (x) <= 0xd7)
+
+// after a restart interval, stbi__jpeg_reset the entropy decoder and
+// the dc prediction
+static void stbi__jpeg_reset(stbi__jpeg *j)
+{
+   j->code_bits = 0;
+   j->code_buffer = 0;
+   j->nomore = 0;
+   j->img_comp[0].dc_pred = j->img_comp[1].dc_pred = j->img_comp[2].dc_pred = 0;
+   j->marker = STBI__MARKER_none;
+   j->todo = j->restart_interval ? j->restart_interval : 0x7fffffff;
+   j->eob_run = 0;
+   // no more than 1<<31 MCUs if no restart_interal? that's plenty safe,
+   // since we don't even allow 1<<30 pixels
+}
+
+static int stbi__parse_entropy_coded_data(stbi__jpeg *z)
+{
+   stbi__jpeg_reset(z);
+   if (!z->progressive) {
+      if (z->scan_n == 1) {
+         int i,j;
+         STBI_SIMD_ALIGN(short, data[64]);
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               int ha = z->img_comp[n].ha;
+               if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  // if it's NOT a restart, then just bail, so we get corrupt data
+                  // rather than no data
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         STBI_SIMD_ALIGN(short, data[64]);
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x)*8;
+                        int y2 = (j*z->img_comp[n].v + y)*8;
+                        int ha = z->img_comp[n].ha;
+                        if (!stbi__jpeg_decode_block(z, data, z->huff_dc+z->img_comp[n].hd, z->huff_ac+ha, z->fast_ac[ha], n, z->dequant[z->img_comp[n].tq])) return 0;
+                        z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*y2+x2, z->img_comp[n].w2, data);
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   } else {
+      if (z->scan_n == 1) {
+         int i,j;
+         int n = z->order[0];
+         // non-interleaved data, we just need to process one block at a time,
+         // in trivial scanline order
+         // number of blocks to do just depends on how many actual "pixels" this
+         // component has, independent of interleaved MCU blocking and such
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               if (z->spec_start == 0) {
+                  if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                     return 0;
+               } else {
+                  int ha = z->img_comp[n].ha;
+                  if (!stbi__jpeg_decode_block_prog_ac(z, data, &z->huff_ac[ha], z->fast_ac[ha]))
+                     return 0;
+               }
+               // every data block is an MCU, so countdown the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      } else { // interleaved
+         int i,j,k,x,y;
+         for (j=0; j < z->img_mcu_y; ++j) {
+            for (i=0; i < z->img_mcu_x; ++i) {
+               // scan an interleaved mcu... process scan_n components in order
+               for (k=0; k < z->scan_n; ++k) {
+                  int n = z->order[k];
+                  // scan out an mcu's worth of this component; that's just determined
+                  // by the basic H and V specified for the component
+                  for (y=0; y < z->img_comp[n].v; ++y) {
+                     for (x=0; x < z->img_comp[n].h; ++x) {
+                        int x2 = (i*z->img_comp[n].h + x);
+                        int y2 = (j*z->img_comp[n].v + y);
+                        short *data = z->img_comp[n].coeff + 64 * (x2 + y2 * z->img_comp[n].coeff_w);
+                        if (!stbi__jpeg_decode_block_prog_dc(z, data, &z->huff_dc[z->img_comp[n].hd], n))
+                           return 0;
+                     }
+                  }
+               }
+               // after all interleaved components, that's an interleaved MCU,
+               // so now count down the restart interval
+               if (--z->todo <= 0) {
+                  if (z->code_bits < 24) stbi__grow_buffer_unsafe(z);
+                  if (!STBI__RESTART(z->marker)) return 1;
+                  stbi__jpeg_reset(z);
+               }
+            }
+         }
+         return 1;
+      }
+   }
+}
+
+static void stbi__jpeg_dequantize(short *data, stbi_uc *dequant)
+{
+   int i;
+   for (i=0; i < 64; ++i)
+      data[i] *= dequant[i];
+}
+
+static void stbi__jpeg_finish(stbi__jpeg *z)
+{
+   if (z->progressive) {
+      // dequantize and idct the data
+      int i,j,n;
+      for (n=0; n < z->s->img_n; ++n) {
+         int w = (z->img_comp[n].x+7) >> 3;
+         int h = (z->img_comp[n].y+7) >> 3;
+         for (j=0; j < h; ++j) {
+            for (i=0; i < w; ++i) {
+               short *data = z->img_comp[n].coeff + 64 * (i + j * z->img_comp[n].coeff_w);
+               stbi__jpeg_dequantize(data, z->dequant[z->img_comp[n].tq]);
+               z->idct_block_kernel(z->img_comp[n].data+z->img_comp[n].w2*j*8+i*8, z->img_comp[n].w2, data);
+            }
+         }
+      }
+   }
+}
+
+static int stbi__process_marker(stbi__jpeg *z, int m)
+{
+   int L;
+   switch (m) {
+      case STBI__MARKER_none: // no marker found
+         return stbi__err("expected marker","Corrupt JPEG");
+
+      case 0xDD: // DRI - specify restart interval
+         if (stbi__get16be(z->s) != 4) return stbi__err("bad DRI len","Corrupt JPEG");
+         z->restart_interval = stbi__get16be(z->s);
+         return 1;
+
+      case 0xDB: // DQT - define quantization table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            int q = stbi__get8(z->s);
+            int p = q >> 4;
+            int t = q & 15,i;
+            if (p != 0) return stbi__err("bad DQT type","Corrupt JPEG");
+            if (t > 3) return stbi__err("bad DQT table","Corrupt JPEG");
+            for (i=0; i < 64; ++i)
+               z->dequant[t][stbi__jpeg_dezigzag[i]] = stbi__get8(z->s);
+            L -= 65;
+         }
+         return L==0;
+
+      case 0xC4: // DHT - define huffman table
+         L = stbi__get16be(z->s)-2;
+         while (L > 0) {
+            stbi_uc *v;
+            int sizes[16],i,n=0;
+            int q = stbi__get8(z->s);
+            int tc = q >> 4;
+            int th = q & 15;
+            if (tc > 1 || th > 3) return stbi__err("bad DHT header","Corrupt JPEG");
+            for (i=0; i < 16; ++i) {
+               sizes[i] = stbi__get8(z->s);
+               n += sizes[i];
+            }
+            L -= 17;
+            if (tc == 0) {
+               if (!stbi__build_huffman(z->huff_dc+th, sizes)) return 0;
+               v = z->huff_dc[th].values;
+            } else {
+               if (!stbi__build_huffman(z->huff_ac+th, sizes)) return 0;
+               v = z->huff_ac[th].values;
+            }
+            for (i=0; i < n; ++i)
+               v[i] = stbi__get8(z->s);
+            if (tc != 0)
+               stbi__build_fast_ac(z->fast_ac[th], z->huff_ac + th);
+            L -= n;
+         }
+         return L==0;
+   }
+   // check for comment block or APP blocks
+   if ((m >= 0xE0 && m <= 0xEF) || m == 0xFE) {
+      stbi__skip(z->s, stbi__get16be(z->s)-2);
+      return 1;
+   }
+   return 0;
+}
+
+// after we see SOS
+static int stbi__process_scan_header(stbi__jpeg *z)
+{
+   int i;
+   int Ls = stbi__get16be(z->s);
+   z->scan_n = stbi__get8(z->s);
+   if (z->scan_n < 1 || z->scan_n > 4 || z->scan_n > (int) z->s->img_n) return stbi__err("bad SOS component count","Corrupt JPEG");
+   if (Ls != 6+2*z->scan_n) return stbi__err("bad SOS len","Corrupt JPEG");
+   for (i=0; i < z->scan_n; ++i) {
+      int id = stbi__get8(z->s), which;
+      int q = stbi__get8(z->s);
+      for (which = 0; which < z->s->img_n; ++which)
+         if (z->img_comp[which].id == id)
+            break;
+      if (which == z->s->img_n) return 0; // no match
+      z->img_comp[which].hd = q >> 4;   if (z->img_comp[which].hd > 3) return stbi__err("bad DC huff","Corrupt JPEG");
+      z->img_comp[which].ha = q & 15;   if (z->img_comp[which].ha > 3) return stbi__err("bad AC huff","Corrupt JPEG");
+      z->order[i] = which;
+   }
+
+   {
+      int aa;
+      z->spec_start = stbi__get8(z->s);
+      z->spec_end   = stbi__get8(z->s); // should be 63, but might be 0
+      aa = stbi__get8(z->s);
+      z->succ_high = (aa >> 4);
+      z->succ_low  = (aa & 15);
+      if (z->progressive) {
+         if (z->spec_start > 63 || z->spec_end > 63  || z->spec_start > z->spec_end || z->succ_high > 13 || z->succ_low > 13)
+            return stbi__err("bad SOS", "Corrupt JPEG");
+      } else {
+         if (z->spec_start != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         if (z->succ_high != 0 || z->succ_low != 0) return stbi__err("bad SOS","Corrupt JPEG");
+         z->spec_end = 63;
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__process_frame_header(stbi__jpeg *z, int scan)
+{
+   stbi__context *s = z->s;
+   int Lf,p,i,q, h_max=1,v_max=1,c;
+   Lf = stbi__get16be(s);         if (Lf < 11) return stbi__err("bad SOF len","Corrupt JPEG"); // JPEG
+   p  = stbi__get8(s);            if (p != 8) return stbi__err("only 8-bit","JPEG format not supported: 8-bit only"); // JPEG baseline
+   s->img_y = stbi__get16be(s);   if (s->img_y == 0) return stbi__err("no header height", "JPEG format not supported: delayed height"); // Legal, but we don't handle it--but neither does IJG
+   s->img_x = stbi__get16be(s);   if (s->img_x == 0) return stbi__err("0 width","Corrupt JPEG"); // JPEG requires
+   c = stbi__get8(s);
+   if (c != 3 && c != 1) return stbi__err("bad component count","Corrupt JPEG");    // JFIF requires
+   s->img_n = c;
+   for (i=0; i < c; ++i) {
+      z->img_comp[i].data = NULL;
+      z->img_comp[i].linebuf = NULL;
+   }
+
+   if (Lf != 8+3*s->img_n) return stbi__err("bad SOF len","Corrupt JPEG");
+
+   z->rgb = 0;
+   for (i=0; i < s->img_n; ++i) {
+      static unsigned char rgb[3] = { 'R', 'G', 'B' };
+      z->img_comp[i].id = stbi__get8(s);
+      if (z->img_comp[i].id != i+1)   // JFIF requires
+         if (z->img_comp[i].id != i) {  // some version of jpegtran outputs non-JFIF-compliant files!
+            // somethings output this (see http://fileformats.archiveteam.org/wiki/JPEG#Color_format)
+            if (z->img_comp[i].id != rgb[i])
+               return stbi__err("bad component ID","Corrupt JPEG");
+            ++z->rgb;
+         }
+      q = stbi__get8(s);
+      z->img_comp[i].h = (q >> 4);  if (!z->img_comp[i].h || z->img_comp[i].h > 4) return stbi__err("bad H","Corrupt JPEG");
+      z->img_comp[i].v = q & 15;    if (!z->img_comp[i].v || z->img_comp[i].v > 4) return stbi__err("bad V","Corrupt JPEG");
+      z->img_comp[i].tq = stbi__get8(s);  if (z->img_comp[i].tq > 3) return stbi__err("bad TQ","Corrupt JPEG");
+   }
+
+   if (scan != STBI__SCAN_load) return 1;
+
+   if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+
+   for (i=0; i < s->img_n; ++i) {
+      if (z->img_comp[i].h > h_max) h_max = z->img_comp[i].h;
+      if (z->img_comp[i].v > v_max) v_max = z->img_comp[i].v;
+   }
+
+   // compute interleaved mcu info
+   z->img_h_max = h_max;
+   z->img_v_max = v_max;
+   z->img_mcu_w = h_max * 8;
+   z->img_mcu_h = v_max * 8;
+   z->img_mcu_x = (s->img_x + z->img_mcu_w-1) / z->img_mcu_w;
+   z->img_mcu_y = (s->img_y + z->img_mcu_h-1) / z->img_mcu_h;
+
+   for (i=0; i < s->img_n; ++i) {
+      // number of effective pixels (e.g. for non-interleaved MCU)
+      z->img_comp[i].x = (s->img_x * z->img_comp[i].h + h_max-1) / h_max;
+      z->img_comp[i].y = (s->img_y * z->img_comp[i].v + v_max-1) / v_max;
+      // to simplify generation, we'll allocate enough memory to decode
+      // the bogus oversized data from using interleaved MCUs and their
+      // big blocks (e.g. a 16x16 iMCU on an image of width 33); we won't
+      // discard the extra data until colorspace conversion
+      z->img_comp[i].w2 = z->img_mcu_x * z->img_comp[i].h * 8;
+      z->img_comp[i].h2 = z->img_mcu_y * z->img_comp[i].v * 8;
+      z->img_comp[i].raw_data = stbi__malloc(z->img_comp[i].w2 * z->img_comp[i].h2+15);
+
+      if (z->img_comp[i].raw_data == NULL) {
+         for(--i; i >= 0; --i) {
+            STBI_FREE(z->img_comp[i].raw_data);
+            z->img_comp[i].raw_data = NULL;
+         }
+         return stbi__err("outofmem", "Out of memory");
+      }
+      // align blocks for idct using mmx/sse
+      z->img_comp[i].data = (stbi_uc*) (((size_t) z->img_comp[i].raw_data + 15) & ~15);
+      z->img_comp[i].linebuf = NULL;
+      if (z->progressive) {
+         z->img_comp[i].coeff_w = (z->img_comp[i].w2 + 7) >> 3;
+         z->img_comp[i].coeff_h = (z->img_comp[i].h2 + 7) >> 3;
+         z->img_comp[i].raw_coeff = STBI_MALLOC(z->img_comp[i].coeff_w * z->img_comp[i].coeff_h * 64 * sizeof(short) + 15);
+         z->img_comp[i].coeff = (short*) (((size_t) z->img_comp[i].raw_coeff + 15) & ~15);
+      } else {
+         z->img_comp[i].coeff = 0;
+         z->img_comp[i].raw_coeff = 0;
+      }
+   }
+
+   return 1;
+}
+
+// use comparisons since in some cases we handle more than one case (e.g. SOF)
+#define stbi__DNL(x)         ((x) == 0xdc)
+#define stbi__SOI(x)         ((x) == 0xd8)
+#define stbi__EOI(x)         ((x) == 0xd9)
+#define stbi__SOF(x)         ((x) == 0xc0 || (x) == 0xc1 || (x) == 0xc2)
+#define stbi__SOS(x)         ((x) == 0xda)
+
+#define stbi__SOF_progressive(x)   ((x) == 0xc2)
+
+static int stbi__decode_jpeg_header(stbi__jpeg *z, int scan)
+{
+   int m;
+   z->marker = STBI__MARKER_none; // initialize cached marker to empty
+   m = stbi__get_marker(z);
+   if (!stbi__SOI(m)) return stbi__err("no SOI","Corrupt JPEG");
+   if (scan == STBI__SCAN_type) return 1;
+   m = stbi__get_marker(z);
+   while (!stbi__SOF(m)) {
+      if (!stbi__process_marker(z,m)) return 0;
+      m = stbi__get_marker(z);
+      while (m == STBI__MARKER_none) {
+         // some files have extra padding after their blocks, so ok, we'll scan
+         if (stbi__at_eof(z->s)) return stbi__err("no SOF", "Corrupt JPEG");
+         m = stbi__get_marker(z);
+      }
+   }
+   z->progressive = stbi__SOF_progressive(m);
+   if (!stbi__process_frame_header(z, scan)) return 0;
+   return 1;
+}
+
+// decode image to YCbCr format
+static int stbi__decode_jpeg_image(stbi__jpeg *j)
+{
+   int m;
+   for (m = 0; m < 4; m++) {
+      j->img_comp[m].raw_data = NULL;
+      j->img_comp[m].raw_coeff = NULL;
+   }
+   j->restart_interval = 0;
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_load)) return 0;
+   m = stbi__get_marker(j);
+   while (!stbi__EOI(m)) {
+      if (stbi__SOS(m)) {
+         if (!stbi__process_scan_header(j)) return 0;
+         if (!stbi__parse_entropy_coded_data(j)) return 0;
+         if (j->marker == STBI__MARKER_none ) {
+            // handle 0s at the end of image data from IP Kamera 9060
+            while (!stbi__at_eof(j->s)) {
+               int x = stbi__get8(j->s);
+               if (x == 255) {
+                  j->marker = stbi__get8(j->s);
+                  break;
+               } else if (x != 0) {
+                  return stbi__err("junk before marker", "Corrupt JPEG");
+               }
+            }
+            // if we reach eof without hitting a marker, stbi__get_marker() below will fail and we'll eventually return 0
+         }
+      } else {
+         if (!stbi__process_marker(j, m)) return 0;
+      }
+      m = stbi__get_marker(j);
+   }
+   if (j->progressive)
+      stbi__jpeg_finish(j);
+   return 1;
+}
+
+// static jfif-centered resampling (across block boundaries)
+
+typedef stbi_uc *(*resample_row_func)(stbi_uc *out, stbi_uc *in0, stbi_uc *in1,
+                                    int w, int hs);
+
+#define stbi__div4(x) ((stbi_uc) ((x) >> 2))
+
+static stbi_uc *resample_row_1(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   STBI_NOTUSED(out);
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(w);
+   STBI_NOTUSED(hs);
+   return in_near;
+}
+
+static stbi_uc* stbi__resample_row_v_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples vertically for every one in input
+   int i;
+   STBI_NOTUSED(hs);
+   for (i=0; i < w; ++i)
+      out[i] = stbi__div4(3*in_near[i] + in_far[i] + 2);
+   return out;
+}
+
+static stbi_uc*  stbi__resample_row_h_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate two samples horizontally for every one in input
+   int i;
+   stbi_uc *input = in_near;
+
+   if (w == 1) {
+      // if only one sample, can't do any interpolation
+      out[0] = out[1] = input[0];
+      return out;
+   }
+
+   out[0] = input[0];
+   out[1] = stbi__div4(input[0]*3 + input[1] + 2);
+   for (i=1; i < w-1; ++i) {
+      int n = 3*input[i]+2;
+      out[i*2+0] = stbi__div4(n+input[i-1]);
+      out[i*2+1] = stbi__div4(n+input[i+1]);
+   }
+   out[i*2+0] = stbi__div4(input[w-2]*3 + input[w-1] + 2);
+   out[i*2+1] = input[w-1];
+
+   STBI_NOTUSED(in_far);
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#define stbi__div16(x) ((stbi_uc) ((x) >> 4))
+
+static stbi_uc *stbi__resample_row_hv_2(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i,t0,t1;
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   out[0] = stbi__div4(t1+2);
+   for (i=1; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static stbi_uc *stbi__resample_row_hv_2_simd(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // need to generate 2x2 samples for every one in input
+   int i=0,t0,t1;
+
+   if (w == 1) {
+      out[0] = out[1] = stbi__div4(3*in_near[0] + in_far[0] + 2);
+      return out;
+   }
+
+   t1 = 3*in_near[0] + in_far[0];
+   // process groups of 8 pixels for as long as we can.
+   // note we can't handle the last pixel in a row in this loop
+   // because we need to handle the filter boundary conditions.
+   for (; i < ((w-1) & ~7); i += 8) {
+#if defined(STBI_SSE2)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      __m128i zero  = _mm_setzero_si128();
+      __m128i farb  = _mm_loadl_epi64((__m128i *) (in_far + i));
+      __m128i nearb = _mm_loadl_epi64((__m128i *) (in_near + i));
+      __m128i farw  = _mm_unpacklo_epi8(farb, zero);
+      __m128i nearw = _mm_unpacklo_epi8(nearb, zero);
+      __m128i diff  = _mm_sub_epi16(farw, nearw);
+      __m128i nears = _mm_slli_epi16(nearw, 2);
+      __m128i curr  = _mm_add_epi16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      __m128i prv0 = _mm_slli_si128(curr, 2);
+      __m128i nxt0 = _mm_srli_si128(curr, 2);
+      __m128i prev = _mm_insert_epi16(prv0, t1, 0);
+      __m128i next = _mm_insert_epi16(nxt0, 3*in_near[i+8] + in_far[i+8], 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      __m128i bias  = _mm_set1_epi16(8);
+      __m128i curs = _mm_slli_epi16(curr, 2);
+      __m128i prvd = _mm_sub_epi16(prev, curr);
+      __m128i nxtd = _mm_sub_epi16(next, curr);
+      __m128i curb = _mm_add_epi16(curs, bias);
+      __m128i even = _mm_add_epi16(prvd, curb);
+      __m128i odd  = _mm_add_epi16(nxtd, curb);
+
+      // interleave even and odd pixels, then undo scaling.
+      __m128i int0 = _mm_unpacklo_epi16(even, odd);
+      __m128i int1 = _mm_unpackhi_epi16(even, odd);
+      __m128i de0  = _mm_srli_epi16(int0, 4);
+      __m128i de1  = _mm_srli_epi16(int1, 4);
+
+      // pack and write output
+      __m128i outv = _mm_packus_epi16(de0, de1);
+      _mm_storeu_si128((__m128i *) (out + i*2), outv);
+#elif defined(STBI_NEON)
+      // load and perform the vertical filtering pass
+      // this uses 3*x + y = 4*x + (y - x)
+      uint8x8_t farb  = vld1_u8(in_far + i);
+      uint8x8_t nearb = vld1_u8(in_near + i);
+      int16x8_t diff  = vreinterpretq_s16_u16(vsubl_u8(farb, nearb));
+      int16x8_t nears = vreinterpretq_s16_u16(vshll_n_u8(nearb, 2));
+      int16x8_t curr  = vaddq_s16(nears, diff); // current row
+
+      // horizontal filter works the same based on shifted vers of current
+      // row. "prev" is current row shifted right by 1 pixel; we need to
+      // insert the previous pixel value (from t1).
+      // "next" is current row shifted left by 1 pixel, with first pixel
+      // of next block of 8 pixels added in.
+      int16x8_t prv0 = vextq_s16(curr, curr, 7);
+      int16x8_t nxt0 = vextq_s16(curr, curr, 1);
+      int16x8_t prev = vsetq_lane_s16(t1, prv0, 0);
+      int16x8_t next = vsetq_lane_s16(3*in_near[i+8] + in_far[i+8], nxt0, 7);
+
+      // horizontal filter, polyphase implementation since it's convenient:
+      // even pixels = 3*cur + prev = cur*4 + (prev - cur)
+      // odd  pixels = 3*cur + next = cur*4 + (next - cur)
+      // note the shared term.
+      int16x8_t curs = vshlq_n_s16(curr, 2);
+      int16x8_t prvd = vsubq_s16(prev, curr);
+      int16x8_t nxtd = vsubq_s16(next, curr);
+      int16x8_t even = vaddq_s16(curs, prvd);
+      int16x8_t odd  = vaddq_s16(curs, nxtd);
+
+      // undo scaling and round, then store with even/odd phases interleaved
+      uint8x8x2_t o;
+      o.val[0] = vqrshrun_n_s16(even, 4);
+      o.val[1] = vqrshrun_n_s16(odd,  4);
+      vst2_u8(out + i*2, o);
+#endif
+
+      // "previous" value for next iter
+      t1 = 3*in_near[i+7] + in_far[i+7];
+   }
+
+   t0 = t1;
+   t1 = 3*in_near[i] + in_far[i];
+   out[i*2] = stbi__div16(3*t1 + t0 + 8);
+
+   for (++i; i < w; ++i) {
+      t0 = t1;
+      t1 = 3*in_near[i]+in_far[i];
+      out[i*2-1] = stbi__div16(3*t0 + t1 + 8);
+      out[i*2  ] = stbi__div16(3*t1 + t0 + 8);
+   }
+   out[w*2-1] = stbi__div4(t1+2);
+
+   STBI_NOTUSED(hs);
+
+   return out;
+}
+#endif
+
+static stbi_uc *stbi__resample_row_generic(stbi_uc *out, stbi_uc *in_near, stbi_uc *in_far, int w, int hs)
+{
+   // resample with nearest-neighbor
+   int i,j;
+   STBI_NOTUSED(in_far);
+   for (i=0; i < w; ++i)
+      for (j=0; j < hs; ++j)
+         out[i*hs+j] = in_near[i];
+   return out;
+}
+
+#ifdef STBI_JPEG_OLD
+// this is the same YCbCr-to-RGB calculation that stb_image has used
+// historically before the algorithm changes in 1.49
+#define float2fixed(x)  ((int) ((x) * 65536 + 0.5))
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 16) + 32768; // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr*float2fixed(1.40200f);
+      g = y_fixed - cr*float2fixed(0.71414f) - cb*float2fixed(0.34414f);
+      b = y_fixed                            + cb*float2fixed(1.77200f);
+      r >>= 16;
+      g >>= 16;
+      b >>= 16;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#else
+// this is a reduced-precision calculation of YCbCr-to-RGB introduced
+// to make sure the code produces the same results in both SIMD and scalar
+#define float2fixed(x)  (((int) ((x) * 4096.0f + 0.5f)) << 8)
+static void stbi__YCbCr_to_RGB_row(stbi_uc *out, const stbi_uc *y, const stbi_uc *pcb, const stbi_uc *pcr, int count, int step)
+{
+   int i;
+   for (i=0; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed +  cr* float2fixed(1.40200f);
+      g = y_fixed + (cr*-float2fixed(0.71414f)) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                               +   cb* float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+#if defined(STBI_SSE2) || defined(STBI_NEON)
+static void stbi__YCbCr_to_RGB_simd(stbi_uc *out, stbi_uc const *y, stbi_uc const *pcb, stbi_uc const *pcr, int count, int step)
+{
+   int i = 0;
+
+#ifdef STBI_SSE2
+   // step == 3 is pretty ugly on the final interleave, and i'm not convinced
+   // it's useful in practice (you wouldn't use it for textures, for example).
+   // so just accelerate step == 4 case.
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      __m128i signflip  = _mm_set1_epi8(-0x80);
+      __m128i cr_const0 = _mm_set1_epi16(   (short) ( 1.40200f*4096.0f+0.5f));
+      __m128i cr_const1 = _mm_set1_epi16( - (short) ( 0.71414f*4096.0f+0.5f));
+      __m128i cb_const0 = _mm_set1_epi16( - (short) ( 0.34414f*4096.0f+0.5f));
+      __m128i cb_const1 = _mm_set1_epi16(   (short) ( 1.77200f*4096.0f+0.5f));
+      __m128i y_bias = _mm_set1_epi8((char) (unsigned char) 128);
+      __m128i xw = _mm_set1_epi16(255); // alpha channel
+
+      for (; i+7 < count; i += 8) {
+         // load
+         __m128i y_bytes = _mm_loadl_epi64((__m128i *) (y+i));
+         __m128i cr_bytes = _mm_loadl_epi64((__m128i *) (pcr+i));
+         __m128i cb_bytes = _mm_loadl_epi64((__m128i *) (pcb+i));
+         __m128i cr_biased = _mm_xor_si128(cr_bytes, signflip); // -128
+         __m128i cb_biased = _mm_xor_si128(cb_bytes, signflip); // -128
+
+         // unpack to short (and left-shift cr, cb by 8)
+         __m128i yw  = _mm_unpacklo_epi8(y_bias, y_bytes);
+         __m128i crw = _mm_unpacklo_epi8(_mm_setzero_si128(), cr_biased);
+         __m128i cbw = _mm_unpacklo_epi8(_mm_setzero_si128(), cb_biased);
+
+         // color transform
+         __m128i yws = _mm_srli_epi16(yw, 4);
+         __m128i cr0 = _mm_mulhi_epi16(cr_const0, crw);
+         __m128i cb0 = _mm_mulhi_epi16(cb_const0, cbw);
+         __m128i cb1 = _mm_mulhi_epi16(cbw, cb_const1);
+         __m128i cr1 = _mm_mulhi_epi16(crw, cr_const1);
+         __m128i rws = _mm_add_epi16(cr0, yws);
+         __m128i gwt = _mm_add_epi16(cb0, yws);
+         __m128i bws = _mm_add_epi16(yws, cb1);
+         __m128i gws = _mm_add_epi16(gwt, cr1);
+
+         // descale
+         __m128i rw = _mm_srai_epi16(rws, 4);
+         __m128i bw = _mm_srai_epi16(bws, 4);
+         __m128i gw = _mm_srai_epi16(gws, 4);
+
+         // back to byte, set up for transpose
+         __m128i brb = _mm_packus_epi16(rw, bw);
+         __m128i gxb = _mm_packus_epi16(gw, xw);
+
+         // transpose to interleave channels
+         __m128i t0 = _mm_unpacklo_epi8(brb, gxb);
+         __m128i t1 = _mm_unpackhi_epi8(brb, gxb);
+         __m128i o0 = _mm_unpacklo_epi16(t0, t1);
+         __m128i o1 = _mm_unpackhi_epi16(t0, t1);
+
+         // store
+         _mm_storeu_si128((__m128i *) (out + 0), o0);
+         _mm_storeu_si128((__m128i *) (out + 16), o1);
+         out += 32;
+      }
+   }
+#endif
+
+#ifdef STBI_NEON
+   // in this version, step=3 support would be easy to add. but is there demand?
+   if (step == 4) {
+      // this is a fairly straightforward implementation and not super-optimized.
+      uint8x8_t signflip = vdup_n_u8(0x80);
+      int16x8_t cr_const0 = vdupq_n_s16(   (short) ( 1.40200f*4096.0f+0.5f));
+      int16x8_t cr_const1 = vdupq_n_s16( - (short) ( 0.71414f*4096.0f+0.5f));
+      int16x8_t cb_const0 = vdupq_n_s16( - (short) ( 0.34414f*4096.0f+0.5f));
+      int16x8_t cb_const1 = vdupq_n_s16(   (short) ( 1.77200f*4096.0f+0.5f));
+
+      for (; i+7 < count; i += 8) {
+         // load
+         uint8x8_t y_bytes  = vld1_u8(y + i);
+         uint8x8_t cr_bytes = vld1_u8(pcr + i);
+         uint8x8_t cb_bytes = vld1_u8(pcb + i);
+         int8x8_t cr_biased = vreinterpret_s8_u8(vsub_u8(cr_bytes, signflip));
+         int8x8_t cb_biased = vreinterpret_s8_u8(vsub_u8(cb_bytes, signflip));
+
+         // expand to s16
+         int16x8_t yws = vreinterpretq_s16_u16(vshll_n_u8(y_bytes, 4));
+         int16x8_t crw = vshll_n_s8(cr_biased, 7);
+         int16x8_t cbw = vshll_n_s8(cb_biased, 7);
+
+         // color transform
+         int16x8_t cr0 = vqdmulhq_s16(crw, cr_const0);
+         int16x8_t cb0 = vqdmulhq_s16(cbw, cb_const0);
+         int16x8_t cr1 = vqdmulhq_s16(crw, cr_const1);
+         int16x8_t cb1 = vqdmulhq_s16(cbw, cb_const1);
+         int16x8_t rws = vaddq_s16(yws, cr0);
+         int16x8_t gws = vaddq_s16(vaddq_s16(yws, cb0), cr1);
+         int16x8_t bws = vaddq_s16(yws, cb1);
+
+         // undo scaling, round, convert to byte
+         uint8x8x4_t o;
+         o.val[0] = vqrshrun_n_s16(rws, 4);
+         o.val[1] = vqrshrun_n_s16(gws, 4);
+         o.val[2] = vqrshrun_n_s16(bws, 4);
+         o.val[3] = vdup_n_u8(255);
+
+         // store, interleaving r/g/b/a
+         vst4_u8(out, o);
+         out += 8*4;
+      }
+   }
+#endif
+
+   for (; i < count; ++i) {
+      int y_fixed = (y[i] << 20) + (1<<19); // rounding
+      int r,g,b;
+      int cr = pcr[i] - 128;
+      int cb = pcb[i] - 128;
+      r = y_fixed + cr* float2fixed(1.40200f);
+      g = y_fixed + cr*-float2fixed(0.71414f) + ((cb*-float2fixed(0.34414f)) & 0xffff0000);
+      b = y_fixed                             +   cb* float2fixed(1.77200f);
+      r >>= 20;
+      g >>= 20;
+      b >>= 20;
+      if ((unsigned) r > 255) { if (r < 0) r = 0; else r = 255; }
+      if ((unsigned) g > 255) { if (g < 0) g = 0; else g = 255; }
+      if ((unsigned) b > 255) { if (b < 0) b = 0; else b = 255; }
+      out[0] = (stbi_uc)r;
+      out[1] = (stbi_uc)g;
+      out[2] = (stbi_uc)b;
+      out[3] = 255;
+      out += step;
+   }
+}
+#endif
+
+// set up the kernels
+static void stbi__setup_jpeg(stbi__jpeg *j)
+{
+   j->idct_block_kernel = stbi__idct_block;
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_row;
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2;
+
+#ifdef STBI_SSE2
+   if (stbi__sse2_available()) {
+      j->idct_block_kernel = stbi__idct_simd;
+      #ifndef STBI_JPEG_OLD
+      j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+      #endif
+      j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+   }
+#endif
+
+#ifdef STBI_NEON
+   j->idct_block_kernel = stbi__idct_simd;
+   #ifndef STBI_JPEG_OLD
+   j->YCbCr_to_RGB_kernel = stbi__YCbCr_to_RGB_simd;
+   #endif
+   j->resample_row_hv_2_kernel = stbi__resample_row_hv_2_simd;
+#endif
+}
+
+// clean up the temporary component buffers
+static void stbi__cleanup_jpeg(stbi__jpeg *j)
+{
+   int i;
+   for (i=0; i < j->s->img_n; ++i) {
+      if (j->img_comp[i].raw_data) {
+         STBI_FREE(j->img_comp[i].raw_data);
+         j->img_comp[i].raw_data = NULL;
+         j->img_comp[i].data = NULL;
+      }
+      if (j->img_comp[i].raw_coeff) {
+         STBI_FREE(j->img_comp[i].raw_coeff);
+         j->img_comp[i].raw_coeff = 0;
+         j->img_comp[i].coeff = 0;
+      }
+      if (j->img_comp[i].linebuf) {
+         STBI_FREE(j->img_comp[i].linebuf);
+         j->img_comp[i].linebuf = NULL;
+      }
+   }
+}
+
+typedef struct
+{
+   resample_row_func resample;
+   stbi_uc *line0,*line1;
+   int hs,vs;   // expansion factor in each axis
+   int w_lores; // horizontal pixels pre-expansion
+   int ystep;   // how far through vertical expansion we are
+   int ypos;    // which pre-expansion row we're on
+} stbi__resample;
+
+static stbi_uc *load_jpeg_image(stbi__jpeg *z, int *out_x, int *out_y, int *comp, int req_comp)
+{
+   int n, decode_n;
+   z->s->img_n = 0; // make stbi__cleanup_jpeg safe
+
+   // validate req_comp
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+
+   // load a jpeg image from whichever source, but leave in YCbCr format
+   if (!stbi__decode_jpeg_image(z)) { stbi__cleanup_jpeg(z); return NULL; }
+
+   // determine actual number of components to generate
+   n = req_comp ? req_comp : z->s->img_n;
+
+   if (z->s->img_n == 3 && n < 3)
+      decode_n = 1;
+   else
+      decode_n = z->s->img_n;
+
+   // resample and color-convert
+   {
+      int k;
+      unsigned int i,j;
+      stbi_uc *output;
+      stbi_uc *coutput[4];
+
+      stbi__resample res_comp[4];
+
+      for (k=0; k < decode_n; ++k) {
+         stbi__resample *r = &res_comp[k];
+
+         // allocate line buffer big enough for upsampling off the edges
+         // with upsample factor of 4
+         z->img_comp[k].linebuf = (stbi_uc *) stbi__malloc(z->s->img_x + 3);
+         if (!z->img_comp[k].linebuf) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+         r->hs      = z->img_h_max / z->img_comp[k].h;
+         r->vs      = z->img_v_max / z->img_comp[k].v;
+         r->ystep   = r->vs >> 1;
+         r->w_lores = (z->s->img_x + r->hs-1) / r->hs;
+         r->ypos    = 0;
+         r->line0   = r->line1 = z->img_comp[k].data;
+
+         if      (r->hs == 1 && r->vs == 1) r->resample = resample_row_1;
+         else if (r->hs == 1 && r->vs == 2) r->resample = stbi__resample_row_v_2;
+         else if (r->hs == 2 && r->vs == 1) r->resample = stbi__resample_row_h_2;
+         else if (r->hs == 2 && r->vs == 2) r->resample = z->resample_row_hv_2_kernel;
+         else                               r->resample = stbi__resample_row_generic;
+      }
+
+      // can't error after this so, this is safe
+      output = (stbi_uc *) stbi__malloc(n * z->s->img_x * z->s->img_y + 1);
+      if (!output) { stbi__cleanup_jpeg(z); return stbi__errpuc("outofmem", "Out of memory"); }
+
+      // now go ahead and resample
+      for (j=0; j < z->s->img_y; ++j) {
+         stbi_uc *out = output + n * z->s->img_x * j;
+         for (k=0; k < decode_n; ++k) {
+            stbi__resample *r = &res_comp[k];
+            int y_bot = r->ystep >= (r->vs >> 1);
+            coutput[k] = r->resample(z->img_comp[k].linebuf,
+                                     y_bot ? r->line1 : r->line0,
+                                     y_bot ? r->line0 : r->line1,
+                                     r->w_lores, r->hs);
+            if (++r->ystep >= r->vs) {
+               r->ystep = 0;
+               r->line0 = r->line1;
+               if (++r->ypos < z->img_comp[k].y)
+                  r->line1 += z->img_comp[k].w2;
+            }
+         }
+         if (n >= 3) {
+            stbi_uc *y = coutput[0];
+            if (z->s->img_n == 3) {
+               if (z->rgb == 3) {
+                  for (i=0; i < z->s->img_x; ++i) {
+                     out[0] = y[i];
+                     out[1] = coutput[1][i];
+                     out[2] = coutput[2][i];
+                     out[3] = 255;
+                     out += n;
+                  }
+               } else {
+                  z->YCbCr_to_RGB_kernel(out, y, coutput[1], coutput[2], z->s->img_x, n);
+               }
+            } else
+               for (i=0; i < z->s->img_x; ++i) {
+                  out[0] = out[1] = out[2] = y[i];
+                  out[3] = 255; // not used if n==3
+                  out += n;
+               }
+         } else {
+            stbi_uc *y = coutput[0];
+            if (n == 1)
+               for (i=0; i < z->s->img_x; ++i) out[i] = y[i];
+            else
+               for (i=0; i < z->s->img_x; ++i) *out++ = y[i], *out++ = 255;
+         }
+      }
+      stbi__cleanup_jpeg(z);
+      *out_x = z->s->img_x;
+      *out_y = z->s->img_y;
+      if (comp) *comp  = z->s->img_n; // report original components, not output
+      return output;
+   }
+}
+
+static unsigned char *stbi__jpeg_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   unsigned char* result;
+   stbi__jpeg* j = (stbi__jpeg*) stbi__malloc(sizeof(stbi__jpeg));
+   j->s = s;
+   stbi__setup_jpeg(j);
+   result = load_jpeg_image(j, x,y,comp,req_comp);
+   STBI_FREE(j);
+   return result;
+}
+
+static int stbi__jpeg_test(stbi__context *s)
+{
+   int r;
+   stbi__jpeg j;
+   j.s = s;
+   stbi__setup_jpeg(&j);
+   r = stbi__decode_jpeg_header(&j, STBI__SCAN_type);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__jpeg_info_raw(stbi__jpeg *j, int *x, int *y, int *comp)
+{
+   if (!stbi__decode_jpeg_header(j, STBI__SCAN_header)) {
+      stbi__rewind( j->s );
+      return 0;
+   }
+   if (x) *x = j->s->img_x;
+   if (y) *y = j->s->img_y;
+   if (comp) *comp = j->s->img_n;
+   return 1;
+}
+
+static int stbi__jpeg_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int result;
+   stbi__jpeg* j = (stbi__jpeg*) (stbi__malloc(sizeof(stbi__jpeg)));
+   j->s = s;
+   result = stbi__jpeg_info_raw(j, x, y, comp);
+   STBI_FREE(j);
+   return result;
+}
+#endif
+
+// public domain zlib decode    v0.2  Sean Barrett 2006-11-18
+//    simple implementation
+//      - all input must be provided in an upfront buffer
+//      - all output is written to a single output buffer (can malloc/realloc)
+//    performance
+//      - fast huffman
+
+#ifndef STBI_NO_ZLIB
+
+// fast-way is faster to check than jpeg huffman, but slow way is slower
+#define STBI__ZFAST_BITS  9 // accelerate all cases in default tables
+#define STBI__ZFAST_MASK  ((1 << STBI__ZFAST_BITS) - 1)
+
+// zlib-style huffman encoding
+// (jpegs packs from left, zlib from right, so can't share code)
+typedef struct
+{
+   stbi__uint16 fast[1 << STBI__ZFAST_BITS];
+   stbi__uint16 firstcode[16];
+   int maxcode[17];
+   stbi__uint16 firstsymbol[16];
+   stbi_uc  size[288];
+   stbi__uint16 value[288];
+} stbi__zhuffman;
+
+stbi_inline static int stbi__bitreverse16(int n)
+{
+  n = ((n & 0xAAAA) >>  1) | ((n & 0x5555) << 1);
+  n = ((n & 0xCCCC) >>  2) | ((n & 0x3333) << 2);
+  n = ((n & 0xF0F0) >>  4) | ((n & 0x0F0F) << 4);
+  n = ((n & 0xFF00) >>  8) | ((n & 0x00FF) << 8);
+  return n;
+}
+
+stbi_inline static int stbi__bit_reverse(int v, int bits)
+{
+   STBI_ASSERT(bits <= 16);
+   // to bit reverse n bits, reverse 16 and shift
+   // e.g. 11 bits, bit reverse and shift away 5
+   return stbi__bitreverse16(v) >> (16-bits);
+}
+
+static int stbi__zbuild_huffman(stbi__zhuffman *z, stbi_uc *sizelist, int num)
+{
+   int i,k=0;
+   int code, next_code[16], sizes[17];
+
+   // DEFLATE spec for generating codes
+   memset(sizes, 0, sizeof(sizes));
+   memset(z->fast, 0, sizeof(z->fast));
+   for (i=0; i < num; ++i)
+      ++sizes[sizelist[i]];
+   sizes[0] = 0;
+   for (i=1; i < 16; ++i)
+      if (sizes[i] > (1 << i))
+         return stbi__err("bad sizes", "Corrupt PNG");
+   code = 0;
+   for (i=1; i < 16; ++i) {
+      next_code[i] = code;
+      z->firstcode[i] = (stbi__uint16) code;
+      z->firstsymbol[i] = (stbi__uint16) k;
+      code = (code + sizes[i]);
+      if (sizes[i])
+         if (code-1 >= (1 << i)) return stbi__err("bad codelengths","Corrupt PNG");
+      z->maxcode[i] = code << (16-i); // preshift for inner loop
+      code <<= 1;
+      k += sizes[i];
+   }
+   z->maxcode[16] = 0x10000; // sentinel
+   for (i=0; i < num; ++i) {
+      int s = sizelist[i];
+      if (s) {
+         int c = next_code[s] - z->firstcode[s] + z->firstsymbol[s];
+         stbi__uint16 fastv = (stbi__uint16) ((s << 9) | i);
+         z->size [c] = (stbi_uc     ) s;
+         z->value[c] = (stbi__uint16) i;
+         if (s <= STBI__ZFAST_BITS) {
+            int j = stbi__bit_reverse(next_code[s],s);
+            while (j < (1 << STBI__ZFAST_BITS)) {
+               z->fast[j] = fastv;
+               j += (1 << s);
+            }
+         }
+         ++next_code[s];
+      }
+   }
+   return 1;
+}
+
+// zlib-from-memory implementation for PNG reading
+//    because PNG allows splitting the zlib stream arbitrarily,
+//    and it's annoying structurally to have PNG call ZLIB call PNG,
+//    we require PNG read all the IDATs and combine them into a single
+//    memory buffer
+
+typedef struct
+{
+   stbi_uc *zbuffer, *zbuffer_end;
+   int num_bits;
+   stbi__uint32 code_buffer;
+
+   char *zout;
+   char *zout_start;
+   char *zout_end;
+   int   z_expandable;
+
+   stbi__zhuffman z_length, z_distance;
+} stbi__zbuf;
+
+stbi_inline static stbi_uc stbi__zget8(stbi__zbuf *z)
+{
+   if (z->zbuffer >= z->zbuffer_end) return 0;
+   return *z->zbuffer++;
+}
+
+static void stbi__fill_bits(stbi__zbuf *z)
+{
+   do {
+      STBI_ASSERT(z->code_buffer < (1U << z->num_bits));
+      z->code_buffer |= (unsigned int) stbi__zget8(z) << z->num_bits;
+      z->num_bits += 8;
+   } while (z->num_bits <= 24);
+}
+
+stbi_inline static unsigned int stbi__zreceive(stbi__zbuf *z, int n)
+{
+   unsigned int k;
+   if (z->num_bits < n) stbi__fill_bits(z);
+   k = z->code_buffer & ((1 << n) - 1);
+   z->code_buffer >>= n;
+   z->num_bits -= n;
+   return k;
+}
+
+static int stbi__zhuffman_decode_slowpath(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s,k;
+   // not resolved by fast table, so compute it the slow way
+   // use jpeg approach, which requires MSbits at top
+   k = stbi__bit_reverse(a->code_buffer, 16);
+   for (s=STBI__ZFAST_BITS+1; ; ++s)
+      if (k < z->maxcode[s])
+         break;
+   if (s == 16) return -1; // invalid code!
+   // code size is s, so:
+   b = (k >> (16-s)) - z->firstcode[s] + z->firstsymbol[s];
+   STBI_ASSERT(z->size[b] == s);
+   a->code_buffer >>= s;
+   a->num_bits -= s;
+   return z->value[b];
+}
+
+stbi_inline static int stbi__zhuffman_decode(stbi__zbuf *a, stbi__zhuffman *z)
+{
+   int b,s;
+   if (a->num_bits < 16) stbi__fill_bits(a);
+   b = z->fast[a->code_buffer & STBI__ZFAST_MASK];
+   if (b) {
+      s = b >> 9;
+      a->code_buffer >>= s;
+      a->num_bits -= s;
+      return b & 511;
+   }
+   return stbi__zhuffman_decode_slowpath(a, z);
+}
+
+static int stbi__zexpand(stbi__zbuf *z, char *zout, int n)  // need to make room for n bytes
+{
+   char *q;
+   int cur, limit, old_limit;
+   z->zout = zout;
+   if (!z->z_expandable) return stbi__err("output buffer limit","Corrupt PNG");
+   cur   = (int) (z->zout     - z->zout_start);
+   limit = old_limit = (int) (z->zout_end - z->zout_start);
+   while (cur + n > limit)
+      limit *= 2;
+   q = (char *) STBI_REALLOC_SIZED(z->zout_start, old_limit, limit);
+   STBI_NOTUSED(old_limit);
+   if (q == NULL) return stbi__err("outofmem", "Out of memory");
+   z->zout_start = q;
+   z->zout       = q + cur;
+   z->zout_end   = q + limit;
+   return 1;
+}
+
+static int stbi__zlength_base[31] = {
+   3,4,5,6,7,8,9,10,11,13,
+   15,17,19,23,27,31,35,43,51,59,
+   67,83,99,115,131,163,195,227,258,0,0 };
+
+static int stbi__zlength_extra[31]=
+{ 0,0,0,0,0,0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,0,0,0 };
+
+static int stbi__zdist_base[32] = { 1,2,3,4,5,7,9,13,17,25,33,49,65,97,129,193,
+257,385,513,769,1025,1537,2049,3073,4097,6145,8193,12289,16385,24577,0,0};
+
+static int stbi__zdist_extra[32] =
+{ 0,0,0,0,1,1,2,2,3,3,4,4,5,5,6,6,7,7,8,8,9,9,10,10,11,11,12,12,13,13};
+
+static int stbi__parse_huffman_block(stbi__zbuf *a)
+{
+   char *zout = a->zout;
+   for(;;) {
+      int z = stbi__zhuffman_decode(a, &a->z_length);
+      if (z < 256) {
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG"); // error in huffman codes
+         if (zout >= a->zout_end) {
+            if (!stbi__zexpand(a, zout, 1)) return 0;
+            zout = a->zout;
+         }
+         *zout++ = (char) z;
+      } else {
+         stbi_uc *p;
+         int len,dist;
+         if (z == 256) {
+            a->zout = zout;
+            return 1;
+         }
+         z -= 257;
+         len = stbi__zlength_base[z];
+         if (stbi__zlength_extra[z]) len += stbi__zreceive(a, stbi__zlength_extra[z]);
+         z = stbi__zhuffman_decode(a, &a->z_distance);
+         if (z < 0) return stbi__err("bad huffman code","Corrupt PNG");
+         dist = stbi__zdist_base[z];
+         if (stbi__zdist_extra[z]) dist += stbi__zreceive(a, stbi__zdist_extra[z]);
+         if (zout - a->zout_start < dist) return stbi__err("bad dist","Corrupt PNG");
+         if (zout + len > a->zout_end) {
+            if (!stbi__zexpand(a, zout, len)) return 0;
+            zout = a->zout;
+         }
+         p = (stbi_uc *) (zout - dist);
+         if (dist == 1) { // run of one byte; common in images.
+            stbi_uc v = *p;
+            if (len) { do *zout++ = v; while (--len); }
+         } else {
+            if (len) { do *zout++ = *p++; while (--len); }
+         }
+      }
+   }
+}
+
+static int stbi__compute_huffman_codes(stbi__zbuf *a)
+{
+   static stbi_uc length_dezigzag[19] = { 16,17,18,0,8,7,9,6,10,5,11,4,12,3,13,2,14,1,15 };
+   stbi__zhuffman z_codelength;
+   stbi_uc lencodes[286+32+137];//padding for maximum single op
+   stbi_uc codelength_sizes[19];
+   int i,n;
+
+   int hlit  = stbi__zreceive(a,5) + 257;
+   int hdist = stbi__zreceive(a,5) + 1;
+   int hclen = stbi__zreceive(a,4) + 4;
+
+   memset(codelength_sizes, 0, sizeof(codelength_sizes));
+   for (i=0; i < hclen; ++i) {
+      int s = stbi__zreceive(a,3);
+      codelength_sizes[length_dezigzag[i]] = (stbi_uc) s;
+   }
+   if (!stbi__zbuild_huffman(&z_codelength, codelength_sizes, 19)) return 0;
+
+   n = 0;
+   while (n < hlit + hdist) {
+      int c = stbi__zhuffman_decode(a, &z_codelength);
+      if (c < 0 || c >= 19) return stbi__err("bad codelengths", "Corrupt PNG");
+      if (c < 16)
+         lencodes[n++] = (stbi_uc) c;
+      else if (c == 16) {
+         c = stbi__zreceive(a,2)+3;
+         memset(lencodes+n, lencodes[n-1], c);
+         n += c;
+      } else if (c == 17) {
+         c = stbi__zreceive(a,3)+3;
+         memset(lencodes+n, 0, c);
+         n += c;
+      } else {
+         STBI_ASSERT(c == 18);
+         c = stbi__zreceive(a,7)+11;
+         memset(lencodes+n, 0, c);
+         n += c;
+      }
+   }
+   if (n != hlit+hdist) return stbi__err("bad codelengths","Corrupt PNG");
+   if (!stbi__zbuild_huffman(&a->z_length, lencodes, hlit)) return 0;
+   if (!stbi__zbuild_huffman(&a->z_distance, lencodes+hlit, hdist)) return 0;
+   return 1;
+}
+
+static int stbi__parse_uncompressed_block(stbi__zbuf *a)
+{
+   stbi_uc header[4];
+   int len,nlen,k;
+   if (a->num_bits & 7)
+      stbi__zreceive(a, a->num_bits & 7); // discard
+   // drain the bit-packed data into header
+   k = 0;
+   while (a->num_bits > 0) {
+      header[k++] = (stbi_uc) (a->code_buffer & 255); // suppress MSVC run-time check
+      a->code_buffer >>= 8;
+      a->num_bits -= 8;
+   }
+   STBI_ASSERT(a->num_bits == 0);
+   // now fill header the normal way
+   while (k < 4)
+      header[k++] = stbi__zget8(a);
+   len  = header[1] * 256 + header[0];
+   nlen = header[3] * 256 + header[2];
+   if (nlen != (len ^ 0xffff)) return stbi__err("zlib corrupt","Corrupt PNG");
+   if (a->zbuffer + len > a->zbuffer_end) return stbi__err("read past buffer","Corrupt PNG");
+   if (a->zout + len > a->zout_end)
+      if (!stbi__zexpand(a, a->zout, len)) return 0;
+   memcpy(a->zout, a->zbuffer, len);
+   a->zbuffer += len;
+   a->zout += len;
+   return 1;
+}
+
+static int stbi__parse_zlib_header(stbi__zbuf *a)
+{
+   int cmf   = stbi__zget8(a);
+   int cm    = cmf & 15;
+   /* int cinfo = cmf >> 4; */
+   int flg   = stbi__zget8(a);
+   if ((cmf*256+flg) % 31 != 0) return stbi__err("bad zlib header","Corrupt PNG"); // zlib spec
+   if (flg & 32) return stbi__err("no preset dict","Corrupt PNG"); // preset dictionary not allowed in png
+   if (cm != 8) return stbi__err("bad compression","Corrupt PNG"); // DEFLATE required for png
+   // window = 1 << (8 + cinfo)... but who cares, we fully buffer output
+   return 1;
+}
+
+// @TODO: should statically initialize these for optimal thread safety
+static stbi_uc stbi__zdefault_length[288], stbi__zdefault_distance[32];
+static void stbi__init_zdefaults(void)
+{
+   int i;   // use <= to match clearly with spec
+   for (i=0; i <= 143; ++i)     stbi__zdefault_length[i]   = 8;
+   for (   ; i <= 255; ++i)     stbi__zdefault_length[i]   = 9;
+   for (   ; i <= 279; ++i)     stbi__zdefault_length[i]   = 7;
+   for (   ; i <= 287; ++i)     stbi__zdefault_length[i]   = 8;
+
+   for (i=0; i <=  31; ++i)     stbi__zdefault_distance[i] = 5;
+}
+
+static int stbi__parse_zlib(stbi__zbuf *a, int parse_header)
+{
+   int final, type;
+   if (parse_header)
+      if (!stbi__parse_zlib_header(a)) return 0;
+   a->num_bits = 0;
+   a->code_buffer = 0;
+   do {
+      final = stbi__zreceive(a,1);
+      type = stbi__zreceive(a,2);
+      if (type == 0) {
+         if (!stbi__parse_uncompressed_block(a)) return 0;
+      } else if (type == 3) {
+         return 0;
+      } else {
+         if (type == 1) {
+            // use fixed code lengths
+            if (!stbi__zdefault_distance[31]) stbi__init_zdefaults();
+            if (!stbi__zbuild_huffman(&a->z_length  , stbi__zdefault_length  , 288)) return 0;
+            if (!stbi__zbuild_huffman(&a->z_distance, stbi__zdefault_distance,  32)) return 0;
+         } else {
+            if (!stbi__compute_huffman_codes(a)) return 0;
+         }
+         if (!stbi__parse_huffman_block(a)) return 0;
+      }
+   } while (!final);
+   return 1;
+}
+
+static int stbi__do_zlib(stbi__zbuf *a, char *obuf, int olen, int exp, int parse_header)
+{
+   a->zout_start = obuf;
+   a->zout       = obuf;
+   a->zout_end   = obuf + olen;
+   a->z_expandable = exp;
+
+   return stbi__parse_zlib(a, parse_header);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize(const char *buffer, int len, int initial_size, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, 1)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF char *stbi_zlib_decode_malloc(char const *buffer, int len, int *outlen)
+{
+   return stbi_zlib_decode_malloc_guesssize(buffer, len, 16384, outlen);
+}
+
+STBIDEF char *stbi_zlib_decode_malloc_guesssize_headerflag(const char *buffer, int len, int initial_size, int *outlen, int parse_header)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(initial_size);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer + len;
+   if (stbi__do_zlib(&a, p, initial_size, 1, parse_header)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_buffer(char *obuffer, int olen, char const *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 1))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+
+STBIDEF char *stbi_zlib_decode_noheader_malloc(char const *buffer, int len, int *outlen)
+{
+   stbi__zbuf a;
+   char *p = (char *) stbi__malloc(16384);
+   if (p == NULL) return NULL;
+   a.zbuffer = (stbi_uc *) buffer;
+   a.zbuffer_end = (stbi_uc *) buffer+len;
+   if (stbi__do_zlib(&a, p, 16384, 1, 0)) {
+      if (outlen) *outlen = (int) (a.zout - a.zout_start);
+      return a.zout_start;
+   } else {
+      STBI_FREE(a.zout_start);
+      return NULL;
+   }
+}
+
+STBIDEF int stbi_zlib_decode_noheader_buffer(char *obuffer, int olen, const char *ibuffer, int ilen)
+{
+   stbi__zbuf a;
+   a.zbuffer = (stbi_uc *) ibuffer;
+   a.zbuffer_end = (stbi_uc *) ibuffer + ilen;
+   if (stbi__do_zlib(&a, obuffer, olen, 0, 0))
+      return (int) (a.zout - a.zout_start);
+   else
+      return -1;
+}
+#endif
+
+// public domain "baseline" PNG decoder   v0.10  Sean Barrett 2006-11-18
+//    simple implementation
+//      - only 8-bit samples
+//      - no CRC checking
+//      - allocates lots of intermediate memory
+//        - avoids problem of streaming data between subsystems
+//        - avoids explicit window management
+//    performance
+//      - uses stb_zlib, a PD zlib implementation with fast huffman decoding
+
+#ifndef STBI_NO_PNG
+typedef struct
+{
+   stbi__uint32 length;
+   stbi__uint32 type;
+} stbi__pngchunk;
+
+static stbi__pngchunk stbi__get_chunk_header(stbi__context *s)
+{
+   stbi__pngchunk c;
+   c.length = stbi__get32be(s);
+   c.type   = stbi__get32be(s);
+   return c;
+}
+
+static int stbi__check_png_header(stbi__context *s)
+{
+   static stbi_uc png_sig[8] = { 137,80,78,71,13,10,26,10 };
+   int i;
+   for (i=0; i < 8; ++i)
+      if (stbi__get8(s) != png_sig[i]) return stbi__err("bad png sig","Not a PNG");
+   return 1;
+}
+
+typedef struct
+{
+   stbi__context *s;
+   stbi_uc *idata, *expanded, *out;
+   int depth;
+} stbi__png;
+
+
+enum {
+   STBI__F_none=0,
+   STBI__F_sub=1,
+   STBI__F_up=2,
+   STBI__F_avg=3,
+   STBI__F_paeth=4,
+   // synthetic filters used for first scanline to avoid needing a dummy row of 0s
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static stbi_uc first_row_filter[5] =
+{
+   STBI__F_none,
+   STBI__F_sub,
+   STBI__F_none,
+   STBI__F_avg_first,
+   STBI__F_paeth_first
+};
+
+static int stbi__paeth(int a, int b, int c)
+{
+   int p = a + b - c;
+   int pa = abs(p-a);
+   int pb = abs(p-b);
+   int pc = abs(p-c);
+   if (pa <= pb && pa <= pc) return a;
+   if (pb <= pc) return b;
+   return c;
+}
+
+static stbi_uc stbi__depth_scale_table[9] = { 0, 0xff, 0x55, 0, 0x11, 0,0,0, 0x01 };
+
+// create the png data from post-deflated data
+static int stbi__create_png_image_raw(stbi__png *a, stbi_uc *raw, stbi__uint32 raw_len, int out_n, stbi__uint32 x, stbi__uint32 y, int depth, int color)
+{
+   int bytes = (depth == 16? 2 : 1);
+   stbi__context *s = a->s;
+   stbi__uint32 i,j,stride = x*out_n*bytes;
+   stbi__uint32 img_len, img_width_bytes;
+   int k;
+   int img_n = s->img_n; // copy it into a local for later
+
+   int output_bytes = out_n*bytes;
+   int filter_bytes = img_n*bytes;
+   int width = x;
+
+   STBI_ASSERT(out_n == s->img_n || out_n == s->img_n+1);
+   a->out = (stbi_uc *) stbi__malloc(x * y * output_bytes); // extra bytes to write off the end into
+   if (!a->out) return stbi__err("outofmem", "Out of memory");
+
+   img_width_bytes = (((img_n * x * depth) + 7) >> 3);
+   img_len = (img_width_bytes + 1) * y;
+   if (s->img_x == x && s->img_y == y) {
+      if (raw_len != img_len) return stbi__err("not enough pixels","Corrupt PNG");
+   } else { // interlaced:
+      if (raw_len < img_len) return stbi__err("not enough pixels","Corrupt PNG");
+   }
+
+   for (j=0; j < y; ++j) {
+      stbi_uc *cur = a->out + stride*j;
+      stbi_uc *prior = cur - stride;
+      int filter = *raw++;
+
+      if (filter > 4)
+         return stbi__err("invalid filter","Corrupt PNG");
+
+      if (depth < 8) {
+         STBI_ASSERT(img_width_bytes <= x);
+         cur += x*out_n - img_width_bytes; // store output to the rightmost img_len bytes, so we can decode in place
+         filter_bytes = 1;
+         width = img_width_bytes;
+      }
+
+      // if first row, use special filter that doesn't sample previous row
+      if (j == 0) filter = first_row_filter[filter];
+
+      // handle first byte explicitly
+      for (k=0; k < filter_bytes; ++k) {
+         switch (filter) {
+            case STBI__F_none       : cur[k] = raw[k]; break;
+            case STBI__F_sub        : cur[k] = raw[k]; break;
+            case STBI__F_up         : cur[k] = STBI__BYTECAST(raw[k] + prior[k]); break;
+            case STBI__F_avg        : cur[k] = STBI__BYTECAST(raw[k] + (prior[k]>>1)); break;
+            case STBI__F_paeth      : cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(0,prior[k],0)); break;
+            case STBI__F_avg_first  : cur[k] = raw[k]; break;
+            case STBI__F_paeth_first: cur[k] = raw[k]; break;
+         }
+      }
+
+      if (depth == 8) {
+         if (img_n != out_n)
+            cur[img_n] = 255; // first pixel
+         raw += img_n;
+         cur += out_n;
+         prior += out_n;
+      } else if (depth == 16) {
+         if (img_n != out_n) {
+            cur[filter_bytes]   = 255; // first pixel top byte
+            cur[filter_bytes+1] = 255; // first pixel bottom byte
+         }
+         raw += filter_bytes;
+         cur += output_bytes;
+         prior += output_bytes;
+      } else {
+         raw += 1;
+         cur += 1;
+         prior += 1;
+      }
+
+      // this is a little gross, so that we don't switch per-pixel or per-component
+      if (depth < 8 || img_n == out_n) {
+         int nk = (width - 1)*filter_bytes;
+         #define CASE(f) \
+             case f:     \
+                for (k=0; k < nk; ++k)
+         switch (filter) {
+            // "none" filter turns into a memcpy here; make that explicit.
+            case STBI__F_none:         memcpy(cur, raw, nk); break;
+                CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k-filter_bytes]); } break;
+                CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+                CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k-filter_bytes])>>1)); } break;
+                CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],prior[k],prior[k-filter_bytes])); } break;
+                CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k-filter_bytes] >> 1)); } break;
+                CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k-filter_bytes],0,0)); } break;
+         }
+         #undef CASE
+         raw += nk;
+      } else {
+         STBI_ASSERT(img_n+1 == out_n);
+         #define CASE(f) \
+             case f:     \
+                for (i=x-1; i >= 1; --i, cur[filter_bytes]=255,raw+=filter_bytes,cur+=output_bytes,prior+=output_bytes) \
+                   for (k=0; k < filter_bytes; ++k)
+         switch (filter) {
+             CASE(STBI__F_none)         { cur[k] = raw[k]; } break;
+             CASE(STBI__F_sub)          { cur[k] = STBI__BYTECAST(raw[k] + cur[k- output_bytes]); } break;
+             CASE(STBI__F_up)           { cur[k] = STBI__BYTECAST(raw[k] + prior[k]); } break;
+             CASE(STBI__F_avg)          { cur[k] = STBI__BYTECAST(raw[k] + ((prior[k] + cur[k- output_bytes])>>1)); } break;
+             CASE(STBI__F_paeth)        { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],prior[k],prior[k- output_bytes])); } break;
+             CASE(STBI__F_avg_first)    { cur[k] = STBI__BYTECAST(raw[k] + (cur[k- output_bytes] >> 1)); } break;
+             CASE(STBI__F_paeth_first)  { cur[k] = STBI__BYTECAST(raw[k] + stbi__paeth(cur[k- output_bytes],0,0)); } break;
+         }
+         #undef CASE
+
+         // the loop above sets the high byte of the pixels' alpha, but for
+         // 16 bit png files we also need the low byte set. we'll do that here.
+         if (depth == 16) {
+            cur = a->out + stride*j; // start at the beginning of the row again
+            for (i=0; i < x; ++i,cur+=output_bytes) {
+               cur[filter_bytes+1] = 255;
+            }
+         }
+      }
+   }
+
+   // we make a separate pass to expand bits to pixels; for performance,
+   // this could run two scanlines behind the above code, so it won't
+   // intefere with filtering but will still be in the cache.
+   if (depth < 8) {
+      for (j=0; j < y; ++j) {
+         stbi_uc *cur = a->out + stride*j;
+         stbi_uc *in  = a->out + stride*j + x*out_n - img_width_bytes;
+         // unpack 1/2/4-bit into a 8-bit buffer. allows us to keep the common 8-bit path optimal at minimal cost for 1/2/4-bit
+         // png guarante byte alignment, if width is not multiple of 8/4/2 we'll decode dummy trailing data that will be skipped in the later loop
+         stbi_uc scale = (color == 0) ? stbi__depth_scale_table[depth] : 1; // scale grayscale values to 0..255 range
+
+         // note that the final byte might overshoot and write more data than desired.
+         // we can allocate enough data that this never writes out of memory, but it
+         // could also overwrite the next scanline. can it overwrite non-empty data
+         // on the next scanline? yes, consider 1-pixel-wide scanlines with 1-bit-per-pixel.
+         // so we need to explicitly clamp the final ones
+
+         if (depth == 4) {
+            for (k=x*img_n; k >= 2; k-=2, ++in) {
+               *cur++ = scale * ((*in >> 4)       );
+               *cur++ = scale * ((*in     ) & 0x0f);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 4)       );
+         } else if (depth == 2) {
+            for (k=x*img_n; k >= 4; k-=4, ++in) {
+               *cur++ = scale * ((*in >> 6)       );
+               *cur++ = scale * ((*in >> 4) & 0x03);
+               *cur++ = scale * ((*in >> 2) & 0x03);
+               *cur++ = scale * ((*in     ) & 0x03);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 6)       );
+            if (k > 1) *cur++ = scale * ((*in >> 4) & 0x03);
+            if (k > 2) *cur++ = scale * ((*in >> 2) & 0x03);
+         } else if (depth == 1) {
+            for (k=x*img_n; k >= 8; k-=8, ++in) {
+               *cur++ = scale * ((*in >> 7)       );
+               *cur++ = scale * ((*in >> 6) & 0x01);
+               *cur++ = scale * ((*in >> 5) & 0x01);
+               *cur++ = scale * ((*in >> 4) & 0x01);
+               *cur++ = scale * ((*in >> 3) & 0x01);
+               *cur++ = scale * ((*in >> 2) & 0x01);
+               *cur++ = scale * ((*in >> 1) & 0x01);
+               *cur++ = scale * ((*in     ) & 0x01);
+            }
+            if (k > 0) *cur++ = scale * ((*in >> 7)       );
+            if (k > 1) *cur++ = scale * ((*in >> 6) & 0x01);
+            if (k > 2) *cur++ = scale * ((*in >> 5) & 0x01);
+            if (k > 3) *cur++ = scale * ((*in >> 4) & 0x01);
+            if (k > 4) *cur++ = scale * ((*in >> 3) & 0x01);
+            if (k > 5) *cur++ = scale * ((*in >> 2) & 0x01);
+            if (k > 6) *cur++ = scale * ((*in >> 1) & 0x01);
+         }
+         if (img_n != out_n) {
+            int q;
+            // insert alpha = 255
+            cur = a->out + stride*j;
+            if (img_n == 1) {
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*2+1] = 255;
+                  cur[q*2+0] = cur[q];
+               }
+            } else {
+               STBI_ASSERT(img_n == 3);
+               for (q=x-1; q >= 0; --q) {
+                  cur[q*4+3] = 255;
+                  cur[q*4+2] = cur[q*3+2];
+                  cur[q*4+1] = cur[q*3+1];
+                  cur[q*4+0] = cur[q*3+0];
+               }
+            }
+         }
+      }
+   } else if (depth == 16) {
+      // force the image data from big-endian to platform-native.
+      // this is done in a separate pass due to the decoding relying
+      // on the data being untouched, but could probably be done
+      // per-line during decode if care is taken.
+      stbi_uc *cur = a->out;
+      stbi__uint16 *cur16 = (stbi__uint16*)cur;
+
+      for(i=0; i < x*y*out_n; ++i,cur16++,cur+=2) {
+         *cur16 = (cur[0] << 8) | cur[1];
+      }
+   }
+
+   return 1;
+}
+
+static int stbi__create_png_image(stbi__png *a, stbi_uc *image_data, stbi__uint32 image_data_len, int out_n, int depth, int color, int interlaced)
+{
+   stbi_uc *final;
+   int p;
+   if (!interlaced)
+      return stbi__create_png_image_raw(a, image_data, image_data_len, out_n, a->s->img_x, a->s->img_y, depth, color);
+
+   // de-interlacing
+   final = (stbi_uc *) stbi__malloc(a->s->img_x * a->s->img_y * out_n);
+   for (p=0; p < 7; ++p) {
+      int xorig[] = { 0,4,0,2,0,1,0 };
+      int yorig[] = { 0,0,4,0,2,0,1 };
+      int xspc[]  = { 8,8,4,4,2,2,1 };
+      int yspc[]  = { 8,8,8,4,4,2,2 };
+      int i,j,x,y;
+      // pass1_x[4] = 0, pass1_x[5] = 1, pass1_x[12] = 1
+      x = (a->s->img_x - xorig[p] + xspc[p]-1) / xspc[p];
+      y = (a->s->img_y - yorig[p] + yspc[p]-1) / yspc[p];
+      if (x && y) {
+         stbi__uint32 img_len = ((((a->s->img_n * x * depth) + 7) >> 3) + 1) * y;
+         if (!stbi__create_png_image_raw(a, image_data, image_data_len, out_n, x, y, depth, color)) {
+            STBI_FREE(final);
+            return 0;
+         }
+         for (j=0; j < y; ++j) {
+            for (i=0; i < x; ++i) {
+               int out_y = j*yspc[p]+yorig[p];
+               int out_x = i*xspc[p]+xorig[p];
+               memcpy(final + out_y*a->s->img_x*out_n + out_x*out_n,
+                      a->out + (j*x+i)*out_n, out_n);
+            }
+         }
+         STBI_FREE(a->out);
+         image_data += img_len;
+         image_data_len -= img_len;
+      }
+   }
+   a->out = final;
+
+   return 1;
+}
+
+static int stbi__compute_transparency(stbi__png *z, stbi_uc tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 255 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i=0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 255);
+         p += 2;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__compute_transparency16(stbi__png *z, stbi__uint16 tc[3], int out_n)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi__uint16 *p = (stbi__uint16*) z->out;
+
+   // compute color-based transparency, assuming we've
+   // already got 65535 as the alpha value in the output
+   STBI_ASSERT(out_n == 2 || out_n == 4);
+
+   if (out_n == 2) {
+      for (i = 0; i < pixel_count; ++i) {
+         p[1] = (p[0] == tc[0] ? 0 : 65535);
+         p += 2;
+      }
+   } else {
+      for (i = 0; i < pixel_count; ++i) {
+         if (p[0] == tc[0] && p[1] == tc[1] && p[2] == tc[2])
+            p[3] = 0;
+         p += 4;
+      }
+   }
+   return 1;
+}
+
+static int stbi__expand_png_palette(stbi__png *a, stbi_uc *palette, int len, int pal_img_n)
+{
+   stbi__uint32 i, pixel_count = a->s->img_x * a->s->img_y;
+   stbi_uc *p, *temp_out, *orig = a->out;
+
+   p = (stbi_uc *) stbi__malloc(pixel_count * pal_img_n);
+   if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+   // between here and free(out) below, exitting would leak
+   temp_out = p;
+
+   if (pal_img_n == 3) {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p += 3;
+      }
+   } else {
+      for (i=0; i < pixel_count; ++i) {
+         int n = orig[i]*4;
+         p[0] = palette[n  ];
+         p[1] = palette[n+1];
+         p[2] = palette[n+2];
+         p[3] = palette[n+3];
+         p += 4;
+      }
+   }
+   STBI_FREE(a->out);
+   a->out = temp_out;
+
+   STBI_NOTUSED(len);
+
+   return 1;
+}
+
+static int stbi__reduce_png(stbi__png *p)
+{
+   int i;
+   int img_len = p->s->img_x * p->s->img_y * p->s->img_out_n;
+   stbi_uc *reduced;
+   stbi__uint16 *orig = (stbi__uint16*)p->out;
+
+   if (p->depth != 16) return 1; // don't need to do anything if not 16-bit data
+
+   reduced = (stbi_uc *)stbi__malloc(img_len);
+   if (p == NULL) return stbi__err("outofmem", "Out of memory");
+
+   for (i = 0; i < img_len; ++i) reduced[i] = (stbi_uc)((orig[i] >> 8) & 0xFF); // top half of each byte is a decent approx of 16->8 bit scaling
+
+   p->out = reduced;
+   STBI_FREE(orig);
+
+   return 1;
+}
+
+static int stbi__unpremultiply_on_load = 0;
+static int stbi__de_iphone_flag = 0;
+
+STBIDEF void stbi_set_unpremultiply_on_load(int flag_true_if_should_unpremultiply)
+{
+   stbi__unpremultiply_on_load = flag_true_if_should_unpremultiply;
+}
+
+STBIDEF void stbi_convert_iphone_png_to_rgb(int flag_true_if_should_convert)
+{
+   stbi__de_iphone_flag = flag_true_if_should_convert;
+}
+
+static void stbi__de_iphone(stbi__png *z)
+{
+   stbi__context *s = z->s;
+   stbi__uint32 i, pixel_count = s->img_x * s->img_y;
+   stbi_uc *p = z->out;
+
+   if (s->img_out_n == 3) {  // convert bgr to rgb
+      for (i=0; i < pixel_count; ++i) {
+         stbi_uc t = p[0];
+         p[0] = p[2];
+         p[2] = t;
+         p += 3;
+      }
+   } else {
+      STBI_ASSERT(s->img_out_n == 4);
+      if (stbi__unpremultiply_on_load) {
+         // convert bgr to rgb and unpremultiply
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc a = p[3];
+            stbi_uc t = p[0];
+            if (a) {
+               p[0] = p[2] * 255 / a;
+               p[1] = p[1] * 255 / a;
+               p[2] =  t   * 255 / a;
+            } else {
+               p[0] = p[2];
+               p[2] = t;
+            }
+            p += 4;
+         }
+      } else {
+         // convert bgr to rgb
+         for (i=0; i < pixel_count; ++i) {
+            stbi_uc t = p[0];
+            p[0] = p[2];
+            p[2] = t;
+            p += 4;
+         }
+      }
+   }
+}
+
+#define STBI__PNG_TYPE(a,b,c,d)  (((a) << 24) + ((b) << 16) + ((c) << 8) + (d))
+
+static int stbi__parse_png_file(stbi__png *z, int scan, int req_comp)
+{
+   stbi_uc palette[1024], pal_img_n=0;
+   stbi_uc has_trans=0, tc[3];
+   stbi__uint16 tc16[3];
+   stbi__uint32 ioff=0, idata_limit=0, i, pal_len=0;
+   int first=1,k,interlace=0, color=0, is_iphone=0;
+   stbi__context *s = z->s;
+
+   z->expanded = NULL;
+   z->idata = NULL;
+   z->out = NULL;
+
+   if (!stbi__check_png_header(s)) return 0;
+
+   if (scan == STBI__SCAN_type) return 1;
+
+   for (;;) {
+      stbi__pngchunk c = stbi__get_chunk_header(s);
+      switch (c.type) {
+         case STBI__PNG_TYPE('C','g','B','I'):
+            is_iphone = 1;
+            stbi__skip(s, c.length);
+            break;
+         case STBI__PNG_TYPE('I','H','D','R'): {
+            int comp,filter;
+            if (!first) return stbi__err("multiple IHDR","Corrupt PNG");
+            first = 0;
+            if (c.length != 13) return stbi__err("bad IHDR len","Corrupt PNG");
+            s->img_x = stbi__get32be(s); if (s->img_x > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+            s->img_y = stbi__get32be(s); if (s->img_y > (1 << 24)) return stbi__err("too large","Very large image (corrupt?)");
+            z->depth = stbi__get8(s);  if (z->depth != 1 && z->depth != 2 && z->depth != 4 && z->depth != 8 && z->depth != 16)  return stbi__err("1/2/4/8/16-bit only","PNG not supported: 1/2/4/8/16-bit only");
+            color = stbi__get8(s);  if (color > 6)         return stbi__err("bad ctype","Corrupt PNG");
+                       if (color == 3 && z->depth == 16)                  return stbi__err("bad ctype","Corrupt PNG");
+            if (color == 3) pal_img_n = 3; else if (color & 1) return stbi__err("bad ctype","Corrupt PNG");
+            comp  = stbi__get8(s);  if (comp) return stbi__err("bad comp method","Corrupt PNG");
+            filter= stbi__get8(s);  if (filter) return stbi__err("bad filter method","Corrupt PNG");
+            interlace = stbi__get8(s); if (interlace>1) return stbi__err("bad interlace method","Corrupt PNG");
+            if (!s->img_x || !s->img_y) return stbi__err("0-pixel image","Corrupt PNG");
+            if (!pal_img_n) {
+               s->img_n = (color & 2 ? 3 : 1) + (color & 4 ? 1 : 0);
+               if ((1 << 30) / s->img_x / s->img_n < s->img_y) return stbi__err("too large", "Image too large to decode");
+               if (scan == STBI__SCAN_header) return 1;
+            } else {
+               // if paletted, then pal_n is our final components, and
+               // img_n is # components to decompress/filter.
+               s->img_n = 1;
+               if ((1 << 30) / s->img_x / 4 < s->img_y) return stbi__err("too large","Corrupt PNG");
+               // if SCAN_header, have to scan to see if we have a tRNS
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('P','L','T','E'):  {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (c.length > 256*3) return stbi__err("invalid PLTE","Corrupt PNG");
+            pal_len = c.length / 3;
+            if (pal_len * 3 != c.length) return stbi__err("invalid PLTE","Corrupt PNG");
+            for (i=0; i < pal_len; ++i) {
+               palette[i*4+0] = stbi__get8(s);
+               palette[i*4+1] = stbi__get8(s);
+               palette[i*4+2] = stbi__get8(s);
+               palette[i*4+3] = 255;
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('t','R','N','S'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (z->idata) return stbi__err("tRNS after IDAT","Corrupt PNG");
+            if (pal_img_n) {
+               if (scan == STBI__SCAN_header) { s->img_n = 4; return 1; }
+               if (pal_len == 0) return stbi__err("tRNS before PLTE","Corrupt PNG");
+               if (c.length > pal_len) return stbi__err("bad tRNS len","Corrupt PNG");
+               pal_img_n = 4;
+               for (i=0; i < c.length; ++i)
+                  palette[i*4+3] = stbi__get8(s);
+            } else {
+               if (!(s->img_n & 1)) return stbi__err("tRNS with alpha","Corrupt PNG");
+               if (c.length != (stbi__uint32) s->img_n*2) return stbi__err("bad tRNS len","Corrupt PNG");
+               has_trans = 1;
+               if (z->depth == 16) {
+                  for (k = 0; k < s->img_n; ++k) tc16[k] = stbi__get16be(s); // copy the values as-is
+               } else {
+                  for (k = 0; k < s->img_n; ++k) tc[k] = (stbi_uc)(stbi__get16be(s) & 255) * stbi__depth_scale_table[z->depth]; // non 8-bit images will be larger
+               }
+            }
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','D','A','T'): {
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (pal_img_n && !pal_len) return stbi__err("no PLTE","Corrupt PNG");
+            if (scan == STBI__SCAN_header) { s->img_n = pal_img_n; return 1; }
+            if ((int)(ioff + c.length) < (int)ioff) return 0;
+            if (ioff + c.length > idata_limit) {
+               stbi__uint32 idata_limit_old = idata_limit;
+               stbi_uc *p;
+               if (idata_limit == 0) idata_limit = c.length > 4096 ? c.length : 4096;
+               while (ioff + c.length > idata_limit)
+                  idata_limit *= 2;
+               STBI_NOTUSED(idata_limit_old);
+               p = (stbi_uc *) STBI_REALLOC_SIZED(z->idata, idata_limit_old, idata_limit); if (p == NULL) return stbi__err("outofmem", "Out of memory");
+               z->idata = p;
+            }
+            if (!stbi__getn(s, z->idata+ioff,c.length)) return stbi__err("outofdata","Corrupt PNG");
+            ioff += c.length;
+            break;
+         }
+
+         case STBI__PNG_TYPE('I','E','N','D'): {
+            stbi__uint32 raw_len, bpl;
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if (scan != STBI__SCAN_load) return 1;
+            if (z->idata == NULL) return stbi__err("no IDAT","Corrupt PNG");
+            // initial guess for decoded data size to avoid unnecessary reallocs
+            bpl = (s->img_x * z->depth + 7) / 8; // bytes per line, per component
+            raw_len = bpl * s->img_y * s->img_n /* pixels */ + s->img_y /* filter mode per row */;
+            z->expanded = (stbi_uc *) stbi_zlib_decode_malloc_guesssize_headerflag((char *) z->idata, ioff, raw_len, (int *) &raw_len, !is_iphone);
+            if (z->expanded == NULL) return 0; // zlib should set error
+            STBI_FREE(z->idata); z->idata = NULL;
+            if ((req_comp == s->img_n+1 && req_comp != 3 && !pal_img_n) || has_trans)
+               s->img_out_n = s->img_n+1;
+            else
+               s->img_out_n = s->img_n;
+            if (!stbi__create_png_image(z, z->expanded, raw_len, s->img_out_n, z->depth, color, interlace)) return 0;
+            if (has_trans) {
+               if (z->depth == 16) {
+                  if (!stbi__compute_transparency16(z, tc16, s->img_out_n)) return 0;
+               } else {
+                  if (!stbi__compute_transparency(z, tc, s->img_out_n)) return 0;
+               }
+            }
+            if (is_iphone && stbi__de_iphone_flag && s->img_out_n > 2)
+               stbi__de_iphone(z);
+            if (pal_img_n) {
+               // pal_img_n == 3 or 4
+               s->img_n = pal_img_n; // record the actual colors we had
+               s->img_out_n = pal_img_n;
+               if (req_comp >= 3) s->img_out_n = req_comp;
+               if (!stbi__expand_png_palette(z, palette, pal_len, s->img_out_n))
+                  return 0;
+            }
+            STBI_FREE(z->expanded); z->expanded = NULL;
+            return 1;
+         }
+
+         default:
+            // if critical, fail
+            if (first) return stbi__err("first not IHDR", "Corrupt PNG");
+            if ((c.type & (1 << 29)) == 0) {
+               #ifndef STBI_NO_FAILURE_STRINGS
+               // not threadsafe
+               static char invalid_chunk[] = "XXXX PNG chunk not known";
+               invalid_chunk[0] = STBI__BYTECAST(c.type >> 24);
+               invalid_chunk[1] = STBI__BYTECAST(c.type >> 16);
+               invalid_chunk[2] = STBI__BYTECAST(c.type >>  8);
+               invalid_chunk[3] = STBI__BYTECAST(c.type >>  0);
+               #endif
+               return stbi__err(invalid_chunk, "PNG not supported: unknown PNG chunk type");
+            }
+            stbi__skip(s, c.length);
+            break;
+      }
+      // end of PNG chunk, read and skip CRC
+      stbi__get32be(s);
+   }
+}
+
+static unsigned char *stbi__do_png(stbi__png *p, int *x, int *y, int *n, int req_comp)
+{
+   unsigned char *result=NULL;
+   if (req_comp < 0 || req_comp > 4) return stbi__errpuc("bad req_comp", "Internal error");
+   if (stbi__parse_png_file(p, STBI__SCAN_load, req_comp)) {
+      if (p->depth == 16) {
+         if (!stbi__reduce_png(p)) {
+            return result;
+         }
+      }
+      result = p->out;
+      p->out = NULL;
+      if (req_comp && req_comp != p->s->img_out_n) {
+         result = stbi__convert_format(result, p->s->img_out_n, req_comp, p->s->img_x, p->s->img_y);
+         p->s->img_out_n = req_comp;
+         if (result == NULL) return result;
+      }
+      *x = p->s->img_x;
+      *y = p->s->img_y;
+      if (n) *n = p->s->img_n;
+   }
+   STBI_FREE(p->out);      p->out      = NULL;
+   STBI_FREE(p->expanded); p->expanded = NULL;
+   STBI_FREE(p->idata);    p->idata    = NULL;
+
+   return result;
+}
+
+static unsigned char *stbi__png_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__do_png(&p, x,y,comp,req_comp);
+}
+
+static int stbi__png_test(stbi__context *s)
+{
+   int r;
+   r = stbi__check_png_header(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static int stbi__png_info_raw(stbi__png *p, int *x, int *y, int *comp)
+{
+   if (!stbi__parse_png_file(p, STBI__SCAN_header, 0)) {
+      stbi__rewind( p->s );
+      return 0;
+   }
+   if (x) *x = p->s->img_x;
+   if (y) *y = p->s->img_y;
+   if (comp) *comp = p->s->img_n;
+   return 1;
+}
+
+static int stbi__png_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__png p;
+   p.s = s;
+   return stbi__png_info_raw(&p, x, y, comp);
+}
+#endif
+
+// Microsoft/Windows BMP image
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_test_raw(stbi__context *s)
+{
+   int r;
+   int sz;
+   if (stbi__get8(s) != 'B') return 0;
+   if (stbi__get8(s) != 'M') return 0;
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   stbi__get32le(s); // discard data offset
+   sz = stbi__get32le(s);
+   r = (sz == 12 || sz == 40 || sz == 56 || sz == 108 || sz == 124);
+   return r;
+}
+
+static int stbi__bmp_test(stbi__context *s)
+{
+   int r = stbi__bmp_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+
+// returns 0..31 for the highest set bit
+static int stbi__high_bit(unsigned int z)
+{
+   int n=0;
+   if (z == 0) return -1;
+   if (z >= 0x10000) n += 16, z >>= 16;
+   if (z >= 0x00100) n +=  8, z >>=  8;
+   if (z >= 0x00010) n +=  4, z >>=  4;
+   if (z >= 0x00004) n +=  2, z >>=  2;
+   if (z >= 0x00002) n +=  1, z >>=  1;
+   return n;
+}
+
+static int stbi__bitcount(unsigned int a)
+{
+   a = (a & 0x55555555) + ((a >>  1) & 0x55555555); // max 2
+   a = (a & 0x33333333) + ((a >>  2) & 0x33333333); // max 4
+   a = (a + (a >> 4)) & 0x0f0f0f0f; // max 8 per 4, now 8 bits
+   a = (a + (a >> 8)); // max 16 per 8 bits
+   a = (a + (a >> 16)); // max 32 per 8 bits
+   return a & 0xff;
+}
+
+static int stbi__shiftsigned(int v, int shift, int bits)
+{
+   int result;
+   int z=0;
+
+   if (shift < 0) v <<= -shift;
+   else v >>= shift;
+   result = v;
+
+   z = bits;
+   while (z < 8) {
+      result += v >> z;
+      z += bits;
+   }
+   return result;
+}
+
+typedef struct
+{
+   int bpp, offset, hsz;
+   unsigned int mr,mg,mb,ma, all_a;
+} stbi__bmp_data;
+
+static void *stbi__bmp_parse_header(stbi__context *s, stbi__bmp_data *info)
+{
+   int hsz;
+   if (stbi__get8(s) != 'B' || stbi__get8(s) != 'M') return stbi__errpuc("not BMP", "Corrupt BMP");
+   stbi__get32le(s); // discard filesize
+   stbi__get16le(s); // discard reserved
+   stbi__get16le(s); // discard reserved
+   info->offset = stbi__get32le(s);
+   info->hsz = hsz = stbi__get32le(s);
+   info->mr = info->mg = info->mb = info->ma = 0;
+
+   if (hsz != 12 && hsz != 40 && hsz != 56 && hsz != 108 && hsz != 124) return stbi__errpuc("unknown BMP", "BMP type not supported: unknown");
+   if (hsz == 12) {
+      s->img_x = stbi__get16le(s);
+      s->img_y = stbi__get16le(s);
+   } else {
+      s->img_x = stbi__get32le(s);
+      s->img_y = stbi__get32le(s);
+   }
+   if (stbi__get16le(s) != 1) return stbi__errpuc("bad BMP", "bad BMP");
+   info->bpp = stbi__get16le(s);
+   if (info->bpp == 1) return stbi__errpuc("monochrome", "BMP type not supported: 1-bit");
+   if (hsz != 12) {
+      int compress = stbi__get32le(s);
+      if (compress == 1 || compress == 2) return stbi__errpuc("BMP RLE", "BMP type not supported: RLE");
+      stbi__get32le(s); // discard sizeof
+      stbi__get32le(s); // discard hres
+      stbi__get32le(s); // discard vres
+      stbi__get32le(s); // discard colorsused
+      stbi__get32le(s); // discard max important
+      if (hsz == 40 || hsz == 56) {
+         if (hsz == 56) {
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+            stbi__get32le(s);
+         }
+         if (info->bpp == 16 || info->bpp == 32) {
+            if (compress == 0) {
+               if (info->bpp == 32) {
+                  info->mr = 0xffu << 16;
+                  info->mg = 0xffu <<  8;
+                  info->mb = 0xffu <<  0;
+                  info->ma = 0xffu << 24;
+                  info->all_a = 0; // if all_a is 0 at end, then we loaded alpha channel but it was all 0
+               } else {
+                  info->mr = 31u << 10;
+                  info->mg = 31u <<  5;
+                  info->mb = 31u <<  0;
+               }
+            } else if (compress == 3) {
+               info->mr = stbi__get32le(s);
+               info->mg = stbi__get32le(s);
+               info->mb = stbi__get32le(s);
+               // not documented, but generated by photoshop and handled by mspaint
+               if (info->mr == info->mg && info->mg == info->mb) {
+                  // ?!?!?
+                  return stbi__errpuc("bad BMP", "bad BMP");
+               }
+            } else
+               return stbi__errpuc("bad BMP", "bad BMP");
+         }
+      } else {
+         int i;
+         if (hsz != 108 && hsz != 124)
+            return stbi__errpuc("bad BMP", "bad BMP");
+         info->mr = stbi__get32le(s);
+         info->mg = stbi__get32le(s);
+         info->mb = stbi__get32le(s);
+         info->ma = stbi__get32le(s);
+         stbi__get32le(s); // discard color space
+         for (i=0; i < 12; ++i)
+            stbi__get32le(s); // discard color space parameters
+         if (hsz == 124) {
+            stbi__get32le(s); // discard rendering intent
+            stbi__get32le(s); // discard offset of profile data
+            stbi__get32le(s); // discard size of profile data
+            stbi__get32le(s); // discard reserved
+         }
+      }
+   }
+   return (void *) 1;
+}
+
+
+static stbi_uc *stbi__bmp_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *out;
+   unsigned int mr=0,mg=0,mb=0,ma=0, all_a;
+   stbi_uc pal[256][4];
+   int psize=0,i,j,width;
+   int flip_vertically, pad, target;
+   stbi__bmp_data info;
+
+   info.all_a = 255;
+   if (stbi__bmp_parse_header(s, &info) == NULL)
+      return NULL; // error code already set
+
+   flip_vertically = ((int) s->img_y) > 0;
+   s->img_y = abs((int) s->img_y);
+
+   mr = info.mr;
+   mg = info.mg;
+   mb = info.mb;
+   ma = info.ma;
+   all_a = info.all_a;
+
+   if (info.hsz == 12) {
+      if (info.bpp < 24)
+         psize = (info.offset - 14 - 24) / 3;
+   } else {
+      if (info.bpp < 16)
+         psize = (info.offset - 14 - info.hsz) >> 2;
+   }
+
+   s->img_n = ma ? 4 : 3;
+   if (req_comp && req_comp >= 3) // we can directly decode 3 or 4
+      target = req_comp;
+   else
+      target = s->img_n; // if they want monochrome, we'll post-convert
+
+   out = (stbi_uc *) stbi__malloc(target * s->img_x * s->img_y);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   if (info.bpp < 16) {
+      int z=0;
+      if (psize == 0 || psize > 256) { STBI_FREE(out); return stbi__errpuc("invalid", "Corrupt BMP"); }
+      for (i=0; i < psize; ++i) {
+         pal[i][2] = stbi__get8(s);
+         pal[i][1] = stbi__get8(s);
+         pal[i][0] = stbi__get8(s);
+         if (info.hsz != 12) stbi__get8(s);
+         pal[i][3] = 255;
+      }
+      stbi__skip(s, info.offset - 14 - info.hsz - psize * (info.hsz == 12 ? 3 : 4));
+      if (info.bpp == 4) width = (s->img_x + 1) >> 1;
+      else if (info.bpp == 8) width = s->img_x;
+      else { STBI_FREE(out); return stbi__errpuc("bad bpp", "Corrupt BMP"); }
+      pad = (-width)&3;
+      for (j=0; j < (int) s->img_y; ++j) {
+         for (i=0; i < (int) s->img_x; i += 2) {
+            int v=stbi__get8(s),v2=0;
+            if (info.bpp == 4) {
+               v2 = v & 15;
+               v >>= 4;
+            }
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+            if (i+1 == (int) s->img_x) break;
+            v = (info.bpp == 8) ? stbi__get8(s) : v2;
+            out[z++] = pal[v][0];
+            out[z++] = pal[v][1];
+            out[z++] = pal[v][2];
+            if (target == 4) out[z++] = 255;
+         }
+         stbi__skip(s, pad);
+      }
+   } else {
+      int rshift=0,gshift=0,bshift=0,ashift=0,rcount=0,gcount=0,bcount=0,acount=0;
+      int z = 0;
+      int easy=0;
+      stbi__skip(s, info.offset - 14 - info.hsz);
+      if (info.bpp == 24) width = 3 * s->img_x;
+      else if (info.bpp == 16) width = 2*s->img_x;
+      else /* bpp = 32 and pad = 0 */ width=0;
+      pad = (-width) & 3;
+      if (info.bpp == 24) {
+         easy = 1;
+      } else if (info.bpp == 32) {
+         if (mb == 0xff && mg == 0xff00 && mr == 0x00ff0000 && ma == 0xff000000)
+            easy = 2;
+      }
+      if (!easy) {
+         if (!mr || !mg || !mb) { STBI_FREE(out); return stbi__errpuc("bad masks", "Corrupt BMP"); }
+         // right shift amt to put high bit in position #7
+         rshift = stbi__high_bit(mr)-7; rcount = stbi__bitcount(mr);
+         gshift = stbi__high_bit(mg)-7; gcount = stbi__bitcount(mg);
+         bshift = stbi__high_bit(mb)-7; bcount = stbi__bitcount(mb);
+         ashift = stbi__high_bit(ma)-7; acount = stbi__bitcount(ma);
+      }
+      for (j=0; j < (int) s->img_y; ++j) {
+         if (easy) {
+            for (i=0; i < (int) s->img_x; ++i) {
+               unsigned char a;
+               out[z+2] = stbi__get8(s);
+               out[z+1] = stbi__get8(s);
+               out[z+0] = stbi__get8(s);
+               z += 3;
+               a = (easy == 2 ? stbi__get8(s) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = a;
+            }
+         } else {
+            int bpp = info.bpp;
+            for (i=0; i < (int) s->img_x; ++i) {
+               stbi__uint32 v = (bpp == 16 ? (stbi__uint32) stbi__get16le(s) : stbi__get32le(s));
+               int a;
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mr, rshift, rcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mg, gshift, gcount));
+               out[z++] = STBI__BYTECAST(stbi__shiftsigned(v & mb, bshift, bcount));
+               a = (ma ? stbi__shiftsigned(v & ma, ashift, acount) : 255);
+               all_a |= a;
+               if (target == 4) out[z++] = STBI__BYTECAST(a);
+            }
+         }
+         stbi__skip(s, pad);
+      }
+   }
+
+   // if alpha channel is all 0s, replace with all 255s
+   if (target == 4 && all_a == 0)
+      for (i=4*s->img_x*s->img_y-1; i >= 0; i -= 4)
+         out[i] = 255;
+
+   if (flip_vertically) {
+      stbi_uc t;
+      for (j=0; j < (int) s->img_y>>1; ++j) {
+         stbi_uc *p1 = out +      j     *s->img_x*target;
+         stbi_uc *p2 = out + (s->img_y-1-j)*s->img_x*target;
+         for (i=0; i < (int) s->img_x*target; ++i) {
+            t = p1[i], p1[i] = p2[i], p2[i] = t;
+         }
+      }
+   }
+
+   if (req_comp && req_comp != target) {
+      out = stbi__convert_format(out, target, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   *x = s->img_x;
+   *y = s->img_y;
+   if (comp) *comp = s->img_n;
+   return out;
+}
+#endif
+
+// Targa Truevision - TGA
+// by Jonathan Dummer
+#ifndef STBI_NO_TGA
+// returns STBI_rgb or whatever, 0 on error
+static int stbi__tga_get_comp(int bits_per_pixel, int is_grey, int* is_rgb16)
+{
+   // only RGB or RGBA (incl. 16bit) or grey allowed
+   if(is_rgb16) *is_rgb16 = 0;
+   switch(bits_per_pixel) {
+      case 8:  return STBI_grey;
+      case 16: if(is_grey) return STBI_grey_alpha;
+            // else: fall-through
+      case 15: if(is_rgb16) *is_rgb16 = 1;
+            return STBI_rgb;
+      case 24: // fall-through
+      case 32: return bits_per_pixel/8;
+      default: return 0;
+   }
+}
+
+static int stbi__tga_info(stbi__context *s, int *x, int *y, int *comp)
+{
+    int tga_w, tga_h, tga_comp, tga_image_type, tga_bits_per_pixel, tga_colormap_bpp;
+    int sz, tga_colormap_type;
+    stbi__get8(s);                   // discard Offset
+    tga_colormap_type = stbi__get8(s); // colormap type
+    if( tga_colormap_type > 1 ) {
+        stbi__rewind(s);
+        return 0;      // only RGB or indexed allowed
+    }
+    tga_image_type = stbi__get8(s); // image type
+    if ( tga_colormap_type == 1 ) { // colormapped (paletted) image
+        if (tga_image_type != 1 && tga_image_type != 9) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+        sz = stbi__get8(s);    //   check bits per palette color entry
+        if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) {
+            stbi__rewind(s);
+            return 0;
+        }
+        stbi__skip(s,4);       // skip image x and y origin
+        tga_colormap_bpp = sz;
+    } else { // "normal" image w/o colormap - only RGB or grey allowed, +/- RLE
+        if ( (tga_image_type != 2) && (tga_image_type != 3) && (tga_image_type != 10) && (tga_image_type != 11) ) {
+            stbi__rewind(s);
+            return 0; // only RGB or grey allowed, +/- RLE
+        }
+        stbi__skip(s,9); // skip colormap specification and image x/y origin
+        tga_colormap_bpp = 0;
+    }
+    tga_w = stbi__get16le(s);
+    if( tga_w < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test width
+    }
+    tga_h = stbi__get16le(s);
+    if( tga_h < 1 ) {
+        stbi__rewind(s);
+        return 0;   // test height
+    }
+    tga_bits_per_pixel = stbi__get8(s); // bits per pixel
+    stbi__get8(s); // ignore alpha bits
+    if (tga_colormap_bpp != 0) {
+        if((tga_bits_per_pixel != 8) && (tga_bits_per_pixel != 16)) {
+            // when using a colormap, tga_bits_per_pixel is the size of the indexes
+            // I don't think anything but 8 or 16bit indexes makes sense
+            stbi__rewind(s);
+            return 0;
+        }
+        tga_comp = stbi__tga_get_comp(tga_colormap_bpp, 0, NULL);
+    } else {
+        tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3) || (tga_image_type == 11), NULL);
+    }
+    if(!tga_comp) {
+      stbi__rewind(s);
+      return 0;
+    }
+    if (x) *x = tga_w;
+    if (y) *y = tga_h;
+    if (comp) *comp = tga_comp;
+    return 1;                   // seems to have passed everything
+}
+
+static int stbi__tga_test(stbi__context *s)
+{
+   int res = 0;
+   int sz, tga_color_type;
+   stbi__get8(s);      //   discard Offset
+   tga_color_type = stbi__get8(s);   //   color type
+   if ( tga_color_type > 1 ) goto errorEnd;   //   only RGB or indexed allowed
+   sz = stbi__get8(s);   //   image type
+   if ( tga_color_type == 1 ) { // colormapped (paletted) image
+      if (sz != 1 && sz != 9) goto errorEnd; // colortype 1 demands image type 1 or 9
+      stbi__skip(s,4);       // skip index of first colormap entry and number of entries
+      sz = stbi__get8(s);    //   check bits per palette color entry
+      if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+      stbi__skip(s,4);       // skip image x and y origin
+   } else { // "normal" image w/o colormap
+      if ( (sz != 2) && (sz != 3) && (sz != 10) && (sz != 11) ) goto errorEnd; // only RGB or grey allowed, +/- RLE
+      stbi__skip(s,9); // skip colormap specification and image x/y origin
+   }
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test width
+   if ( stbi__get16le(s) < 1 ) goto errorEnd;      //   test height
+   sz = stbi__get8(s);   //   bits per pixel
+   if ( (tga_color_type == 1) && (sz != 8) && (sz != 16) ) goto errorEnd; // for colormapped images, bpp is size of an index
+   if ( (sz != 8) && (sz != 15) && (sz != 16) && (sz != 24) && (sz != 32) ) goto errorEnd;
+
+   res = 1; // if we got this far, everything's good and we can return 1 instead of 0
+
+errorEnd:
+   stbi__rewind(s);
+   return res;
+}
+
+// read 16bit value and convert to 24bit RGB
+void stbi__tga_read_rgb16(stbi__context *s, stbi_uc* out)
+{
+   stbi__uint16 px = stbi__get16le(s);
+   stbi__uint16 fiveBitMask = 31;
+   // we have 3 channels with 5bits each
+   int r = (px >> 10) & fiveBitMask;
+   int g = (px >> 5) & fiveBitMask;
+   int b = px & fiveBitMask;
+   // Note that this saves the data in RGB(A) order, so it doesn't need to be swapped later
+   out[0] = (r * 255)/31;
+   out[1] = (g * 255)/31;
+   out[2] = (b * 255)/31;
+
+   // some people claim that the most significant bit might be used for alpha
+   // (possibly if an alpha-bit is set in the "image descriptor byte")
+   // but that only made 16bit test images completely translucent..
+   // so let's treat all 15 and 16bit TGAs as RGB with no alpha.
+}
+
+static stbi_uc *stbi__tga_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   //   read in the TGA header stuff
+   int tga_offset = stbi__get8(s);
+   int tga_indexed = stbi__get8(s);
+   int tga_image_type = stbi__get8(s);
+   int tga_is_RLE = 0;
+   int tga_palette_start = stbi__get16le(s);
+   int tga_palette_len = stbi__get16le(s);
+   int tga_palette_bits = stbi__get8(s);
+   int tga_x_origin = stbi__get16le(s);
+   int tga_y_origin = stbi__get16le(s);
+   int tga_width = stbi__get16le(s);
+   int tga_height = stbi__get16le(s);
+   int tga_bits_per_pixel = stbi__get8(s);
+   int tga_comp, tga_rgb16=0;
+   int tga_inverted = stbi__get8(s);
+   // int tga_alpha_bits = tga_inverted & 15; // the 4 lowest bits - unused (useless?)
+   //   image data
+   unsigned char *tga_data;
+   unsigned char *tga_palette = NULL;
+   int i, j;
+   unsigned char raw_data[4];
+   int RLE_count = 0;
+   int RLE_repeating = 0;
+   int read_next_pixel = 1;
+
+   //   do a tiny bit of precessing
+   if ( tga_image_type >= 8 )
+   {
+      tga_image_type -= 8;
+      tga_is_RLE = 1;
+   }
+   tga_inverted = 1 - ((tga_inverted >> 5) & 1);
+
+   //   If I'm paletted, then I'll use the number of bits from the palette
+   if ( tga_indexed ) tga_comp = stbi__tga_get_comp(tga_palette_bits, 0, &tga_rgb16);
+   else tga_comp = stbi__tga_get_comp(tga_bits_per_pixel, (tga_image_type == 3), &tga_rgb16);
+
+   if(!tga_comp) // shouldn't really happen, stbi__tga_test() should have ensured basic consistency
+      return stbi__errpuc("bad format", "Can't find out TGA pixelformat");
+
+   //   tga info
+   *x = tga_width;
+   *y = tga_height;
+   if (comp) *comp = tga_comp;
+
+   tga_data = (unsigned char*)stbi__malloc( (size_t)tga_width * tga_height * tga_comp );
+   if (!tga_data) return stbi__errpuc("outofmem", "Out of memory");
+
+   // skip to the data's starting position (offset usually = 0)
+   stbi__skip(s, tga_offset );
+
+   if ( !tga_indexed && !tga_is_RLE && !tga_rgb16 ) {
+      for (i=0; i < tga_height; ++i) {
+         int row = tga_inverted ? tga_height -i - 1 : i;
+         stbi_uc *tga_row = tga_data + row*tga_width*tga_comp;
+         stbi__getn(s, tga_row, tga_width * tga_comp);
+      }
+   } else  {
+      //   do I need to load a palette?
+      if ( tga_indexed)
+      {
+         //   any data to skip? (offset usually = 0)
+         stbi__skip(s, tga_palette_start );
+         //   load the palette
+         tga_palette = (unsigned char*)stbi__malloc( tga_palette_len * tga_comp );
+         if (!tga_palette) {
+            STBI_FREE(tga_data);
+            return stbi__errpuc("outofmem", "Out of memory");
+         }
+         if (tga_rgb16) {
+            stbi_uc *pal_entry = tga_palette;
+            STBI_ASSERT(tga_comp == STBI_rgb);
+            for (i=0; i < tga_palette_len; ++i) {
+               stbi__tga_read_rgb16(s, pal_entry);
+               pal_entry += tga_comp;
+            }
+         } else if (!stbi__getn(s, tga_palette, tga_palette_len * tga_comp)) {
+               STBI_FREE(tga_data);
+               STBI_FREE(tga_palette);
+               return stbi__errpuc("bad palette", "Corrupt TGA");
+         }
+      }
+      //   load the data
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         //   if I'm in RLE mode, do I need to get a RLE stbi__pngchunk?
+         if ( tga_is_RLE )
+         {
+            if ( RLE_count == 0 )
+            {
+               //   yep, get the next byte as a RLE command
+               int RLE_cmd = stbi__get8(s);
+               RLE_count = 1 + (RLE_cmd & 127);
+               RLE_repeating = RLE_cmd >> 7;
+               read_next_pixel = 1;
+            } else if ( !RLE_repeating )
+            {
+               read_next_pixel = 1;
+            }
+         } else
+         {
+            read_next_pixel = 1;
+         }
+         //   OK, if I need to read a pixel, do it now
+         if ( read_next_pixel )
+         {
+            //   load however much data we did have
+            if ( tga_indexed )
+            {
+               // read in index, then perform the lookup
+               int pal_idx = (tga_bits_per_pixel == 8) ? stbi__get8(s) : stbi__get16le(s);
+               if ( pal_idx >= tga_palette_len ) {
+                  // invalid index
+                  pal_idx = 0;
+               }
+               pal_idx *= tga_comp;
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = tga_palette[pal_idx+j];
+               }
+            } else if(tga_rgb16) {
+               STBI_ASSERT(tga_comp == STBI_rgb);
+               stbi__tga_read_rgb16(s, raw_data);
+            } else {
+               //   read in the data raw
+               for (j = 0; j < tga_comp; ++j) {
+                  raw_data[j] = stbi__get8(s);
+               }
+            }
+            //   clear the reading flag for the next pixel
+            read_next_pixel = 0;
+         } // end of reading a pixel
+
+         // copy data
+         for (j = 0; j < tga_comp; ++j)
+           tga_data[i*tga_comp+j] = raw_data[j];
+
+         //   in case we're in RLE mode, keep counting down
+         --RLE_count;
+      }
+      //   do I need to invert the image?
+      if ( tga_inverted )
+      {
+         for (j = 0; j*2 < tga_height; ++j)
+         {
+            int index1 = j * tga_width * tga_comp;
+            int index2 = (tga_height - 1 - j) * tga_width * tga_comp;
+            for (i = tga_width * tga_comp; i > 0; --i)
+            {
+               unsigned char temp = tga_data[index1];
+               tga_data[index1] = tga_data[index2];
+               tga_data[index2] = temp;
+               ++index1;
+               ++index2;
+            }
+         }
+      }
+      //   clear my palette, if I had one
+      if ( tga_palette != NULL )
+      {
+         STBI_FREE( tga_palette );
+      }
+   }
+
+   // swap RGB - if the source data was RGB16, it already is in the right order
+   if (tga_comp >= 3 && !tga_rgb16)
+   {
+      unsigned char* tga_pixel = tga_data;
+      for (i=0; i < tga_width * tga_height; ++i)
+      {
+         unsigned char temp = tga_pixel[0];
+         tga_pixel[0] = tga_pixel[2];
+         tga_pixel[2] = temp;
+         tga_pixel += tga_comp;
+      }
+   }
+
+   // convert to target component count
+   if (req_comp && req_comp != tga_comp)
+      tga_data = stbi__convert_format(tga_data, tga_comp, req_comp, tga_width, tga_height);
+
+   //   the things I do to get rid of an error message, and yet keep
+   //   Microsoft's C compilers happy... [8^(
+   tga_palette_start = tga_palette_len = tga_palette_bits =
+         tga_x_origin = tga_y_origin = 0;
+   //   OK, done
+   return tga_data;
+}
+#endif
+
+// *************************************************************************************************
+// Photoshop PSD loader -- PD by Thatcher Ulrich, integration by Nicolas Schulz, tweaked by STB
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_test(stbi__context *s)
+{
+   int r = (stbi__get32be(s) == 0x38425053);
+   stbi__rewind(s);
+   return r;
+}
+
+static stbi_uc *stbi__psd_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   int   pixelCount;
+   int channelCount, compression;
+   int channel, i, count, len;
+   int bitdepth;
+   int w,h;
+   stbi_uc *out;
+
+   // Check identifier
+   if (stbi__get32be(s) != 0x38425053)   // "8BPS"
+      return stbi__errpuc("not PSD", "Corrupt PSD image");
+
+   // Check file type version.
+   if (stbi__get16be(s) != 1)
+      return stbi__errpuc("wrong version", "Unsupported version of PSD image");
+
+   // Skip 6 reserved bytes.
+   stbi__skip(s, 6 );
+
+   // Read the number of channels (R, G, B, A, etc).
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16)
+      return stbi__errpuc("wrong channel count", "Unsupported number of channels in PSD image");
+
+   // Read the rows and columns of the image.
+   h = stbi__get32be(s);
+   w = stbi__get32be(s);
+
+   // Make sure the depth is 8 bits.
+   bitdepth = stbi__get16be(s);
+   if (bitdepth != 8 && bitdepth != 16)
+      return stbi__errpuc("unsupported bit depth", "PSD bit depth is not 8 or 16 bit");
+
+   // Make sure the color mode is RGB.
+   // Valid options are:
+   //   0: Bitmap
+   //   1: Grayscale
+   //   2: Indexed color
+   //   3: RGB color
+   //   4: CMYK color
+   //   7: Multichannel
+   //   8: Duotone
+   //   9: Lab color
+   if (stbi__get16be(s) != 3)
+      return stbi__errpuc("wrong color format", "PSD is not in RGB color format");
+
+   // Skip the Mode Data.  (It's the palette for indexed color; other info for other modes.)
+   stbi__skip(s,stbi__get32be(s) );
+
+   // Skip the image resources.  (resolution, pen tool paths, etc)
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Skip the reserved data.
+   stbi__skip(s, stbi__get32be(s) );
+
+   // Find out if the data is compressed.
+   // Known values:
+   //   0: no compression
+   //   1: RLE compressed
+   compression = stbi__get16be(s);
+   if (compression > 1)
+      return stbi__errpuc("bad compression", "PSD has an unknown compression format");
+
+   // Create the destination image.
+   out = (stbi_uc *) stbi__malloc(4 * w*h);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   pixelCount = w*h;
+
+   // Initialize the data to zero.
+   //memset( out, 0, pixelCount * 4 );
+
+   // Finally, the image data.
+   if (compression) {
+      // RLE as used by .PSD and .TIFF
+      // Loop until you get the number of unpacked bytes you are expecting:
+      //     Read the next source byte into n.
+      //     If n is between 0 and 127 inclusive, copy the next n+1 bytes literally.
+      //     Else if n is between -127 and -1 inclusive, copy the next byte -n+1 times.
+      //     Else if n is 128, noop.
+      // Endloop
+
+      // The RLE-compressed data is preceeded by a 2-byte data count for each row in the data,
+      // which we're going to just skip.
+      stbi__skip(s, h * channelCount * 2 );
+
+      // Read the RLE data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out+channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = (channel == 3 ? 255 : 0);
+         } else {
+            // Read the RLE data.
+            count = 0;
+            while (count < pixelCount) {
+               len = stbi__get8(s);
+               if (len == 128) {
+                  // No-op.
+               } else if (len < 128) {
+                  // Copy next len+1 bytes literally.
+                  len++;
+                  count += len;
+                  while (len) {
+                     *p = stbi__get8(s);
+                     p += 4;
+                     len--;
+                  }
+               } else if (len > 128) {
+                  stbi_uc   val;
+                  // Next -len+1 bytes in the dest are replicated from next source byte.
+                  // (Interpret len as a negative 8-bit int.)
+                  len ^= 0x0FF;
+                  len += 2;
+                  val = stbi__get8(s);
+                  count += len;
+                  while (len) {
+                     *p = val;
+                     p += 4;
+                     len--;
+                  }
+               }
+            }
+         }
+      }
+
+   } else {
+      // We're at the raw image data.  It's each channel in order (Red, Green, Blue, Alpha, ...)
+      // where each channel consists of an 8-bit value for each pixel in the image.
+
+      // Read the data by channel.
+      for (channel = 0; channel < 4; channel++) {
+         stbi_uc *p;
+
+         p = out + channel;
+         if (channel >= channelCount) {
+            // Fill this channel with default data.
+            stbi_uc val = channel == 3 ? 255 : 0;
+            for (i = 0; i < pixelCount; i++, p += 4)
+               *p = val;
+         } else {
+            // Read the data.
+            if (bitdepth == 16) {
+               for (i = 0; i < pixelCount; i++, p += 4)
+                  *p = (stbi_uc) (stbi__get16be(s) >> 8);
+            } else {
+               for (i = 0; i < pixelCount; i++, p += 4)
+                  *p = stbi__get8(s);
+            }
+         }
+      }
+   }
+
+   if (channelCount >= 4) {
+      for (i=0; i < w*h; ++i) {
+         unsigned char *pixel = out + 4*i;
+         if (pixel[3] != 0 && pixel[3] != 255) {
+            // remove weird white matte from PSD
+            float a = pixel[3] / 255.0f;
+            float ra = 1.0f / a;
+            float inv_a = 255.0f * (1 - ra);
+            pixel[0] = (unsigned char) (pixel[0]*ra + inv_a);
+            pixel[1] = (unsigned char) (pixel[1]*ra + inv_a);
+            pixel[2] = (unsigned char) (pixel[2]*ra + inv_a);
+         }
+      }
+   }
+
+   if (req_comp && req_comp != 4) {
+      out = stbi__convert_format(out, 4, req_comp, w, h);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+
+   if (comp) *comp = 4;
+   *y = h;
+   *x = w;
+
+   return out;
+}
+#endif
+
+// *************************************************************************************************
+// Softimage PIC loader
+// by Tom Seddon
+//
+// See http://softimage.wiki.softimage.com/index.php/INFO:_PIC_file_format
+// See http://ozviz.wasp.uwa.edu.au/~pbourke/dataformats/softimagepic/
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_is4(stbi__context *s,const char *str)
+{
+   int i;
+   for (i=0; i<4; ++i)
+      if (stbi__get8(s) != (stbi_uc)str[i])
+         return 0;
+
+   return 1;
+}
+
+static int stbi__pic_test_core(stbi__context *s)
+{
+   int i;
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34"))
+      return 0;
+
+   for(i=0;i<84;++i)
+      stbi__get8(s);
+
+   if (!stbi__pic_is4(s,"PICT"))
+      return 0;
+
+   return 1;
+}
+
+typedef struct
+{
+   stbi_uc size,type,channel;
+} stbi__pic_packet;
+
+static stbi_uc *stbi__readval(stbi__context *s, int channel, stbi_uc *dest)
+{
+   int mask=0x80, i;
+
+   for (i=0; i<4; ++i, mask>>=1) {
+      if (channel & mask) {
+         if (stbi__at_eof(s)) return stbi__errpuc("bad file","PIC file too short");
+         dest[i]=stbi__get8(s);
+      }
+   }
+
+   return dest;
+}
+
+static void stbi__copyval(int channel,stbi_uc *dest,const stbi_uc *src)
+{
+   int mask=0x80,i;
+
+   for (i=0;i<4; ++i, mask>>=1)
+      if (channel&mask)
+         dest[i]=src[i];
+}
+
+static stbi_uc *stbi__pic_load_core(stbi__context *s,int width,int height,int *comp, stbi_uc *result)
+{
+   int act_comp=0,num_packets=0,y,chained;
+   stbi__pic_packet packets[10];
+
+   // this will (should...) cater for even some bizarre stuff like having data
+    // for the same channel in multiple packets.
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return stbi__errpuc("bad format","too many packets");
+
+      packet = &packets[num_packets++];
+
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s))          return stbi__errpuc("bad file","file too short (reading packets)");
+      if (packet->size != 8)  return stbi__errpuc("bad format","packet isn't 8bpp");
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3); // has alpha channel?
+
+   for(y=0; y<height; ++y) {
+      int packet_idx;
+
+      for(packet_idx=0; packet_idx < num_packets; ++packet_idx) {
+         stbi__pic_packet *packet = &packets[packet_idx];
+         stbi_uc *dest = result+y*width*4;
+
+         switch (packet->type) {
+            default:
+               return stbi__errpuc("bad format","packet has bad compression type");
+
+            case 0: {//uncompressed
+               int x;
+
+               for(x=0;x<width;++x, dest+=4)
+                  if (!stbi__readval(s,packet->channel,dest))
+                     return 0;
+               break;
+            }
+
+            case 1://Pure RLE
+               {
+                  int left=width, i;
+
+                  while (left>0) {
+                     stbi_uc count,value[4];
+
+                     count=stbi__get8(s);
+                     if (stbi__at_eof(s))   return stbi__errpuc("bad file","file too short (pure read count)");
+
+                     if (count > left)
+                        count = (stbi_uc) left;
+
+                     if (!stbi__readval(s,packet->channel,value))  return 0;
+
+                     for(i=0; i<count; ++i,dest+=4)
+                        stbi__copyval(packet->channel,dest,value);
+                     left -= count;
+                  }
+               }
+               break;
+
+            case 2: {//Mixed RLE
+               int left=width;
+               while (left>0) {
+                  int count = stbi__get8(s), i;
+                  if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (mixed read count)");
+
+                  if (count >= 128) { // Repeated
+                     stbi_uc value[4];
+
+                     if (count==128)
+                        count = stbi__get16be(s);
+                     else
+                        count -= 127;
+                     if (count > left)
+                        return stbi__errpuc("bad file","scanline overrun");
+
+                     if (!stbi__readval(s,packet->channel,value))
+                        return 0;
+
+                     for(i=0;i<count;++i, dest += 4)
+                        stbi__copyval(packet->channel,dest,value);
+                  } else { // Raw
+                     ++count;
+                     if (count>left) return stbi__errpuc("bad file","scanline overrun");
+
+                     for(i=0;i<count;++i, dest+=4)
+                        if (!stbi__readval(s,packet->channel,dest))
+                           return 0;
+                  }
+                  left-=count;
+               }
+               break;
+            }
+         }
+      }
+   }
+
+   return result;
+}
+
+static stbi_uc *stbi__pic_load(stbi__context *s,int *px,int *py,int *comp,int req_comp)
+{
+   stbi_uc *result;
+   int i, x,y;
+
+   for (i=0; i<92; ++i)
+      stbi__get8(s);
+
+   x = stbi__get16be(s);
+   y = stbi__get16be(s);
+   if (stbi__at_eof(s))  return stbi__errpuc("bad file","file too short (pic header)");
+   if ((1 << 28) / x < y) return stbi__errpuc("too large", "Image too large to decode");
+
+   stbi__get32be(s); //skip `ratio'
+   stbi__get16be(s); //skip `fields'
+   stbi__get16be(s); //skip `pad'
+
+   // intermediate buffer is RGBA
+   result = (stbi_uc *) stbi__malloc(x*y*4);
+   memset(result, 0xff, x*y*4);
+
+   if (!stbi__pic_load_core(s,x,y,comp, result)) {
+      STBI_FREE(result);
+      result=0;
+   }
+   *px = x;
+   *py = y;
+   if (req_comp == 0) req_comp = *comp;
+   result=stbi__convert_format(result,4,req_comp,x,y);
+
+   return result;
+}
+
+static int stbi__pic_test(stbi__context *s)
+{
+   int r = stbi__pic_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+#endif
+
+// *************************************************************************************************
+// GIF loader -- public domain by Jean-Marc Lienher -- simplified/shrunk by stb
+
+#ifndef STBI_NO_GIF
+typedef struct
+{
+   stbi__int16 prefix;
+   stbi_uc first;
+   stbi_uc suffix;
+} stbi__gif_lzw;
+
+typedef struct
+{
+   int w,h;
+   stbi_uc *out, *old_out;             // output buffer (always 4 components)
+   int flags, bgindex, ratio, transparent, eflags, delay;
+   stbi_uc  pal[256][4];
+   stbi_uc lpal[256][4];
+   stbi__gif_lzw codes[4096];
+   stbi_uc *color_table;
+   int parse, step;
+   int lflags;
+   int start_x, start_y;
+   int max_x, max_y;
+   int cur_x, cur_y;
+   int line_size;
+} stbi__gif;
+
+static int stbi__gif_test_raw(stbi__context *s)
+{
+   int sz;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8') return 0;
+   sz = stbi__get8(s);
+   if (sz != '9' && sz != '7') return 0;
+   if (stbi__get8(s) != 'a') return 0;
+   return 1;
+}
+
+static int stbi__gif_test(stbi__context *s)
+{
+   int r = stbi__gif_test_raw(s);
+   stbi__rewind(s);
+   return r;
+}
+
+static void stbi__gif_parse_colortable(stbi__context *s, stbi_uc pal[256][4], int num_entries, int transp)
+{
+   int i;
+   for (i=0; i < num_entries; ++i) {
+      pal[i][2] = stbi__get8(s);
+      pal[i][1] = stbi__get8(s);
+      pal[i][0] = stbi__get8(s);
+      pal[i][3] = transp == i ? 0 : 255;
+   }
+}
+
+static int stbi__gif_header(stbi__context *s, stbi__gif *g, int *comp, int is_info)
+{
+   stbi_uc version;
+   if (stbi__get8(s) != 'G' || stbi__get8(s) != 'I' || stbi__get8(s) != 'F' || stbi__get8(s) != '8')
+      return stbi__err("not GIF", "Corrupt GIF");
+
+   version = stbi__get8(s);
+   if (version != '7' && version != '9')    return stbi__err("not GIF", "Corrupt GIF");
+   if (stbi__get8(s) != 'a')                return stbi__err("not GIF", "Corrupt GIF");
+
+   stbi__g_failure_reason = "";
+   g->w = stbi__get16le(s);
+   g->h = stbi__get16le(s);
+   g->flags = stbi__get8(s);
+   g->bgindex = stbi__get8(s);
+   g->ratio = stbi__get8(s);
+   g->transparent = -1;
+
+   if (comp != 0) *comp = 4;  // can't actually tell whether it's 3 or 4 until we parse the comments
+
+   if (is_info) return 1;
+
+   if (g->flags & 0x80)
+      stbi__gif_parse_colortable(s,g->pal, 2 << (g->flags & 7), -1);
+
+   return 1;
+}
+
+static int stbi__gif_info_raw(stbi__context *s, int *x, int *y, int *comp)
+{
+   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+   if (!stbi__gif_header(s, g, comp, 1)) {
+      STBI_FREE(g);
+      stbi__rewind( s );
+      return 0;
+   }
+   if (x) *x = g->w;
+   if (y) *y = g->h;
+   STBI_FREE(g);
+   return 1;
+}
+
+static void stbi__out_gif_code(stbi__gif *g, stbi__uint16 code)
+{
+   stbi_uc *p, *c;
+
+   // recurse to decode the prefixes, since the linked-list is backwards,
+   // and working backwards through an interleaved image would be nasty
+   if (g->codes[code].prefix >= 0)
+      stbi__out_gif_code(g, g->codes[code].prefix);
+
+   if (g->cur_y >= g->max_y) return;
+
+   p = &g->out[g->cur_x + g->cur_y];
+   c = &g->color_table[g->codes[code].suffix * 4];
+
+   if (c[3] >= 128) {
+      p[0] = c[2];
+      p[1] = c[1];
+      p[2] = c[0];
+      p[3] = c[3];
+   }
+   g->cur_x += 4;
+
+   if (g->cur_x >= g->max_x) {
+      g->cur_x = g->start_x;
+      g->cur_y += g->step;
+
+      while (g->cur_y >= g->max_y && g->parse > 0) {
+         g->step = (1 << g->parse) * g->line_size;
+         g->cur_y = g->start_y + (g->step >> 1);
+         --g->parse;
+      }
+   }
+}
+
+static stbi_uc *stbi__process_gif_raster(stbi__context *s, stbi__gif *g)
+{
+   stbi_uc lzw_cs;
+   stbi__int32 len, init_code;
+   stbi__uint32 first;
+   stbi__int32 codesize, codemask, avail, oldcode, bits, valid_bits, clear;
+   stbi__gif_lzw *p;
+
+   lzw_cs = stbi__get8(s);
+   if (lzw_cs > 12) return NULL;
+   clear = 1 << lzw_cs;
+   first = 1;
+   codesize = lzw_cs + 1;
+   codemask = (1 << codesize) - 1;
+   bits = 0;
+   valid_bits = 0;
+   for (init_code = 0; init_code < clear; init_code++) {
+      g->codes[init_code].prefix = -1;
+      g->codes[init_code].first = (stbi_uc) init_code;
+      g->codes[init_code].suffix = (stbi_uc) init_code;
+   }
+
+   // support no starting clear code
+   avail = clear+2;
+   oldcode = -1;
+
+   len = 0;
+   for(;;) {
+      if (valid_bits < codesize) {
+         if (len == 0) {
+            len = stbi__get8(s); // start new block
+            if (len == 0)
+               return g->out;
+         }
+         --len;
+         bits |= (stbi__int32) stbi__get8(s) << valid_bits;
+         valid_bits += 8;
+      } else {
+         stbi__int32 code = bits & codemask;
+         bits >>= codesize;
+         valid_bits -= codesize;
+         // @OPTIMIZE: is there some way we can accelerate the non-clear path?
+         if (code == clear) {  // clear code
+            codesize = lzw_cs + 1;
+            codemask = (1 << codesize) - 1;
+            avail = clear + 2;
+            oldcode = -1;
+            first = 0;
+         } else if (code == clear + 1) { // end of stream code
+            stbi__skip(s, len);
+            while ((len = stbi__get8(s)) > 0)
+               stbi__skip(s,len);
+            return g->out;
+         } else if (code <= avail) {
+            if (first) return stbi__errpuc("no clear code", "Corrupt GIF");
+
+            if (oldcode >= 0) {
+               p = &g->codes[avail++];
+               if (avail > 4096)        return stbi__errpuc("too many codes", "Corrupt GIF");
+               p->prefix = (stbi__int16) oldcode;
+               p->first = g->codes[oldcode].first;
+               p->suffix = (code == avail) ? p->first : g->codes[code].first;
+            } else if (code == avail)
+               return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+
+            stbi__out_gif_code(g, (stbi__uint16) code);
+
+            if ((avail & codemask) == 0 && avail <= 0x0FFF) {
+               codesize++;
+               codemask = (1 << codesize) - 1;
+            }
+
+            oldcode = code;
+         } else {
+            return stbi__errpuc("illegal code in raster", "Corrupt GIF");
+         }
+      }
+   }
+}
+
+static void stbi__fill_gif_background(stbi__gif *g, int x0, int y0, int x1, int y1)
+{
+   int x, y;
+   stbi_uc *c = g->pal[g->bgindex];
+   for (y = y0; y < y1; y += 4 * g->w) {
+      for (x = x0; x < x1; x += 4) {
+         stbi_uc *p  = &g->out[y + x];
+         p[0] = c[2];
+         p[1] = c[1];
+         p[2] = c[0];
+         p[3] = 0;
+      }
+   }
+}
+
+// this function is designed to support animated gifs, although stb_image doesn't support it
+static stbi_uc *stbi__gif_load_next(stbi__context *s, stbi__gif *g, int *comp, int req_comp)
+{
+   int i;
+   stbi_uc *prev_out = 0;
+
+   if (g->out == 0 && !stbi__gif_header(s, g, comp,0))
+      return 0; // stbi__g_failure_reason set by stbi__gif_header
+
+   prev_out = g->out;
+   g->out = (stbi_uc *) stbi__malloc(4 * g->w * g->h);
+   if (g->out == 0) return stbi__errpuc("outofmem", "Out of memory");
+
+   switch ((g->eflags & 0x1C) >> 2) {
+      case 0: // unspecified (also always used on 1st frame)
+         stbi__fill_gif_background(g, 0, 0, 4 * g->w, 4 * g->w * g->h);
+         break;
+      case 1: // do not dispose
+         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+         g->old_out = prev_out;
+         break;
+      case 2: // dispose to background
+         if (prev_out) memcpy(g->out, prev_out, 4 * g->w * g->h);
+         stbi__fill_gif_background(g, g->start_x, g->start_y, g->max_x, g->max_y);
+         break;
+      case 3: // dispose to previous
+         if (g->old_out) {
+            for (i = g->start_y; i < g->max_y; i += 4 * g->w)
+               memcpy(&g->out[i + g->start_x], &g->old_out[i + g->start_x], g->max_x - g->start_x);
+         }
+         break;
+   }
+
+   for (;;) {
+      switch (stbi__get8(s)) {
+         case 0x2C: /* Image Descriptor */
+         {
+            int prev_trans = -1;
+            stbi__int32 x, y, w, h;
+            stbi_uc *o;
+
+            x = stbi__get16le(s);
+            y = stbi__get16le(s);
+            w = stbi__get16le(s);
+            h = stbi__get16le(s);
+            if (((x + w) > (g->w)) || ((y + h) > (g->h)))
+               return stbi__errpuc("bad Image Descriptor", "Corrupt GIF");
+
+            g->line_size = g->w * 4;
+            g->start_x = x * 4;
+            g->start_y = y * g->line_size;
+            g->max_x   = g->start_x + w * 4;
+            g->max_y   = g->start_y + h * g->line_size;
+            g->cur_x   = g->start_x;
+            g->cur_y   = g->start_y;
+
+            g->lflags = stbi__get8(s);
+
+            if (g->lflags & 0x40) {
+               g->step = 8 * g->line_size; // first interlaced spacing
+               g->parse = 3;
+            } else {
+               g->step = g->line_size;
+               g->parse = 0;
+            }
+
+            if (g->lflags & 0x80) {
+               stbi__gif_parse_colortable(s,g->lpal, 2 << (g->lflags & 7), g->eflags & 0x01 ? g->transparent : -1);
+               g->color_table = (stbi_uc *) g->lpal;
+            } else if (g->flags & 0x80) {
+               if (g->transparent >= 0 && (g->eflags & 0x01)) {
+                  prev_trans = g->pal[g->transparent][3];
+                  g->pal[g->transparent][3] = 0;
+               }
+               g->color_table = (stbi_uc *) g->pal;
+            } else
+               return stbi__errpuc("missing color table", "Corrupt GIF");
+
+            o = stbi__process_gif_raster(s, g);
+            if (o == NULL) return NULL;
+
+            if (prev_trans != -1)
+               g->pal[g->transparent][3] = (stbi_uc) prev_trans;
+
+            return o;
+         }
+
+         case 0x21: // Comment Extension.
+         {
+            int len;
+            if (stbi__get8(s) == 0xF9) { // Graphic Control Extension.
+               len = stbi__get8(s);
+               if (len == 4) {
+                  g->eflags = stbi__get8(s);
+                  g->delay = stbi__get16le(s);
+                  g->transparent = stbi__get8(s);
+               } else {
+                  stbi__skip(s, len);
+                  break;
+               }
+            }
+            while ((len = stbi__get8(s)) != 0)
+               stbi__skip(s, len);
+            break;
+         }
+
+         case 0x3B: // gif stream termination code
+            return (stbi_uc *) s; // using '1' causes warning on some compilers
+
+         default:
+            return stbi__errpuc("unknown code", "Corrupt GIF");
+      }
+   }
+
+   STBI_NOTUSED(req_comp);
+}
+
+static stbi_uc *stbi__gif_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *u = 0;
+   stbi__gif* g = (stbi__gif*) stbi__malloc(sizeof(stbi__gif));
+   memset(g, 0, sizeof(*g));
+
+   u = stbi__gif_load_next(s, g, comp, req_comp);
+   if (u == (stbi_uc *) s) u = 0;  // end of animated gif marker
+   if (u) {
+      *x = g->w;
+      *y = g->h;
+      if (req_comp && req_comp != 4)
+         u = stbi__convert_format(u, 4, req_comp, g->w, g->h);
+   }
+   else if (g->out)
+      STBI_FREE(g->out);
+   STBI_FREE(g);
+   return u;
+}
+
+static int stbi__gif_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   return stbi__gif_info_raw(s,x,y,comp);
+}
+#endif
+
+// *************************************************************************************************
+// Radiance RGBE HDR loader
+// originally by Nicolas Schulz
+#ifndef STBI_NO_HDR
+static int stbi__hdr_test_core(stbi__context *s)
+{
+   const char *signature = "#?RADIANCE\n";
+   int i;
+   for (i=0; signature[i]; ++i)
+      if (stbi__get8(s) != signature[i])
+         return 0;
+   return 1;
+}
+
+static int stbi__hdr_test(stbi__context* s)
+{
+   int r = stbi__hdr_test_core(s);
+   stbi__rewind(s);
+   return r;
+}
+
+#define STBI__HDR_BUFLEN  1024
+static char *stbi__hdr_gettoken(stbi__context *z, char *buffer)
+{
+   int len=0;
+   char c = '\0';
+
+   c = (char) stbi__get8(z);
+
+   while (!stbi__at_eof(z) && c != '\n') {
+      buffer[len++] = c;
+      if (len == STBI__HDR_BUFLEN-1) {
+         // flush to end of line
+         while (!stbi__at_eof(z) && stbi__get8(z) != '\n')
+            ;
+         break;
+      }
+      c = (char) stbi__get8(z);
+   }
+
+   buffer[len] = 0;
+   return buffer;
+}
+
+static void stbi__hdr_convert(float *output, stbi_uc *input, int req_comp)
+{
+   if ( input[3] != 0 ) {
+      float f1;
+      // Exponent
+      f1 = (float) ldexp(1.0f, input[3] - (int)(128 + 8));
+      if (req_comp <= 2)
+         output[0] = (input[0] + input[1] + input[2]) * f1 / 3;
+      else {
+         output[0] = input[0] * f1;
+         output[1] = input[1] * f1;
+         output[2] = input[2] * f1;
+      }
+      if (req_comp == 2) output[1] = 1;
+      if (req_comp == 4) output[3] = 1;
+   } else {
+      switch (req_comp) {
+         case 4: output[3] = 1; /* fallthrough */
+         case 3: output[0] = output[1] = output[2] = 0;
+                 break;
+         case 2: output[1] = 1; /* fallthrough */
+         case 1: output[0] = 0;
+                 break;
+      }
+   }
+}
+
+static float *stbi__hdr_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+   int width, height;
+   stbi_uc *scanline;
+   float *hdr_data;
+   int len;
+   unsigned char count, value;
+   int i, j, k, c1,c2, z;
+
+
+   // Check identifier
+   if (strcmp(stbi__hdr_gettoken(s,buffer), "#?RADIANCE") != 0)
+      return stbi__errpf("not HDR", "Corrupt HDR image");
+
+   // Parse header
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid)    return stbi__errpf("unsupported format", "Unsupported HDR format");
+
+   // Parse width and height
+   // can't use sscanf() if we're not using stdio!
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   height = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3))  return stbi__errpf("unsupported data layout", "Unsupported HDR format");
+   token += 3;
+   width = (int) strtol(token, NULL, 10);
+
+   *x = width;
+   *y = height;
+
+   if (comp) *comp = 3;
+   if (req_comp == 0) req_comp = 3;
+
+   // Read data
+   hdr_data = (float *) stbi__malloc(height * width * req_comp * sizeof(float));
+
+   // Load image data
+   // image data is stored as some number of sca
+   if ( width < 8 || width >= 32768) {
+      // Read flat data
+      for (j=0; j < height; ++j) {
+         for (i=0; i < width; ++i) {
+            stbi_uc rgbe[4];
+           main_decode_loop:
+            stbi__getn(s, rgbe, 4);
+            stbi__hdr_convert(hdr_data + j * width * req_comp + i * req_comp, rgbe, req_comp);
+         }
+      }
+   } else {
+      // Read RLE-encoded data
+      scanline = NULL;
+
+      for (j = 0; j < height; ++j) {
+         c1 = stbi__get8(s);
+         c2 = stbi__get8(s);
+         len = stbi__get8(s);
+         if (c1 != 2 || c2 != 2 || (len & 0x80)) {
+            // not run-length encoded, so we have to actually use THIS data as a decoded
+            // pixel (note this can't be a valid pixel--one of RGB must be >= 128)
+            stbi_uc rgbe[4];
+            rgbe[0] = (stbi_uc) c1;
+            rgbe[1] = (stbi_uc) c2;
+            rgbe[2] = (stbi_uc) len;
+            rgbe[3] = (stbi_uc) stbi__get8(s);
+            stbi__hdr_convert(hdr_data, rgbe, req_comp);
+            i = 1;
+            j = 0;
+            STBI_FREE(scanline);
+            goto main_decode_loop; // yes, this makes no sense
+         }
+         len <<= 8;
+         len |= stbi__get8(s);
+         if (len != width) { STBI_FREE(hdr_data); STBI_FREE(scanline); return stbi__errpf("invalid decoded scanline length", "corrupt HDR"); }
+         if (scanline == NULL) scanline = (stbi_uc *) stbi__malloc(width * 4);
+
+         for (k = 0; k < 4; ++k) {
+            i = 0;
+            while (i < width) {
+               count = stbi__get8(s);
+               if (count > 128) {
+                  // Run
+                  value = stbi__get8(s);
+                  count -= 128;
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = value;
+               } else {
+                  // Dump
+                  for (z = 0; z < count; ++z)
+                     scanline[i++ * 4 + k] = stbi__get8(s);
+               }
+            }
+         }
+         for (i=0; i < width; ++i)
+            stbi__hdr_convert(hdr_data+(j*width + i)*req_comp, scanline + i*4, req_comp);
+      }
+      STBI_FREE(scanline);
+   }
+
+   return hdr_data;
+}
+
+static int stbi__hdr_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   char buffer[STBI__HDR_BUFLEN];
+   char *token;
+   int valid = 0;
+
+   if (stbi__hdr_test(s) == 0) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   for(;;) {
+      token = stbi__hdr_gettoken(s,buffer);
+      if (token[0] == 0) break;
+      if (strcmp(token, "FORMAT=32-bit_rle_rgbe") == 0) valid = 1;
+   }
+
+   if (!valid) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token = stbi__hdr_gettoken(s,buffer);
+   if (strncmp(token, "-Y ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *y = (int) strtol(token, &token, 10);
+   while (*token == ' ') ++token;
+   if (strncmp(token, "+X ", 3)) {
+       stbi__rewind( s );
+       return 0;
+   }
+   token += 3;
+   *x = (int) strtol(token, NULL, 10);
+   *comp = 3;
+   return 1;
+}
+#endif // STBI_NO_HDR
+
+#ifndef STBI_NO_BMP
+static int stbi__bmp_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   void *p;
+   stbi__bmp_data info;
+
+   info.all_a = 255;
+   p = stbi__bmp_parse_header(s, &info);
+   stbi__rewind( s );
+   if (p == NULL)
+      return 0;
+   *x = s->img_x;
+   *y = s->img_y;
+   *comp = info.ma ? 4 : 3;
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PSD
+static int stbi__psd_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int channelCount;
+   if (stbi__get32be(s) != 0x38425053) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 1) {
+       stbi__rewind( s );
+       return 0;
+   }
+   stbi__skip(s, 6);
+   channelCount = stbi__get16be(s);
+   if (channelCount < 0 || channelCount > 16) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *y = stbi__get32be(s);
+   *x = stbi__get32be(s);
+   if (stbi__get16be(s) != 8) {
+       stbi__rewind( s );
+       return 0;
+   }
+   if (stbi__get16be(s) != 3) {
+       stbi__rewind( s );
+       return 0;
+   }
+   *comp = 4;
+   return 1;
+}
+#endif
+
+#ifndef STBI_NO_PIC
+static int stbi__pic_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int act_comp=0,num_packets=0,chained;
+   stbi__pic_packet packets[10];
+
+   if (!stbi__pic_is4(s,"\x53\x80\xF6\x34")) {
+      stbi__rewind(s);
+      return 0;
+   }
+
+   stbi__skip(s, 88);
+
+   *x = stbi__get16be(s);
+   *y = stbi__get16be(s);
+   if (stbi__at_eof(s)) {
+      stbi__rewind( s);
+      return 0;
+   }
+   if ( (*x) != 0 && (1 << 28) / (*x) < (*y)) {
+      stbi__rewind( s );
+      return 0;
+   }
+
+   stbi__skip(s, 8);
+
+   do {
+      stbi__pic_packet *packet;
+
+      if (num_packets==sizeof(packets)/sizeof(packets[0]))
+         return 0;
+
+      packet = &packets[num_packets++];
+      chained = stbi__get8(s);
+      packet->size    = stbi__get8(s);
+      packet->type    = stbi__get8(s);
+      packet->channel = stbi__get8(s);
+      act_comp |= packet->channel;
+
+      if (stbi__at_eof(s)) {
+          stbi__rewind( s );
+          return 0;
+      }
+      if (packet->size != 8) {
+          stbi__rewind( s );
+          return 0;
+      }
+   } while (chained);
+
+   *comp = (act_comp & 0x10 ? 4 : 3);
+
+   return 1;
+}
+#endif
+
+// *************************************************************************************************
+// Portable Gray Map and Portable Pixel Map loader
+// by Ken Miller
+//
+// PGM: http://netpbm.sourceforge.net/doc/pgm.html
+// PPM: http://netpbm.sourceforge.net/doc/ppm.html
+//
+// Known limitations:
+//    Does not support comments in the header section
+//    Does not support ASCII image data (formats P2 and P3)
+//    Does not support 16-bit-per-channel
+
+#ifndef STBI_NO_PNM
+
+static int      stbi__pnm_test(stbi__context *s)
+{
+   char p, t;
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+   return 1;
+}
+
+static stbi_uc *stbi__pnm_load(stbi__context *s, int *x, int *y, int *comp, int req_comp)
+{
+   stbi_uc *out;
+   if (!stbi__pnm_info(s, (int *)&s->img_x, (int *)&s->img_y, (int *)&s->img_n))
+      return 0;
+   *x = s->img_x;
+   *y = s->img_y;
+   *comp = s->img_n;
+
+   out = (stbi_uc *) stbi__malloc(s->img_n * s->img_x * s->img_y);
+   if (!out) return stbi__errpuc("outofmem", "Out of memory");
+   stbi__getn(s, out, s->img_n * s->img_x * s->img_y);
+
+   if (req_comp && req_comp != s->img_n) {
+      out = stbi__convert_format(out, s->img_n, req_comp, s->img_x, s->img_y);
+      if (out == NULL) return out; // stbi__convert_format frees input on failure
+   }
+   return out;
+}
+
+static int      stbi__pnm_isspace(char c)
+{
+   return c == ' ' || c == '\t' || c == '\n' || c == '\v' || c == '\f' || c == '\r';
+}
+
+static void     stbi__pnm_skip_whitespace(stbi__context *s, char *c)
+{
+   for (;;) {
+      while (!stbi__at_eof(s) && stbi__pnm_isspace(*c))
+         *c = (char) stbi__get8(s);
+
+      if (stbi__at_eof(s) || *c != '#')
+         break;
+
+      while (!stbi__at_eof(s) && *c != '\n' && *c != '\r' )
+         *c = (char) stbi__get8(s);
+   }
+}
+
+static int      stbi__pnm_isdigit(char c)
+{
+   return c >= '0' && c <= '9';
+}
+
+static int      stbi__pnm_getinteger(stbi__context *s, char *c)
+{
+   int value = 0;
+
+   while (!stbi__at_eof(s) && stbi__pnm_isdigit(*c)) {
+      value = value*10 + (*c - '0');
+      *c = (char) stbi__get8(s);
+   }
+
+   return value;
+}
+
+static int      stbi__pnm_info(stbi__context *s, int *x, int *y, int *comp)
+{
+   int maxv;
+   char c, p, t;
+
+   stbi__rewind( s );
+
+   // Get identifier
+   p = (char) stbi__get8(s);
+   t = (char) stbi__get8(s);
+   if (p != 'P' || (t != '5' && t != '6')) {
+       stbi__rewind( s );
+       return 0;
+   }
+
+   *comp = (t == '6') ? 3 : 1;  // '5' is 1-component .pgm; '6' is 3-component .ppm
+
+   c = (char) stbi__get8(s);
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *x = stbi__pnm_getinteger(s, &c); // read width
+   stbi__pnm_skip_whitespace(s, &c);
+
+   *y = stbi__pnm_getinteger(s, &c); // read height
+   stbi__pnm_skip_whitespace(s, &c);
+
+   maxv = stbi__pnm_getinteger(s, &c);  // read max value
+
+   if (maxv > 255)
+      return stbi__err("max value > 255", "PPM image not 8-bit");
+   else
+      return 1;
+}
+#endif
+
+static int stbi__info_main(stbi__context *s, int *x, int *y, int *comp)
+{
+   #ifndef STBI_NO_JPEG
+   if (stbi__jpeg_info(s, x, y, comp)) return 1;
+   #endif
+
+   #ifndef STBI_NO_PNG
+   if (stbi__png_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_GIF
+   if (stbi__gif_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_BMP
+   if (stbi__bmp_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PSD
+   if (stbi__psd_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PIC
+   if (stbi__pic_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_PNM
+   if (stbi__pnm_info(s, x, y, comp))  return 1;
+   #endif
+
+   #ifndef STBI_NO_HDR
+   if (stbi__hdr_info(s, x, y, comp))  return 1;
+   #endif
+
+   // test tga last because it's a crappy test!
+   #ifndef STBI_NO_TGA
+   if (stbi__tga_info(s, x, y, comp))
+       return 1;
+   #endif
+   return stbi__err("unknown image type", "Image not of any known type, or corrupt");
+}
+
+#ifndef STBI_NO_STDIO
+STBIDEF int stbi_info(char const *filename, int *x, int *y, int *comp)
+{
+    FILE *f = stbi__fopen(filename, "rb");
+    int result;
+    if (!f) return stbi__err("can't fopen", "Unable to open file");
+    result = stbi_info_from_file(f, x, y, comp);
+    fclose(f);
+    return result;
+}
+
+STBIDEF int stbi_info_from_file(FILE *f, int *x, int *y, int *comp)
+{
+   int r;
+   stbi__context s;
+   long pos = ftell(f);
+   stbi__start_file(&s, f);
+   r = stbi__info_main(&s,x,y,comp);
+   fseek(f,pos,SEEK_SET);
+   return r;
+}
+#endif // !STBI_NO_STDIO
+
+STBIDEF int stbi_info_from_memory(stbi_uc const *buffer, int len, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_mem(&s,buffer,len);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+STBIDEF int stbi_info_from_callbacks(stbi_io_callbacks const *c, void *user, int *x, int *y, int *comp)
+{
+   stbi__context s;
+   stbi__start_callbacks(&s, (stbi_io_callbacks *) c, user);
+   return stbi__info_main(&s,x,y,comp);
+}
+
+#endif // STB_IMAGE_IMPLEMENTATION
+
+/*
+   revision history:
+      2.12  (2016-04-02) fix typo in 2.11 PSD fix that caused crashes
+      2.11  (2016-04-02) allocate large structures on the stack
+                         remove white matting for transparent PSD
+                         fix reported channel count for PNG & BMP
+                         re-enable SSE2 in non-gcc 64-bit
+                         support RGB-formatted JPEG
+                         read 16-bit PNGs (only as 8-bit)
+      2.10  (2016-01-22) avoid warning introduced in 2.09 by STBI_REALLOC_SIZED
+      2.09  (2016-01-16) allow comments in PNM files
+                         16-bit-per-pixel TGA (not bit-per-component)
+                         info() for TGA could break due to .hdr handling
+                         info() for BMP to shares code instead of sloppy parse
+                         can use STBI_REALLOC_SIZED if allocator doesn't support realloc
+                         code cleanup
+      2.08  (2015-09-13) fix to 2.07 cleanup, reading RGB PSD as RGBA
+      2.07  (2015-09-13) fix compiler warnings
+                         partial animated GIF support
+                         limited 16-bpc PSD support
+                         #ifdef unused functions
+                         bug with < 92 byte PIC,PNM,HDR,TGA
+      2.06  (2015-04-19) fix bug where PSD returns wrong '*comp' value
+      2.05  (2015-04-19) fix bug in progressive JPEG handling, fix warning
+      2.04  (2015-04-15) try to re-enable SIMD on MinGW 64-bit
+      2.03  (2015-04-12) extra corruption checking (mmozeiko)
+                         stbi_set_flip_vertically_on_load (nguillemot)
+                         fix NEON support; fix mingw support
+      2.02  (2015-01-19) fix incorrect assert, fix warning
+      2.01  (2015-01-17) fix various warnings; suppress SIMD on gcc 32-bit without -msse2
+      2.00b (2014-12-25) fix STBI_MALLOC in progressive JPEG
+      2.00  (2014-12-25) optimize JPG, including x86 SSE2 & NEON SIMD (ryg)
+                         progressive JPEG (stb)
+                         PGM/PPM support (Ken Miller)
+                         STBI_MALLOC,STBI_REALLOC,STBI_FREE
+                         GIF bugfix -- seemingly never worked
+                         STBI_NO_*, STBI_ONLY_*
+      1.48  (2014-12-14) fix incorrectly-named assert()
+      1.47  (2014-12-14) 1/2/4-bit PNG support, both direct and paletted (Omar Cornut & stb)
+                         optimize PNG (ryg)
+                         fix bug in interlaced PNG with user-specified channel count (stb)
+      1.46  (2014-08-26)
+              fix broken tRNS chunk (colorkey-style transparency) in non-paletted PNG
+      1.45  (2014-08-16)
+              fix MSVC-ARM internal compiler error by wrapping malloc
+      1.44  (2014-08-07)
+              various warning fixes from Ronny Chevalier
+      1.43  (2014-07-15)
+              fix MSVC-only compiler problem in code changed in 1.42
+      1.42  (2014-07-09)
+              don't define _CRT_SECURE_NO_WARNINGS (affects user code)
+              fixes to stbi__cleanup_jpeg path
+              added STBI_ASSERT to avoid requiring assert.h
+      1.41  (2014-06-25)
+              fix search&replace from 1.36 that messed up comments/error messages
+      1.40  (2014-06-22)
+              fix gcc struct-initialization warning
+      1.39  (2014-06-15)
+              fix to TGA optimization when req_comp != number of components in TGA;
+              fix to GIF loading because BMP wasn't rewinding (whoops, no GIFs in my test suite)
+              add support for BMP version 5 (more ignored fields)
+      1.38  (2014-06-06)
+              suppress MSVC warnings on integer casts truncating values
+              fix accidental rename of 'skip' field of I/O
+      1.37  (2014-06-04)
+              remove duplicate typedef
+      1.36  (2014-06-03)
+              convert to header file single-file library
+              if de-iphone isn't set, load iphone images color-swapped instead of returning NULL
+      1.35  (2014-05-27)
+              various warnings
+              fix broken STBI_SIMD path
+              fix bug where stbi_load_from_file no longer left file pointer in correct place
+              fix broken non-easy path for 32-bit BMP (possibly never used)
+              TGA optimization by Arseny Kapoulkine
+      1.34  (unknown)
+              use STBI_NOTUSED in stbi__resample_row_generic(), fix one more leak in tga failure case
+      1.33  (2011-07-14)
+              make stbi_is_hdr work in STBI_NO_HDR (as specified), minor compiler-friendly improvements
+      1.32  (2011-07-13)
+              support for "info" function for all supported filetypes (SpartanJ)
+      1.31  (2011-06-20)
+              a few more leak fixes, bug in PNG handling (SpartanJ)
+      1.30  (2011-06-11)
+              added ability to load files via callbacks to accomidate custom input streams (Ben Wenger)
+              removed deprecated format-specific test/load functions
+              removed support for installable file formats (stbi_loader) -- would have been broken for IO callbacks anyway
+              error cases in bmp and tga give messages and don't leak (Raymond Barbiero, grisha)
+              fix inefficiency in decoding 32-bit BMP (David Woo)
+      1.29  (2010-08-16)
+              various warning fixes from Aurelien Pocheville
+      1.28  (2010-08-01)
+              fix bug in GIF palette transparency (SpartanJ)
+      1.27  (2010-08-01)
+              cast-to-stbi_uc to fix warnings
+      1.26  (2010-07-24)
+              fix bug in file buffering for PNG reported by SpartanJ
+      1.25  (2010-07-17)
+              refix trans_data warning (Won Chun)
+      1.24  (2010-07-12)
+              perf improvements reading from files on platforms with lock-heavy fgetc()
+              minor perf improvements for jpeg
+              deprecated type-specific functions so we'll get feedback if they're needed
+              attempt to fix trans_data warning (Won Chun)
+      1.23    fixed bug in iPhone support
+      1.22  (2010-07-10)
+              removed image *writing* support
+              stbi_info support from Jetro Lauha
+              GIF support from Jean-Marc Lienher
+              iPhone PNG-extensions from James Brown
+              warning-fixes from Nicolas Schulz and Janez Zemva (i.stbi__err. Janez (U+017D)emva)
+      1.21    fix use of 'stbi_uc' in header (reported by jon blow)
+      1.20    added support for Softimage PIC, by Tom Seddon
+      1.19    bug in interlaced PNG corruption check (found by ryg)
+      1.18  (2008-08-02)
+              fix a threading bug (local mutable static)
+      1.17    support interlaced PNG
+      1.16    major bugfix - stbi__convert_format converted one too many pixels
+      1.15    initialize some fields for thread safety
+      1.14    fix threadsafe conversion bug
+              header-file-only version (#define STBI_HEADER_FILE_ONLY before including)
+      1.13    threadsafe
+      1.12    const qualifiers in the API
+      1.11    Support installable IDCT, colorspace conversion routines
+      1.10    Fixes for 64-bit (don't use "unsigned long")
+              optimized upsampling by Fabian "ryg" Giesen
+      1.09    Fix format-conversion for PSD code (bad global variables!)
+      1.08    Thatcher Ulrich's PSD code integrated by Nicolas Schulz
+      1.07    attempt to fix C++ warning/errors again
+      1.06    attempt to fix C++ warning/errors again
+      1.05    fix TGA loading to return correct *comp and use good luminance calc
+      1.04    default float alpha is 1, not 255; use 'void *' for stbi_image_free
+      1.03    bugfixes to STBI_NO_STDIO, STBI_NO_HDR
+      1.02    support for (subset of) HDR files, float interface for preferred access to them
+      1.01    fix bug: possible bug in handling right-side up bmps... not sure
+              fix bug: the stbi__bmp_load() and stbi__tga_load() functions didn't work at all
+      1.00    interface to zlib that skips zlib header
+      0.99    correct handling of alpha in palette
+      0.98    TGA loader by lonesock; dynamically add loaders (untested)
+      0.97    jpeg errors on too large a file; also catch another malloc failure
+      0.96    fix detection of invalid v value - particleman@mollyrocket forum
+      0.95    during header scan, seek to markers in case of padding
+      0.94    STBI_NO_STDIO to disable stdio usage; rename all #defines the same
+      0.93    handle jpegtran output; verbose errors
+      0.92    read 4,8,16,24,32-bit BMP files of several formats
+      0.91    output 24-bit Windows 3.0 BMP files
+      0.90    fix a few more warnings; bump version number to approach 1.0
+      0.61    bugfixes due to Marc LeBlanc, Christopher Lloyd
+      0.60    fix compiling as c++
+      0.59    fix warnings: merge Dave Moore's -Wall fixes
+      0.58    fix bug: zlib uncompressed mode len/nlen was wrong endian
+      0.57    fix bug: jpg last huffman symbol before marker was >9 bits but less than 16 available
+      0.56    fix bug: zlib uncompressed mode len vs. nlen
+      0.55    fix bug: restart_interval not initialized to 0
+      0.54    allow NULL for 'int *comp'
+      0.53    fix bug in png 3->4; speedup png decoding
+      0.52    png handles req_comp=3,4 directly; minor cleanup; jpeg comments
+      0.51    obey req_comp requests, 1-component jpegs return as 1-component,
+              on 'test' only check type, not whether we support this variant
+      0.50  (2006-11-19)
+              first released version
+*/
diff --git a/core/generated/.gitkeep b/core/generated/.gitkeep
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/core/include/tangram/data/clientGeoJsonSource.h b/core/include/tangram/data/clientGeoJsonSource.h
new file mode 100644 (file)
index 0000000..cdfddbd
--- /dev/null
@@ -0,0 +1,55 @@
+#pragma once
+
+#include "data/tileSource.h"
+#include "util/types.h"
+
+#include <mutex>
+
+
+namespace Tangram {
+
+class Platform;
+
+struct Properties;
+
+struct ClientGeoJsonData;
+
+class ClientGeoJsonSource : public TileSource {
+
+public:
+
+    ClientGeoJsonSource(std::shared_ptr<Platform> _platform, const std::string& _name, const std::string& _url,
+                        int32_t _minDisplayZoom = -1, int32_t _maxDisplayZoom = -1, int32_t _maxZoom = 18,
+                        int32_t _zoomBias = 0);
+    ~ClientGeoJsonSource();
+
+    // http://www.iana.org/assignments/media-types/application/geo+json
+    virtual const char* mimeType() const override { return "application/geo+json"; };
+
+    // Add geometry from a GeoJSON string
+    void addData(const std::string& _data);
+    void addPoint(const Properties& _tags, LngLat _point);
+    void addLine(const Properties& _tags, const Coordinates& _line);
+    void addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly);
+
+    virtual void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
+    std::shared_ptr<TileTask> createTask(TileID _tileId, int _subTask) override;
+
+    virtual void cancelLoadingTile(const TileID& _tile) override {};
+    virtual void clearData() override;
+
+protected:
+
+    virtual std::shared_ptr<TileData> parse(const TileTask& _task,
+                                            const MapProjection& _projection) const override;
+
+    std::unique_ptr<ClientGeoJsonData> m_store;
+
+    mutable std::mutex m_mutexStore;
+    bool m_hasPendingData = false;
+
+    std::shared_ptr<Platform> m_platform;
+
+};
+
+}
diff --git a/core/include/tangram/data/properties.h b/core/include/tangram/data/properties.h
new file mode 100644 (file)
index 0000000..708655a
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma once
+
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class Value;
+struct PropertyItem;
+
+struct Properties {
+    using Item = PropertyItem;
+
+    Properties();
+    ~Properties();
+
+    Properties(const Properties& _other) = default;
+    Properties(Properties&& _other) = default;
+    Properties(std::vector<Item>&& _items);
+    Properties& operator=(const Properties& _other) = default;
+    Properties& operator=(Properties&& _other);
+
+    const Value& get(const std::string& key) const;
+
+    void sort();
+
+    void clear();
+
+    bool contains(const std::string& key) const;
+
+    bool getNumber(const std::string& key, double& value) const;
+
+    double getNumber(const std::string& key) const;
+
+    bool getString(const std::string& key, std::string& value) const;
+
+    const std::string& getString(const std::string& key) const;
+
+    std::string asString(const Value& value) const;
+
+    std::string getAsString(const std::string& key) const;
+
+    bool getAsString(const std::string& key, std::string& value) const;
+
+    std::string toJson() const;
+
+    void set(std::string key, std::string value);
+    void set(std::string key, double value);
+
+    void setSorted(std::vector<Item>&& _items);
+
+    // template <typename... Args> void set(std::string key, Args&&... args) {
+    //     props.emplace_back(std::move(key), Value{std::forward<Args>(args)...});
+    //     sort();
+    // }
+
+    const std::vector<Item>& items() const { return props; }
+
+    int32_t sourceId;
+
+    static bool keyComparator(const std::string& a, const std::string& b) {
+        if (a.size() == b.size()) {
+            return a < b;
+        } else {
+            return a.size() < b.size();
+        }
+    }
+private:
+    std::vector<Item> props;
+};
+
+}
diff --git a/core/include/tangram/data/propertyItem.h b/core/include/tangram/data/propertyItem.h
new file mode 100644 (file)
index 0000000..e2a20d9
--- /dev/null
@@ -0,0 +1,20 @@
+#pragma once
+
+#include "util/variant.h"
+
+namespace Tangram {
+
+struct PropertyItem {
+    PropertyItem(std::string _key, Value _value) :
+        key(std::move(_key)), value(std::move(_value)) {}
+
+    std::string key;
+    Value value;
+    bool operator<(const PropertyItem& _rhs) const {
+        return key.size() == _rhs.key.size()
+            ? key < _rhs.key
+            : key.size() < _rhs.key.size();
+    }
+};
+
+}
diff --git a/core/include/tangram/data/tileSource.h b/core/include/tangram/data/tileSource.h
new file mode 100644 (file)
index 0000000..6d5d4a7
--- /dev/null
@@ -0,0 +1,165 @@
+#pragma once
+
+#include "tile/tileTask.h"
+
+#include <memory>
+#include <mutex>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class MapProjection;
+struct TileData;
+struct TileID;
+struct Raster;
+class Tile;
+class TileManager;
+struct RawCache;
+class Texture;
+
+class TileSource : public std::enable_shared_from_this<TileSource> {
+
+public:
+
+    /* Calculate the zoom level bias to be applied given tileSize in pixel units.
+     * 256  pixel -> 0
+     * 512  pixel -> 1
+     * 1024 pixel -> 2
+     */
+    static int32_t zoomBiasFromTileSize(int32_t tileSize);
+
+    struct DataSource {
+        virtual ~DataSource() {}
+
+        virtual bool loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) = 0;
+
+        /* Stops any running I/O tasks pertaining to @_tile */
+        virtual void cancelLoadingTile(const TileID& _tile) {
+            if (next) { next->cancelLoadingTile(_tile); }
+        }
+
+        virtual void clear() { if (next) next->clear(); }
+
+        void setNext(std::unique_ptr<DataSource> _next) {
+            next = std::move(_next);
+            next->level = level + 1;
+        }
+        std::unique_ptr<DataSource> next;
+        int level = 0;
+    };
+
+    enum class Format {
+        GeoJson,
+        TopoJson,
+        Mvt,
+    };
+
+    /* Tile data sources must have a name and a URL template that defines where to find
+     * a tile based on its coordinates. A URL template includes exactly one occurrance
+     * each of '{x}', '{y}', and '{z}' which will be replaced by the x index, y index,
+     * and zoom level of tiles to produce their URL.
+     */
+    TileSource(const std::string& _name, std::unique_ptr<DataSource> _sources,
+               int32_t _minDisplayZoom = -1, int32_t _maxDisplayZoom = -1, int32_t _maxZoom = 18,
+               int32_t _zoomBias = 0);
+
+    virtual ~TileSource();
+
+    /**
+     * @return the mime-type of the DataSource.
+     */
+    virtual const char* mimeType() const;
+
+    /* Fetches data for the map tile specified by @_tileID
+     *
+     * LoadTile starts an asynchronous I/O task to retrieve the data for a tile. When
+     * the I/O task is complete, the tile data is added to a queue in @_tileManager for
+     * further processing before it is renderable.
+     */
+    virtual void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb);
+
+    /* Stops any running I/O tasks pertaining to @_tile */
+    virtual void cancelLoadingTile(const TileID& _tile);
+
+    /* Parse a <TileTask> with data into a <TileData>, returning an empty TileData on failure */
+    virtual std::shared_ptr<TileData> parse(const TileTask& _task, const MapProjection& _projection) const;
+
+    /* Clears all data associated with this TileSource */
+    virtual void clearData();
+
+    const std::string& name() const { return m_name; }
+
+    virtual void clearRasters();
+    virtual void clearRaster(const TileID& id);
+
+    virtual std::shared_ptr<TileTask> createTask(TileID _tile, int _subTask = -1);
+
+    /* ID of this TileSource instance */
+    int32_t id() const { return m_id; }
+
+    /* Generation ID of TileSource state (incremented for each update, e.g. on clearData()) */
+    int64_t generation() const { return m_generation; }
+
+    int32_t minDisplayZoom() const { return m_minDisplayZoom; }
+    int32_t maxDisplayZoom() const { return m_maxDisplayZoom; }
+    int32_t maxZoom() const { return m_maxZoom; }
+    int32_t zoomBias() const { return m_zoomBias; }
+
+    bool isActiveForZoom(const float _zoom) const {
+        return _zoom >= m_minDisplayZoom && (m_maxDisplayZoom == -1 || _zoom <= m_maxDisplayZoom);
+    }
+
+    /* assign/get raster datasources to this datasource */
+    void addRasterSource(std::shared_ptr<TileSource> _dataSource);
+    auto& rasterSources() { return m_rasterSources; }
+    const auto& rasterSources() const { return m_rasterSources; }
+
+    bool generateGeometry() const { return m_generateGeometry; }
+    void generateGeometry(bool generateGeometry) { m_generateGeometry = generateGeometry; }
+
+    /* Avoid RTTI by adding a boolean check on the data source object */
+    virtual bool isRaster() const { return false; }
+
+    void setFormat(Format format) { m_format = format; }
+
+protected:
+
+    void createSubTasks(std::shared_ptr<TileTask> _task);
+
+    // This datasource is used to generate actual tile geometry
+    bool m_generateGeometry = false;
+
+    // Name used to identify this source in the style sheet
+    std::string m_name;
+
+    // Minimum zoom for which tiles will be displayed
+    int32_t m_minDisplayZoom;
+
+    // Maximum zoom for which tiles will be displayed
+    int32_t m_maxDisplayZoom;
+
+    // Maximum zoom for which tiles will be requested
+    int32_t m_maxZoom;
+
+    // controls the zoom level for the tiles of the tilesource to scale the tiles to
+    // apt pixel
+    // 0: 256 pixel tiles
+    // 1: 512 pixel tiles
+    int32_t m_zoomBias;
+
+    // Unique id for TileSource
+    int32_t m_id;
+
+    // Generation of dynamic TileSource state (incremented for each update)
+    int64_t m_generation = 1;
+
+    Format m_format = Format::GeoJson;
+
+    /* vector of raster sources (as raster samplers) referenced by this datasource */
+    std::vector<std::shared_ptr<TileSource>> m_rasterSources;
+
+    std::unique_ptr<DataSource> m_sources;
+};
+
+}
diff --git a/core/include/tangram/log.h b/core/include/tangram/log.h
new file mode 100644 (file)
index 0000000..3c251e3
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+
+#include "debug/textDisplay.h"
+#include "platform.h"
+
+#include <atomic>
+
+/*
+ * Log utilities:
+ * LOGD: Debug log, LOG_LEVEL >= 3
+ * LOGW: Warning log, LOG_LEVEL >= 2
+ * LOGE: Error log, LOG_LEVEL >= 1
+ * LOGN: Notification log (displayed once), LOG_LEVEL >= 0
+ * LOG: Default log, LOG_LEVEL >= 0
+ * LOGS: Screen log, no LOG_LEVEL
+ */
+
+#define __FILENAME__ (strrchr(__FILE__, '/') ? strrchr(__FILE__, '/') + 1 : __FILE__)
+#define TANGRAM_MAX_BUFFER_LOG_SIZE 99999
+
+#if LOG_LEVEL >= 3
+#define LOGD(fmt, ...) \
+do { logMsg("DEBUG %s:%d: " fmt "\n", __FILENAME__, __LINE__, ## __VA_ARGS__); } while(0)
+#else
+#define LOGD(fmt, ...)
+#endif
+
+#if LOG_LEVEL >= 2
+#define LOGW(fmt, ...) \
+do { logMsg("WARNING %s:%d: " fmt "\n", __FILENAME__, __LINE__, ## __VA_ARGS__); } while(0)
+#else
+#define LOGW(fmt, ...)
+#endif
+
+#if LOG_LEVEL >= 1
+#define LOGE(fmt, ...) \
+do { logMsg("ERROR %s:%d: " fmt "\n", __FILENAME__, __LINE__, ## __VA_ARGS__); } while(0)
+#else
+#define LOGE(fmt, ...)
+#endif
+
+#if LOG_LEVEL >= 0
+// The 'please notice but don't be too annoying' logger:
+#define LOGN(fmt, ...)                                                                                                 \
+    do {                                                                                                               \
+        static std::atomic<size_t> _lock(0);                                                            \
+        if (_lock++ < 42) { logMsg("NOTIFY %s:%d: " fmt "\n", __FILENAME__, __LINE__, ##__VA_ARGS__); } \
+    } while (0)
+
+#define LOG(fmt, ...)                                                   \
+    do { logMsg("TANGRAM %s:%d: " fmt "\n", __FILENAME__, __LINE__, ##__VA_ARGS__); } while (0)
+#else
+#define LOG(fmt, ...)
+#define LOGN(fmt, ...)
+#endif
+
+#define LOGS(fmt, ...) \
+do { TextDisplay::Instance().log(fmt, ## __VA_ARGS__); } while(0)
diff --git a/core/include/tangram/platform.h b/core/include/tangram/platform.h
new file mode 100644 (file)
index 0000000..6c8ccc8
--- /dev/null
@@ -0,0 +1,83 @@
+#pragma once
+
+#include <functional>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+
+// Function type for receiving data from a successful network request
+using UrlCallback = std::function<void(std::vector<char>&&)>;
+
+using FontSourceLoader = std::function<std::vector<char>()>;
+
+struct FontSourceHandle {
+    FontSourceHandle(std::string _path) : path(_path) {}
+    FontSourceHandle(FontSourceLoader _loader) : load(_loader) {}
+
+    std::string path;
+    FontSourceLoader load;
+};
+
+// Print a formatted message to the console
+// Uses printf syntax to write a string to stderr (or logcat, on Android)
+void logMsg(const char* fmt, ...);
+
+void initGLExtensions();
+
+// Set the priority of the current thread. Priority is equivalent to pthread niceness
+void setCurrentThreadPriority(int priority);
+
+class Platform {
+
+public:
+
+    Platform();
+    virtual ~Platform();
+
+    // Request that a new frame be rendered by the windowing system
+    virtual void requestRender() const = 0;
+
+    // If called with 'true', the windowing system will re-draw frames continuously;
+    // otherwise new frames will only be drawn when 'requestRender' is called.
+    virtual void setContinuousRendering(bool _isContinuous);
+
+    virtual bool isContinuousRendering() const;
+
+    virtual std::string resolveAssetPath(const std::string& path) const;
+
+    // Read a file as a string
+    // Opens the file at the _path and returns a string with its contents.
+    // If the file cannot be found or read, the returned string is empty.
+    virtual std::string stringFromFile(const char* _path) const;
+
+    // Read a file into memory
+    // Opens the file at _path then allocates and returns a pointer to memory
+    // containing the contents of the file. The size of the memory in bytes is written to _size.
+    // If the file cannot be read, nothing is allocated and nullptr is returned.
+    virtual std::vector<char> bytesFromFile(const char* _path) const;
+
+    // Start retrieving data from a URL asynchronously
+    // When the request is finished, the callback _callback will be
+    // run with the data that was retrieved from the URL _url
+    virtual bool startUrlRequest(const std::string& _url, UrlCallback _callback) = 0;
+
+    // Stop retrieving data from a URL that was previously requested
+    virtual void cancelUrlRequest(const std::string& _url) = 0;
+
+    virtual std::vector<char> systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const;
+
+    virtual std::vector<FontSourceHandle> systemFontFallbacksHandle() const;
+
+protected:
+
+    bool bytesFromFileSystem(const char* _path, std::function<char*(size_t)> _allocator) const;
+
+private:
+
+    bool m_continuousRendering;
+
+};
+
+} // namespace Tangram
diff --git a/core/include/tangram/tangram.h b/core/include/tangram/tangram.h
new file mode 100644 (file)
index 0000000..64b731c
--- /dev/null
@@ -0,0 +1,370 @@
+#pragma once
+
+#include "data/properties.h"
+#include "util/types.h"
+
+#include <array>
+#include <functional>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class Platform;
+class TileSource;
+
+enum LabelType {
+    icon,
+    text,
+};
+
+struct FeaturePickResult {
+    FeaturePickResult(std::shared_ptr<Properties> _properties,
+                      std::array<float, 2> _position)
+        : properties(_properties), position(_position) {}
+
+    std::shared_ptr<Properties> properties;
+    std::array<float, 2> position;
+};
+
+// Returns a pointer to the selected feature pick result or null, only valid on the callback scope
+using FeaturePickCallback = std::function<void(const FeaturePickResult*)>;
+
+struct LabelPickResult {
+    LabelPickResult(LabelType _type, LngLat _coordinates, FeaturePickResult _touchItem)
+        : type(_type),
+          coordinates(_coordinates),
+          touchItem(_touchItem) {}
+
+    LabelType type;
+    LngLat coordinates;
+    FeaturePickResult touchItem;
+};
+
+// Returns a pointer to the selected label pick result or null, only valid on the callback scope
+using LabelPickCallback = std::function<void(const LabelPickResult*)>;
+
+struct MarkerPickResult {
+    MarkerPickResult(MarkerID _id, LngLat _coordinates, std::array<float, 2> _position)
+        : id(_id), coordinates(_coordinates), position(_position) {}
+
+    MarkerID id;
+    LngLat coordinates;
+    std::array<float, 2> position;
+};
+
+// Returns a pointer to the selected marker pick result or null, only valid on the callback scope
+using MarkerPickCallback = std::function<void(const MarkerPickResult*)>;
+
+struct SceneUpdate {
+    std::string path;
+    std::string value;
+    SceneUpdate(std::string p, std::string v) : path(p), value(v) {}
+    SceneUpdate() {}
+};
+
+enum Error {
+    scene_update_path_not_found,
+    scene_update_path_yaml_syntax_error,
+    scene_update_value_yaml_syntax_error,
+};
+
+struct SceneUpdateError {
+    SceneUpdate update;
+    Error error;
+};
+
+using SceneUpdateErrorCallback = std::function<void(const SceneUpdateError&)>;
+
+// Function type for a mapReady callback
+using MapReady = std::function<void(void*)>;
+
+enum class EaseType : char {
+    linear = 0,
+    cubic,
+    quint,
+    sine,
+};
+
+class Map {
+
+public:
+
+    // Create an empty map object. To display a map, call either loadScene() or loadSceneAsync().
+    Map(std::shared_ptr<Platform> _platform);
+    ~Map();
+
+    // Load the scene at the given absolute file path asynchronously
+    // Any pending scene update will be cleared
+    void loadSceneAsync(const char* _scenePath,
+                        bool _useScenePosition = false,
+                        MapReady _onMapReady = nullptr,
+                        void *_onMapReadyUserData = nullptr,
+                        const std::vector<SceneUpdate>& sceneUpdates = {},
+                        SceneUpdateErrorCallback _onSceneUpdateError = nullptr);
+
+    // Load the scene at the given absolute file path synchronously
+    // Any pending scene update will be cleared
+    void loadScene(const char* _scenePath,
+                   bool _useScenePosition = false,
+                   const std::vector<SceneUpdate>& sceneUpdates = {},
+                   SceneUpdateErrorCallback _onSceneUpdateError = nullptr);
+
+    // Request an update to the scene configuration; the path is a series of yaml keys
+    // separated by a '.' and the value is a string of yaml to replace the current value
+    // at the given path in the scene
+    void queueSceneUpdate(const char* _path, const char* _value);
+    void queueSceneUpdate(const std::vector<SceneUpdate>& sceneUpdates);
+
+    // Apply all previously requested scene updates
+    void applySceneUpdates(SceneUpdateErrorCallback _onSceneUpdateError = nullptr);
+
+    // Set an MBTiles SQLite database file for a DataSource in the scene.
+    void setMBTiles(const char* _dataSourceName, const char* _mbtilesFilePath);
+
+    // Initialize graphics resources; OpenGL context must be created prior to calling this
+    void setupGL();
+
+    // Resize the map view to a new width and height (in pixels)
+    void resize(int _newWidth, int _newHeight);
+
+    // Update the map state with the time interval since the last update, returns
+    // true when the current view is completely loaded (all tiles are available and
+    // no animation in progress)
+    bool update(float _dt);
+
+    // Render a new frame of the map view (if needed)
+    void render();
+
+    // Gets the viewport height in physical pixels (framebuffer size)
+    int getViewportHeight();
+
+    // Gets the viewport width in physical pixels (framebuffer size)
+    int getViewportWidth();
+
+    // Set the ratio of hardware pixels to logical pixels (defaults to 1.0);
+    // this operation can be slow, so only perform this when necessary.
+    void setPixelScale(float _pixelsPerPoint);
+
+    // Gets the pixel scale
+    float getPixelScale();
+
+    // Capture a snapshot of the current frame and store it in the allocated _data
+    // _data is expected to be of size getViewportHeight() * getViewportWidth()
+    // Pixel data is stored starting from the lower left corner of the viewport
+    // Each pixel(x, y) would be located at _data[y * getViewportWidth() + x]
+    // Each unsigned int corresponds to an RGBA pixel value
+    void captureSnapshot(unsigned int* _data);
+
+    // Set the position of the map view in degrees longitude and latitude; if duration
+    // (in seconds) is provided, position eases to the set value over the duration;
+    // calling either version of the setter overrides all previous calls
+    void setPosition(double _lon, double _lat);
+    void setPositionEased(double _lon, double _lat, float _duration, EaseType _e = EaseType::quint);
+
+    // Set the values of the arguments to the position of the map view in degrees
+    // longitude and latitude
+    void getPosition(double& _lon, double& _lat);
+
+    // Set the fractional zoom level of the view; if duration (in seconds) is provided,
+    // zoom eases to the set value over the duration; calling either version of the setter
+    // overrides all previous calls
+    void setZoom(float _z);
+    void setZoomEased(float _z, float _duration, EaseType _e = EaseType::quint);
+
+    // Get the fractional zoom level of the view
+    float getZoom();
+
+    // Set the counter-clockwise rotation of the view in radians; 0 corresponds to
+    // North pointing up; if duration (in seconds) is provided, rotation eases to the
+    // the set value over the duration; calling either version of the setter overrides
+    // all previous calls
+    void setRotation(float _radians);
+    void setRotationEased(float _radians, float _duration, EaseType _e = EaseType::quint);
+
+    // Get the counter-clockwise rotation of the view in radians; 0 corresponds to
+    // North pointing up
+    float getRotation();
+
+    // Set the tilt angle of the view in radians; 0 corresponds to straight down;
+    // if duration (in seconds) is provided, tilt eases to the set value over the
+    // duration; calling either version of the setter overrides all previous calls
+    void setTilt(float _radians);
+    void setTiltEased(float _radians, float _duration, EaseType _e = EaseType::quint);
+
+    // Get the tilt angle of the view in radians; 0 corresponds to straight down
+    float getTilt();
+
+    // Set the camera type (0 = perspective, 1 = isometric, 2 = flat)
+    void setCameraType(int _type);
+
+    // Get the camera type (0 = perspective, 1 = isometric, 2 = flat)
+    int getCameraType();
+
+    // Given coordinates in screen space (x right, y down), set the output longitude and
+    // latitude to the geographic location corresponding to that point; returns false if
+    // no geographic position corresponds to the screen location, otherwise returns true
+    bool screenPositionToLngLat(double _x, double _y, double* _lng, double* _lat);
+
+    // Given longitude and latitude coordinates, set the output coordinates to the
+    // corresponding point in screen space (x right, y down); returns false if the
+    // point is not visible on the screen, otherwise returns true
+    bool lngLatToScreenPosition(double _lng, double _lat, double* _x, double* _y);
+
+    // Add a tile source for adding drawable map data, which will be styled
+    // according to the scene file using the provided data source name;
+    void addTileSource(std::shared_ptr<TileSource> _source);
+
+    // Remove a tile source from the map; returns true if the source was found
+    // and removed, otherwise returns false.
+    bool removeTileSource(TileSource& _source);
+
+    void clearTileSource(TileSource& _source, bool _data, bool _tiles);
+
+    // Add a marker object to the map and return an ID for it; an ID of 0 indicates an invalid marker;
+    // the marker will not be drawn until both styling and geometry are set using the functions below.
+    MarkerID markerAdd();
+
+    // Remove a marker object from the map; returns true if the marker ID was found and successfully
+    // removed, otherwise returns false.
+    bool markerRemove(MarkerID _marker);
+
+    // Set the styling for a marker object; _styling is a string of YAML that specifies a 'draw rule'
+    // according to the scene file syntax; returns true if the marker ID was found and successfully
+    // updated, otherwise returns false.
+    bool markerSetStylingFromString(MarkerID _marker, const char* _styling);
+
+    // Set an explicit draw group for a marker object; _path is a '.' delimited path to a draw rule
+    // in the current scene. The Marker will be styled using the draw rule specified at this path;
+    // returns true if the marker ID was found and successfully updated, otherwise returns false.
+    bool markerSetStylingFromPath(MarkerID _marker, const char* _path);
+
+    // Set a bitmap to use as the image for a point marker; _data is a buffer of RGBA pixel data with
+    // length of _width * _height; pixels are in row-major order beginning from the bottom-left of the
+    // image; returns true if the marker ID was found and successfully updated, otherwise returns false.
+    bool markerSetBitmap(MarkerID _marker, int _width, int _height, const unsigned int* _data);
+
+    // Set the geometry of a marker to a point at the given coordinates; markers can have their
+    // geometry set multiple times with possibly different geometry types; returns true if the
+    // marker ID was found and successfully updated, otherwise returns false.
+    bool markerSetPoint(MarkerID _marker, LngLat _lngLat);
+
+    // Set the geometry of a marker to a point at the given coordinates; if the marker was previously
+    // set to a point, this eases the position over the given duration in seconds with the given EaseType;
+    // returns true if the marker ID was found and successfully updated, otherwise returns false.
+    bool markerSetPointEased(MarkerID _marker, LngLat _lngLat, float _duration, EaseType _ease);
+
+    // Set the geometry of a marker to a polyline along the given coordinates; _coordinates is a
+    // pointer to a sequence of _count LngLats; markers can have their geometry set multiple times
+    // with possibly different geometry types; returns true if the marker ID was found and
+    // successfully updated, otherwise returns false.
+    bool markerSetPolyline(MarkerID _marker, LngLat* _coordinates, int _count);
+
+    // Set the geometry of a marker to a polygon with the given coordinates; _counts is a pointer
+    // to a sequence of _rings integers and _coordinates is a pointer to a sequence of LngLats with
+    // a total length equal to the sum of _counts; for each integer n in _counts, a polygon is created
+    // by taking the next n LngLats from _coordinates, with winding order and internal polygons
+    // behaving according to the GeoJSON specification; markers can have their geometry set multiple
+    // times with possibly different geometry types; returns true if the marker ID was found and
+    // successfully updated, otherwise returns false.
+    bool markerSetPolygon(MarkerID _marker, LngLat* _coordinates, int* _counts, int _rings);
+
+    // Set the visibility of a marker object; returns true if the marker ID was found and successfully
+    // updated, otherwise returns false.
+    bool markerSetVisible(MarkerID _marker, bool _visible);
+
+    // Set the ordering of point marker object relative to other markers; higher values are drawn 'above';
+    // returns true if the marker ID was found and successfully updated, otherwise returns false.
+    bool markerSetDrawOrder(MarkerID _marker, int _drawOrder);
+
+    // Remove all marker objects from the map; Any marker IDs previously returned from 'markerAdd'
+    // are invalidated after this.
+    void markerRemoveAll();
+
+    // Respond to a tap at the given screen coordinates (x right, y down)
+    void handleTapGesture(float _posX, float _posY);
+
+    // Respond to a double tap at the given screen coordinates (x right, y down)
+    void handleDoubleTapGesture(float _posX, float _posY);
+
+    // Respond to a drag with the given displacement in screen coordinates (x right, y down)
+    void handlePanGesture(float _startX, float _startY, float _endX, float _endY);
+
+    // Respond to a fling from the given position with the given velocity in screen coordinates
+    void handleFlingGesture(float _posX, float _posY, float _velocityX, float _velocityY);
+
+    // Respond to a pinch at the given position in screen coordinates with the given
+    // incremental scale
+    void handlePinchGesture(float _posX, float _posY, float _scale, float _velocity);
+
+    // Respond to a rotation gesture with the given incremental rotation in radians
+    void handleRotateGesture(float _posX, float _posY, float _rotation);
+
+    // Respond to a two-finger shove with the given distance in screen coordinates
+    void handleShoveGesture(float _distance);
+
+    // Set whether the OpenGL state will be cached between subsequent frames; this improves rendering
+    // efficiency, but can cause errors if your application code makes OpenGL calls (false by default)
+    void useCachedGlState(bool _use);
+
+    // Set the radius in logical pixels to use when picking features on the map (default is 0.5).
+    void setPickRadius(float _radius);
+
+    // Create a query to select a feature marked as 'interactive'. The query runs on the next frame.
+    // Calls _onFeaturePickCallback once the query has completed, and returns the FeaturePickResult
+    // with its associated properties or null if no feature was found.
+    void pickFeatureAt(float _x, float _y, FeaturePickCallback _onFeaturePickCallback);
+
+    // Create a query to select a label created for a feature marked as 'interactive'. The query runs
+    // on the next frame.
+    // Calls _onLabelPickCallback once the query has completed, and returns the LabelPickResult
+    // with its associated properties or null if no label was found.
+    void pickLabelAt(float _x, float _y, LabelPickCallback _onLabelPickCallback);
+
+    // Create a query to select a marker that is 'interactive'. The query runs on the next frame.
+    // Calls _onLMarkerPickCallback once the query has completed, and returns the MarkerPickResult
+    // with its associated properties or null if no marker was found.
+    void pickMarkerAt(float _x, float _y, MarkerPickCallback _onMarkerPickCallback);
+
+    // Run this task asynchronously to Tangram's main update loop.
+    void runAsyncTask(std::function<void()> _task);
+
+    // Send a signal to Tangram that the platform received a memory warning
+    void onMemoryWarning();
+
+    std::shared_ptr<Platform>& getPlatform();
+
+private:
+
+    class Impl;
+    std::unique_ptr<Impl> impl;
+
+protected:
+
+    std::shared_ptr<Platform> platform;
+
+};
+
+enum DebugFlags {
+    freeze_tiles = 0,   // While on, the set of tiles currently being drawn will not update to match the view
+    proxy_colors,       // Applies a color change to every other zoom level of tiles to visualize proxy tile behavior
+    tile_bounds,        // Draws tile boundaries
+    tile_infos,         // Debug tile infos
+    labels,             // Debug label bounding boxes
+    tangram_infos,      // Various text tangram debug info printed on the screen
+    draw_all_labels,    // Draw all labels
+    tangram_stats,      // Tangram frame graph stats
+    selection_buffer,   // Render selection framebuffer
+};
+
+// Set debug features on or off using a boolean (see debug.h)
+void setDebugFlag(DebugFlags _flag, bool _on);
+
+// Get the boolean state of a debug feature (see debug.h)
+bool getDebugFlag(DebugFlags _flag);
+
+// Toggle the boolean state of a debug feature (see debug.h)
+void toggleDebugFlag(DebugFlags _flag);
+
+}
diff --git a/core/include/tangram/tile/tileID.h b/core/include/tangram/tile/tileID.h
new file mode 100644 (file)
index 0000000..c18438f
--- /dev/null
@@ -0,0 +1,101 @@
+#pragma once
+
+#include <cassert>
+#include <cstdint>
+#include <string>
+
+/* An immutable identifier for a map tile
+ *
+ * Contains the x, y, and z indices of a tile in a quad tree; TileIDs are ordered by:
+ * 1. z, highest to lowest
+ * 2. x, lowest to highest
+ * 3. y, lowest to highest
+ */
+
+namespace Tangram {
+
+struct TileID {
+
+    int32_t x; // Index from left edge of projection space
+    int32_t y; // Index from top edge of projection space
+    int8_t  z; // Data zoom
+    int8_t  s; // Styling zoom
+    int16_t wrap;
+
+    TileID(int32_t _x, int32_t _y, int32_t _z, int32_t _s, int32_t _wrap) : x(_x), y(_y), z(_z), s(_s), wrap(_wrap) {}
+
+    TileID(int32_t _x, int32_t _y, int32_t _z) : TileID(_x, _y, _z, _z, 0) {}
+
+    TileID(const TileID& _rhs) = default;
+
+    bool operator< (const TileID& _rhs) const {
+        return s > _rhs.s || (s == _rhs.s && (z > _rhs.z || (z == _rhs.z && (x < _rhs.x || (x == _rhs.x && (y < _rhs.y || (y == _rhs.y && wrap < _rhs.wrap)))))));
+    }
+    bool operator> (const TileID& _rhs) const { return _rhs < const_cast<TileID&>(*this); }
+    bool operator<=(const TileID& _rhs) const { return !(*this > _rhs); }
+    bool operator>=(const TileID& _rhs) const { return !(*this < _rhs); }
+    bool operator==(const TileID& _rhs) const { return x == _rhs.x && y == _rhs.y && z == _rhs.z && s == _rhs.s && wrap == _rhs.wrap; }
+    bool operator!=(const TileID& _rhs) const { return !(*this == _rhs); }
+
+    bool isValid() const {
+        int max = 1 << z;
+        return x >= 0 && x < max && y >= 0 && y < max && z >= 0;
+    }
+
+    bool isValid(int _maxZoom) const {
+        return isValid() && z <= _maxZoom;
+    }
+
+    TileID withMaxSourceZoom(int32_t _maxZoom) const {
+
+        if (z <= _maxZoom) {
+            return *this;
+        }
+
+        int32_t over = z - _maxZoom;
+
+        return TileID(x >> over, y >> over, _maxZoom, s, wrap);
+    }
+
+    TileID zoomBiasAdjusted(int32_t _zoomBias) const {
+        assert(_zoomBias >= 0);
+
+        if (!_zoomBias) { return *this; }
+
+        auto scaledZ = std::max(0, z - _zoomBias);
+        return TileID(x >> _zoomBias, y >> _zoomBias, scaledZ, z, wrap);
+    }
+
+    TileID getParent(int32_t _zoomBias = 0) const {
+        if (s > (z + _zoomBias)) {
+            // Over-zoomed, keep the same data coordinates
+            return TileID(x, y, z, s - 1, wrap);
+        }
+        return TileID(x >> 1, y >> 1, z - 1, s - 1, wrap);
+    }
+
+    TileID getChild(int32_t _index, int32_t _maxZoom) const {
+        if (_index > 3 || _index < 0) {
+            return TileID(-1, -1, -1, -1, -1);
+        }
+
+        int i = _index / 2;
+        int j = _index % 2;
+
+        // _index: 0, 1, 2, 3
+        // i:      0, 0, 1, 1
+        // j:      0, 1, 0, 1
+
+        auto childID = TileID((x<<1)+i, (y<<1)+j, z + 1, s + 1, wrap);
+        return childID.withMaxSourceZoom(_maxZoom);
+    }
+
+    std::string toString() const {
+        return std::to_string(x) + "/" + std::to_string(y) + "/" + std::to_string(z) + "/" + std::to_string(s);
+    }
+
+};
+
+static const TileID NOT_A_TILE(-1, -1, -1, -1, -1);
+
+}
diff --git a/core/include/tangram/tile/tileTask.h b/core/include/tangram/tile/tileTask.h
new file mode 100644 (file)
index 0000000..8a29474
--- /dev/null
@@ -0,0 +1,131 @@
+#pragma once
+
+#include "tile/tileID.h"
+
+#include <atomic>
+#include <functional>
+#include <memory>
+#include <vector>
+
+namespace Tangram {
+
+class TileManager;
+class TileBuilder;
+class TileSource;
+class Tile;
+class MapProjection;
+struct TileData;
+
+
+class TileTask {
+
+public:
+
+    TileTask(TileID& _tileId, std::shared_ptr<TileSource> _source, int _subTask);
+
+    // No copies
+    TileTask(const TileTask& _other) = delete;
+    TileTask& operator=(const TileTask& _other) = delete;
+
+    virtual ~TileTask() {}
+
+    virtual bool hasData() const { return true; }
+
+    virtual bool isReady() const {
+        if (needsLoading()) { return false; }
+
+        return bool(m_tile);
+    }
+
+    std::shared_ptr<Tile>& tile() { return m_tile; }
+
+    TileSource& source() { return *m_source; }
+    int64_t sourceGeneration() const { return m_sourceGeneration; }
+
+    TileID tileId() const { return m_tileId; }
+
+    void cancel() { m_canceled = true; }
+    bool isCanceled() const { return m_canceled; }
+
+    double getPriority() const {
+        return m_priority.load();
+    }
+
+    void setPriority(double _priority) {
+        m_priority.store(_priority);
+    }
+
+    void setProxyState(bool isProxy) { m_proxyState = isProxy; }
+    bool isProxy() const { return m_proxyState; }
+
+    auto& subTasks() { return m_subTasks; }
+    int subTaskId() const { return m_subTaskId; }
+    bool isSubTask() const { return m_subTaskId >= 0; }
+
+    // running on worker thread
+    virtual void process(TileBuilder& _tileBuilder);
+
+    // running on main thread when the tile is added to
+    virtual void complete();
+
+    // onDone for sub-tasks
+    virtual void complete(TileTask& _mainTask) {}
+
+    int rawSource = 0;
+
+    bool needsLoading() const { return m_needsLoading; }
+
+    // Set whether DataSource should (re)try loading data
+    void setNeedsLoading(bool _needsLoading) {
+         m_needsLoading = _needsLoading;
+    }
+
+    void startedLoading() { m_needsLoading = false; }
+
+protected:
+
+    const TileID m_tileId;
+
+    const int m_subTaskId;
+
+    // Save shared reference to Datasource while building tile
+    std::shared_ptr<TileSource> m_source;
+
+    // Vector of tasks to download raster samplers
+    std::vector<std::shared_ptr<TileTask>> m_subTasks;
+
+    const int64_t m_sourceGeneration;
+
+    // Tile result, set when tile was  sucessfully created
+    std::shared_ptr<Tile> m_tile;
+
+    bool m_canceled = false;
+    bool m_needsLoading = true;
+
+    std::atomic<float> m_priority;
+    bool m_proxyState = false;
+};
+
+class BinaryTileTask : public TileTask {
+public:
+    BinaryTileTask(TileID& _tileId, std::shared_ptr<TileSource> _source, int _subTask)
+        : TileTask(_tileId, _source, _subTask) {}
+
+    virtual bool hasData() const override {
+        return rawTileData && !rawTileData->empty();
+    }
+    // Raw tile data that will be processed by TileSource.
+    std::shared_ptr<std::vector<char>> rawTileData;
+
+    bool dataFromCache = false;
+};
+
+struct TileTaskQueue {
+    virtual void enqueue(std::shared_ptr<TileTask> task) = 0;
+};
+
+struct TileTaskCb {
+    std::function<void(std::shared_ptr<TileTask>)> func;
+};
+
+}
diff --git a/core/include/tangram/util/types.h b/core/include/tangram/util/types.h
new file mode 100644 (file)
index 0000000..6913e1c
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <vector>
+
+namespace Tangram {
+
+struct Range {
+    int start;
+    int length;
+
+    int end() const { return start + length; }
+
+    Range(int _start, int _length) : start(_start), length(_length) {}
+
+    Range() : start(0), length(0) {}
+};
+
+struct LngLat {
+    LngLat() {}
+    LngLat(double _lon, double _lat) : longitude(_lon), latitude(_lat) {}
+
+    LngLat(const LngLat& _other) = default;
+    LngLat(LngLat&& _other) = default;
+    LngLat& operator=(const LngLat& _other) = default;
+    LngLat& operator=(LngLat&& _other) = default;
+
+    bool operator==(const LngLat& _other) {
+        return longitude == _other.longitude &&
+               latitude == _other.latitude;
+    }
+
+    double longitude = 0.0;
+    double latitude = 0.0;
+};
+
+typedef std::vector<LngLat> Coordinates;
+
+typedef uint32_t MarkerID;
+
+}
diff --git a/core/include/tangram/util/url.h b/core/include/tangram/util/url.h
new file mode 100644 (file)
index 0000000..918e4ad
--- /dev/null
@@ -0,0 +1,162 @@
+#pragma once
+
+#include <string>
+
+namespace Tangram {
+
+// This class is based on the URL concept specified by IETF RFC 1808
+// (https://tools.ietf.org/html/rfc1808) and the URI concept specified by
+// IETF RFC 3986 (https://tools.ietf.org/html/rfc3986) In particular this
+// class is intended to handle URLs using the 'http' and 'file' schemes,
+// with special case handling of some data URIs.
+//
+// URLs are decomposed as:
+//
+// foo://user:pword@host.com:80/over/there.txt;type=a?name=ferret#nose
+// \_/   \____________________/\_____________/ \____/ \_________/ \__/
+//  |              |                  |          |        |        |
+// scheme      netLocation           path   parameters  query  fragment
+//
+// Data URIs are decomposed as:
+//
+// data:image/png;base64,iVBORw0KGgoAAAANSUhE... (abbreviated)
+// \__/ \_______/ \____/ \__________________ _ _
+//  |       |       |         |
+// scheme mediaType isBase64 data
+//
+// Ideas were borrowed from:
+// https://github.com/cpp-netlib/uri/blob/master/include/network/uri/uri.hpp
+// https://github.com/opensource-apple/CF/blob/master/CFURL.h
+//
+
+class Url {
+
+public:
+
+    // Create an empty URL.
+    Url();
+
+    // Create an absolute or relative URL from a string.
+    Url(const std::string& source);
+    Url(std::string&& source);
+    Url(const char* source);
+
+    // Create a URL by copy.
+    Url(const Url& other);
+
+    // Create a URL by move.
+    Url(Url&& other);
+
+    // Replace the contents of this URL.
+    Url& operator=(const Url& other);
+    Url& operator=(Url&& other);
+
+    // Compare this URL and another using their string representations.
+    bool operator==(const Url& other) const;
+
+    // Query the state of this URL.
+    bool isEmpty() const;
+    bool isAbsolute() const;
+    bool isStandardized() const;
+    bool hasHttpScheme() const;
+    bool hasFileScheme() const;
+    bool hasDataScheme() const;
+    bool hasBase64Data() const;
+
+    // Query the presence of URL components.
+    bool hasScheme() const;
+    bool hasNetLocation() const;
+    bool hasPath() const;
+    bool hasParameters() const;
+    bool hasQuery() const;
+    bool hasFragment() const;
+
+    // Query the presence of data URI components.
+    bool hasMediaType() const;
+    bool hasData() const;
+
+    // Get copies of URL components.
+    std::string scheme() const;
+    std::string netLocation() const;
+    std::string path() const;
+    std::string parameters() const;
+    std::string query() const;
+    std::string fragment() const;
+
+    // Get copies of data URI components.
+    std::string mediaType() const;
+    std::string data() const;
+
+    // Get the entire URL as a string.
+    const std::string& string() const;
+
+    // Get an equivalent URL with dot segments removed from the path. If this is
+    // a data URI then the same URI is returned.
+    Url standardized() const;
+
+    // Get an absolute URL by applying this URL relative to the given base.
+    // e.g. "example.com/a/b/c.txt" == ("b/c.txt").resolved("example.com/a/")
+    Url resolved(const Url& base) const;
+
+    // Get an absolute URL by applying a relative URL to a base URL.
+    // e.g. "example.com/a/b/c.txt" == resolve("example.com/a/", "b/c.txt")
+    static Url resolve(const Url& base, const Url& relative);
+
+    // Remove any '.' or '..' segments from a string containing a heirarchical path
+    // and return a modified copy of the string.
+    static std::string removeDotSegmentsFromString(std::string path);
+
+    // Get the file extension for a path. The extension may be empty.
+    // e.g. getPathExtension("example.com/a/b/c.txt") == "txt"
+    static std::string getPathExtension(const std::string& path);
+
+private:
+
+    // buffer contains the actual text of the URL.
+    std::string buffer;
+
+    // parts describes URL components by their location within the buffer.
+    struct Parts {
+        struct Range {
+            size_t start = 0, count = 0;
+        } scheme, location, path, parameters, query, fragment, media, data;
+    } parts;
+
+    // flags contains Boolean information about the URL state.
+    int flags = 0;
+
+    // flags uses these bitmasks.
+    enum {
+        IS_ABSOLUTE =     1 << 0,
+        IS_STANDARDIZED = 1 << 1,
+        HAS_HTTP_SCHEME = 1 << 2,
+        HAS_FILE_SCHEME = 1 << 3,
+        HAS_DATA_SCHEME = 1 << 4,
+        HAS_BASE64_DATA = 1 << 5,
+    };
+
+    // parse the URL parts and flags from the source text.
+    void parse();
+
+    // Remove the last segment and its preceding '/' (if any) from a string range
+    // containing a heirarchical path and return the index past the end of the new path.
+    static size_t removeLastSegmentFromRange(std::string& string, size_t start, size_t count);
+
+    // Remove any '.' or '..' segments from a string range containing a heirarchical
+    // path and return the size of the new path.
+    static size_t removeDotSegmentsFromRange(std::string& string, size_t start, size_t count);
+
+}; // class Url
+
+} // namespace Tangram
+
+// A hash function allows Tangram::Url to be a key type for STL containers.
+// To match the '==' operator, the hash function should only use the string value.
+namespace std {
+    template <>
+    struct hash<Tangram::Url> {
+        size_t operator()(const Tangram::Url& url) const {
+            return std::hash<std::string>{}(url.string());
+        }
+    };
+}
diff --git a/core/include/tangram/util/variant.h b/core/include/tangram/util/variant.h
new file mode 100644 (file)
index 0000000..7b883ee
--- /dev/null
@@ -0,0 +1,63 @@
+#pragma once
+
+// Always compile variant with NDEBUG
+// to properly inline functions
+#ifdef NDEBUG
+#define KEEP_NDEBUG
+#else
+#define NDEBUG
+#endif
+
+#include "variant/include/mapbox/variant.hpp"
+
+#ifndef KEEP_NDEBUG
+#undef NDEBUG
+#endif
+
+#include <string>
+
+namespace Tangram {
+// Primarily used when duk evaluated jsFunction results in a a null or undefined value
+struct Undefined {
+    template<typename T>
+    bool operator==(T const& rhs) const {
+        return false;
+    }
+    bool operator==(Undefined const& rhs) const {
+        return true;
+    }
+    bool operator<(Undefined const& rhs) const {
+        return false;
+    }
+};
+
+struct none_type {
+    template<typename T>
+    bool operator==(T const& rhs) const {
+        return false;
+    }
+    bool operator==(none_type const& rhs) const {
+        return true;
+    }
+    bool operator<(none_type const& rhs) const {
+        return false;
+    }
+
+};
+
+template<typename... Types>
+using variant = mapbox::util::variant<Types...>;
+
+namespace detail {
+/* Common Value type for Feature Properties and Filter Values */
+using Value = variant<none_type, double, std::string>;
+}
+
+class Value : public detail::Value {
+    using Base = detail::Value;
+    using Base::Base;
+};
+
+const static Value NOT_A_VALUE(none_type{});
+
+}
diff --git a/core/shaders/ambientLight.glsl b/core/shaders/ambientLight.glsl
new file mode 100644 (file)
index 0000000..1625e9a
--- /dev/null
@@ -0,0 +1,16 @@
+/*
+
+Expected globals:
+light_accumulator_*
+
+*/
+
+struct AmbientLight {
+    vec4 ambient;
+    vec4 diffuse;
+    vec4 specular;
+};
+
+void calculateLight(in AmbientLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
+    light_accumulator_ambient += _light.ambient;
+}
diff --git a/core/shaders/debug.fs b/core/shaders/debug.fs
new file mode 100644 (file)
index 0000000..c25d952
--- /dev/null
@@ -0,0 +1,11 @@
+#ifdef GL_ES
+precision highp float;
+#endif
+
+varying vec4 v_color;
+
+void main() {
+
+    gl_FragColor = v_color;
+
+}
diff --git a/core/shaders/debug.vs b/core/shaders/debug.vs
new file mode 100644 (file)
index 0000000..5e8766c
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef GL_ES
+precision highp float;
+#endif
+
+uniform mat4 u_model;
+uniform mat4 u_view;
+uniform mat4 u_proj;
+
+attribute vec4 a_position;
+attribute vec4 a_color;
+
+varying vec4 v_color;
+
+void main() {
+
+    v_color = a_color;
+
+    gl_Position = u_proj * u_view * u_model * a_position;
+}
diff --git a/core/shaders/debugPrimitive.fs b/core/shaders/debugPrimitive.fs
new file mode 100644 (file)
index 0000000..052b6c4
--- /dev/null
@@ -0,0 +1,10 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform vec3 u_color;
+
+void main() {
+    gl_FragColor = vec4(u_color, 1.0);
+}
+
diff --git a/core/shaders/debugPrimitive.vs b/core/shaders/debugPrimitive.vs
new file mode 100644 (file)
index 0000000..b45a396
--- /dev/null
@@ -0,0 +1,12 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+attribute vec2 a_position;
+
+uniform mat4 u_proj;
+
+void main() {
+    gl_Position = u_proj * vec4(a_position, 1.0, 1.0);
+}
+
diff --git a/core/shaders/debugTexture.fs b/core/shaders/debugTexture.fs
new file mode 100644 (file)
index 0000000..eb055c5
--- /dev/null
@@ -0,0 +1,11 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform sampler2D u_tex;
+varying vec2 uv;
+
+void main() {
+    gl_FragColor = texture2D(u_tex, uv);
+}
+
diff --git a/core/shaders/debugTexture.vs b/core/shaders/debugTexture.vs
new file mode 100644 (file)
index 0000000..7d804ab
--- /dev/null
@@ -0,0 +1,16 @@
+#ifdef GL_ES
+precision mediump float;
+#endif
+
+uniform mat4 u_proj;
+
+attribute vec2 a_position;
+attribute vec2 a_uv;
+
+varying vec2 uv;
+
+void main() {
+    uv = a_uv;
+    gl_Position = u_proj * vec4(a_position, 1.0, 1.0);
+}
+
diff --git a/core/shaders/directionalLight.glsl b/core/shaders/directionalLight.glsl
new file mode 100644 (file)
index 0000000..ac5a127
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+
+Expected globals:
+material
+light_accumulator_*
+
+*/
+
+struct DirectionalLight {
+    vec4 ambient;
+    vec4 diffuse;
+    vec4 specular;
+    vec3 direction;
+};
+
+void calculateLight(in DirectionalLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
+
+    light_accumulator_ambient += _light.ambient;
+
+    float nDotVP = clamp(dot(_normal, -_light.direction), 0.0, 1.0);
+
+    #ifdef TANGRAM_MATERIAL_DIFFUSE
+        light_accumulator_diffuse += _light.diffuse * nDotVP;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_SPECULAR
+        float pf = 0.0;
+        if (nDotVP > 0.0) {
+            vec3 reflectVector = reflect(_light.direction, _normal);
+            float eyeDotR = max(dot(normalize(_eyeToPoint), reflectVector), 0.0);
+            pf = pow(eyeDotR, material.shininess);
+        }
+        light_accumulator_specular += _light.specular * pf;
+    #endif
+}
diff --git a/core/shaders/lights.glsl b/core/shaders/lights.glsl
new file mode 100644 (file)
index 0000000..fe6dae0
--- /dev/null
@@ -0,0 +1,39 @@
+#if (defined(TANGRAM_VERTEX_SHADER) && defined(TANGRAM_LIGHTING_VERTEX)) || (defined(TANGRAM_FRAGMENT_SHADER) && defined(TANGRAM_LIGHTING_FRAGMENT))
+vec4 calculateLighting(in vec3 _eyeToPoint, in vec3 _normal, in vec4 _color) {
+
+    // Do initial material calculations over normal, emission, ambient, diffuse and specular values
+    calculateMaterial(_eyeToPoint,_normal);
+   
+
+    // Unroll the loop of individual lights to calculate
+    #pragma tangram: lights_to_compute
+
+    //  Final light intensity calculation
+    vec4 color = vec4(0.0);
+
+    #ifdef TANGRAM_MATERIAL_EMISSION
+        color = material.emission;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_AMBIENT
+        color += light_accumulator_ambient * _color * material.ambient;
+    #else
+        #ifdef TANGRAM_MATERIAL_DIFFUSE
+            color += light_accumulator_ambient * _color * material.diffuse;
+        #endif
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_DIFFUSE
+        color += light_accumulator_diffuse * _color * material.diffuse;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_SPECULAR
+        color += light_accumulator_specular * material.specular;
+    #endif
+
+    // Clamp final color
+    color = clamp(color, 0.0, 1.0);
+
+    return color;
+}
+#endif
diff --git a/core/shaders/material.glsl b/core/shaders/material.glsl
new file mode 100644 (file)
index 0000000..4427b0e
--- /dev/null
@@ -0,0 +1,231 @@
+/*
+
+Defines globals:
+material
+light_accumulator_*
+
+*/
+
+
+#ifdef TANGRAM_WEBGL
+    #define TANGRAM_SKEW u_vanishing_point
+#else
+    #define TANGRAM_SKEW vec2(0.0)
+#endif
+
+// MATERIALS
+//
+struct Material {
+    #ifdef TANGRAM_MATERIAL_EMISSION
+        vec4 emission;
+        #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE
+            vec3 emissionScale;
+        #endif
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_AMBIENT
+        vec4 ambient;
+        #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE
+            vec3 ambientScale;
+        #endif
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_DIFFUSE
+        vec4 diffuse;
+        #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE
+            vec3 diffuseScale;
+        #endif
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_SPECULAR
+        vec4 specular;
+        float shininess;
+        #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE
+            vec3 specularScale;
+        #endif
+    #endif
+
+
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE
+        vec3 normalScale;
+        vec3 normalAmount;
+    #endif
+};
+
+// Note: uniform is copied to a global instance to allow modification
+uniform Material u_material;
+Material material;
+
+#ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE
+uniform sampler2D u_material_emission_texture;
+#endif
+
+#ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE
+uniform sampler2D u_material_ambient_texture;
+#endif
+
+#ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE
+uniform sampler2D u_material_diffuse_texture;
+#endif
+
+#ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE
+uniform sampler2D u_material_specular_texture;
+#endif
+
+#ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE
+uniform sampler2D u_material_normal_texture;
+#endif
+
+// Global light accumulators for each property
+vec4 light_accumulator_ambient = vec4(0.0);
+vec4 light_accumulator_diffuse = vec4(0.0);
+#ifdef TANGRAM_MATERIAL_SPECULAR
+    vec4 light_accumulator_specular = vec4(0.0);
+#endif
+
+
+#ifdef TANGRAM_MATERIAL_TEXTURE_SPHEREMAP
+vec4 getSphereMap (in sampler2D _tex, in vec3 _eyeToPoint, in vec3 _normal, in vec2 _skew) {
+    vec3 eye = normalize(_eyeToPoint);
+    eye.xy -= _skew;
+    eye = normalize(eye);
+    vec3 r = reflect(eye, _normal);
+
+    r.z += 1.0;
+    float m = 2. * length(r);
+    vec2 uv = r.xy / m + .5;
+    return texture2D(_tex, uv);
+}
+#endif
+
+
+#ifdef TANGRAM_MATERIAL_TEXTURE_TRIPLANAR
+vec3 getTriPlanarBlend (in vec3 _normal) {
+    vec3 blending = abs(_normal);
+    blending = normalize(max(blending, 0.00001));
+    float b = (blending.x + blending.y + blending.z);
+    return blending / b;
+}
+
+vec4 getTriPlanar (in sampler2D _tex, in vec3 _pos, in vec3 _normal, in vec3 _scale) {
+    vec3 blending = getTriPlanarBlend(_normal);
+    vec4 xaxis = texture2D(_tex, fract(_pos.yz * _scale.x));
+    vec4 yaxis = texture2D(_tex, fract(_pos.xz * _scale.y));
+    vec4 zaxis = texture2D(_tex, fract(_pos.xy * _scale.z));
+    return  xaxis * blending.x + yaxis * blending.y + zaxis * blending.z;
+}
+#endif
+
+
+#ifdef TANGRAM_MATERIAL_TEXTURE_PLANAR
+vec4 getPlanar (in sampler2D _tex, in vec3 _pos, in vec2 _scale) {
+    return texture2D( _tex, fract(_pos.xy * _scale.x) );
+}
+#endif
+
+
+#ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE
+void calculateNormal (inout vec3 _normal) {
+    // Get NORMALMAP
+    //------------------------------------------------
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE_UV
+    _normal += texture2D(u_material_normal_texture, fract(v_texcoord*material.normalScale.xy)).rgb*2.0-1.0;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE_PLANAR
+    vec3 normalTex = getPlanar(u_material_normal_texture, v_world_position.xyz, material.normalScale.xy).rgb*2.0-1.0;
+    _normal += normalTex;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE_TRIPLANAR
+    vec3 normalTex = getTriPlanar(u_material_normal_texture, v_world_position.xyz, _normal, material.normalScale).rgb*2.0-1.0;
+    _normal += normalTex;
+    #endif
+
+    _normal = normalize(_normal);
+}
+#endif
+
+#if (defined(TANGRAM_VERTEX_SHADER) && defined(TANGRAM_LIGHTING_VERTEX)) || (defined(TANGRAM_FRAGMENT_SHADER) && defined(TANGRAM_LIGHTING_FRAGMENT))
+void calculateMaterial (in vec3 _eyeToPoint, inout vec3 _normal) {
+    // get EMISSION TEXTUREMAP
+    //------------------------------------------------
+    #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE
+        #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE_UV
+        material.emission *= texture2D(u_material_emission_texture,v_texcoord);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE_PLANAR
+        material.emission *= getPlanar(u_material_emission_texture, v_world_position.xyz, material.emissionScale.xy);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE_TRIPLANAR
+        material.emission *= getTriPlanar(u_material_emission_texture, v_world_position.xyz, _normal, material.emissionScale);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_EMISSION_TEXTURE_SPHEREMAP
+        material.emission *= getSphereMap(u_material_emission_texture, _eyeToPoint, _normal, TANGRAM_SKEW);
+        #endif
+    #endif
+
+    // get AMBIENT TEXTUREMAP
+    //------------------------------------------------
+    #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE
+        #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE_UV
+        material.ambient *= texture2D(u_material_ambient_texture,v_texcoord);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE_PLANAR
+        material.ambient *= getPlanar(u_material_ambient_texture, v_world_position.xyz, material.ambientScale.xy);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE_TRIPLANAR
+        material.ambient *= getTriPlanar(u_material_ambient_texture, v_world_position.xyz, _normal, material.ambientScale);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_AMBIENT_TEXTURE_SPHEREMAP
+        material.ambient *= getSphereMap(u_material_ambient_texture, _eyeToPoint, _normal, TANGRAM_SKEW);
+        #endif
+    #endif
+
+    // get DIFFUSE TEXTUREMAP
+    //------------------------------------------------
+    #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE
+        #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE_UV
+        material.diffuse *= texture2D(u_material_diffuse_texture,v_texcoord);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE_PLANAR
+        material.diffuse *= getPlanar(u_material_diffuse_texture, v_world_position.xyz, material.diffuseScale.xy);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE_TRIPLANAR
+        material.diffuse *= getTriPlanar(u_material_diffuse_texture, v_world_position.xyz, _normal, material.diffuseScale);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_DIFFUSE_TEXTURE_SPHEREMAP
+        material.diffuse *= getSphereMap(u_material_diffuse_texture, _eyeToPoint, _normal, TANGRAM_SKEW);
+        #endif
+    #endif
+
+    // get SPECULAR TEXTUREMAP
+    //------------------------------------------------
+    #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE
+        #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE_UV
+        material.specular *= texture2D(u_material_specular_texture,v_texcoord);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE_PLANAR
+        material.specular *= getPlanar(u_material_specular_texture, v_world_position.xyz, material.specularScale.xy);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE_TRIPLANAR
+        material.specular *= getTriPlanar(u_material_specular_texture, v_world_position.xyz, _normal, material.specularScale);
+        #endif
+
+        #ifdef TANGRAM_MATERIAL_SPECULAR_TEXTURE_SPHEREMAP
+        material.specular *= getSphereMap(u_material_specular_texture, _eyeToPoint, _normal, TANGRAM_SKEW);
+        #endif
+    #endif
+}
+#endif
diff --git a/core/shaders/point.fs b/core/shaders/point.fs
new file mode 100644 (file)
index 0000000..984a1bb
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision mediump float;
+#define LOWP lowp
+#else
+#define LOWP
+#endif
+
+#pragma tangram: defines
+
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+
+#pragma tangram: uniforms
+
+varying vec4 v_color;
+varying vec2 v_texcoords;
+varying float v_alpha;
+
+uniform sampler2D u_tex;
+
+#pragma tangram: global
+
+void main(void) {
+    if (v_alpha < TANGRAM_EPSILON) {
+        discard;
+    } else {
+        vec4 texColor = texture2D(u_tex, v_texcoords);
+        vec4 color = vec4(texColor.rgb * v_color.rgb, v_alpha * texColor.a * v_color.a);
+
+        #pragma tangram: color
+        #pragma tangram: filter
+
+        gl_FragColor = color;
+    }
+}
diff --git a/core/shaders/point.vs b/core/shaders/point.vs
new file mode 100644 (file)
index 0000000..919408b
--- /dev/null
@@ -0,0 +1,106 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision mediump float;
+#define LOWP lowp
+#else
+#define LOWP
+#endif
+
+#pragma tangram: defines
+
+uniform mat4 u_ortho;
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+#ifdef TANGRAM_TEXT
+uniform vec2 u_uv_scale_factor;
+uniform float u_max_stroke_width;
+uniform LOWP int u_pass;
+#endif
+
+#pragma tangram: uniforms
+
+attribute vec2 a_uv;
+attribute LOWP float a_alpha;
+attribute LOWP vec4 a_color;
+#ifdef TANGRAM_TEXT
+attribute vec2 a_position;
+attribute LOWP vec4 a_stroke;
+attribute float a_scale;
+#else
+attribute vec3 a_position;
+#endif
+
+#ifdef TANGRAM_FEATURE_SELECTION
+attribute vec4 a_selection_color;
+varying vec4 v_selection_color;
+#endif
+
+varying vec4 v_color;
+varying vec2 v_texcoords;
+#ifdef TANGRAM_TEXT
+varying float v_sdf_threshold;
+varying float v_sdf_pixel;
+#endif
+varying float v_alpha;
+
+#pragma tangram: global
+
+#define UNPACK_POSITION(x) (x / 4.0) // 4 subpixel precision
+#define UNPACK_EXTRUDE(x) (x / 256.0)
+#define UNPACK_TEXTURE(x) (x * u_uv_scale_factor)
+
+void main() {
+
+    v_alpha = a_alpha;
+    v_color = a_color;
+
+#ifdef TANGRAM_FEATURE_SELECTION
+    v_selection_color = a_selection_color;
+    // Skip non-selectable meshes
+    if (v_selection_color == vec4(0.0)) {
+        gl_Position = vec4(0.0);
+        return;
+    }
+#endif
+
+#ifdef TANGRAM_TEXT
+    vec2 vertex_pos = UNPACK_POSITION(a_position);
+    v_texcoords = UNPACK_TEXTURE(a_uv);
+    float sdf_scale = a_scale / 64.0;
+    v_sdf_pixel = 0.5 / (u_max_stroke_width * sdf_scale);
+
+    if (u_pass == 0) {
+        v_sdf_threshold = 0.5;
+    } else {
+        if ((a_stroke.a > 0.0)) {
+            float stroke_width;
+            stroke_width = ((a_stroke.a * u_max_stroke_width) * (0.5 / u_max_stroke_width));
+            stroke_width = (stroke_width / sdf_scale);
+            v_sdf_threshold = max ((0.5 - stroke_width), 0.0);
+            v_color.xyz = a_stroke.xyz;
+        } else {
+            v_alpha = 0.0;
+        }
+    }
+
+    vec4 position;
+    position.zw = vec2(0.0, 1.0);
+    position.xy = vertex_pos;
+
+    #pragma tangram: position
+
+    gl_Position = (u_ortho * position);
+
+#else
+    v_texcoords = a_uv;
+
+    gl_Position = vec4(a_position, 1.0);
+
+#endif
+
+}
diff --git a/core/shaders/pointLight.glsl b/core/shaders/pointLight.glsl
new file mode 100644 (file)
index 0000000..bc46332
--- /dev/null
@@ -0,0 +1,100 @@
+/*
+
+Expected globals:
+material
+light_accumulator_*
+
+*/
+
+struct PointLight {
+    vec4 ambient;
+    vec4 diffuse;
+    vec4 specular;
+    vec4 position;
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_EXPONENT
+    float attenuationExponent;
+#endif
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+    float innerRadius;
+#endif
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+    float outerRadius;
+#endif
+};
+
+void calculateLight(in PointLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
+
+    float dist = length(_light.position.xyz - _eyeToPoint);
+
+    // Compute vector from surface to light position
+    vec3 VP = (_light.position.xyz - _eyeToPoint) / dist;
+
+    // Normalize the vector from surface to light position
+    float nDotVP = clamp(dot(VP, _normal), 0.0, 1.0);
+
+    // Attenuation defaults
+    float attenuation = 1.0;
+    #ifdef TANGRAM_POINTLIGHT_ATTENUATION_EXPONENT
+        float Rin = 1.0;
+        float e = _light.attenuationExponent;
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+            Rin = _light.innerRadius;
+        #endif
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+            float Rdiff = _light.outerRadius-Rin;
+            float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
+            attenuation = 1.0-(pow(d,e));
+        #else
+            // If no outer is provide behaves like:
+            // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
+            float d = max(0.0,dist-Rin)/Rin+1.0;
+            attenuation = clamp(1.0/(pow(d,e)), 0.0, 1.0);
+        #endif
+    #else
+        float Rin = 0.0;
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+            Rin = _light.innerRadius;
+            #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+                float Rdiff = _light.outerRadius-Rin;
+                float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
+                attenuation = 1.0-d*d;
+            #else
+                // If no outer is provide behaves like:
+                // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
+                float d = max(0.0,dist-Rin)/Rin+1.0;
+                attenuation = clamp(1.0/d, 0.0, 1.0);
+            #endif
+        #else
+            #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+                float d = clamp(dist/_light.outerRadius, 0.0, 1.0);
+                attenuation = 1.0-d*d;
+            #else
+                attenuation = 1.0;
+            #endif
+        #endif
+    #endif
+
+    // Computer accumulators
+    light_accumulator_ambient += _light.ambient * attenuation;
+
+    #ifdef TANGRAM_MATERIAL_DIFFUSE
+        light_accumulator_diffuse += _light.diffuse * nDotVP * attenuation;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_SPECULAR
+        float pf = 0.0; // power factor for shiny speculars
+        if (nDotVP > 0.0) {
+            vec3 reflectVector = reflect(-VP, _normal);
+            float eyeDotR = max(0.0, dot(-normalize(_eyeToPoint), reflectVector));
+            pf = pow(eyeDotR, material.shininess);
+        }
+
+        light_accumulator_specular += _light.specular * pf * attenuation;
+    #endif
+}
diff --git a/core/shaders/polygon.fs b/core/shaders/polygon.fs
new file mode 100644 (file)
index 0000000..5b5b0a7
--- /dev/null
@@ -0,0 +1,92 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision highp float;
+#endif
+
+#pragma tangram: defines
+
+uniform mat4 u_model;
+uniform mat4 u_view;
+uniform mat4 u_proj;
+uniform mat3 u_normal_matrix;
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform mat3 u_inverse_normal_matrix;
+
+#pragma tangram: uniforms
+
+varying vec4 v_world_position;
+varying vec4 v_position;
+varying vec4 v_color;
+varying vec3 v_normal;
+
+#ifdef TANGRAM_USE_TEX_COORDS
+    varying vec2 v_texcoord;
+#endif
+
+#ifdef TANGRAM_LIGHTING_VERTEX
+    varying vec4 v_lighting;
+#endif
+
+vec4 worldPosition() {
+    return v_world_position;
+}
+
+vec3 worldNormal() {
+    return normalize(u_inverse_normal_matrix * v_normal);
+}
+
+#pragma tangram: material
+#pragma tangram: lighting
+#pragma tangram: global
+#pragma tangram: raster
+
+#ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+    varying vec4 v_modelpos_base_zoom;
+#endif
+
+void main(void) {
+
+    // Initialize globals
+    #pragma tangram: setup
+
+    vec4 color = v_color;
+    vec3 normal = v_normal;
+
+    #ifdef TANGRAM_RASTER_TEXTURE_COLOR
+        color *= sampleRaster(0);
+    #endif
+
+    #ifdef TANGRAM_RASTER_TEXTURE_NORMAL
+        normal = normalize(sampleRaster(0).rgb * 2.0 - 1.0);
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE
+        calculateNormal(normal);
+    #endif
+
+    // Modify normal before lighting if not already modified in vertex shader
+    #if !defined(TANGRAM_LIGHTING_VERTEX)
+        #pragma tangram: normal
+    #endif
+
+    // Modify color before lighting is applied
+    #pragma tangram: color
+
+    #if defined(TANGRAM_LIGHTING_FRAGMENT)
+        color = calculateLighting(v_position.xyz, normal, color);
+    #elif defined(TANGRAM_LIGHTING_VERTEX)
+        color *= v_lighting;
+    #endif
+
+    // Modify color after lighting (filter-like effects that don't require a additional render passes)
+    #pragma tangram: filter
+
+    //color.rgb = pow(color.rgb, vec3(1.0/2.2)); // gamma correction
+    gl_FragColor = color;
+}
diff --git a/core/shaders/polygon.vs b/core/shaders/polygon.vs
new file mode 100644 (file)
index 0000000..e9174c5
--- /dev/null
@@ -0,0 +1,137 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision highp float;
+#endif
+
+#pragma tangram: defines
+
+uniform mat4 u_model;
+uniform mat4 u_view;
+uniform mat4 u_proj;
+uniform mat3 u_normal_matrix;
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform float u_proxy_depth;
+
+#pragma tangram: uniforms
+
+attribute vec4 a_position;
+attribute vec4 a_color;
+attribute vec3 a_normal;
+
+#ifdef TANGRAM_USE_TEX_COORDS
+    attribute vec2 a_texcoord;
+    varying vec2 v_texcoord;
+#endif
+
+#ifdef TANGRAM_FEATURE_SELECTION
+    // Make sure lighting is a no-op for feature selection pass
+    #undef TANGRAM_LIGHTING_VERTEX
+
+    attribute vec4 a_selection_color;
+    varying vec4 v_selection_color;
+#endif
+
+varying vec4 v_world_position;
+varying vec4 v_position;
+varying vec4 v_color;
+varying vec3 v_normal;
+
+#ifdef TANGRAM_LIGHTING_VERTEX
+    varying vec4 v_lighting;
+#endif
+
+#define UNPACK_POSITION(x) (x / 8192.0)
+
+vec4 modelPosition() {
+    return vec4(UNPACK_POSITION(a_position.xyz) * exp2(u_tile_origin.z - u_tile_origin.w), 1.0);
+}
+
+vec4 worldPosition() {
+    return v_world_position;
+}
+
+vec3 worldNormal() {
+    return a_normal;
+}
+
+vec4 modelPositionBaseZoom() {
+    return vec4(UNPACK_POSITION(a_position.xyz), 1.0);
+}
+
+#pragma tangram: material
+#pragma tangram: lighting
+#pragma tangram: global
+#pragma tangram: raster
+
+#ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+    varying vec4 v_modelpos_base_zoom;
+#endif
+
+void main() {
+
+    vec4 position = vec4(UNPACK_POSITION(a_position.xyz), 1.0);
+
+    #ifdef TANGRAM_FEATURE_SELECTION
+        v_selection_color = a_selection_color;
+        // Skip non-selectable meshes
+        if (v_selection_color == vec4(0.0)) {
+            gl_Position = vec4(0.0);
+            return;
+        }
+    #else
+        // Initialize globals
+        #pragma tangram: setup
+    #endif
+
+    v_color = a_color;
+
+    #ifdef TANGRAM_USE_TEX_COORDS
+        v_texcoord = a_texcoord;
+    #endif
+
+    #ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+        v_modelpos_base_zoom = modelPositionBaseZoom();
+    #endif
+
+    v_normal = normalize(u_normal_matrix * a_normal);
+
+    // Transform position into meters relative to map center
+    position = u_model * position;
+
+    // World coordinates for 3d procedural textures
+    vec4 local_origin = vec4(u_map_position.xy, 0., 0.);
+    #ifdef TANGRAM_WORLD_POSITION_WRAP
+        local_origin = mod(local_origin, TANGRAM_WORLD_POSITION_WRAP);
+    #endif
+    v_world_position = position + local_origin;
+
+    // Modify position before lighting and camera projection
+    #pragma tangram: position
+
+    // Set position varying to the camera-space vertex position
+    v_position = u_view * position;
+
+    #if defined(TANGRAM_LIGHTING_VERTEX)
+        // Modify normal before lighting
+        vec3 normal = v_normal;
+        #pragma tangram: normal
+
+        v_lighting = calculateLighting(v_position.xyz, normal, vec4(1.));
+    #endif
+
+    gl_Position = u_proj * v_position;
+
+    // Proxy tiles are placed deeper in the depth buffer than non-proxy tiles
+    gl_Position.z += TANGRAM_DEPTH_DELTA * gl_Position.w * u_proxy_depth;
+
+    #ifdef TANGRAM_DEPTH_DELTA
+        float layer = a_position.w;
+        gl_Position.z -= layer * TANGRAM_DEPTH_DELTA * gl_Position.w;
+    #endif
+}
diff --git a/core/shaders/polyline.fs b/core/shaders/polyline.fs
new file mode 100644 (file)
index 0000000..a4f5421
--- /dev/null
@@ -0,0 +1,110 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision highp float;
+#endif
+
+#pragma tangram: defines
+
+uniform mat4 u_model;
+uniform mat4 u_view;
+uniform mat4 u_proj;
+uniform mat3 u_normal_matrix;
+uniform mat3 u_inverse_normal_matrix;
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform float u_texture_ratio;
+uniform sampler2D u_texture;
+
+#pragma tangram: uniforms
+
+varying vec4 v_world_position;
+varying vec4 v_position;
+varying vec4 v_color;
+varying vec3 v_normal;
+
+#ifdef TANGRAM_USE_TEX_COORDS
+    varying vec2 v_texcoord;
+#endif
+
+#ifdef TANGRAM_LIGHTING_VERTEX
+    varying vec4 v_lighting;
+#endif
+
+vec4 worldPosition() {
+    return v_world_position;
+}
+
+vec3 worldNormal() {
+    return normalize(u_inverse_normal_matrix * v_normal);
+}
+
+#pragma tangram: material
+#pragma tangram: lighting
+#pragma tangram: global
+#pragma tangram: raster
+
+#ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+    varying vec4 v_modelpos_base_zoom;
+#endif
+
+void main(void) {
+
+    // Initialize globals
+    #pragma tangram: setup
+
+    vec4 color = v_color;
+    vec3 normal = v_normal;
+
+    #ifdef TANGRAM_RASTER_TEXTURE_COLOR
+        color *= sampleRaster(0);
+    #endif
+
+    #ifdef TANGRAM_LINE_TEXTURE
+        vec2 line_st = vec2(v_texcoord.x, fract(v_texcoord.y * TANGRAM_DASHLINE_TEX_SCALE / u_texture_ratio));
+        vec4 line_color = texture2D(u_texture, line_st);
+
+        if (line_color.a < TANGRAM_ALPHA_TEST) {
+            #ifdef TANGRAM_LINE_BACKGROUND_COLOR
+                color.rgb = TANGRAM_LINE_BACKGROUND_COLOR;
+            #elif !defined(TANGRAM_BLEND_OVERLAY) && !defined(TANGRAM_BLEND_INLAY)
+                discard;
+            #else
+                color.a = 0.0;
+            #endif
+        } else {
+            color *= line_color;
+        }
+    #endif
+
+    #ifdef TANGRAM_RASTER_TEXTURE_NORMAL
+        normal = normalize(sampleRaster(0).rgb * 2.0 - 1.0);
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_NORMAL_TEXTURE
+        calculateNormal(normal);
+    #endif
+
+    // Modify normal before lighting if not already modified in vertex shader
+    #if !defined(TANGRAM_LIGHTING_VERTEX)
+        #pragma tangram: normal
+    #endif
+
+    // Modify color before lighting is applied
+    #pragma tangram: color
+
+    #if defined(TANGRAM_LIGHTING_FRAGMENT)
+        color = calculateLighting(v_position.xyz, normal, color);
+    #elif defined(TANGRAM_LIGHTING_VERTEX)
+        color *= v_lighting;
+    #endif
+
+    // Modify color after lighting (filter-like effects that don't require a additional render passes)
+    #pragma tangram: filter
+
+    gl_FragColor = color;
+}
diff --git a/core/shaders/polyline.vs b/core/shaders/polyline.vs
new file mode 100644 (file)
index 0000000..0ee0835
--- /dev/null
@@ -0,0 +1,162 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision highp float;
+#endif
+
+#pragma tangram: defines
+
+uniform mat4 u_model;
+uniform mat4 u_view;
+uniform mat4 u_proj;
+uniform mat3 u_normal_matrix;
+uniform vec4 u_tile_origin;
+uniform vec3 u_map_position;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform float u_proxy_depth;
+
+#pragma tangram: uniforms
+
+attribute vec4 a_position;
+attribute vec4 a_color;
+attribute vec4 a_extrude;
+
+#ifdef TANGRAM_USE_TEX_COORDS
+    attribute vec2 a_texcoord;
+    varying vec2 v_texcoord;
+#endif
+
+#ifdef TANGRAM_FEATURE_SELECTION
+    // Make sure lighting is a no-op for feature selection pass
+    #undef TANGRAM_LIGHTING_VERTEX
+
+    attribute vec4 a_selection_color;
+    varying vec4 v_selection_color;
+#endif
+
+varying vec4 v_world_position;
+varying vec4 v_position;
+varying vec4 v_color;
+varying vec3 v_normal;
+
+#ifdef TANGRAM_LIGHTING_VERTEX
+    varying vec4 v_lighting;
+#endif
+
+#define UNPACK_POSITION(x) (x / 8192.0)
+#define UNPACK_EXTRUSION(x) (x / 4096.0)
+#define UNPACK_ORDER(x) (x / 2.0)
+#define UNPACK_TEXCOORD(x) (x / 8192.0)
+
+vec4 modelPosition() {
+    return vec4(UNPACK_POSITION(a_position.xyz) * exp2(u_tile_origin.z - u_tile_origin.w), 1.0);
+}
+
+vec4 worldPosition() {
+    return v_world_position;
+}
+
+vec3 worldNormal() {
+    return vec3(0.0, 0.0, 1.0);
+}
+
+vec4 modelPositionBaseZoom() {
+    return vec4(UNPACK_POSITION(a_position.xyz), 1.0);
+}
+
+#pragma tangram: material
+#pragma tangram: lighting
+#pragma tangram: global
+#pragma tangram: raster
+
+#ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+    varying vec4 v_modelpos_base_zoom;
+#endif
+
+void main() {
+
+    vec4 position = vec4(UNPACK_POSITION(a_position.xyz), 1.0);
+
+    #ifdef TANGRAM_FEATURE_SELECTION
+        v_selection_color = a_selection_color;
+        // Skip non-selectable meshes
+        if (v_selection_color == vec4(0.0)) {
+            gl_Position = vec4(0.0);
+            return;
+        }
+    #else
+        // Initialize globals
+        #pragma tangram: setup
+    #endif
+
+    v_color = a_color;
+
+    #ifdef TANGRAM_USE_TEX_COORDS
+        v_texcoord = UNPACK_TEXCOORD(a_texcoord);
+    #endif
+
+    #ifdef TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING
+        v_modelpos_base_zoom = modelPositionBaseZoom();
+    #endif
+
+    v_normal = u_normal_matrix * vec3(0.,0.,1.);
+
+    {
+        vec4 extrude = UNPACK_EXTRUSION(a_extrude);
+        float width = extrude.z;
+        float dwdz = extrude.w;
+        float dz = u_map_position.z - u_tile_origin.z;
+
+        // Interpolate between zoom levels
+        width += dwdz * clamp(dz, 0.0, 1.0);
+        // Scale pixel dimensions to be consistent in screen space
+        // and adjust scale for overzooming.
+        width *= exp2(-dz + (u_tile_origin.w - u_tile_origin.z));
+
+        // Modify line width in model space before extrusion
+        #pragma tangram: width
+
+        #ifdef TANGRAM_USE_TEX_COORDS
+            v_texcoord.y /= 2. * extrude.z;
+        #endif
+
+        position.xy += extrude.xy * width;
+    }
+
+    // Transform position into meters relative to map center
+    position = u_model * position;
+
+    // World coordinates for 3d procedural textures
+    vec4 local_origin = vec4(u_map_position.xy, 0., 0.);
+    #ifdef TANGRAM_WORLD_POSITION_WRAP
+        local_origin = mod(local_origin, TANGRAM_WORLD_POSITION_WRAP);
+    #endif
+    v_world_position = position + local_origin;
+
+    // Modify position before lighting and camera projection
+    #pragma tangram: position
+
+    // Set position varying to the camera-space vertex position
+    v_position = u_view * position;
+
+    #ifdef TANGRAM_LIGHTING_VERTEX
+        // Modify normal before lighting
+        vec3 normal = v_normal;
+        #pragma tangram: normal
+
+        v_lighting = calculateLighting(v_position.xyz, normal, vec4(1.));
+    #endif
+
+    gl_Position = u_proj * v_position;
+
+    // Proxy tiles are placed deeper in the depth buffer than non-proxy tiles
+    gl_Position.z += TANGRAM_DEPTH_DELTA * gl_Position.w * u_proxy_depth;
+
+    #ifdef TANGRAM_DEPTH_DELTA
+        float layer = UNPACK_ORDER(a_position.w);
+        gl_Position.z -= layer * TANGRAM_DEPTH_DELTA * gl_Position.w;
+    #endif
+}
diff --git a/core/shaders/rasters.glsl b/core/shaders/rasters.glsl
new file mode 100644 (file)
index 0000000..275ac79
--- /dev/null
@@ -0,0 +1,19 @@
+#ifdef TANGRAM_FRAGMENT_SHADER
+
+uniform sampler2D u_rasters[TANGRAM_NUM_RASTER_SOURCES];
+uniform vec2 u_raster_sizes[TANGRAM_NUM_RASTER_SOURCES];
+uniform vec3 u_raster_offsets[TANGRAM_NUM_RASTER_SOURCES];
+
+#define adjustRasterUV(raster_index, uv) ((uv) * u_raster_offsets[raster_index].z + u_raster_offsets[raster_index].xy)
+
+#define currentRasterUV(raster_index) (adjustRasterUV(raster_index, v_modelpos_base_zoom.xy))
+
+#define currentRasterPixel(raster_index) (currentRasterUV(raster_index) * rasterPixelSize(raster_index))
+
+#define sampleRasterAtPixel(raster_index, pixel) (texture2D(u_rasters[raster_index], adjustRasterUV(raster_index, (pixel) / rasterPixelSize(raster_index))))
+
+#define sampleRaster(raster_index) (texture2D(u_rasters[raster_index], currentRasterUV(raster_index)))
+
+#define rasterPixelSize(raster_index) (u_raster_sizes[raster_index])
+
+#endif
diff --git a/core/shaders/sdf.fs b/core/shaders/sdf.fs
new file mode 100644 (file)
index 0000000..a893453
--- /dev/null
@@ -0,0 +1,78 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+    precision mediump float;
+    #define LOWP lowp
+#else
+    #define LOWP
+#endif
+
+#pragma tangram: defines
+
+uniform sampler2D u_tex;
+uniform vec3 u_map_position;
+uniform vec4 u_tile_origin;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform float u_max_stroke_width;
+uniform LOWP int u_pass;
+
+#pragma tangram: uniforms
+
+varying vec4 v_color;
+varying vec2 v_texcoords;
+varying float v_sdf_threshold;
+varying float v_alpha;
+varying float v_sdf_pixel;
+
+#pragma tangram: global
+
+void main(void) {
+
+    vec4 color = v_color;
+
+    float signed_distance = texture2D(u_tex, v_texcoords).a;
+
+    // - At the glyph outline alpha is 0.5
+    //
+    // - The sdf-radius is 3.0px, i.e. within 3px distance
+    //   from the outline alpha is in the range (0.5 -> 0.0)
+    //
+    // - 0.5 pixel threshold (to both sides of the outline)
+    //   plus 0.25 for a bit of smoothness
+    //
+    //   ==> (0.5 / 3.0) * (0.5 + 0.25) == 0.1245
+    //   This value is added to sdf_threshold to antialias
+    //   the outline within one pixel for the *unscaled* glyph.
+    //
+    // - sdf_scale == fontScale / glyphScale:
+    //   When the glyph is scaled down, 's' must be increased
+    //   (used to interpolate 1px of the scaled glyph around v_sdf_threshold)
+
+    float add_smooth = 0.25;
+    float filter_width = (v_sdf_pixel * (0.5 + add_smooth));
+
+    float start = max(v_sdf_threshold - filter_width, 0.0);
+    float end = v_sdf_threshold + filter_width;
+
+    float alpha;
+
+    if (u_pass == 0) {
+        alpha = smoothstep(start, end, signed_distance);
+    } else {
+        // smooth the signed distance for outlines
+        float signed_distance_1_over_2 = 1.0 / (2.0 * signed_distance);
+        float smooth_signed_distance = pow(signed_distance, signed_distance_1_over_2);
+
+        alpha = smoothstep(start, end, smooth_signed_distance);
+    }
+
+    color.a *= v_alpha * alpha;
+
+    #pragma tangram: color
+    #pragma tangram: filter
+
+    gl_FragColor = color;
+}
diff --git a/core/shaders/selection.fs b/core/shaders/selection.fs
new file mode 100644 (file)
index 0000000..46316d1
--- /dev/null
@@ -0,0 +1,10 @@
+
+#ifdef GL_ES
+precision highp float;
+#endif
+
+varying vec4 v_selection_color;
+
+void main(void) {
+    gl_FragColor = v_selection_color;
+}
diff --git a/core/shaders/spotLight.glsl b/core/shaders/spotLight.glsl
new file mode 100644 (file)
index 0000000..b16f2cd
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+
+Expected globals:
+material
+light_accumulator_*
+
+*/
+
+struct SpotLight {
+    vec4 ambient;
+    vec4 diffuse;
+    vec4 specular;
+    vec4 position;
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_EXPONENT
+    float attenuationExponent;
+#endif
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+    float innerRadius;
+#endif
+
+#ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+    float outerRadius;
+#endif
+
+    vec3 direction;
+    float spotCosCutoff;
+    float spotExponent;
+};
+
+void calculateLight(in SpotLight _light, in vec3 _eyeToPoint, in vec3 _normal) {
+
+    float dist = length(_light.position.xyz - _eyeToPoint);
+
+    // Compute vector from surface to light position
+    vec3 VP = (_light.position.xyz - _eyeToPoint) / dist;
+
+    // normal . light direction
+    float nDotVP = clamp(dot(_normal, VP), 0.0, 1.0);
+
+    // Attenuation defaults
+    float attenuation = 1.0;
+    #ifdef TANGRAM_POINTLIGHT_ATTENUATION_EXPONENT
+        float Rin = 1.0;
+        float e = _light.attenuationExponent;
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+            Rin = _light.innerRadius;
+        #endif
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+            float Rdiff = _light.outerRadius-Rin;
+            float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
+            attenuation = 1.0-(pow(d,e));
+        #else
+            // If no outer is provide behaves like:
+            // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
+            float d = max(0.0,dist-Rin)/Rin+1.0;
+            attenuation = clamp(1.0/(pow(d,e)), 0.0, 1.0);
+        #endif
+    #else
+        float Rin = 0.0;
+
+        #ifdef TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS
+            Rin = _light.innerRadius;
+            #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+                float Rdiff = _light.outerRadius-Rin;
+                float d = clamp(max(0.0,dist-Rin)/Rdiff, 0.0, 1.0);
+                attenuation = 1.0-d*d;
+            #else
+                // If no outer is provide behaves like:
+                // https://imdoingitwrong.wordpress.com/2011/01/31/light-attenuation/
+                float d = max(0.0,dist-Rin)/Rin+1.0;
+                attenuation = clamp(1.0/d, 0.0, 1.0);
+            #endif
+        #else
+            #ifdef TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS
+                float d = clamp(dist/_light.outerRadius, 0.0, 1.0);
+                attenuation = 1.0-d*d;
+            #else
+                attenuation = 1.0;
+            #endif
+        #endif
+    #endif
+
+    // spotlight attenuation factor
+    float spotAttenuation = 0.0;
+
+    // See if point on surface is inside cone of illumination
+    float spotDot = clamp(dot(-VP, normalize(_light.direction)), 0.0, 1.0);
+
+    if (spotDot >= _light.spotCosCutoff) {
+        spotAttenuation = pow(spotDot, _light.spotExponent);
+    }
+
+    light_accumulator_ambient += _light.ambient * attenuation * spotAttenuation;
+
+    #ifdef TANGRAM_MATERIAL_DIFFUSE
+        light_accumulator_diffuse += _light.diffuse * nDotVP * attenuation * spotAttenuation;
+    #endif
+
+    #ifdef TANGRAM_MATERIAL_SPECULAR
+        // Power factor for shiny speculars
+        float pf = 0.0;
+        if (nDotVP > 0.0) {
+            vec3 reflectVector = reflect(-VP, _normal);
+            float eyeDotR = max(dot(-normalize(_eyeToPoint), reflectVector), 0.0);
+            pf = pow(eyeDotR, material.shininess);
+        }
+        light_accumulator_specular += _light.specular * pf * attenuation * spotAttenuation;
+    #endif
+}
diff --git a/core/shaders/text.fs b/core/shaders/text.fs
new file mode 100644 (file)
index 0000000..6ea5468
--- /dev/null
@@ -0,0 +1,43 @@
+#pragma tangram: extensions
+
+#ifdef GL_ES
+precision mediump float;
+#define LOWP lowp
+#else
+#define LOWP
+#endif
+
+#pragma tangram: defines
+
+uniform sampler2D u_tex;
+uniform vec3 u_map_position;
+uniform vec4 u_tile_origin;
+uniform vec2 u_resolution;
+uniform float u_time;
+uniform float u_meters_per_pixel;
+uniform float u_device_pixel_ratio;
+uniform vec2 u_uv_scale_factor;
+
+#pragma tangram: uniforms
+
+varying vec2 v_uv;
+varying float v_alpha;
+varying vec4 v_color;
+
+#pragma tangram: global
+
+void main(void) {
+    if (v_alpha < TANGRAM_EPSILON) {
+        discard;
+    } else {
+        vec4 color;
+        vec4 texColor = texture2D(u_tex, v_uv * u_uv_scale_factor);
+
+        color = vec4(v_color.rgb, texColor.a * v_alpha * v_color.a);
+
+        #pragma tangram: color
+        #pragma tangram: filter
+
+        gl_FragColor = color;
+    }
+}
diff --git a/core/src/data/clientGeoJsonSource.cpp b/core/src/data/clientGeoJsonSource.cpp
new file mode 100644 (file)
index 0000000..4ab8106
--- /dev/null
@@ -0,0 +1,278 @@
+#include "data/clientGeoJsonSource.h"
+
+#include "platform.h"
+#include "tile/tileTask.h"
+#include "util/geom.h"
+#include "data/propertyItem.h"
+#include "data/tileData.h"
+#include "tile/tile.h"
+#include "view/view.h"
+
+#include "mapbox/geojsonvt.hpp"
+
+// RapidJson parser
+#include "mapbox/geojson.hpp"
+#include <mapbox/geojson_impl.hpp>
+
+
+#include <regex>
+
+namespace Tangram {
+
+using namespace mapbox;
+
+geojsonvt::Options options() {
+    geojsonvt::Options opt;
+    opt.maxZoom = 18;
+    opt.indexMaxZoom = 5;
+    opt.indexMaxPoints = 100000;
+    opt.solidChildren = true;
+    opt.tolerance = 3;
+    opt.extent = 4096;
+    opt.buffer = 0;
+    return opt;
+}
+
+struct ClientGeoJsonData {
+    std::unique_ptr<geojsonvt::GeoJSONVT> tiles;
+    mapbox::geometry::feature_collection<double> features;
+    std::vector<Properties> properties;
+};
+
+std::shared_ptr<TileTask> ClientGeoJsonSource::createTask(TileID _tileId, int _subTask) {
+    return std::make_shared<TileTask>(_tileId, shared_from_this(), _subTask);
+}
+
+
+// TODO: pass scene's resourcePath to constructor to be used with `stringFromFile`
+ClientGeoJsonSource::ClientGeoJsonSource(std::shared_ptr<Platform> _platform,
+                                         const std::string& _name, const std::string& _url,
+                                         int32_t _minDisplayZoom, int32_t _maxDisplayZoom, int32_t _maxZoom,
+                                         int32_t _zoomBias)
+
+    : TileSource(_name, nullptr, _minDisplayZoom, _maxDisplayZoom, _maxZoom, _zoomBias),
+      m_platform(_platform) {
+
+    // TODO: handle network url for client datasource data
+    // TODO: generic uri handling
+    m_generateGeometry = true;
+    m_store = std::make_unique<ClientGeoJsonData>();
+
+    if (!_url.empty()) {
+        std::regex r("^(http|https):/");
+        std::smatch match;
+        if (std::regex_search(_url, match, r)) {
+            m_platform->startUrlRequest(_url,
+                    [&, this](std::vector<char>&& rawData) {
+                        addData(std::string(rawData.begin(), rawData.end()));
+                        m_hasPendingData = false;
+                    });
+            m_hasPendingData = true;
+        } else {
+            // Load from file
+            addData(m_platform->stringFromFile(_url.c_str()));
+        }
+    }
+}
+
+ClientGeoJsonSource::~ClientGeoJsonSource() {}
+
+void ClientGeoJsonSource::addData(const std::string& _data) {
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    const auto json = geojson::parse(_data);
+    auto features = geojsonvt::geojson::visit(json, geojsonvt::ToFeatureCollection{});
+
+    for (auto& feature : features) {
+
+        feature.id = uint64_t(m_store->properties.size());
+        m_store->properties.emplace_back();
+        Properties& props = m_store->properties.back();
+
+        for (const auto& prop : feature.properties) {
+
+            if (prop.second.is<std::string>()) {
+                props.set(prop.first, prop.second.get<std::string>());
+
+            } else if (prop.second.is<bool>()) {
+                props.set(prop.first, double(prop.second.get<bool>()));
+
+            } else if (prop.second.is<uint64_t>()) {
+                props.set(prop.first, double(prop.second.get<uint64_t>()));
+
+            } else if (prop.second.is<int64_t>()) {
+                props.set(prop.first, double(prop.second.get<int64_t>()));
+
+            } else if (prop.second.is<double>()) {
+                props.set(prop.first, prop.second.get<double>());
+            }
+        }
+        feature.properties.clear();
+    }
+
+    m_store->features.insert(m_store->features.end(),
+                             std::make_move_iterator(features.begin()),
+                             std::make_move_iterator(features.end()));
+
+    m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
+    m_generation++;
+}
+
+void ClientGeoJsonSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+
+    if (m_hasPendingData) {
+        return;
+    }
+
+    if (_task->needsLoading()) {
+        _task->startedLoading();
+
+        _cb.func(_task);
+    }
+
+    // Load subsources
+    TileSource::loadTileData(_task, _cb);
+}
+
+void ClientGeoJsonSource::clearData() {
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    m_store->features.clear();
+    m_store->properties.clear();
+    m_store->tiles.reset();
+
+    m_generation++;
+}
+
+void ClientGeoJsonSource::addPoint(const Properties& _tags, LngLat _point) {
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    geometry::point<double> geom { _point.longitude, _point.latitude };
+
+    uint64_t id = m_store->features.size();
+
+    m_store->features.emplace_back(geom, id);
+    m_store->properties.emplace_back(_tags);
+
+    m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
+    m_generation++;
+}
+
+void ClientGeoJsonSource::addLine(const Properties& _tags, const Coordinates& _line) {
+
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    geometry::line_string<double> geom;
+    for (auto& p : _line) {
+        geom.emplace_back(p.longitude, p.latitude);
+    }
+
+    uint64_t id = m_store->features.size();
+
+    m_store->features.emplace_back(geom, id);
+    m_store->properties.emplace_back(_tags);
+
+    m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
+    m_generation++;
+}
+
+void ClientGeoJsonSource::addPoly(const Properties& _tags, const std::vector<Coordinates>& _poly) {
+
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    geometry::polygon<double> geom;
+    for (auto& ring : _poly) {
+        geom.emplace_back();
+        auto &line = geom.back();
+        for (auto& p : ring) {
+            line.emplace_back(p.longitude, p.latitude);
+        }
+    }
+
+    uint64_t id = m_store->features.size();
+
+    m_store->features.emplace_back(geom, id);
+    m_store->properties.emplace_back(_tags);
+
+    m_store->tiles = std::make_unique<geojsonvt::GeoJSONVT>(m_store->features, options());
+    m_generation++;
+}
+
+struct add_geometry {
+
+    static constexpr double extent = 4096.0;
+
+    // Transform a geojsonvt::TilePoint into the corresponding Tangram::Point
+    Point transformPoint(geometry::point<int16_t> pt) {
+        return { pt.x / extent, 1. - pt.y / extent, 0 };
+    }
+
+    Feature& feature;
+
+    bool operator()(const geometry::point<int16_t>& p) {
+        feature.geometryType = GeometryType::points;
+        feature.points.push_back(transformPoint(p));
+        return true;
+    }
+    bool operator()(const geometry::line_string<int16_t>& geom) {
+        feature.geometryType = GeometryType::lines;
+        feature.lines.emplace_back();
+        Line& line = feature.lines.back();
+        for (const auto& p : geom) {
+            line.push_back(transformPoint(p));
+        }
+        return true;
+    }
+    bool operator()(const geometry::polygon<int16_t>& geom) {
+        feature.geometryType = GeometryType::polygons;
+        feature.polygons.emplace_back();
+        for (const auto& ring : geom) {
+            feature.polygons.back().emplace_back();
+            Line& line = feature.polygons.back().back();
+            for (const auto& p : ring) {
+                line.push_back(transformPoint(p));
+            }
+        }
+        return true;
+    }
+
+    template <typename T>
+    bool operator()(T) {
+        // Unreachable: All multi-geometries and feature collections
+        // are split up in vector tiles.
+        return false;
+    }
+};
+
+std::shared_ptr<TileData> ClientGeoJsonSource::parse(const TileTask& _task,
+                                                     const MapProjection& _projection) const {
+
+    std::lock_guard<std::mutex> lock(m_mutexStore);
+
+    auto data = std::make_shared<TileData>();
+
+    if (!m_store->tiles) { return nullptr; }
+    auto tile = m_store->tiles->getTile(_task.tileId().z, _task.tileId().x, _task.tileId().y);
+
+    data->layers.emplace_back("");  // empty name will skip filtering by 'collection'
+    Layer& layer = data->layers.back();
+
+    for (auto& it : tile.features) {
+        Feature feature(m_id);
+
+        if (geometry::geometry<int16_t>::visit(it.geometry, add_geometry{ feature })) {
+            feature.props = m_store->properties[it.id.get<uint64_t>()];
+            layer.features.emplace_back(std::move(feature));
+        }
+    }
+
+
+    return data;
+}
+
+}
diff --git a/core/src/data/formats/geoJson.cpp b/core/src/data/formats/geoJson.cpp
new file mode 100644 (file)
index 0000000..6ca0ecf
--- /dev/null
@@ -0,0 +1,209 @@
+#include "data/formats/geoJson.h"
+
+#include "data/propertyItem.h"
+#include "log.h"
+#include "tile/tileTask.h"
+#include "util/geom.h"
+#include "util/mapProjection.h"
+
+#include "glm/glm.hpp"
+
+namespace Tangram {
+
+bool GeoJson::isFeatureCollection(const JsonValue& _in) {
+
+    // A FeatureCollection must have a "type" of "FeatureCollection"
+    // and a member named "features" that is an array.
+    // http://geojson.org/geojson-spec.html#feature-collection-objects
+
+    auto type = _in.FindMember("type");
+    if (type == _in.MemberEnd() || !type->value.IsString() ||
+        std::strcmp(type->value.GetString(), "FeatureCollection") != 0) {
+        return false;
+    }
+
+    auto features = _in.FindMember("features");
+    if (features == _in.MemberEnd() || !features->value.IsArray()) {
+        return false;
+    }
+
+    return true;
+
+}
+
+Point GeoJson::getPoint(const JsonValue& _in, const Transform& _proj) {
+    return _proj(glm::dvec2(_in[0].GetDouble(), _in[1].GetDouble()));
+}
+
+Line GeoJson::getLine(const JsonValue& _in, const Transform& _proj) {
+
+    Line line;
+    for (auto itr = _in.Begin(); itr != _in.End(); ++itr) {
+        line.push_back(getPoint(*itr, _proj));
+    }
+    return line;
+
+}
+
+Polygon GeoJson::getPolygon(const JsonValue& _in, const Transform& _proj) {
+
+    Polygon polygon;
+    for (auto itr = _in.Begin(); itr != _in.End(); ++itr) {
+        polygon.push_back(getLine(*itr, _proj));
+    }
+    return polygon;
+
+}
+
+Properties GeoJson::getProperties(const JsonValue& _in, int32_t _sourceId) {
+
+    std::vector<PropertyItem> items;
+    items.reserve(_in.MemberCount());
+
+    for (auto it = _in.MemberBegin(); it != _in.MemberEnd(); ++it) {
+
+        const auto& name = it->name.GetString();
+        const auto& value = it->value;
+        if (value.IsNumber()) {
+            items.emplace_back(name, value.GetDouble());
+        } else if (it->value.IsString()) {
+            items.emplace_back(name, value.GetString());
+        } else if (it->value.IsBool()) {
+            items.emplace_back(name, double(value.GetBool()));
+        }
+    }
+
+    Properties properties;
+    properties.sourceId = _sourceId;
+    properties.setSorted(std::move(items));
+    properties.sort();
+
+    return properties;
+
+}
+
+Feature GeoJson::getFeature(const JsonValue& _in, const Transform& _proj, int32_t _sourceId) {
+
+    Feature feature;
+
+    // Copy properties into tile data
+    auto properties = _in.FindMember("properties");
+    if (properties != _in.MemberEnd()) {
+        feature.props = getProperties(properties->value, _sourceId);
+    }
+
+    // Copy geometry into tile data
+    const JsonValue& geometry = _in["geometry"];
+    const JsonValue& coords = geometry["coordinates"];
+    const std::string& geometryType = geometry["type"].GetString();
+
+    if (geometryType.compare("Point") == 0) {
+
+        feature.geometryType = GeometryType::points;
+        feature.points.push_back(getPoint(coords, _proj));
+
+    } else if (geometryType.compare("MultiPoint") == 0) {
+
+        feature.geometryType = GeometryType::points;
+        for (auto pointCoords = coords.Begin(); pointCoords != coords.End(); ++pointCoords) {
+            feature.points.push_back(getPoint(*pointCoords, _proj));
+        }
+
+    } else if (geometryType.compare("LineString") == 0) {
+
+        feature.geometryType = GeometryType::lines;
+        feature.lines.push_back(getLine(coords, _proj));
+
+    } else if (geometryType.compare("MultiLineString") == 0) {
+
+        feature.geometryType = GeometryType::lines;
+        for (auto lineCoords = coords.Begin(); lineCoords != coords.End(); ++lineCoords) {
+            feature.lines.push_back(getLine(*lineCoords, _proj));
+        }
+
+    } else if (geometryType.compare("Polygon") == 0) {
+
+        feature.geometryType = GeometryType::polygons;
+        feature.polygons.push_back(getPolygon(coords, _proj));
+
+    } else if (geometryType.compare("MultiPolygon") == 0) {
+
+        feature.geometryType = GeometryType::polygons;
+        for (auto polyCoords = coords.Begin(); polyCoords != coords.End(); ++polyCoords) {
+            feature.polygons.push_back(getPolygon(*polyCoords, _proj));
+        }
+
+    }
+
+    return feature;
+
+}
+
+Layer GeoJson::getLayer(const JsonValue& _in, const Transform& _proj, int32_t _sourceId) {
+
+    Layer layer("");
+
+    auto features = _in.FindMember("features");
+
+    if (features == _in.MemberEnd()) {
+        LOGE("GeoJSON missing 'features' member");
+        return layer;
+    }
+
+    for (auto featureIt = features->value.Begin(); featureIt != features->value.End(); ++featureIt) {
+        layer.features.push_back(getFeature(*featureIt, _proj, _sourceId));
+    }
+
+    return layer;
+
+}
+
+std::shared_ptr<TileData> GeoJson::parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _sourceId) {
+
+    auto& task = static_cast<const BinaryTileTask&>(_task);
+
+    std::shared_ptr<TileData> tileData = std::make_shared<TileData>();
+
+    // Parse data into a JSON document
+    const char* error;
+    size_t offset;
+    auto document = JsonParseBytes(task.rawTileData->data(), task.rawTileData->size(), &error, &offset);
+
+    if (error) {
+        LOGE("Json parsing failed on tile [%s]: %s (%u)", task.tileId().toString().c_str(), error, offset);
+        return tileData;
+    }
+
+    BoundingBox tileBounds(_projection.TileBounds(task.tileId()));
+    glm::dvec2 tileOrigin = {tileBounds.min.x, tileBounds.max.y*-1.0};
+    double tileInverseScale = 1.0 / tileBounds.width();
+
+    const auto projFn = [&](glm::dvec2 _lonLat){
+        glm::dvec2 tmp = _projection.LonLatToMeters(_lonLat);
+        return Point {
+            (tmp.x - tileOrigin.x) * tileInverseScale,
+            (tmp.y - tileOrigin.y) * tileInverseScale,
+             0
+        };
+    };
+
+    // Transform JSON data into TileData using GeoJson functions
+    if (GeoJson::isFeatureCollection(document)) {
+        tileData->layers.push_back(GeoJson::getLayer(document, projFn, _sourceId));
+    } else {
+        for (auto layer = document.MemberBegin(); layer != document.MemberEnd(); ++layer) {
+            if (GeoJson::isFeatureCollection(layer->value)) {
+                tileData->layers.push_back(GeoJson::getLayer(layer->value, projFn, _sourceId));
+                tileData->layers.back().name = layer->name.GetString();
+            }
+        }
+    }
+
+
+    // Discard original JSON object and return TileData
+
+    return tileData;
+
+}
+
+}
diff --git a/core/src/data/formats/geoJson.h b/core/src/data/formats/geoJson.h
new file mode 100644 (file)
index 0000000..2b2f035
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "data/tileData.h"
+#include "util/json.h"
+#include <functional>
+#include <memory>
+
+namespace Tangram {
+
+class TileTask;
+class MapProjection;
+
+namespace GeoJson {
+
+using Transform = std::function<Point(glm::dvec2 _lonLat)>;
+
+bool isFeatureCollection(const JsonValue& _in);
+
+Point getPoint(const JsonValue& _in, const Transform& _proj);
+
+Line getLine(const JsonValue& _in, const Transform& _proj);
+
+Polygon getPolygon(const JsonValue& _in, const Transform& _proj);
+
+Properties getProperties(const JsonValue& _in, int32_t _sourceId);
+
+Feature getFeature(const JsonValue& _in, const Transform& _proj, int32_t _sourceId);
+
+Layer getLayer(const JsonValue& _in, const Transform& _proj, int32_t _sourceId);
+
+std::shared_ptr<TileData> parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _sourceId);
+
+} // namespace GeoJson
+
+} // namespace Tangram
diff --git a/core/src/data/formats/mvt.cpp b/core/src/data/formats/mvt.cpp
new file mode 100644 (file)
index 0000000..31690a1
--- /dev/null
@@ -0,0 +1,351 @@
+#include "data/formats/mvt.h"
+#include "data/propertyItem.h"
+#include "tile/tile.h"
+#include "tile/tileTask.h"
+#include "log.h"
+#include "platform.h"
+#include "util/geom.h"
+
+#include <algorithm>
+#include <iterator>
+
+#define FEATURE_ID 1
+#define FEATURE_TAGS 2
+#define FEATURE_TYPE 3
+#define FEATURE_GEOM 4
+
+#define LAYER_NAME 1
+#define LAYER_FEATURE 2
+#define LAYER_KEY 3
+#define LAYER_VALUE 4
+#define LAYER_TILE_EXTENT 5
+
+namespace Tangram {
+
+Mvt::Geometry Mvt::getGeometry(ParserContext& _ctx, protobuf::message _geomIn) {
+
+    Geometry geometry;
+
+    GeomCmd cmd = GeomCmd::moveTo;
+    uint32_t cmdRepeat = 0;
+
+    double invTileExtent = (1.0/(_ctx.tileExtent-1.0));
+
+    int64_t x = 0;
+    int64_t y = 0;
+
+    size_t numCoordinates = 0;
+
+    while(_geomIn.getData() < _geomIn.getEnd()) {
+
+        if(cmdRepeat == 0) { // get new command, length and parameters..
+            uint32_t cmdData = static_cast<uint32_t>(_geomIn.varint());
+            cmd = static_cast<GeomCmd>(cmdData & 0x7); //first 3 bits of the cmdData
+            cmdRepeat = cmdData >> 3; //last 5 bits
+        }
+
+        if(cmd == GeomCmd::moveTo || cmd == GeomCmd::lineTo) { // get parameters/points
+            // if cmd is move then move to a new line/set of points and save this line
+            if(cmd == GeomCmd::moveTo) {
+                if (geometry.coordinates.size() > 0) {
+                    geometry.sizes.push_back(numCoordinates);
+                }
+                numCoordinates = 0;
+            }
+
+            x += _geomIn.svarint();
+            y += _geomIn.svarint();
+
+            // bring the points in 0 to 1 space
+            Point p;
+            p.x = invTileExtent * (double)x;
+            p.y = invTileExtent * (double)(_ctx.tileExtent - y);
+
+            if (numCoordinates == 0 || geometry.coordinates.back() != p) {
+                geometry.coordinates.push_back(p);
+                numCoordinates++;
+            }
+        } else if(cmd == GeomCmd::closePath) {
+            // end of a polygon, push first point in this line as last and push line to poly
+            geometry.coordinates.push_back(geometry.coordinates[geometry.coordinates.size() - numCoordinates]);
+            geometry.sizes.push_back(numCoordinates + 1);
+            numCoordinates = 0;
+        }
+
+        cmdRepeat--;
+    }
+
+    // Enter the last line
+    if (numCoordinates > 0) {
+        geometry.sizes.push_back(numCoordinates);
+    }
+
+    return geometry;
+}
+
+Feature Mvt::getFeature(ParserContext& _ctx, protobuf::message _featureIn) {
+
+    Feature feature(_ctx.sourceId);
+
+    _ctx.featureTags.clear();
+    _ctx.featureTags.assign(_ctx.keys.size(), -1);
+
+
+    while(_featureIn.next()) {
+        switch(_featureIn.tag) {
+            case FEATURE_ID:
+                // ignored for now, also not used in json parsing
+                _featureIn.skip();
+                break;
+
+            case FEATURE_TAGS: {
+                protobuf::message tagsMsg = _featureIn.getMessage();
+
+                while(tagsMsg) {
+                    auto tagKey = tagsMsg.varint();
+
+                    if(_ctx.keys.size() <= tagKey) {
+                        LOGE("accessing out of bound key");
+                        return feature;
+                    }
+
+                    if(!tagsMsg) {
+                        LOGE("uneven number of feature tag ids");
+                        return feature;
+                    }
+
+                    auto valueKey = tagsMsg.varint();
+
+                    if( _ctx.values.size() <= valueKey ) {
+                        LOGE("accessing out of bound values");
+                        return feature;
+                    }
+
+                    _ctx.featureTags[tagKey] = valueKey;
+                }
+                break;
+            }
+            case FEATURE_TYPE:
+                feature.geometryType = (GeometryType)_featureIn.varint();
+                break;
+            // Actual geometry data
+            case FEATURE_GEOM:
+                _ctx.geometry = getGeometry(_ctx, _featureIn.getMessage());
+                break;
+
+            default:
+                _featureIn.skip();
+                break;
+        }
+    }
+
+    std::vector<Properties::Item> properties;
+    properties.reserve(_ctx.featureTags.size());
+
+    for (int tagKey : _ctx.orderedKeys) {
+        int tagValue = _ctx.featureTags[tagKey];
+        if (tagValue >= 0) {
+            properties.emplace_back(_ctx.keys[tagKey], _ctx.values[tagValue]);
+        }
+    }
+    feature.props.setSorted(std::move(properties));
+
+    switch(feature.geometryType) {
+        case GeometryType::points:
+            feature.points.insert(feature.points.begin(),
+                                  _ctx.geometry.coordinates.begin(),
+                                  _ctx.geometry.coordinates.end());
+            break;
+
+        case GeometryType::lines:
+        {
+            auto pos = _ctx.geometry.coordinates.begin();
+            for (int length : _ctx.geometry.sizes) {
+                if (length == 0) { continue; }
+                Line line;
+                line.reserve(length);
+                line.insert(line.begin(), pos, pos + length);
+                pos += length;
+                feature.lines.emplace_back(std::move(line));
+            }
+            break;
+        }
+        case GeometryType::polygons:
+        {
+            auto pos = _ctx.geometry.coordinates.begin();
+            auto rpos = _ctx.geometry.coordinates.rend();
+            for (int length : _ctx.geometry.sizes) {
+                if (length == 0) { continue; }
+                float area = signedArea(pos, pos + length);
+                if (area == 0) {
+                    pos += length;
+                    rpos -= length;
+                    continue;
+                }
+                int winding = area > 0 ? 1 : -1;
+                // Determine exterior winding from first polygon.
+                if (_ctx.winding == 0) {
+                    _ctx.winding = winding;
+                }
+                Line line;
+                line.reserve(length);
+                if (_ctx.winding > 0) {
+                    line.insert(line.end(), pos, pos + length);
+                } else {
+                    line.insert(line.end(), rpos - length, rpos);
+                }
+                pos += length;
+                rpos -= length;
+                if (winding == _ctx.winding || feature.polygons.empty()) {
+                    // This is an exterior polygon.
+                    feature.polygons.emplace_back();
+                }
+                feature.polygons.back().push_back(std::move(line));
+            }
+            break;
+        }
+        case GeometryType::unknown:
+            break;
+        default:
+            break;
+    }
+
+    return feature;
+}
+
+Layer Mvt::getLayer(ParserContext& _ctx, protobuf::message _layerIn) {
+
+    Layer layer("");
+
+    _ctx.keys.clear();
+    _ctx.values.clear();
+    _ctx.featureMsgs.clear();
+
+    bool lastWasFeature = false;
+    size_t numFeatures = 0;
+    protobuf::message featureItr;
+
+    // Iterate layer to populate featureMsgs, keys and values
+    while(_layerIn.next()) {
+
+        switch(_layerIn.tag) {
+            case LAYER_NAME: {
+                layer.name = _layerIn.string();
+                break;
+            }
+            case LAYER_FEATURE: {
+                numFeatures++;
+                if (!lastWasFeature) {
+                    _ctx.featureMsgs.push_back(_layerIn);
+                    lastWasFeature = true;
+                }
+                _layerIn.skip();
+                continue;
+            }
+            case LAYER_KEY: {
+                _ctx.keys.push_back(_layerIn.string());
+                break;
+            }
+            case LAYER_VALUE: {
+                protobuf::message valueItr = _layerIn.getMessage();
+
+                while (valueItr.next()) {
+                    switch (valueItr.tag) {
+                        case 1: // string value
+                            _ctx.values.push_back(valueItr.string());
+                            break;
+                        case 2: // float value
+                            _ctx.values.push_back(valueItr.float32());
+                            break;
+                        case 3: // double value
+                            _ctx.values.push_back(valueItr.float64());
+                            break;
+                        case 4: // int value
+                            _ctx.values.push_back(valueItr.int64());
+                            break;
+                        case 5: // uint value
+                            _ctx.values.push_back(valueItr.varint());
+                            break;
+                        case 6: // sint value
+                            _ctx.values.push_back(valueItr.int64());
+                            break;
+                        case 7: // bool value
+                            _ctx.values.push_back(valueItr.boolean());
+                            break;
+                        default:
+                            _ctx.values.push_back(none_type{});
+                            valueItr.skip();
+                            break;
+                    }
+                }
+                break;
+            }
+            case LAYER_TILE_EXTENT:
+                _ctx.tileExtent = static_cast<int>(_layerIn.int64());
+                break;
+
+            default: // skip
+                _layerIn.skip();
+                break;
+        }
+        lastWasFeature = false;
+    }
+
+    if (_ctx.featureMsgs.empty()) { return layer; }
+
+    //// Assign ordering to keys for faster sorting
+    _ctx.orderedKeys.clear();
+    _ctx.orderedKeys.reserve(_ctx.keys.size());
+    // assign key ids
+    for (int i = 0, n = _ctx.keys.size(); i < n; i++) {
+        _ctx.orderedKeys.push_back(i);
+    }
+    // sort by Property key ordering
+    std::sort(_ctx.orderedKeys.begin(), _ctx.orderedKeys.end(),
+              [&](int a, int b) {
+                  return Properties::keyComparator(_ctx.keys[a], _ctx.keys[b]);
+              });
+
+    layer.features.reserve(numFeatures);
+    for (auto& featureItr : _ctx.featureMsgs) {
+        do {
+            auto featureMsg = featureItr.getMessage();
+
+            layer.features.push_back(getFeature(_ctx, featureMsg));
+
+        } while (featureItr.next() && featureItr.tag == LAYER_FEATURE);
+    }
+
+    return layer;
+}
+
+std::shared_ptr<TileData> Mvt::parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _sourceId) {
+
+    auto tileData = std::make_shared<TileData>();
+
+    auto& task = static_cast<const BinaryTileTask&>(_task);
+
+    protobuf::message item(task.rawTileData->data(), task.rawTileData->size());
+    ParserContext ctx(_sourceId);
+
+    try {
+        while(item.next()) {
+            if(item.tag == 3) {
+                tileData->layers.push_back(getLayer(ctx, item.getMessage()));
+            } else {
+                item.skip();
+            }
+        }
+    } catch(const std::invalid_argument& e) {
+        LOGE("Cannot parse tile %s: %s", _task.tileId().toString().c_str(), e.what());
+        return {};
+    } catch(const std::runtime_error& e) {
+        LOGE("Cannot parse tile %s: %s", _task.tileId().toString().c_str(), e.what());
+        return {};
+    } catch(...) {
+        return {};
+    }
+    return tileData;
+}
+
+}
diff --git a/core/src/data/formats/mvt.h b/core/src/data/formats/mvt.h
new file mode 100644 (file)
index 0000000..2a40b11
--- /dev/null
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "data/tileData.h"
+#include "pbf/pbf.hpp"
+#include "util/variant.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class Tile;
+class TileTask;
+class MapProjection;
+
+namespace Mvt {
+
+    struct Geometry {
+        std::vector<Point> coordinates;
+        std::vector<int> sizes;
+    };
+
+    struct ParserContext {
+        ParserContext(int32_t _sourceId) : sourceId(_sourceId){}
+
+        int32_t sourceId;
+        std::vector<std::string> keys;
+        std::vector<Value> values;
+        std::vector<protobuf::message> featureMsgs;
+        Geometry geometry;
+        // Map Key ID -> Tag values
+        std::vector<int> featureTags;
+        // Key IDs sorted by Property key ordering
+        std::vector<int> orderedKeys;
+
+        int tileExtent = 0;
+        int winding = 0;
+    };
+
+    enum GeomCmd {
+        moveTo = 1,
+        lineTo = 2,
+        closePath = 7
+    };
+
+    Geometry getGeometry(ParserContext& _ctx, protobuf::message _geomIn);
+
+    Feature getFeature(ParserContext& _ctx, protobuf::message _featureIn);
+
+    Layer getLayer(ParserContext& _ctx, protobuf::message _layerIn);
+
+    std::shared_ptr<TileData> parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _sourceId);
+
+} // namespace Mvt
+
+} // namespace Tangram
diff --git a/core/src/data/formats/topoJson.cpp b/core/src/data/formats/topoJson.cpp
new file mode 100644 (file)
index 0000000..f9f93f9
--- /dev/null
@@ -0,0 +1,293 @@
+#include "data/formats/topoJson.h"
+#include "data/formats/geoJson.h"
+#include "data/propertyItem.h"
+#include "tile/tileTask.h"
+#include "util/geom.h"
+#include "util/mapProjection.h"
+#include "log.h"
+
+namespace Tangram {
+
+TopoJson::Topology TopoJson::getTopology(const JsonDocument& _document, const Transform& _proj) {
+
+    Topology topo;
+
+    topo.proj = _proj;
+
+    auto transform = _document.FindMember("transform");
+    if (transform != _document.MemberEnd()) {
+        auto scale = transform->value.FindMember("scale");
+        if (scale != transform->value.MemberEnd() && scale->value.Size() == 2) {
+            topo.scale = { scale->value[0].GetDouble(), scale->value[1].GetDouble() };
+        }
+        auto translate = transform->value.FindMember("translate");
+        if (translate != transform->value.MemberEnd() && translate->value.Size() == 2) {
+            topo.translate = { translate->value[0].GetDouble(), translate->value[1].GetDouble() };
+        }
+    }
+
+    // Quantized, delta-encoded 'arcs' in Json
+    auto jsonArcList = _document.FindMember("arcs");
+
+    if (jsonArcList == _document.MemberEnd()) {
+        return topo;
+    }
+
+    const auto& jsonArcs = jsonArcList->value;
+
+    if (!jsonArcs.IsArray()) {
+        return topo;
+    }
+
+    topo.arcs.reserve(jsonArcs.Size());
+
+    // Decode and transform the points that make up 'arcs'
+    for (auto jsonArcsIt = jsonArcs.Begin(); jsonArcsIt != jsonArcs.End(); ++jsonArcsIt) {
+
+        const auto& jsonArc = *jsonArcsIt;
+
+        if (!jsonArc.IsArray()) { // According to spec, jsonArc.Size() >= 2 should also hold
+            continue;
+        }
+
+        Line arc;
+        arc.reserve(jsonArc.Size());
+
+        // Quantized position
+        glm::ivec2 q;
+
+        for (auto jsonCoordsIt = jsonArc.Begin(); jsonCoordsIt != jsonArc.End(); ++jsonCoordsIt) {
+
+            const auto& jsonCoords = *jsonCoordsIt;
+
+            arc.push_back(getPoint(jsonCoords, topo, q));
+        }
+
+        topo.arcs.push_back(arc);
+    }
+
+    return topo;
+}
+
+Point TopoJson::getPoint(const JsonValue& _coordinates, const Topology& _topology, glm::ivec2& _cursor) {
+
+    if (!_coordinates.IsArray() || _coordinates.Size() < 2) {
+        return Point();
+    }
+
+    _cursor.x += _coordinates[0].GetInt();
+    _cursor.y += _coordinates[1].GetInt();
+
+    return _topology.proj(glm::dvec2(_cursor) * _topology.scale + _topology.translate);
+
+}
+
+Line TopoJson::getLine(const JsonValue& _arcs, const Topology& _topology) {
+
+    Line line;
+
+    if (!_arcs.IsArray()) {
+        return line;
+    }
+
+    for (auto arcIt = _arcs.Begin(); arcIt != _arcs.End(); ++arcIt) {
+
+        auto index = arcIt->GetInt();
+        bool reverse = false;
+        if (index < 0) {
+            reverse = true;
+            index = -1 - index;
+        }
+
+        if (index < 0 || (std::vector<Line>::size_type)index >= _topology.arcs.size()) {
+            continue;
+        }
+
+        const auto& arc = _topology.arcs[index];
+
+        auto begin = arc.begin();
+        auto end = arc.end();
+        size_t inc = 1;
+        if (reverse) {
+            begin = arc.end() - 1;
+            end = arc.begin() - 1;
+            inc = -inc;
+        }
+
+        // If a line is made from multiple arcs, the first position of an arc must
+        // be equal to the last position of the previous arc. So when reconstructing
+        // the geometry, the first position of each arc except the first may be dropped
+        if (arcIt != _arcs.Begin()) {
+            begin = begin + inc;
+        }
+
+        for (auto pointIt = begin; pointIt != end; pointIt += inc) {
+            line.push_back(*pointIt);
+        }
+
+    }
+
+    return line;
+
+}
+
+Polygon TopoJson::getPolygon(const JsonValue& _arcSets, const Topology& _topology) {
+
+    Polygon polygon;
+
+    if (!_arcSets.IsArray()) {
+        return polygon;
+    }
+
+    for (auto arcSetIt = _arcSets.Begin(); arcSetIt != _arcSets.End(); ++arcSetIt) {
+
+        auto ring = getLine(*arcSetIt, _topology);
+        polygon.push_back(ring);
+
+    }
+
+    return polygon;
+
+}
+
+Feature TopoJson::getFeature(const JsonValue& _geometry, const Topology& _topology, int32_t _source) {
+
+    static const JsonValue keyProperties("properties");
+    static const JsonValue keyType("type");
+    static const JsonValue keyCoordinates("coordinates");
+    static const JsonValue keyArcs("arcs");
+
+    Feature feature;
+
+    auto propertiesIt = _geometry.FindMember(keyProperties);
+    if (propertiesIt != _geometry.MemberEnd() && propertiesIt->value.IsObject()) {
+        feature.props = GeoJson::getProperties(propertiesIt->value, _source);
+    }
+
+    std::string type;
+    auto typeIt = _geometry.FindMember(keyType);
+    if (typeIt != _geometry.MemberEnd() && typeIt->value.IsString()) {
+        type = typeIt->value.GetString();
+    }
+
+    if (type == "Point") {
+        feature.geometryType = GeometryType::points;
+        auto coordinatesIt = _geometry.FindMember(keyCoordinates);
+        if (coordinatesIt != _geometry.MemberEnd()) {
+            glm::ivec2 cursor;
+            feature.points.push_back(getPoint(coordinatesIt->value, _topology, cursor));
+        }
+    } else if (type == "MultiPoint") {
+        feature.geometryType = GeometryType::points;
+        auto coordinatesIt = _geometry.FindMember(keyCoordinates);
+        if (coordinatesIt != _geometry.MemberEnd() && coordinatesIt->value.IsArray()) {
+            auto& coordinates = coordinatesIt->value;
+            for (auto point = coordinates.Begin(); point != coordinates.End(); ++point) {
+                glm::ivec2 cursor;
+                feature.points.push_back(getPoint(*point, _topology, cursor));
+            }
+        }
+    } else if (type == "LineString") {
+        feature.geometryType = GeometryType::lines;
+        auto arcsIt = _geometry.FindMember(keyArcs);
+        if (arcsIt != _geometry.MemberEnd()) {
+            feature.lines.push_back(getLine(arcsIt->value, _topology));
+        }
+    } else if (type == "MultiLineString") {
+        feature.geometryType = GeometryType::lines;
+        auto arcsIt = _geometry.FindMember(keyArcs);
+        if (arcsIt != _geometry.MemberEnd() && arcsIt->value.IsArray()) {
+            auto& arcs = arcsIt->value;
+            for (auto arcList = arcs.Begin(); arcList != arcs.End(); ++arcList) {
+                feature.lines.push_back(getLine(*arcList, _topology));
+            }
+        }
+    } else if (type == "Polygon") {
+        feature.geometryType = GeometryType::polygons;
+        auto arcsIt = _geometry.FindMember(keyArcs);
+        if (arcsIt != _geometry.MemberEnd()) {
+            feature.polygons.push_back(getPolygon(arcsIt->value, _topology));
+        }
+    } else if (type == "MultiPolygon") {
+        feature.geometryType = GeometryType::polygons;
+        auto arcsIt = _geometry.FindMember(keyArcs);
+        if (arcsIt != _geometry.MemberEnd() && arcsIt->value.IsArray()) {
+            auto& arcs = arcsIt->value;
+            for (auto arcList = arcs.Begin(); arcList != arcs.End(); ++arcList) {
+                feature.polygons.push_back(getPolygon(*arcList, _topology));
+            }
+        }
+    } else if (type == "GeometryCollection") {
+        // Not handled
+    }
+
+    return feature;
+
+}
+
+Layer TopoJson::getLayer(JsonValue::MemberIterator& _objectIt, const Topology& _topology, int32_t _source) {
+
+    Layer layer(_objectIt->name.GetString());
+
+    JsonValue& object = _objectIt->value;
+    auto type = object.FindMember("type");
+    if (type != object.MemberEnd() && strcmp("GeometryCollection", type->value.GetString()) == 0) {
+        auto geometries = object.FindMember("geometries");
+        if (geometries != object.MemberEnd() && geometries->value.IsArray()) {
+            for (auto it = geometries->value.Begin(); it != geometries->value.End(); ++it) {
+                layer.features.push_back(getFeature(*it, _topology, _source));
+            }
+        }
+    }
+
+    return layer;
+
+}
+
+std::shared_ptr<TileData> TopoJson::parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _source) {
+
+    auto& task = static_cast<const BinaryTileTask&>(_task);
+
+    std::shared_ptr<TileData> tileData = std::make_shared<TileData>();
+
+    // Parse data into a JSON document
+    const char* error;
+    size_t offset;
+    auto document = JsonParseBytes(task.rawTileData->data(), task.rawTileData->size(), &error, &offset);
+
+    if (error) {
+        LOGE("Json parsing failed on tile [%s]: %s (%u)", task.tileId().toString().c_str(), error, offset);
+        return tileData;
+    }
+
+    // Transform JSON data into a TileData using TopoJson functions
+    BoundingBox tileBounds(_projection.TileBounds(task.tileId()));
+    glm::dvec2 tileOrigin = {tileBounds.min.x, tileBounds.max.y*-1.0};
+    double tileInverseScale = 1.0 / tileBounds.width();
+
+    const auto projFn = [&](glm::dvec2 _lonLat){
+        glm::dvec2 tmp = _projection.LonLatToMeters(_lonLat);
+        return Point {
+            (tmp.x - tileOrigin.x) * tileInverseScale,
+            (tmp.y - tileOrigin.y) * tileInverseScale,
+             0
+        };
+    };
+
+    // Parse topology and transform
+    auto topology = TopoJson::getTopology(document, projFn);
+
+    // Parse each TopoJson object as a data layer
+    auto objectsIt = document.FindMember("objects");
+    if (objectsIt == document.MemberEnd()) { return tileData; }
+    auto& objects = objectsIt->value;
+    for (auto layer = objects.MemberBegin(); layer != objects.MemberEnd(); ++layer) {
+        tileData->layers.push_back(TopoJson::getLayer(layer, topology, _source));
+    }
+
+    // Discard JSON object and return TileData
+    return tileData;
+
+}
+
+} // namespace Tangram
diff --git a/core/src/data/formats/topoJson.h b/core/src/data/formats/topoJson.h
new file mode 100644 (file)
index 0000000..d1cf295
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "data/tileData.h"
+#include "util/json.h"
+
+#include "glm/vec2.hpp"
+#include <functional>
+#include <memory>
+
+namespace Tangram {
+
+class TileTask;
+class MapProjection;
+
+namespace TopoJson {
+
+using Transform = std::function<Point(glm::dvec2 _lonLat)>;
+
+struct Topology {
+    glm::dvec2 scale = { 1., 1. };
+    glm::dvec2 translate = { 0., 0. };
+    std::vector<Line> arcs;
+    Transform proj;
+};
+
+Topology getTopology(const JsonDocument& _document, const Transform& _proj);
+
+Point getPoint(const JsonValue& _coordinates, const Topology& _topology, glm::ivec2& _cursor);
+
+Line getLine(const JsonValue& _arcs, const Topology& _topology);
+
+Polygon getPolygon(const JsonValue& _arcs, const Topology& _topology);
+
+Feature getFeature(const JsonValue& _geometry, const Topology& _topology, int32_t _sourceId);
+
+Layer getLayer(JsonValue::MemberIterator& _object, const Topology& _topology, int32_t _sourceId);
+
+std::shared_ptr<TileData> parseTile(const TileTask& _task, const MapProjection& _projection, int32_t _sourceId);
+
+} // namespace TopoJson
+
+} // namespace Tangram
diff --git a/core/src/data/mbtilesDataSource.cpp b/core/src/data/mbtilesDataSource.cpp
new file mode 100644 (file)
index 0000000..c469bdd
--- /dev/null
@@ -0,0 +1,516 @@
+#include "data/mbtilesDataSource.h"
+
+#include "util/asyncWorker.h"
+#include "util/zlibHelper.h"
+#include "log.h"
+#include "platform.h"
+#include "util/url.h"
+
+#include <SQLiteCpp/Database.h>
+#include "hash-library/md5.cpp"
+
+
+namespace Tangram {
+
+/**
+ * The schema.sql used to set up an MBTiles Database.
+ *
+ * https://github.com/mapbox/node-mbtiles/blob/4bbfaf991969ce01c31b95184c4f6d5485f717c3/lib/schema.sql
+ */
+static const char* SCHEMA = R"SQL_ESC(BEGIN;
+
+CREATE TABLE IF NOT EXISTS map (
+   zoom_level INTEGER,
+   tile_column INTEGER,
+   tile_row INTEGER,
+   tile_id TEXT,
+   grid_id TEXT
+);
+
+CREATE TABLE IF NOT EXISTS grid_key (
+    grid_id TEXT,
+    key_name TEXT
+);
+
+CREATE TABLE IF NOT EXISTS keymap (
+    key_name TEXT,
+    key_json TEXT
+);
+
+CREATE TABLE IF NOT EXISTS grid_utfgrid (
+    grid_id TEXT,
+    grid_utfgrid BLOB
+);
+
+CREATE TABLE IF NOT EXISTS images (
+    tile_data blob,
+    tile_id text
+);
+
+CREATE TABLE IF NOT EXISTS metadata (
+    name text,
+    value text
+);
+
+-- CREATE TABLE IF NOT EXISTS geocoder_data (
+--     type TEXT,
+--     shard INTEGER,
+--     data BLOB
+-- );
+
+CREATE UNIQUE INDEX IF NOT EXISTS map_index ON map (zoom_level, tile_column, tile_row);
+CREATE UNIQUE INDEX IF NOT EXISTS grid_key_lookup ON grid_key (grid_id, key_name);
+CREATE UNIQUE INDEX IF NOT EXISTS keymap_lookup ON keymap (key_name);
+CREATE UNIQUE INDEX IF NOT EXISTS grid_utfgrid_lookup ON grid_utfgrid (grid_id);
+CREATE UNIQUE INDEX IF NOT EXISTS images_id ON images (tile_id);
+CREATE UNIQUE INDEX IF NOT EXISTS name ON metadata (name);
+CREATE INDEX IF NOT EXISTS map_grid_id ON map (grid_id);
+-- CREATE INDEX IF NOT EXISTS geocoder_type_index ON geocoder_data (type);
+-- CREATE UNIQUE INDEX IF NOT EXISTS geocoder_shard_index ON geocoder_data (type, shard);
+
+CREATE VIEW IF NOT EXISTS tiles AS
+    SELECT
+        map.zoom_level AS zoom_level,
+        map.tile_column AS tile_column,
+        map.tile_row AS tile_row,
+        images.tile_data AS tile_data
+    FROM map
+    JOIN images ON images.tile_id = map.tile_id;
+
+CREATE VIEW IF NOT EXISTS grids AS
+    SELECT
+        map.zoom_level AS zoom_level,
+        map.tile_column AS tile_column,
+        map.tile_row AS tile_row,
+        grid_utfgrid.grid_utfgrid AS grid
+    FROM map
+    JOIN grid_utfgrid ON grid_utfgrid.grid_id = map.grid_id;
+
+CREATE VIEW IF NOT EXISTS grid_data AS
+    SELECT
+        map.zoom_level AS zoom_level,
+        map.tile_column AS tile_column,
+        map.tile_row AS tile_row,
+        keymap.key_name AS key_name,
+        keymap.key_json AS key_json
+    FROM map
+    JOIN grid_key ON map.grid_id = grid_key.grid_id
+    JOIN keymap ON grid_key.key_name = keymap.key_name;
+COMMIT;)SQL_ESC";
+
+struct MBTilesQueries {
+    // SELECT statement from tiles view
+    SQLite::Statement getTileData;
+
+    // REPLACE INTO statement in map table
+    SQLite::Statement putMap;
+
+    // REPLACE INTO statement in images table
+    SQLite::Statement putImage;
+
+    MBTilesQueries(SQLite::Database& _db, bool _cache)
+        : getTileData(_db, "SELECT tile_data FROM tiles WHERE zoom_level = ? AND tile_column = ? AND tile_row = ?;"),
+          putMap(_db, _cache ? "REPLACE INTO map (zoom_level, tile_column, tile_row, tile_id) VALUES (?, ?, ?, ?);" : ";" ),
+          putImage(_db, _cache ? "REPLACE INTO images (tile_id, tile_data) VALUES (?, ?);" : ";") {}
+
+};
+
+MBTilesDataSource::MBTilesDataSource(std::shared_ptr<Platform> _platform, std::string _name,
+                                     std::string _path, std::string _mime, bool _cache, bool _offlineFallback)
+    : m_name(_name),
+      m_path(_path),
+      m_mime(_mime),
+      m_cacheMode(_cache),
+      m_offlineMode(_offlineFallback),
+      m_platform(_platform) {
+
+    m_worker = std::make_unique<AsyncWorker>();
+
+    openMBTiles();
+}
+
+MBTilesDataSource::~MBTilesDataSource() {
+}
+
+bool MBTilesDataSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+
+    if (m_offlineMode) {
+        if (_task->rawSource == this->level) {
+            // Try next source
+            _task->rawSource = next->level;
+        }
+
+        return loadNextSource(_task, _cb);
+    }
+
+    if (!m_db) { return false; }
+
+    if (_task->rawSource == this->level) {
+
+        m_worker->enqueue([this, _task, _cb](){
+            TileID tileId = _task->tileId();
+
+            auto& task = static_cast<BinaryTileTask&>(*_task);
+            task.rawTileData = std::make_shared<std::vector<char>>();
+
+            getTileData(tileId, *task.rawTileData);
+
+            if (task.hasData()) {
+                LOGW("loaded tile: %s, %d", tileId.toString().c_str(), task.rawTileData->size());
+
+                _cb.func(_task);
+
+            } else if (next) {
+
+                // Don't try this source again
+                _task->rawSource = next->level;
+
+                if (!loadNextSource(_task, _cb)) {
+                    // Trigger TileManager update so that tile will be
+                    // downloaded next time.
+                    _task->setNeedsLoading(true);
+                    m_platform->requestRender();
+                }
+            } else {
+                LOGW("missing tile: %s, %d", _task->tileId().toString().c_str());
+            }
+        });
+        return true;
+    }
+
+    return loadNextSource(_task, _cb);
+}
+
+bool MBTilesDataSource::loadNextSource(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+    if (!next) { return false; }
+
+    if (!m_db) {
+        return next->loadTileData(_task, _cb);
+    }
+
+    // Intercept TileTaskCb to store result from next source.
+    TileTaskCb cb{[this, _cb](std::shared_ptr<TileTask> _task) {
+
+        if (_task->hasData()) {
+
+            if (m_cacheMode) {
+                m_worker->enqueue([this, _task](){
+
+                        auto& task = static_cast<BinaryTileTask&>(*_task);
+
+                        LOGW("store tile: %s, %d", _task->tileId().toString().c_str(), task.hasData());
+
+                        storeTileData(_task->tileId(), *task.rawTileData);
+                    });
+            }
+
+            _cb.func(_task);
+
+        } else if (m_offlineMode) {
+            LOGW("try fallback tile: %s, %d", _task->tileId().toString().c_str());
+
+            m_worker->enqueue([this, _task, _cb](){
+
+                auto& task = static_cast<BinaryTileTask&>(*_task);
+                task.rawTileData = std::make_shared<std::vector<char>>();
+
+                getTileData(_task->tileId(), *task.rawTileData);
+
+                LOGW("loaded tile: %s, %d", _task->tileId().toString().c_str(), task.rawTileData->size());
+
+                _cb.func(_task);
+
+            });
+        } else {
+            LOGW("missing tile: %s, %d", _task->tileId().toString().c_str());
+            _cb.func(_task);
+        }
+    }};
+
+    return next->loadTileData(_task, cb);
+}
+
+void MBTilesDataSource::openMBTiles() {
+
+    try {
+        auto mode = SQLite::OPEN_READONLY;
+        if (m_cacheMode) {
+            // Need to explicitly open a SQLite DB with OPEN_READWRITE
+            // and OPEN_CREATE flags to make a file and write.
+            mode = SQLite::OPEN_READWRITE | SQLite::OPEN_CREATE;
+        }
+
+        auto url = Url(m_path);
+        auto path = url.path();
+        const char* vfs = "";
+        if (url.scheme() == "asset") {
+            vfs = "ndk-asset";
+            path.erase(path.begin()); // Remove leading '/'.
+        }
+        m_db = std::make_unique<SQLite::Database>(path, mode, 0, vfs);
+        LOG("SQLite database opened: %s", path.c_str());
+
+    } catch (std::exception& e) {
+        LOGE("Unable to open SQLite database: %s - %s", m_path.c_str(), e.what());
+        m_db.reset();
+        return;
+    }
+
+    bool ok = testSchema(*m_db);
+    if (ok) {
+        if (m_cacheMode && !m_schemaOptions.isCache) {
+            // TODO better description
+            LOGE("Cannot cache to 'externally created' MBTiles database");
+            // Run in non-caching mode
+            m_cacheMode = false;
+            return;
+        }
+    } else if (m_cacheMode) {
+
+        // Setup the database by running the schema.sql.
+        initSchema(*m_db, m_name, m_mime);
+
+        ok = testSchema(*m_db);
+        if (!ok) {
+            LOGE("Unable to initialize MBTiles schema");
+            m_db.reset();
+            return;
+        }
+    } else {
+        LOGE("Invalid MBTiles schema");
+        m_db.reset();
+        return;
+    }
+
+    if (m_schemaOptions.compression == Compression::unsupported) {
+        m_db.reset();
+        return;
+    }
+
+    try {
+        m_queries = std::make_unique<MBTilesQueries>(*m_db, m_cacheMode);
+    } catch (std::exception& e) {
+        LOGE("Unable to initialize queries: %s", e.what());
+        m_db.reset();
+        return;
+    }
+}
+
+/**
+ * We check to see if the database has the MBTiles Schema.
+ * Sets m_schemaOptions from metadata table
+ *
+ * @param _source A pointer to a the data source in which we will setup a db.
+ * @return true if database contains MBTiles schema
+ */
+bool MBTilesDataSource::testSchema(SQLite::Database& db) {
+
+    bool metadata = false, tiles = false, grids = false, grid_data = false;
+
+    try {
+        SQLite::Statement query(db, "SELECT name FROM sqlite_master WHERE type IN ('table', 'view')");
+        while (query.executeStep()) {
+            std::string name = query.getColumn(0);
+            // required
+            if (name == "metadata") metadata = true;
+            else if (name == "tiles") tiles = true;
+            // optional
+            else if (name == "grids") grids = true;
+            else if (name == "grid_data") grid_data = true;
+            // schema implementation specific
+            // else if (name == "map") map = true;
+            // else if (name == "images") images = true;
+            // else if (name == "grid_key") grid_key = true;
+            // else if (name == "keymap") keymap = true;
+            // else if (name == "grid_utfgrid") grid_utfgrid = true;
+            // else if (name == "geocoder_data") geocoder_data = true;
+        }
+    } catch (std::exception& e) {
+        LOGE("Unable to check schema of SQLite MBTiles database: %s", e.what());
+        return false;
+    }
+
+    if (!metadata || !tiles) {
+        LOGW("Missing MBTiles tables");
+        return false;
+    }
+
+    try {
+        SQLite::Statement query(db, "SELECT value FROM metadata WHERE name = 'description';");
+        if (query.executeStep()) {
+            std::string description = query.getColumn(0);
+            if (description == "MBTiles tile container created by Tangram ES.") {
+                m_schemaOptions.isCache = true;
+            }
+        }
+    } catch (std::exception& e) {
+        LOGE("TODO");
+    }
+
+    try {
+        SQLite::Statement query(db, "SELECT value FROM metadata WHERE name = 'compression';");
+        if (query.executeStep()) {
+            std::string compression = query.getColumn(0);
+
+            if (compression == "identity") {
+                m_schemaOptions.compression = Compression::identity;
+            } else if (compression == "deflate") {
+                m_schemaOptions.compression = Compression::deflate;
+            } else {
+                LOGE("Unsupported MBTiles tile compression: %s", compression.c_str());
+                m_schemaOptions.compression = Compression::unsupported;
+            }
+        }
+    } catch (std::exception& e) {
+        LOGE("TODO");
+    }
+
+    if (grids && grid_data) {
+        m_schemaOptions.utfGrid = true;
+    }
+
+    return true;
+}
+
+void MBTilesDataSource::initSchema(SQLite::Database& db, std::string _name, std::string _mimeType) {
+
+    // Otherwise, we need to execute schema.sql to set up the db with the right schema.
+    try {
+        // Execute schema.
+        db.exec(SCHEMA);
+
+        // Fill in metadata table.
+        // https://github.com/pnorman/mbtiles-spec/blob/2.0/2.0/spec.md#content
+        // https://github.com/mapbox/mbtiles-spec/pull/46
+        SQLite::Statement stmt(db, "REPLACE INTO metadata (name, value) VALUES (?, ?);");
+
+        // name, type, version, description, format, compression
+        stmt.bind(1, "name");
+        stmt.bind(2, _name);
+        stmt.exec();
+        stmt.reset();
+
+        stmt.bind(1, "type");
+        stmt.bind(2, "baselayer");
+        stmt.exec();
+        stmt.reset();
+
+        stmt.bind(1, "version");
+        stmt.bind(2, 1);
+        stmt.exec();
+        stmt.reset();
+
+        stmt.bind(1, "description");
+        stmt.bind(2, "MBTiles tile container created by Tangram ES.");
+        stmt.exec();
+        stmt.reset();
+
+        stmt.bind(1, "format");
+        stmt.bind(2, _mimeType);
+        stmt.exec();
+        stmt.reset();
+
+        // Compression not yet implemented.
+        // http://www.iana.org/assignments/http-parameters/http-parameters.xhtml#content-coding
+        // identity means no compression
+        stmt.bind(1, "compression");
+        stmt.bind(2, "identity");
+        stmt.exec();
+
+    } catch (std::exception& e) {
+        LOGE("Unable to setup SQLite MBTiles database: %s", e.what());
+    }
+}
+
+bool MBTilesDataSource::getTileData(const TileID& _tileId, std::vector<char>& _data) {
+
+    auto& stmt = m_queries->getTileData;
+    try {
+        // Google TMS to WMTS
+        // https://github.com/mapbox/node-mbtiles/blob/
+        // 4bbfaf991969ce01c31b95184c4f6d5485f717c3/lib/mbtiles.js#L149
+        int z = _tileId.z;
+        int y = (1 << z) - 1 - _tileId.y;
+
+        stmt.bind(1, z);
+        stmt.bind(2, _tileId.x);
+        stmt.bind(3, y);
+
+        if (stmt.executeStep()) {
+            SQLite::Column column = stmt.getColumn(0);
+            const char* blob = (const char*) column.getBlob();
+            const int length = column.getBytes();
+
+            if ((m_schemaOptions.compression == Compression::undefined) ||
+                (m_schemaOptions.compression == Compression::deflate)) {
+
+                if (zlib::inflate(blob, length, _data) != 0) {
+                    if (m_schemaOptions.compression == Compression::undefined) {
+                        _data.resize(length);
+                        memcpy(_data.data(), blob, length);
+                    } else {
+                        LOGW("Invalid deflate compression");
+                    }
+                }
+            } else {
+                _data.resize(length);
+                memcpy(_data.data(), blob, length);
+            }
+
+            stmt.reset();
+            return true;
+        }
+
+    } catch (std::exception& e) {
+        LOGE("MBTiles SQLite get tile_data statement failed: %s", e.what());
+    }
+    try {
+        stmt.reset();
+    } catch(...) {}
+
+    return false;
+}
+
+void MBTilesDataSource::storeTileData(const TileID& _tileId, const std::vector<char>& _data) {
+    int z = _tileId.z;
+    int y = (1 << z) - 1 - _tileId.y;
+
+    const char* data = _data.data();
+    size_t size = _data.size();
+
+    /**
+     * We create an MD5 of the raw tile data. The MD5 functions as a hash
+     * between the map and images tables. With this, tiles with duplicate
+     * data will join to a single entry in the images table.
+     */
+    MD5 md5;
+    std::string md5id = md5(data, size);
+
+    try {
+        auto& stmt = m_queries->putMap;
+        stmt.bind(1, z);
+        stmt.bind(2, _tileId.x);
+        stmt.bind(3, y);
+        stmt.bind(4, md5id);
+        stmt.exec();
+
+        stmt.reset();
+
+    } catch (std::exception& e) {
+        LOGE("MBTiles SQLite put map statement failed: %s", e.what());
+    }
+
+    try {
+        auto& stmt = m_queries->putImage;
+        stmt.bind(1, md5id);
+        stmt.bind(2, data, size);
+        stmt.exec();
+
+        stmt.reset();
+
+    } catch (std::exception& e) {
+        LOGE("MBTiles SQLite put image statement failed: %s", e.what());
+    }
+}
+
+}
diff --git a/core/src/data/mbtilesDataSource.h b/core/src/data/mbtilesDataSource.h
new file mode 100644 (file)
index 0000000..9f9354f
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma once
+
+#include "data/tileSource.h"
+
+namespace SQLite {
+class Database;
+}
+
+
+namespace Tangram {
+
+class Platform;
+
+struct MBTilesQueries;
+class AsyncWorker;
+
+class MBTilesDataSource : public TileSource::DataSource {
+public:
+
+    MBTilesDataSource(std::shared_ptr<Platform> _platform, std::string _name, std::string _path, std::string _mime,
+                      bool _cache = false, bool _offlineFallback = false);
+
+    ~MBTilesDataSource();
+
+    bool loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
+
+    void clear() override {}
+
+private:
+    bool getTileData(const TileID& _tileId, std::vector<char>& _data);
+    void storeTileData(const TileID& _tileId, const std::vector<char>& _data);
+    bool loadNextSource(std::shared_ptr<TileTask> _task, TileTaskCb _cb);
+
+    void openMBTiles();
+    bool testSchema(SQLite::Database& db);
+    void initSchema(SQLite::Database& db, std::string _name, std::string _mimeType);
+
+    std::string m_name;
+
+    // The path to an mbtiles tile store.
+    std::string m_path;
+    std::string m_mime;
+
+    // Store tiles from next source
+    bool m_cacheMode;
+
+    // Offline fallback: Try next source (download) first, then fall back to mbtiles
+    bool m_offlineMode;
+
+    // Pointer to SQLite DB of MBTiles store
+    std::unique_ptr<SQLite::Database> m_db;
+    std::unique_ptr<MBTilesQueries> m_queries;
+    std::unique_ptr<AsyncWorker> m_worker;
+
+    // Platform reference
+    std::shared_ptr<Platform> m_platform;
+
+    enum class Compression {
+        undefined,
+        identity,
+        deflate,
+        unsupported
+    };
+
+    struct {
+        Compression compression = Compression::undefined;
+        bool isCache = false;
+        bool utfGrid = false;
+    } m_schemaOptions;
+};
+
+}
diff --git a/core/src/data/memoryCacheDataSource.cpp b/core/src/data/memoryCacheDataSource.cpp
new file mode 100644 (file)
index 0000000..cf7de63
--- /dev/null
@@ -0,0 +1,142 @@
+#include "data/memoryCacheDataSource.h"
+
+#include "tile/tileHash.h"
+#include "tile/tileID.h"
+#include "log.h"
+
+#include <list>
+#include <mutex>
+#include <unordered_map>
+
+namespace Tangram {
+
+struct RawCache {
+
+    // Used to ensure safe access from async loading threads
+    std::mutex m_mutex;
+
+    // LRU in-memory cache for raw tile data
+    using CacheEntry = std::pair<TileID, std::shared_ptr<std::vector<char>>>;
+    using CacheList = std::list<CacheEntry>;
+    using CacheMap = std::unordered_map<TileID, typename CacheList::iterator>;
+
+    CacheMap m_cacheMap;
+    CacheList m_cacheList;
+    int m_usage = 0;
+    int m_maxUsage = 0;
+
+    bool get(BinaryTileTask& _task) {
+
+        if (m_maxUsage <= 0) { return false; }
+
+        std::lock_guard<std::mutex> lock(m_mutex);
+        const auto& taskTileID = _task.tileId();
+        TileID id(taskTileID.x, taskTileID.y, taskTileID.z);
+
+        auto it = m_cacheMap.find(id);
+        if (it != m_cacheMap.end()) {
+            // Move cached entry to start of list
+            m_cacheList.splice(m_cacheList.begin(), m_cacheList, it->second);
+            _task.rawTileData = m_cacheList.front().second;
+
+            return true;
+        }
+
+        return false;
+    }
+    void put(const TileID& tileID, std::shared_ptr<std::vector<char>> rawDataRef) {
+
+        if (m_maxUsage <= 0) { return; }
+
+        std::lock_guard<std::mutex> lock(m_mutex);
+        TileID id(tileID.x, tileID.y, tileID.z);
+
+        m_cacheList.push_front({id, rawDataRef});
+        m_cacheMap[id] = m_cacheList.begin();
+
+        m_usage += rawDataRef->size();
+
+        while (m_usage > m_maxUsage) {
+            if (m_cacheList.empty()) {
+                LOGE("Error: invalid cache state!");
+                m_usage = 0;
+                break;
+            }
+
+            // LOGE("Limit raw cache tiles:%d, %fMB ", m_cacheList.size(),
+            //        double(m_cacheUsage) / (1024*1024));
+
+            auto& entry = m_cacheList.back();
+            m_usage -= entry.second->size();
+
+            m_cacheMap.erase(entry.first);
+            m_cacheList.pop_back();
+        }
+    }
+
+    void clear() {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_cacheMap.clear();
+        m_cacheList.clear();
+        m_usage = 0;
+    }
+};
+
+
+MemoryCacheDataSource::MemoryCacheDataSource() :
+    m_cache(std::make_unique<RawCache>()) {
+}
+
+MemoryCacheDataSource::~MemoryCacheDataSource() {}
+
+void MemoryCacheDataSource::setCacheSize(size_t _cacheSize) {
+    m_cache->m_maxUsage = _cacheSize;
+}
+
+bool MemoryCacheDataSource::cacheGet(BinaryTileTask& _task) {
+    return m_cache->get(_task);
+}
+
+void MemoryCacheDataSource::cachePut(const TileID& _tileID, std::shared_ptr<std::vector<char>> _rawDataRef) {
+    m_cache->put(_tileID, _rawDataRef);
+}
+
+bool MemoryCacheDataSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+
+    auto& task = static_cast<BinaryTileTask&>(*_task);
+
+    if (_task->rawSource == this->level) {
+
+        cacheGet(task);
+
+        if (task.hasData()) {
+            _cb.func(_task);
+            return true;
+        }
+
+        // Try next source on subsequent calls
+        if (next) { _task->rawSource = next->level; }
+    }
+
+    if (next) {
+
+        return next->loadTileData(_task, {[this, _cb](std::shared_ptr<TileTask> _task) {
+
+            auto& task = static_cast<BinaryTileTask&>(*_task);
+
+            if (task.hasData()) { cachePut(task.tileId(), task.rawTileData); }
+
+            _cb.func(_task);
+        }});
+    }
+
+    return false;
+}
+
+void MemoryCacheDataSource::clear() {
+    m_cache->clear();
+
+    if (next) { next->clear(); }
+}
+
+}
diff --git a/core/src/data/memoryCacheDataSource.h b/core/src/data/memoryCacheDataSource.h
new file mode 100644 (file)
index 0000000..ba19e98
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "data/tileSource.h"
+
+namespace Tangram {
+
+class MemoryCacheDataSource : public TileSource::DataSource {
+public:
+
+    MemoryCacheDataSource();
+    ~MemoryCacheDataSource();
+
+    bool loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
+
+    void clear() override;
+
+    /* @_cacheSize: Set size of in-memory cache for tile data in bytes.
+     * This cache holds unprocessed tile data for fast recreation of recently used tiles.
+     */
+    void setCacheSize(size_t _cacheSize);
+
+private:
+    bool cacheGet(BinaryTileTask& _task);
+
+    void cachePut(const TileID& _tileID, std::shared_ptr<std::vector<char>> _rawDataRef);
+
+    std::unique_ptr<RawCache> m_cache;
+
+};
+
+}
diff --git a/core/src/data/networkDataSource.cpp b/core/src/data/networkDataSource.cpp
new file mode 100644 (file)
index 0000000..a7c7d37
--- /dev/null
@@ -0,0 +1,115 @@
+#include "data/networkDataSource.h"
+
+#include "log.h"
+#include "platform.h"
+
+#define MAX_DOWNLOADS 4
+
+namespace Tangram {
+
+NetworkDataSource::NetworkDataSource(std::shared_ptr<Platform> _platform, const std::string& _urlTemplate,
+        std::vector<std::string>&& _urlSubdomains) :
+    m_platform(_platform),
+    m_urlTemplate(_urlTemplate),
+    m_urlSubdomains(std::move(_urlSubdomains)),
+    m_maxDownloads(MAX_DOWNLOADS) {}
+
+std::string NetworkDataSource::constructURL(const TileID& _tileCoord, size_t _subdomainIndex) const {
+    std::string url = m_urlTemplate;
+
+    size_t xPos = url.find("{x}");
+    if (xPos != std::string::npos) {
+        url.replace(xPos, 3, std::to_string(_tileCoord.x));
+    }
+    size_t yPos = url.find("{y}");
+    if (yPos != std::string::npos) {
+        url.replace(yPos, 3, std::to_string(_tileCoord.y));
+    }
+    size_t zPos = url.find("{z}");
+    if (zPos != std::string::npos) {
+        url.replace(zPos, 3, std::to_string(_tileCoord.z));
+    }
+    if (_subdomainIndex < m_urlSubdomains.size()) {
+        size_t sPos = url.find("{s}");
+        if (sPos != std::string::npos) {
+            url.replace(sPos, 3, m_urlSubdomains[_subdomainIndex]);
+        }
+    }
+
+    return url;
+}
+
+bool NetworkDataSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+
+    if (_task->rawSource != this->level) {
+        LOGE("NetworkDataSource must be last!");
+        return false;
+    }
+
+    if (m_pending.size() >= m_maxDownloads) {
+        return false;
+    }
+
+    auto tileId = _task->tileId();
+
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if (std::find(m_pending.begin(), m_pending.end(), tileId) != m_pending.end()) {
+            return false;
+        }
+        m_pending.push_back(tileId);
+    }
+
+    std::string url = constructURL(_task->tileId(), m_urlSubdomainIndex);
+
+    if (!m_urlSubdomains.empty()) {
+        m_urlSubdomainIndex = (m_urlSubdomainIndex + 1) % m_urlSubdomains.size();
+    }
+
+    bool started = m_platform->startUrlRequest(url,
+        [this, cb = _cb, task = _task](std::vector<char>&& _rawData) mutable {
+
+            removePending(task->tileId());
+
+            if (task->isCanceled()) {
+                return;
+            }
+
+            if (!_rawData.empty()) {
+                auto rawDataRef = std::make_shared<std::vector<char>>();
+                std::swap(*rawDataRef, _rawData);
+
+                auto& dlTask = static_cast<BinaryTileTask&>(*task);
+                // NB: Sets hasData() state true
+                dlTask.rawTileData = rawDataRef;
+            }
+            cb.func(task);
+        });
+
+    if (!started) {
+        removePending(_task->tileId());
+
+        // Set canceled state, so that tile will not be tried
+        // for reloading until sourceGeneration increased.
+        _task->cancel();
+    }
+
+    return started;
+}
+
+void NetworkDataSource::removePending(const TileID& _tileId) {
+    std::unique_lock<std::mutex> lock(m_mutex);
+    auto it = std::find(m_pending.begin(), m_pending.end(), _tileId);
+    if (it != m_pending.end()) { m_pending.erase(it); }
+}
+
+void NetworkDataSource::cancelLoadingTile(const TileID& _tileId) {
+    removePending(_tileId);
+    // cancel all possible requests for this tile
+    auto maxIndex = m_urlSubdomains.empty() ? 1 : m_urlSubdomains.size();
+    for (size_t index = 0; index < maxIndex; index++) {
+        m_platform->cancelUrlRequest(constructURL(_tileId, index));
+    }
+}
+
+}
diff --git a/core/src/data/networkDataSource.h b/core/src/data/networkDataSource.h
new file mode 100644 (file)
index 0000000..b6fcd99
--- /dev/null
@@ -0,0 +1,40 @@
+#pragma once
+
+#include "data/tileSource.h"
+
+namespace Tangram {
+
+class Platform;
+
+class NetworkDataSource : public TileSource::DataSource {
+public:
+
+    NetworkDataSource(std::shared_ptr<Platform> _platform, const std::string& _urlTemplate,
+            std::vector<std::string>&& _urlSubdomains);
+
+    bool loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
+
+    void cancelLoadingTile(const TileID& _tile) override;
+
+private:
+    /* Constructs the URL of a tile using <m_urlTemplate> */
+    std::string constructURL(const TileID& _tileCoord, size_t index) const;
+
+    void removePending(const TileID& _tileId);
+
+    std::shared_ptr<Platform> m_platform;
+
+    // URL template for requesting tiles from a network or filesystem
+    std::string m_urlTemplate;
+    std::vector<std::string> m_urlSubdomains;
+    size_t m_urlSubdomainIndex = 0;
+
+    std::vector<TileID> m_pending;
+
+    size_t m_maxDownloads;
+
+    std::mutex m_mutex;
+
+};
+
+}
diff --git a/core/src/data/properties.cpp b/core/src/data/properties.cpp
new file mode 100644 (file)
index 0000000..f273337
--- /dev/null
@@ -0,0 +1,171 @@
+#include "data/propertyItem.h"
+#include "data/properties.h"
+#include <algorithm>
+
+namespace Tangram {
+
+// Helper to cleanup double string values from trailing 0s
+std::string doubleToString(double _doubleValue) {
+    std::string value = std::to_string(_doubleValue);
+
+    // Remove trailing '0's
+    value.erase(value.find_last_not_of('0') + 1, std::string::npos);
+    // If last value is '.', clear it too
+    value.erase(value.find_last_not_of('.') + 1, std::string::npos);
+
+    return value;
+}
+
+Properties::Properties() : sourceId(0) {}
+
+Properties::~Properties() {}
+
+Properties& Properties::operator=(Properties&& _other) {
+    props = std::move(_other.props);
+    sourceId = _other.sourceId;
+    return *this;
+}
+
+void Properties::setSorted(std::vector<Item>&& _items) {
+    props = std::move(_items);
+}
+
+const Value& Properties::get(const std::string& key) const {
+
+    const auto it = std::find_if(props.begin(), props.end(),
+                                 [&](const auto& item) {
+                                     return item.key == key;
+                                 });
+    if (it == props.end()) {
+        return NOT_A_VALUE;
+    }
+
+    // auto it = std::lower_bound(props.begin(), props.end(), key,
+    //                            [](auto& item, auto& key) {
+    //                                return keyComparator(item.key, key);
+    //                            });
+    // if (it == props.end() || it->key != key) {
+    //     return NOT_FOUND;
+    // }
+
+    return it->value;
+}
+
+void Properties::clear() { props.clear(); }
+
+bool Properties::contains(const std::string& key) const {
+    return !get(key).is<none_type>();
+}
+
+bool Properties::getNumber(const std::string& key, double& value) const {
+    auto& it = get(key);
+    if (it.is<double>()) {
+        value = it.get<double>();
+        return true;
+    }
+    return false;
+}
+
+double Properties::getNumber(const std::string& key) const {
+    auto& it = get(key);
+    if (it.is<double>()) {
+        return it.get<double>();
+    }
+    return 0;
+}
+
+bool Properties::getString(const std::string& key, std::string& value) const {
+    auto& it = get(key);
+    if (it.is<std::string>()) {
+        value = it.get<std::string>();
+        return true;
+    }
+    return false;
+}
+
+const std::string& Properties::getString(const std::string& key) const {
+    const static std::string EMPTY_STRING = "";
+
+    auto& it = get(key);
+    if (it.is<std::string>()) {
+        return it.get<std::string>();
+    }
+    return EMPTY_STRING;
+}
+
+bool Properties::getAsString(const std::string& key, std::string& value) const {
+    auto& it = get(key);
+
+    if (it.is<std::string>()) {
+        value = it.get<std::string>();
+        return true;
+    } else if (it.is<double>()) {
+        value = doubleToString(it.get<double>());
+        return true;
+    }
+
+    return false;
+}
+
+std::string Properties::asString(const Value& value) const {
+    if (value.is<std::string>()) {
+        return value.get<std::string>();
+    } else if (value.is<double>()) {
+        return doubleToString(value.get<double>());
+    }
+    return "";
+}
+
+std::string Properties::getAsString(const std::string& key) const {
+
+    return asString(get(key));
+
+}
+
+void Properties::sort() {
+    std::sort(props.begin(), props.end());
+}
+
+void Properties::set(std::string key, std::string value) {
+
+    auto it = std::lower_bound(props.begin(), props.end(), key,
+                               [](auto& item, auto& key) {
+                                   return keyComparator(item.key, key);
+                               });
+
+    if (it == props.end() || it->key != key) {
+        props.emplace(it, std::move(key), std::move(value));
+    } else {
+        it->value = std::move(value);
+    }
+}
+
+void Properties::set(std::string key, double value) {
+
+    auto it = std::lower_bound(props.begin(), props.end(), key,
+                               [](auto& item, auto& key) {
+                                   return keyComparator(item.key, key);
+                               });
+
+    if (it == props.end() || it->key != key) {
+        props.emplace(it, std::move(key), value);
+    } else {
+        it->value = value;
+    }
+}
+
+std::string Properties::toJson() const {
+
+    std::string json = "{ ";
+
+    for (const auto& item : props) {
+        bool last = (&item == &props.back());
+        json += "\"" + item.key + "\": \"" + asString(item.value) + (last ? "\"" : "\",");
+    }
+
+    json += " }";
+
+    return json;
+}
+
+}
diff --git a/core/src/data/rasterSource.cpp b/core/src/data/rasterSource.cpp
new file mode 100644 (file)
index 0000000..8d61e89
--- /dev/null
@@ -0,0 +1,190 @@
+#include "data/rasterSource.h"
+#include "data/propertyItem.h"
+#include "data/tileData.h"
+#include "tile/tile.h"
+#include "tile/tileTask.h"
+#include "util/mapProjection.h"
+#include "platform.h"
+
+namespace Tangram {
+
+class RasterTileTask : public BinaryTileTask {
+public:
+    RasterTileTask(TileID& _tileId, std::shared_ptr<TileSource> _source, int _subTask)
+        : BinaryTileTask(_tileId, _source, _subTask) {}
+
+    std::shared_ptr<Texture> m_texture;
+
+    bool hasData() const override {
+        return bool(rawTileData) || bool(m_texture);
+    }
+
+    bool isReady() const override {
+        if (!isSubTask()) {
+            return bool(m_tile);
+        } else {
+            return bool(m_texture);
+        }
+    }
+
+    void process(TileBuilder& _tileBuilder) override {
+
+        auto source = reinterpret_cast<RasterSource*>(m_source.get());
+
+        if (!m_texture) {
+            // Decode texture data
+            m_texture = source->createTexture(*rawTileData);
+        }
+
+        // Create tile geometries
+        if (!isSubTask()) {
+            BinaryTileTask::process(_tileBuilder);
+        }
+    }
+
+    void complete() override {
+        auto source = reinterpret_cast<RasterSource*>(m_source.get());
+
+        auto raster = source->getRaster(*this);
+        assert(raster.isValid());
+
+        m_tile->rasters().push_back(std::move(raster));
+
+        for (auto& subTask : m_subTasks) {
+            assert(subTask->isReady());
+            subTask->complete(*this);
+        }
+    }
+
+    void complete(TileTask& _mainTask) override {
+        auto source = reinterpret_cast<RasterSource*>(m_source.get());
+
+        auto raster = source->getRaster(*this);
+        assert(raster.isValid());
+
+        _mainTask.tile()->rasters().push_back(std::move(raster));
+    }
+};
+
+
+RasterSource::RasterSource(const std::string& _name, std::unique_ptr<DataSource> _sources,
+                           int32_t _minDisplayZoom, int32_t _maxDisplayZoom, int32_t _maxZoom,
+                           int32_t _zoomBias, TextureOptions _options, bool _genMipmap)
+    : TileSource(_name, std::move(_sources), _minDisplayZoom, _maxDisplayZoom, _maxZoom, _zoomBias),
+      m_texOptions(_options),
+      m_genMipmap(_genMipmap) {
+
+    std::vector<char> data = {};
+    m_emptyTexture = std::make_shared<Texture>(data, m_texOptions, m_genMipmap);
+}
+
+std::shared_ptr<Texture> RasterSource::createTexture(const std::vector<char>& _rawTileData) {
+    if (_rawTileData.size() == 0) {
+        return m_emptyTexture;
+    }
+
+    auto texture = std::make_shared<Texture>(_rawTileData, m_texOptions, m_genMipmap);
+
+    return texture;
+}
+
+void RasterSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+    // TODO, remove this
+    // Overwrite cb to set empty texture on failure
+    TileTaskCb cb{[this, _cb](std::shared_ptr<TileTask> _task) {
+
+            if (!_task->hasData()) {
+                auto& task = static_cast<RasterTileTask&>(*_task);
+                task.m_texture = m_emptyTexture;
+            }
+            _cb.func(_task);
+        }};
+
+    TileSource::loadTileData(_task, cb);
+}
+
+std::shared_ptr<TileData> RasterSource::parse(const TileTask& _task, const MapProjection& _projection) const {
+
+    std::shared_ptr<TileData> tileData = std::make_shared<TileData>();
+
+    Feature rasterFeature;
+    rasterFeature.geometryType = GeometryType::polygons;
+    rasterFeature.polygons = { { {
+                                         {0.0f, 0.0f, 0.0f},
+                                         {1.0f, 0.0f, 0.0f},
+                                         {1.0f, 1.0f, 0.0f},
+                                         {0.0f, 1.0f, 0.0f},
+                                         {0.0f, 0.0f, 0.0f}
+                                 } } };
+    rasterFeature.props = Properties();
+
+    tileData->layers.emplace_back("");
+    tileData->layers.back().features.push_back(rasterFeature);
+    return tileData;
+
+}
+
+std::shared_ptr<TileTask> RasterSource::createTask(TileID _tileId, int _subTask) {
+    auto task = std::make_shared<RasterTileTask>(_tileId, shared_from_this(), _subTask);
+
+    createSubTasks(task);
+
+    // First try existing textures cache
+    {
+        TileID id(_tileId.x, _tileId.y, _tileId.z);
+
+        auto texIt = m_textures.find(id);
+        if (texIt != m_textures.end()) {
+            task->m_texture = texIt->second;
+
+            // No more loading needed.
+            task->startedLoading();
+
+            return task;
+        }
+    }
+
+    return task;
+}
+
+Raster RasterSource::getRaster(const TileTask& _task) {
+    const auto& taskTileID = _task.tileId();
+    TileID id(taskTileID.x, taskTileID.y, taskTileID.z);
+
+    auto texIt = m_textures.find(id);
+    if (texIt != m_textures.end()) {
+        return { id, texIt->second };
+    }
+
+    auto& task = static_cast<const RasterTileTask&>(_task);
+    m_textures.emplace(id, task.m_texture);
+
+    return { id, task.m_texture };
+}
+
+void RasterSource::clearRasters() {
+    for (auto& raster: m_rasterSources) {
+        raster->clearRasters();
+    }
+
+    m_textures.clear();
+}
+
+void RasterSource::clearRaster(const TileID &tileID) {
+    TileID id(tileID.x, tileID.y, tileID.z);
+
+    for (auto& raster: m_rasterSources) {
+        TileID rasterID = id.withMaxSourceZoom(raster->maxZoom());
+        raster->clearRaster(rasterID);
+    }
+
+    auto rasterID = id.withMaxSourceZoom(m_maxZoom);
+
+    // We do not want to delete the texture reference from the
+    // DS if any of the tiles is still using this as a reference
+    if (m_textures[rasterID].use_count() <= 1) {
+        m_textures.erase(rasterID);
+    }
+}
+
+}
diff --git a/core/src/data/rasterSource.h b/core/src/data/rasterSource.h
new file mode 100644 (file)
index 0000000..a23560b
--- /dev/null
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "data/tileSource.h"
+#include "gl/texture.h"
+#include "tile/tileTask.h"
+#include "tile/tileHash.h"
+
+#include <functional>
+#include <unordered_map>
+#include <mutex>
+
+namespace Tangram {
+
+class RasterTileTask;
+
+class RasterSource : public TileSource {
+
+    TextureOptions m_texOptions;
+    bool m_genMipmap;
+    std::unordered_map<TileID, std::shared_ptr<Texture>> m_textures;
+
+    std::shared_ptr<Texture> m_emptyTexture;
+
+protected:
+
+    virtual std::shared_ptr<TileData> parse(const TileTask& _task,
+                                            const MapProjection& _projection) const override;
+
+public:
+
+    RasterSource(const std::string& _name, std::unique_ptr<DataSource> _sources,
+                 int32_t _minDisplayZoom, int32_t _maxDisplayZoom, int32_t _maxZoom,
+                 int32_t _zoomBias, TextureOptions _options, bool genMipmap = false);
+
+    // TODO Is this always PNG or can it also be JPEG?
+    virtual const char* mimeType() const override { return "image/png"; };
+
+    void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override;
+
+    virtual std::shared_ptr<TileTask> createTask(TileID _tile, int _subTask) override;
+
+    virtual void clearRasters() override;
+    virtual void clearRaster(const TileID& id) override;
+    virtual bool isRaster() const override { return true; }
+
+    std::shared_ptr<Texture> createTexture(const std::vector<char>& _rawTileData);
+
+    Raster getRaster(const TileTask& _task);
+
+};
+
+}
diff --git a/core/src/data/tileData.h b/core/src/data/tileData.h
new file mode 100644 (file)
index 0000000..4e62f17
--- /dev/null
@@ -0,0 +1,101 @@
+#pragma once
+
+#include "glm/vec3.hpp"
+#include "data/properties.h"
+
+#include <vector>
+#include <string>
+
+/*
+
+Tile Coordinates:
+
+  A point in the geometry of a tile is represented with 32-bit floating point
+  x, y, and z coordinates. Coordinates represent normalized displacement from
+  the origin (i.e. lower-left corner) of a tile.
+
+  (0.0, 1.0) ---------- (1.0, 1.0)
+            |          |             N
+            ^ +y       |          W <|> E
+            |          |             S
+            |    +x    |
+  (0.0, 0.0) ----->---- (1.0, 0.0)
+
+  Coordinates that fall outside the range [0.0, 1.0] are permissible, as tile
+  servers may choose not to clip certain geometries to tile boundaries, but these
+  points are clipped in the client-side geometry processing.
+
+  Z coordinates are expected to be normalized to the same scale as x, y coordinates.
+
+Data heirarchy:
+
+  TileData is a heirarchical container of structs modeled after the geoJSON spec:
+  http://geojson.org/geojson-spec.html
+
+  A <TileData> contains a collection of <Layer>s
+
+  A <Layer> contains a name and a collection of <Feature>s
+
+  A <Feature> contains a <GeometryType> denoting what variety of geometry is
+  contained in the feature, a <Properties> struct describing the feature, and
+  one collection each of <Point>s, <Line>s, and <Polygon>s. Only the geometry
+  collection corresponding to the feature's geometryType should contain data.
+
+  A <Properties> contains a sorted vector of key-value pairs storing the
+  properties of a <Feature>
+
+  A <Polygon> is a collection of <Line>s representing the contours of a polygon.
+  Contour winding rules follow the conventions of the OpenGL red book described
+  here: http://www.glprogramming.com/red/chapter11.html
+
+  A <Line> is a collection of <Point>s.
+
+  A <Point> is 3 32-bit floating point coordinates representing x, y, and z
+  (in that order).
+
+*/
+namespace Tangram {
+
+enum GeometryType {
+    unknown,
+    points,
+    lines,
+    polygons
+};
+
+typedef glm::vec3 Point;
+
+typedef std::vector<Point> Line;
+
+typedef std::vector<Line> Polygon;
+
+struct Feature {
+    Feature() {}
+    Feature(int32_t _sourceId) { props.sourceId = _sourceId; }
+
+    GeometryType geometryType = GeometryType::polygons;
+
+    std::vector<Point> points;
+    std::vector<Line> lines;
+    std::vector<Polygon> polygons;
+
+    Properties props;
+};
+
+struct Layer {
+
+    Layer(const std::string& _name) : name(_name) {}
+
+    std::string name;
+
+    std::vector<Feature> features;
+
+};
+
+struct TileData {
+
+    std::vector<Layer> layers;
+
+};
+
+}
diff --git a/core/src/data/tileSource.cpp b/core/src/data/tileSource.cpp
new file mode 100644 (file)
index 0000000..dd1376b
--- /dev/null
@@ -0,0 +1,157 @@
+#include "data/tileSource.h"
+
+#include "data/formats/geoJson.h"
+#include "data/formats/mvt.h"
+#include "data/formats/topoJson.h"
+#include "data/tileData.h"
+#include "platform.h"
+#include "tile/tileID.h"
+#include "tile/tile.h"
+#include "tile/tileTask.h"
+#include "log.h"
+#include "util/geom.h"
+
+#include <atomic>
+#include <functional>
+
+namespace Tangram {
+
+TileSource::TileSource(const std::string& _name, std::unique_ptr<DataSource> _sources,
+                       int32_t _minDisplayZoom, int32_t _maxDisplayZoom, int32_t _maxZoom,
+                       int32_t _zoomBias) :
+    m_name(_name),
+    m_minDisplayZoom(_minDisplayZoom),
+    m_maxDisplayZoom(_maxDisplayZoom),
+    m_maxZoom(_maxZoom),
+    m_zoomBias(_zoomBias),
+    m_sources(std::move(_sources)) {
+
+    static std::atomic<int32_t> s_serial;
+
+    m_id = s_serial++;
+}
+
+TileSource::~TileSource() {
+    clearData();
+}
+
+int32_t TileSource::zoomBiasFromTileSize(int32_t tileSize) {
+    const auto BaseTileSize = 256;
+
+    // zero tileSize (log(0) is undefined)
+    if (!tileSize) { return 0; }
+
+    if (isPowerOfTwo(tileSize)) {
+        return std::log(static_cast<float>(tileSize)/static_cast<float>(BaseTileSize)) / std::log(2);
+    }
+
+    LOGW("Illegal tile_size defined. Must be power of 2. Default tileSize of 256px set");
+    return 0;
+}
+
+const char* TileSource::mimeType() const {
+    switch (m_format) {
+    case Format::GeoJson: return "application/geo+json";
+    case Format::TopoJson: return "application/topo+json";
+    case Format::Mvt: return "application/vnd.mapbox-vector-tile";
+    }
+    assert(false);
+    return "";
+}
+
+std::shared_ptr<TileTask> TileSource::createTask(TileID _tileId, int _subTask) {
+    auto task = std::make_shared<BinaryTileTask>(_tileId, shared_from_this(), _subTask);
+
+    createSubTasks(task);
+
+    return task;
+}
+
+void TileSource::createSubTasks(std::shared_ptr<TileTask> _task) {
+    size_t index = 0;
+
+    for (auto& subSource : m_rasterSources) {
+        TileID subTileID = _task->tileId();
+
+        // get tile for lower zoom if we are past max zoom
+        if (subTileID.z > subSource->maxZoom()) {
+            subTileID = subTileID.withMaxSourceZoom(subSource->maxZoom());
+        }
+
+        _task->subTasks().push_back(subSource->createTask(subTileID, index++));
+    }
+}
+
+void TileSource::clearData() {
+
+    if (m_sources) { m_sources->clear(); }
+
+    m_generation++;
+}
+
+void TileSource::loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) {
+
+    if (m_sources) {
+        if (_task->needsLoading()) {
+            if (m_sources->loadTileData(_task, _cb)) {
+                _task->startedLoading();
+            }
+        } else if(_task->hasData()) {
+            _cb.func(_task);
+        }
+    }
+
+    for (auto& subTask : _task->subTasks()) {
+        subTask->source().loadTileData(subTask, _cb);
+    }
+}
+
+std::shared_ptr<TileData> TileSource::parse(const TileTask& _task, const MapProjection& _projection) const {
+    switch (m_format) {
+    case Format::TopoJson: return TopoJson::parseTile(_task, _projection, m_id);
+    case Format::GeoJson: return GeoJson::parseTile(_task, _projection, m_id);
+    case Format::Mvt: return Mvt::parseTile(_task, _projection, m_id);
+    }
+    assert(false);
+    return nullptr;
+}
+
+void TileSource::cancelLoadingTile(const TileID& _tileID) {
+
+    if (m_sources) { return m_sources->cancelLoadingTile(_tileID); }
+
+    for (auto& raster : m_rasterSources) {
+        TileID rasterID = _tileID.withMaxSourceZoom(raster->maxZoom());
+        raster->cancelLoadingTile(rasterID);
+    }
+}
+
+void TileSource::clearRasters() {
+    for (auto& raster : m_rasterSources) {
+        raster->clearRasters();
+    }
+}
+
+void TileSource::clearRaster(const TileID& id) {
+    for (auto& raster : m_rasterSources) {
+        TileID rasterID = id.withMaxSourceZoom(raster->maxZoom());
+        raster->clearRaster(rasterID);
+    }
+}
+
+void TileSource::addRasterSource(std::shared_ptr<TileSource> _rasterSource) {
+    /*
+     * We limit the parent source by any attached raster source's min/max.
+     */
+    int32_t rasterMinDisplayZoom = _rasterSource->minDisplayZoom();
+    int32_t rasterMaxDisplayZoom = _rasterSource->maxDisplayZoom();
+    if (rasterMinDisplayZoom > m_minDisplayZoom) {
+        m_minDisplayZoom = rasterMinDisplayZoom;
+    }
+    if (rasterMaxDisplayZoom < m_maxDisplayZoom) {
+        m_maxDisplayZoom = rasterMaxDisplayZoom;
+    }
+    m_rasterSources.push_back(_rasterSource);
+}
+
+}
diff --git a/core/src/debug/frameInfo.cpp b/core/src/debug/frameInfo.cpp
new file mode 100644 (file)
index 0000000..36e4b80
--- /dev/null
@@ -0,0 +1,154 @@
+#include "debug/frameInfo.h"
+
+#include "tangram.h"
+#include "debug/textDisplay.h"
+#include "tile/tileManager.h"
+#include "tile/tile.h"
+#include "tile/tileCache.h"
+#include "gl/primitives.h"
+#include "view/view.h"
+#include "gl.h"
+#include "gl/glError.h"
+
+#include <deque>
+#include <ctime>
+
+#define TIME_TO_MS(start, end) (float(end - start) / CLOCKS_PER_SEC * 1000.0f)
+
+#define DEBUG_STATS_MAX_SIZE 128
+
+namespace Tangram {
+
+static float s_lastUpdateTime = 0.0;
+
+static clock_t s_startFrameTime = 0,
+    s_endFrameTime = 0,
+    s_startUpdateTime = 0,
+    s_endUpdateTime = 0;
+
+void FrameInfo::beginUpdate() {
+
+    if (getDebugFlag(DebugFlags::tangram_infos) || getDebugFlag(DebugFlags::tangram_stats)) {
+        s_startUpdateTime = clock();
+    }
+
+}
+
+void FrameInfo::endUpdate() {
+
+    if (getDebugFlag(DebugFlags::tangram_infos) || getDebugFlag(DebugFlags::tangram_stats)) {
+        s_endUpdateTime = clock();
+        s_lastUpdateTime = TIME_TO_MS(s_startUpdateTime, s_endUpdateTime);
+    }
+
+}
+
+void FrameInfo::beginFrame() {
+
+    if (getDebugFlag(DebugFlags::tangram_infos) || getDebugFlag(DebugFlags::tangram_stats)) {
+        s_startFrameTime = clock();
+    }
+
+}
+
+
+void FrameInfo::draw(RenderState& rs, const View& _view, TileManager& _tileManager) {
+
+    if (getDebugFlag(DebugFlags::tangram_infos) || getDebugFlag(DebugFlags::tangram_stats)) {
+        static int cpt = 0;
+
+        static std::deque<float> updatetime;
+        static std::deque<float> rendertime;
+
+        clock_t endCpu = clock();
+        static float timeCpu[60] = { 0 };
+        static float timeUpdate[60] = { 0 };
+        static float timeRender[60] = { 0 };
+        timeCpu[cpt] = TIME_TO_MS(s_startFrameTime, endCpu);
+
+        if (updatetime.size() >= DEBUG_STATS_MAX_SIZE) {
+            updatetime.pop_front();
+        }
+        if (rendertime.size() >= DEBUG_STATS_MAX_SIZE) {
+            rendertime.pop_front();
+        }
+
+        rendertime.push_back(timeRender[cpt]);
+        updatetime.push_back(timeUpdate[cpt]);
+
+        // Force opengl to finish commands (for accurate frame time)
+        GL::finish();
+
+        s_endFrameTime = clock();
+        timeRender[cpt] = TIME_TO_MS(s_startFrameTime, s_endFrameTime);
+
+        if (++cpt == 60) { cpt = 0; }
+
+        // Only compute average frame time every 60 frames
+        float avgTimeRender = 0.f;
+        float avgTimeCpu = 0.f;
+        float avgTimeUpdate = 0.f;
+
+        timeUpdate[cpt] = s_lastUpdateTime;
+
+        for (int i = 0; i < 60; i++) {
+            avgTimeRender += timeRender[i];
+            avgTimeCpu += timeCpu[i];
+            avgTimeUpdate += timeUpdate[i];
+        }
+        avgTimeRender /= 60;
+        avgTimeCpu /= 60;
+        avgTimeUpdate /= 60;
+
+        size_t memused = 0;
+        size_t features = 0;
+        for (const auto& tile : _tileManager.getVisibleTiles()) {
+            memused += tile->getMemoryUsage();
+            features += tile->getSelectionFeatures().size();
+        }
+
+        if (getDebugFlag(DebugFlags::tangram_infos)) {
+            std::vector<std::string> debuginfos;
+
+            debuginfos.push_back("visible tiles:"
+                                 + std::to_string(_tileManager.getVisibleTiles().size()));
+            debuginfos.push_back("selectable features:"
+                                 + std::to_string(features));
+            debuginfos.push_back("tile cache size:"
+                                 + std::to_string(_tileManager.getTileCache()->getMemoryUsage() / 1024) + "kb");
+            debuginfos.push_back("tile size:" + std::to_string(memused / 1024) + "kb");
+            debuginfos.push_back("avg frame cpu time:" + to_string_with_precision(avgTimeCpu, 2) + "ms");
+            debuginfos.push_back("avg frame render time:" + to_string_with_precision(avgTimeRender, 2) + "ms");
+            debuginfos.push_back("avg frame update time:" + to_string_with_precision(avgTimeUpdate, 2) + "ms");
+            debuginfos.push_back("zoom:" + std::to_string(_view.getZoom()));
+            debuginfos.push_back("pos:" + std::to_string(_view.getPosition().x) + "/"
+                                 + std::to_string(_view.getPosition().y));
+            debuginfos.push_back("tilt:" + std::to_string(_view.getPitch() * 57.3) + "deg");
+            debuginfos.push_back("pixel scale:" + std::to_string(_view.pixelScale()));
+
+            TextDisplay::Instance().draw(rs, debuginfos);
+        }
+
+        if (getDebugFlag(DebugFlags::tangram_stats)) {
+            const int scale = 5 * _view.pixelScale();
+
+            for (size_t i = 0; i < updatetime.size(); i++) {
+                float tupdate = updatetime[i] * scale;
+                float trender = rendertime[i] * scale;
+                float offsetx = i * 4 * _view.pixelScale();
+
+                Primitives::setColor(rs, 0xfff000);
+                Primitives::drawLine(rs, glm::vec2(offsetx, 0), glm::vec2(offsetx, tupdate));
+                Primitives::setColor(rs, 0x0000ff);
+                Primitives::drawLine(rs, glm::vec2(offsetx, tupdate), glm::vec2(offsetx, tupdate + trender));
+            }
+
+            // Draw 16.6ms horizontal line
+            Primitives::setColor(rs, 0xff0000);
+            Primitives::drawLine(rs, glm::vec2(0.0, 16.6 * scale),
+                glm::vec2(DEBUG_STATS_MAX_SIZE * 4 * _view.pixelScale() + 4, 16.6 * scale));
+        }
+    }
+}
+
+}
diff --git a/core/src/debug/frameInfo.h b/core/src/debug/frameInfo.h
new file mode 100644 (file)
index 0000000..f3c607b
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+namespace Tangram {
+
+class RenderState;
+class TileManager;
+class View;
+
+struct FrameInfo {
+
+    static void beginUpdate();
+    static void beginFrame();
+
+    static void endUpdate();
+
+    static void draw(RenderState& rs, const View& _view, TileManager& _tileManager);
+};
+
+}
diff --git a/core/src/debug/textDisplay.cpp b/core/src/debug/textDisplay.cpp
new file mode 100644 (file)
index 0000000..5b3166e
--- /dev/null
@@ -0,0 +1,148 @@
+#include "debug/textDisplay.h"
+
+#include "platform.h"
+#include "gl/glError.h"
+#include "gl/vertexLayout.h"
+#include "gl/renderState.h"
+#include "glm/glm.hpp"
+#include "glm/gtc/matrix_transform.hpp"
+#include <cstdarg>
+
+#define STB_EASY_FONT_IMPLEMENTATION
+#include "stb_easy_font.h"
+
+namespace Tangram {
+
+TextDisplay::TextDisplay() : m_textDisplayResolution(350.0), m_initialized(false) {
+    m_vertexBuffer = new char[VERTEX_BUFFER_SIZE];
+}
+
+TextDisplay::~TextDisplay() {
+    delete[] m_vertexBuffer;
+}
+
+void TextDisplay::init() {
+    if (m_initialized) {
+        return;
+    }
+
+    std::string vertShaderSrcStr = R"END(
+        #ifdef GL_ES
+        precision mediump float;
+        #define LOWP lowp
+        #else
+        #define LOWP
+        #endif
+        uniform mat4 u_orthoProj;
+        attribute vec2 a_position;
+        void main() {
+            gl_Position = u_orthoProj * vec4(a_position, 0.0, 1.0);
+        }
+    )END";
+    std::string fragShaderSrcStr = R"END(
+        #ifdef GL_ES
+        precision mediump float;
+        #define LOWP lowp
+        #else
+        #define LOWP
+        #endif
+        uniform vec3 u_color;
+        void main(void) {
+            gl_FragColor = vec4(u_color, 1.0);
+        }
+    )END";
+
+    m_shader = std::make_unique<ShaderProgram>();
+    m_shader->setShaderSource(vertShaderSrcStr, fragShaderSrcStr);
+
+    m_initialized = true;
+}
+
+void TextDisplay::deinit() {
+
+    m_shader.reset(nullptr);
+    m_initialized = false;
+
+}
+
+void TextDisplay::log(const char* fmt, ...) {
+    static char text[99999];
+
+    va_list args;
+    va_start(args, fmt);
+    vsprintf(text, fmt, args);
+    va_end(args);
+
+    {
+        std::lock_guard<std::mutex> lock(m_mutex);
+
+        for (int i = LOG_CAPACITY - 1; i >= 1; i--) {
+            m_log[i] = m_log[i - 1];
+        }
+
+        m_log[0] = std::string(text);
+    }
+}
+
+void TextDisplay::draw(RenderState& rs, const std::string& _text, int _posx, int _posy) {
+    static VertexLayout vertexLayout({{"a_position", 2, GL_FLOAT, false, 0}});
+    std::vector<glm::vec2> vertices;
+    int nquads;
+
+    nquads = stb_easy_font_print(_posx, _posy, _text.c_str(), NULL, m_vertexBuffer, VERTEX_BUFFER_SIZE);
+
+    float* data = reinterpret_cast<float*>(m_vertexBuffer);
+
+    vertices.reserve(nquads * 6);
+    for (int quad = 0, stride = 0; quad < nquads; ++quad, stride += 16) {
+        vertices.push_back({data[(0 * 4) + stride], data[(0 * 4) + 1 + stride]});
+        vertices.push_back({data[(1 * 4) + stride], data[(1 * 4) + 1 + stride]});
+        vertices.push_back({data[(2 * 4) + stride], data[(2 * 4) + 1 + stride]});
+        vertices.push_back({data[(2 * 4) + stride], data[(2 * 4) + 1 + stride]});
+        vertices.push_back({data[(3 * 4) + stride], data[(3 * 4) + 1 + stride]});
+        vertices.push_back({data[(0 * 4) + stride], data[(0 * 4) + 1 + stride]});
+    }
+    vertexLayout.enable(rs, *m_shader, 0, (void*)vertices.data());
+
+    GL::drawArrays(GL_TRIANGLES, 0, nquads * 6);
+}
+
+void TextDisplay::draw(RenderState& rs, const std::vector<std::string>& _infos) {
+    GLint boundbuffer = -1;
+
+    if (!m_shader->use(rs)) { return; }
+
+    rs.culling(GL_FALSE);
+    rs.blending(GL_FALSE);
+    rs.depthTest(GL_FALSE);
+    rs.depthMask(GL_FALSE);
+
+    GL::getIntegerv(GL_ARRAY_BUFFER_BINDING, &boundbuffer);
+    rs.vertexBuffer(0);
+
+    glm::mat4 orthoProj = glm::ortho(0.f, (float)m_textDisplayResolution.x, (float)m_textDisplayResolution.y, 0.f, -1.f, 1.f);
+    m_shader->setUniformMatrix4f(rs, m_uOrthoProj, orthoProj);
+
+    // Display Tangram info messages
+    m_shader->setUniformf(rs, m_uColor, 0.f, 0.f, 0.f);
+    int offset = 0;
+    for (auto& text : _infos) {
+        draw(rs, text, 3, 3 + offset);
+        offset += 10;
+    }
+
+    // Display screen log
+    offset = 0;
+    m_shader->setUniformf(rs, m_uColor, 51 / 255.f, 73 / 255.f, 120 / 255.f);
+    for (int i = 0; i < LOG_CAPACITY; ++i) {
+        draw(rs, m_log[i], 3, m_textDisplayResolution.y - 10 + offset);
+        offset -= 10;
+    }
+
+    rs.culling(GL_TRUE);
+    rs.vertexBuffer(boundbuffer);
+}
+
+}
+
+
diff --git a/core/src/debug/textDisplay.h b/core/src/debug/textDisplay.h
new file mode 100644 (file)
index 0000000..0395bb7
--- /dev/null
@@ -0,0 +1,70 @@
+#pragma once
+
+#include "gl/texture.h"
+#include "gl/mesh.h"
+#include "gl/shaderProgram.h"
+#include "glm/vec2.hpp"
+#include <string>
+#include <vector>
+#include <mutex>
+#include <cstdio>
+#include <sstream>
+#include <iomanip>
+
+namespace Tangram {
+
+#define LOG_CAPACITY        20
+#define VERTEX_BUFFER_SIZE  99999
+
+typedef int FontID;
+class RenderState;
+
+template <typename T>
+std::string to_string_with_precision(const T a_value, const int n = 6) {
+    std::ostringstream out;
+    out << std::fixed << std::setprecision(n) << a_value;
+    return out.str();
+}
+
+class TextDisplay {
+
+public:
+
+    static TextDisplay& Instance() {
+        static TextDisplay instance;
+        instance.init();
+        return instance;
+    }
+
+    ~TextDisplay();
+
+    void setResolution(glm::vec2 _textDisplayResolution) { m_textDisplayResolution = _textDisplayResolution; }
+
+    void init();
+    void deinit();
+
+    /* Draw stacked messages added through log and draw _infos string list */
+    void draw(RenderState& rs, const std::vector<std::string>& _infos);
+
+    /* Stack the log message to be displayed in the screen log */
+    void log(const char* fmt, ...);
+
+private:
+
+    TextDisplay();
+
+    void draw(RenderState& rs, const std::string& _text, int _posx, int _posy);
+
+    glm::vec2 m_textDisplayResolution;
+    bool m_initialized;
+    std::unique_ptr<ShaderProgram> m_shader;
+    std::string m_log[LOG_CAPACITY];
+    std::mutex m_mutex;
+    char* m_vertexBuffer;
+
+    UniformLocation m_uOrthoProj{"u_orthoProj"};
+    UniformLocation m_uColor{"u_color"};
+
+};
+
+}
diff --git a/core/src/gl.h b/core/src/gl.h
new file mode 100644 (file)
index 0000000..daabfd3
--- /dev/null
@@ -0,0 +1,421 @@
+#pragma once
+
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_RPI) || defined(PLATFORM_IOS)
+typedef long GLsizeiptr;
+typedef long GLintptr;
+#elif defined(PLATFORM_TIZEN)
+typedef signed long int  GLintptr;
+typedef signed long int  GLsizeiptr;
+#else
+#include <stddef.h>
+typedef ptrdiff_t GLsizeiptr;
+typedef ptrdiff_t GLintptr;
+#endif
+
+/*
+ * Mesa 3-D graphics library
+ *
+ * Copyright (C) 1999-2006  Brian Paul   All Rights Reserved.
+ * Copyright (C) 2009  VMware, Inc.  All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+typedef unsigned int    GLenum;
+typedef unsigned char   GLboolean;
+typedef unsigned int    GLbitfield;
+typedef void            GLvoid;
+typedef signed char     GLbyte;     /* 1-byte signed */
+typedef short           GLshort;    /* 2-byte signed */
+typedef int             GLint;      /* 4-byte signed */
+typedef unsigned char   GLubyte;    /* 1-byte unsigned */
+typedef unsigned short  GLushort;   /* 2-byte unsigned */
+typedef unsigned int    GLuint;     /* 4-byte unsigned */
+typedef int             GLsizei;    /* 4-byte signed */
+typedef float           GLfloat;    /* single precision float */
+typedef float           GLclampf;   /*single precision float in [0,1] */
+typedef double          GLdouble;   /* double precision float */
+typedef double          GLclampd;   /* double precision float in [0,1] */
+typedef char            GLchar;
+
+/* Utility */
+#define GL_VENDOR                       0x1F00
+#define GL_RENDERER                     0x1F01
+#define GL_VERSION                      0x1F02
+#define GL_EXTENSIONS                   0x1F03
+
+/* Boolean values */
+#define GL_FALSE                        0
+#define GL_TRUE                         1
+
+#define GL_DEPTH_BUFFER_BIT             0x00000100
+#define GL_STENCIL_BUFFER_BIT           0x00000400
+#define GL_COLOR_BUFFER_BIT             0x00004000
+
+/* Errors */
+#define GL_NO_ERROR                     0
+#define GL_INVALID_ENUM                 0x0500
+#define GL_INVALID_VALUE                0x0501
+#define GL_INVALID_OPERATION            0x0502
+#define GL_OUT_OF_MEMORY                0x0505
+#define GL_INVALID_FRAMEBUFFER_OPERATION  0x0506
+
+/* Data types */
+#define GL_BYTE                         0x1400
+#define GL_UNSIGNED_BYTE                0x1401
+#define GL_SHORT                        0x1402
+#define GL_UNSIGNED_SHORT               0x1403
+#define GL_INT                          0x1404
+#define GL_UNSIGNED_INT                 0x1405
+#define GL_FLOAT                        0x1406
+#define GL_2_BYTES                      0x1407
+#define GL_3_BYTES                      0x1408
+#define GL_4_BYTES                      0x1409
+#define GL_DOUBLE                       0x140A
+
+/* Primitives */
+#define GL_POINTS                       0x0000
+#define GL_LINES                        0x0001
+#define GL_LINE_LOOP                    0x0002
+#define GL_LINE_STRIP                   0x0003
+#define GL_TRIANGLES                    0x0004
+#define GL_TRIANGLE_STRIP               0x0005
+#define GL_TRIANGLE_FAN                 0x0006
+#define GL_QUADS                        0x0007
+#define GL_QUAD_STRIP                   0x0008
+#define GL_POLYGON                      0x0009
+
+/* Blending */
+#define GL_BLEND                        0x0BE2
+#define GL_BLEND_SRC                    0x0BE1
+#define GL_BLEND_DST                    0x0BE0
+#define GL_ZERO                         0
+#define GL_ONE                          1
+#define GL_SRC_COLOR                    0x0300
+#define GL_ONE_MINUS_SRC_COLOR          0x0301
+#define GL_SRC_ALPHA                    0x0302
+#define GL_ONE_MINUS_SRC_ALPHA          0x0303
+#define GL_DST_ALPHA                    0x0304
+#define GL_ONE_MINUS_DST_ALPHA          0x0305
+#define GL_DST_COLOR                    0x0306
+#define GL_ONE_MINUS_DST_COLOR          0x0307
+#define GL_SRC_ALPHA_SATURATE           0x0308
+
+/* Buffers, Pixel Drawing/Reading */
+#define GL_NONE                         0
+#define GL_RED                          0x1903
+#define GL_GREEN                        0x1904
+#define GL_BLUE                         0x1905
+#define GL_ALPHA                        0x1906
+#define GL_LUMINANCE                    0x1909
+#define GL_LUMINANCE_ALPHA              0x190A
+#define GL_ALPHA_BITS                   0x0D55
+#define GL_RED_BITS                     0x0D52
+#define GL_GREEN_BITS                   0x0D53
+#define GL_BLUE_BITS                    0x0D54
+#define GL_INDEX_BITS                   0x0D51
+#define GL_READ_BUFFER                  0x0C02
+#define GL_DRAW_BUFFER                  0x0C01
+#define GL_STEREO                       0x0C33
+#define GL_BITMAP                       0x1A00
+#define GL_COLOR                        0x1800
+#define GL_DEPTH                        0x1801
+#define GL_STENCIL                      0x1802
+#define GL_RGB                          0x1907
+#define GL_RGBA                         0x1908
+#define GL_RGBA8_OES                    0x8058
+
+#define GL_NEAREST                      0x2600
+#define GL_LINEAR                       0x2601
+#define GL_NEAREST_MIPMAP_NEAREST       0x2700
+#define GL_LINEAR_MIPMAP_NEAREST        0x2701
+#define GL_NEAREST_MIPMAP_LINEAR        0x2702
+#define GL_LINEAR_MIPMAP_LINEAR         0x2703
+
+#define GL_CLAMP_TO_EDGE                0x812F
+#define GL_CLAMP                        0x2900
+#define GL_REPEAT                       0x2901
+
+/* texture_cube_map */
+#define GL_NORMAL_MAP                   0x8511
+#define GL_REFLECTION_MAP               0x8512
+#define GL_TEXTURE_CUBE_MAP             0x8513
+#define GL_TEXTURE_BINDING_CUBE_MAP     0x8514
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_X  0x8515
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_X  0x8516
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Y  0x8517
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Y  0x8518
+#define GL_TEXTURE_CUBE_MAP_POSITIVE_Z  0x8519
+#define GL_TEXTURE_CUBE_MAP_NEGATIVE_Z  0x851A
+#define GL_PROXY_TEXTURE_CUBE_MAP       0x851B
+#define GL_MAX_CUBE_MAP_TEXTURE_SIZE    0x851C
+
+/* Polygons */
+#define GL_POINT                        0x1B00
+#define GL_LINE                         0x1B01
+#define GL_FILL                         0x1B02
+#define GL_CW                           0x0900
+#define GL_CCW                          0x0901
+#define GL_FRONT                        0x0404
+#define GL_BACK                         0x0405
+#define GL_EDGE_FLAG                    0x0B43
+#define GL_CULL_FACE                    0x0B44
+#define GL_CULL_FACE_MODE               0x0B45
+#define GL_FRONT_FACE                   0x0B46
+
+/* Depth buffer */
+#define GL_NEVER                        0x0200
+#define GL_LESS                         0x0201
+#define GL_EQUAL                        0x0202
+#define GL_LEQUAL                       0x0203
+#define GL_GREATER                      0x0204
+#define GL_NOTEQUAL                     0x0205
+#define GL_GEQUAL                       0x0206
+#define GL_ALWAYS                       0x0207
+#define GL_DEPTH_TEST                   0x0B71
+#define GL_DEPTH_BITS                   0x0D56
+#define GL_DEPTH_CLEAR_VALUE            0x0B73
+#define GL_DEPTH_FUNC                   0x0B74
+#define GL_DEPTH_RANGE                  0x0B70
+#define GL_DEPTH_WRITEMASK              0x0B72
+#define GL_DEPTH_COMPONENT              0x1902
+#define GL_DEPTH_COMPONENT16            0x81A5
+
+/* Stencil */
+#define GL_STENCIL_BITS                 0x0D57
+#define GL_STENCIL_TEST                 0x0B90
+#define GL_STENCIL_CLEAR_VALUE          0x0B91
+#define GL_STENCIL_FUNC                 0x0B92
+#define GL_STENCIL_VALUE_MASK           0x0B93
+#define GL_STENCIL_FAIL                 0x0B94
+#define GL_STENCIL_PASS_DEPTH_FAIL      0x0B95
+#define GL_STENCIL_PASS_DEPTH_PASS      0x0B96
+#define GL_STENCIL_REF                  0x0B97
+#define GL_STENCIL_WRITEMASK            0x0B98
+#define GL_STENCIL_INDEX                0x1901
+#define GL_KEEP                         0x1E00
+#define GL_REPLACE                      0x1E01
+#define GL_INCR                         0x1E02
+#define GL_DECR                         0x1E03
+
+/* Texture mapping */
+#define GL_NEAREST_MIPMAP_NEAREST       0x2700
+#define GL_NEAREST_MIPMAP_LINEAR        0x2702
+#define GL_LINEAR_MIPMAP_NEAREST        0x2701
+#define GL_LINEAR_MIPMAP_LINEAR         0x2703
+#define GL_NEAREST                      0x2600
+#define GL_TEXTURE0                     0x84C0
+#define GL_TEXTURE_2D                   0x0DE1
+#define GL_TEXTURE_WRAP_S               0x2802
+#define GL_TEXTURE_WRAP_T               0x2803
+#define GL_TEXTURE_MAG_FILTER           0x2800
+#define GL_TEXTURE_MIN_FILTER           0x2801
+
+/* Framebuffers, Render buffers */
+#define GL_FRAMEBUFFER                  0x8D40
+#define GL_RENDERBUFFER                 0x8D41
+#define GL_RENDERBUFFER_WIDTH           0x8D42
+#define GL_RENDERBUFFER_HEIGHT          0x8D43
+#define GL_RENDERBUFFER_INTERNAL_FORMAT 0x8D44
+#define GL_RENDERBUFFER_RED_SIZE        0x8D50
+#define GL_RENDERBUFFER_GREEN_SIZE      0x8D51
+#define GL_RENDERBUFFER_BLUE_SIZE       0x8D52
+#define GL_RENDERBUFFER_ALPHA_SIZE      0x8D53
+#define GL_RENDERBUFFER_DEPTH_SIZE      0x8D54
+#define GL_RENDERBUFFER_STENCIL_SIZE    0x8D55
+#define GL_COLOR_ATTACHMENT0            0x8CE0
+#define GL_DEPTH_ATTACHMENT             0x8D00
+#define GL_STENCIL_ATTACHMENT           0x8D20
+#define GL_NONE                         0
+#define GL_FRAMEBUFFER_COMPLETE         0x8CD5
+#define GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT 0x8CD6
+#define GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT 0x8CD7
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_FRAMEBUFFER_UNSUPPORTED      0x8CDD
+#define GL_FRAMEBUFFER_BINDING          0x8CA6
+#define GL_RENDERBUFFER_BINDING         0x8CA7
+#define GL_MAX_RENDERBUFFER_SIZE        0x84E8
+#define GL_INVALID_FRAMEBUFFER_OPERATION 0x0506
+
+// glext.h
+#define GL_ARRAY_BUFFER                 0x8892
+#define GL_ELEMENT_ARRAY_BUFFER         0x8893
+#define GL_ARRAY_BUFFER_BINDING         0x8894
+#define GL_ELEMENT_ARRAY_BUFFER_BINDING 0x8895
+#define GL_STATIC_DRAW                  0x88E4
+#define GL_DYNAMIC_DRAW                 0x88E8
+
+// Program
+#define GL_FRAGMENT_SHADER              0x8B30
+#define GL_VERTEX_SHADER                0x8B31
+#define GL_COMPILE_STATUS               0x8B81
+#define GL_LINK_STATUS                  0x8B82
+#define GL_INFO_LOG_LENGTH              0x8B84
+
+// mapbuffer
+#define GL_READ_ONLY                    0x88B8
+#define GL_WRITE_ONLY                   0x88B9
+#define GL_READ_WRITE                   0x88BA
+
+#define GL_MAX_TEXTURE_SIZE             0x0D33
+#define GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS 0x8B4D
+
+namespace Tangram {
+struct GL {
+    static GLenum getError(void);
+    static const GLubyte* getString(GLenum name);
+
+    static void clear(GLbitfield mask);
+    static void lineWidth(GLfloat width);
+    static void viewport(GLint x, GLint y, GLsizei width, GLsizei height);
+
+    static void enable(GLenum);
+    static void disable(GLenum);
+    static void depthFunc(GLenum func);
+    static void depthMask(GLboolean flag);
+    static void depthRange(GLfloat n, GLfloat f);
+    static void clearDepth(GLfloat d);
+    static void blendFunc(GLenum sfactor, GLenum dfactor);
+    static void stencilFunc(GLenum func, GLint ref, GLuint mask);
+    static void stencilMask(GLuint mask);
+    static void stencilOp(GLenum fail, GLenum zfail, GLenum zpass);
+    static void clearStencil(GLint s);
+    static void colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha);
+    static void cullFace(GLenum mode);
+    static void frontFace(GLenum mode);
+    static void clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha);
+    static void getIntegerv(GLenum pname, GLint *params );
+
+    // Program
+    static void useProgram(GLuint program);
+    static void deleteProgram(GLuint program);
+    static void deleteShader(GLuint shader);
+    static GLuint createShader(GLenum type);
+    static GLuint createProgram();
+    static void compileShader(GLuint shader);
+    static void attachShader(GLuint program, GLuint shader);
+    static void linkProgram(GLuint program);
+    static void shaderSource(GLuint shader, GLsizei count, const GLchar** string, const GLint *length);
+    static void getShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+    static void getProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog);
+    static GLint getUniformLocation(GLuint program, const GLchar *name);
+    static GLint getAttribLocation(GLuint program, const GLchar *name);
+    static void getProgramiv(GLuint program, GLenum pname, GLint *params);
+    static void getShaderiv(GLuint shader, GLenum pname, GLint *params);
+
+    // Buffers
+    static void bindBuffer(GLenum target, GLuint buffer);
+    static void deleteBuffers(GLsizei n, const GLuint *buffers);
+    static void genBuffers(GLsizei n, GLuint *buffers);
+    static void bufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage);
+    static void bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data);
+
+    // Framebuffers
+    static void bindFramebuffer(GLenum target, GLuint framebuffer);
+    static void genFramebuffers(GLsizei n, GLuint *framebuffers);
+    static void framebufferTexture2D(GLenum target,
+                                     GLenum attachment,
+                                     GLenum textarget,
+                                     GLuint texture,
+                                     GLint level);
+
+    static void renderbufferStorage(GLenum target,
+                                    GLenum internalformat,
+                                    GLsizei width,
+                                    GLsizei height);
+
+    static void framebufferRenderbuffer(GLenum target,
+                                        GLenum attachment,
+                                        GLenum renderbuffertarget,
+                                        GLuint renderbuffer);
+
+    static void genRenderbuffers(GLsizei n, GLuint *renderbuffers);
+    static void bindRenderbuffer(GLenum target, GLuint renderbuffer);
+    static void deleteFramebuffers(GLsizei n, const GLuint *framebuffers);
+    static void deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers);
+    static GLenum checkFramebufferStatus(GLenum target);
+
+    // Texture
+    static void bindTexture(GLenum target, GLuint texture );
+    static void activeTexture(GLenum texture);
+    static void genTextures(GLsizei n, GLuint *textures );
+    static void deleteTextures(GLsizei n, const GLuint *textures);
+    static void texParameteri(GLenum target, GLenum pname, GLint param );
+    static void texImage2D(GLenum target, GLint level,
+                           GLint internalFormat,
+                           GLsizei width, GLsizei height,
+                           GLint border, GLenum format, GLenum type,
+                           const GLvoid *pixels);
+
+    static void texSubImage2D(GLenum target, GLint level,
+                              GLint xoffset, GLint yoffset,
+                              GLsizei width, GLsizei height,
+                              GLenum format, GLenum type,
+                              const GLvoid *pixels);
+
+    static void generateMipmap(GLenum target);
+
+
+    static void enableVertexAttribArray(GLuint index);
+    static void disableVertexAttribArray(GLuint index);
+    static void vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
+                                    GLsizei stride, const void *pointer);
+
+    static void drawArrays(GLenum mode, GLint first, GLsizei count );
+    static void drawElements(GLenum mode, GLsizei count,
+                             GLenum type, const GLvoid *indices );
+
+    static void uniform1f(GLint location, GLfloat v0);
+    static void uniform2f(GLint location, GLfloat v0, GLfloat v1);
+    static void uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+    static void uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+
+    static void uniform1i(GLint location, GLint v0);
+    static void uniform2i(GLint location, GLint v0, GLint v1);
+    static void uniform3i(GLint location, GLint v0, GLint v1, GLint v2);
+    static void uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+
+    static void uniform1fv(GLint location, GLsizei count, const GLfloat *value);
+    static void uniform2fv(GLint location, GLsizei count, const GLfloat *value);
+    static void uniform3fv(GLint location, GLsizei count, const GLfloat *value);
+    static void uniform4fv(GLint location, GLsizei count, const GLfloat *value);
+    static void uniform1iv(GLint location, GLsizei count, const GLint *value);
+    static void uniform2iv(GLint location, GLsizei count, const GLint *value);
+    static void uniform3iv(GLint location, GLsizei count, const GLint *value);
+    static void uniform4iv(GLint location, GLsizei count, const GLint *value);
+
+    static void uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    static void uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+    static void uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value);
+
+    // mapbuffer
+    static void *mapBuffer(GLenum target, GLenum access);
+    static GLboolean unmapBuffer(GLenum target);
+
+    static void finish(void);
+
+    static void readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+                           GLenum format, GLenum type, GLvoid* pixels);
+
+    static void bindVertexArray(GLuint array);
+    static void deleteVertexArrays(GLsizei n, const GLuint *arrays);
+    static void genVertexArrays(GLsizei n, GLuint *arrays);
+
+};
+}
diff --git a/core/src/gl/disposer.cpp b/core/src/gl/disposer.cpp
new file mode 100644 (file)
index 0000000..bc2b5dd
--- /dev/null
@@ -0,0 +1,12 @@
+#include "gl/disposer.h"
+#include "gl/renderState.h"
+
+namespace Tangram {
+
+void Disposer::operator()(std::function<void(RenderState&)> _task) {
+    if (!m_rs) { return; }
+
+    m_rs->jobQueue.add(std::bind(_task, std::ref(*m_rs)));
+}
+
+} // namespace Tangram
diff --git a/core/src/gl/disposer.h b/core/src/gl/disposer.h
new file mode 100644 (file)
index 0000000..f9c61b7
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#include <functional>
+
+namespace Tangram {
+
+class RenderState;
+
+class Disposer {
+
+public:
+
+    Disposer() : m_rs(nullptr){}
+
+    Disposer(RenderState& _rs) : m_rs(&_rs) {}
+
+    void operator()(std::function<void(RenderState&)> _task);
+
+private:
+    RenderState* m_rs = nullptr;
+};
+
+}
diff --git a/core/src/gl/dynamicQuadMesh.h b/core/src/gl/dynamicQuadMesh.h
new file mode 100644 (file)
index 0000000..11131e8
--- /dev/null
@@ -0,0 +1,190 @@
+#pragma once
+
+#include "gl/mesh.h"
+#include "gl/glError.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "gl/texture.h"
+#include "gl/hardware.h"
+#include "gl/vao.h"
+
+#include <memory>
+#include <vector>
+#include <atomic>
+
+namespace Tangram {
+
+template<class T>
+class DynamicQuadMesh : public StyledMesh, protected MeshBase {
+
+public:
+
+    DynamicQuadMesh(std::shared_ptr<VertexLayout> _vertexLayout, GLenum _drawMode)
+        : MeshBase(_vertexLayout, _drawMode, GL_DYNAMIC_DRAW) {
+    }
+
+    bool draw(RenderState& rs, ShaderProgram& _shader, bool _useVao = true) override;
+
+    // Draw the mesh while swapping textures using the given texture unit.
+    bool draw(RenderState& rs, ShaderProgram& _shader, int textureUnit, bool _useVao = true);
+
+    size_t bufferSize() const override {
+        return MeshBase::bufferSize();
+    }
+
+    void clear() {
+        // Clear vertices for next frame
+        m_nVertices = 0;
+        m_isUploaded = false;
+        m_vertices.clear();
+        m_batches.clear();
+    }
+
+    size_t numberOfVertices() const { return m_vertices.size(); }
+
+    void upload(RenderState& rs) override;
+
+    bool isReady() { return m_isUploaded; }
+
+    // Reserves space for one quad and returns pointer
+    // into m_vertices to write into 4 vertices.
+    T* pushQuad() {
+        m_nVertices += 4;
+        m_vertices.insert(m_vertices.end(), 4, {});
+        return &m_vertices[m_nVertices - 4];
+    }
+
+    // Signals that all vertices added until the next call to pushTexture
+    // are meant to be drawn with this texture. Push a nullptr to use the
+    // default point texture.
+    void pushTexture(Texture* texture);
+
+private:
+
+    struct TextureBatch {
+        TextureBatch(Texture* t, size_t s) : texture(t), startVertex(s) {}
+        Texture* texture = nullptr;
+        size_t startVertex = 0;
+    };
+
+    std::vector<T> m_vertices;
+    std::vector<TextureBatch> m_batches;
+    Vao m_vaos;
+};
+
+template<class T>
+void DynamicQuadMesh<T>::pushTexture(Texture* texture) {
+    if (m_batches.empty() || m_batches.back().texture != texture) {
+        m_batches.push_back({ texture, m_vertices.size() });
+    }
+}
+
+template<class T>
+void DynamicQuadMesh<T>::upload(RenderState& rs) {
+
+    if (m_nVertices == 0 || m_isUploaded) { return; }
+
+    // Generate vertex buffer, if needed
+    if (m_glVertexBuffer == 0) {
+        GL::genBuffers(1, &m_glVertexBuffer);
+    }
+
+    MeshBase::subDataUpload(rs, reinterpret_cast<GLbyte*>(m_vertices.data()));
+
+    m_isUploaded = true;
+}
+
+template<class T>
+bool DynamicQuadMesh<T>::draw(RenderState& rs, ShaderProgram& shader, bool useVao) {
+    return draw(rs, shader, 0, useVao);
+}
+
+template<class T>
+bool DynamicQuadMesh<T>::draw(RenderState& rs, ShaderProgram& shader, int textureUnit, bool useVao) {
+
+    if (m_nVertices == 0) { return false; }
+
+    // Enable shader program
+    if (!shader.use(rs)) {
+        return false;
+    }
+
+#ifdef DYNAMIC_MESH_VAOS
+    useVao &= Hardware::supportsVAOs;
+
+    if (useVao) {
+        // Capture vao state for a default vertex offset of 0/0
+        if (!m_vaos.isInitialized()) {
+            VertexOffsets vertexOffsets;
+            vertexOffsets.emplace_back(0, 0);
+            m_vaos.initialize(rs, shader, vertexOffsets, *m_vertexLayout,
+                              m_glVertexBuffer, rs.getQuadIndexBuffer());
+        }
+    }
+#endif
+
+    const size_t verticesIndexed = RenderState::MAX_QUAD_VERTICES;
+    size_t vertexPos = 0;
+    size_t vertexBatchEnd = 0;
+    auto textureBatch = m_batches.begin();
+
+    // Draw vertices in batches until the end of the mesh.
+    while (vertexPos < m_nVertices) {
+
+        assert(vertexPos <= vertexBatchEnd);
+
+        if (vertexPos == vertexBatchEnd) {
+            vertexBatchEnd = m_nVertices;
+
+            // Bind texture for current batch, if present. Otherwise the
+            // externally bound texture is used (E.g. by TextStyle).
+            if (textureBatch != m_batches.end()) {
+                auto tex = textureBatch->texture;
+                if (!tex) { tex = rs.getDefaultPointTexture(); }
+                tex->update(rs, textureUnit);
+                tex->bind(rs, textureUnit);
+
+                if (++textureBatch != m_batches.end()) {
+                    vertexBatchEnd = textureBatch->startVertex;
+                }
+            }
+        }
+
+        // Determine the largest batch of vertices we can draw at once,
+        // limited by either a texture swap or the max index value.
+        size_t verticesInBatch = std::min(vertexBatchEnd - vertexPos, verticesIndexed);
+
+        // Set up and draw the batch.
+#ifdef DYNAMIC_MESH_VAOS
+        if (useVao && vertexPos == 0) {
+            // Use vao only for first batch of offsets, other vertices can use a
+            // different stride so just reuse the vertex layout with a different
+            // byte offset instead
+            m_vaos.bind(0);
+        } else
+#endif
+        {
+            rs.vertexBuffer(m_glVertexBuffer);
+            rs.indexBuffer(rs.getQuadIndexBuffer());
+
+            size_t byteOffset = vertexPos * m_vertexLayout->getStride();
+            m_vertexLayout->enable(rs, shader, byteOffset);
+        }
+
+        size_t elementsInBatch = verticesInBatch * 6 / 4;
+        GL::drawElements(m_drawMode, elementsInBatch, GL_UNSIGNED_SHORT, 0);
+
+#ifdef DYNAMIC_MESH_VAOS
+        if (useVao && vertexPos == 0) {
+            m_vaos.unbind();
+        }
+#endif
+
+        // Update counters.
+        vertexPos += verticesInBatch;
+    }
+
+    return true;
+}
+
+}
diff --git a/core/src/gl/framebuffer.cpp b/core/src/gl/framebuffer.cpp
new file mode 100644 (file)
index 0000000..89c359a
--- /dev/null
@@ -0,0 +1,183 @@
+#include "gl/framebuffer.h"
+
+#include "gl/glError.h"
+#include "gl/primitives.h"
+#include "gl/renderState.h"
+#include "gl/hardware.h"
+#include "gl/texture.h"
+#include "log.h"
+#include "glm/vec2.hpp"
+
+namespace Tangram {
+
+FrameBuffer::FrameBuffer(int _width, int _height, bool _colorRenderBuffer) :
+    m_glFrameBufferHandle(0),
+    m_valid(false),
+    m_colorRenderBuffer(_colorRenderBuffer),
+    m_width(_width), m_height(_height) {
+
+}
+
+bool FrameBuffer::applyAsRenderTarget(RenderState& _rs, glm::vec4 _clearColor) {
+
+    if (!m_glFrameBufferHandle) {
+        init(_rs);
+    }
+
+    if (!m_valid) {
+        return false;
+    }
+
+    FrameBuffer::apply(_rs, m_glFrameBufferHandle, {m_width, m_height}, _clearColor);
+
+    return true;
+}
+
+void FrameBuffer::apply(RenderState& _rs, GLuint _handle, glm::vec2 _viewport, glm::vec4 _clearColor) {
+
+    _rs.framebuffer(_handle);
+    _rs.viewport(0, 0, _viewport.x, _viewport.y);
+
+    _rs.clearColor(_clearColor.r / 255.f,
+                   _clearColor.g / 255.f,
+                   _clearColor.b / 255.f,
+                   _clearColor.a / 255.f);
+
+    // Enable depth testing
+    _rs.depthMask(GL_TRUE);
+
+    // Setup raster state
+    _rs.culling(GL_TRUE);
+    _rs.cullFace(GL_BACK);
+
+    GL::clear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+}
+
+void FrameBuffer::bind(RenderState& _rs) const {
+
+    if (m_valid) {
+        _rs.framebuffer(m_glFrameBufferHandle);
+    }
+}
+
+GLuint FrameBuffer::readAt(float _normalizedX, float _normalizedY) const {
+
+    glm::vec2 position(_normalizedX * m_width, _normalizedY * m_height);
+
+    GLuint pixel;
+    GL::readPixels(floorf(position.x), floorf(position.y),
+                   1, 1, GL_RGBA, GL_UNSIGNED_BYTE, &pixel);
+
+    return pixel;
+}
+
+FrameBuffer::PixelRect FrameBuffer::readRect(float _normalizedX, float _normalizedY, float _normalizedW, float _normalizedH) const {
+
+    PixelRect rect;
+    rect.left = fminf(fmaxf(floorf(_normalizedX * m_width), 0.f), m_width);
+    rect.bottom = fminf(fmaxf(floorf(_normalizedY * m_height), 0.f), m_height);
+    rect.width = fminf(fmaxf(ceilf(_normalizedW * m_width), 0.f), m_width - rect.left);
+    rect.height = fminf(fmaxf(ceilf(_normalizedH * m_height), 0.f), m_height - rect.bottom);
+
+    rect.pixels.resize(rect.width * rect.height);
+
+    GL::readPixels(rect.left, rect.bottom, rect.width, rect.height, GL_RGBA, GL_UNSIGNED_BYTE, rect.pixels.data());
+
+    return rect;
+}
+
+void FrameBuffer::init(RenderState& _rs) {
+
+    if (!Hardware::supportsGLRGBA8OES && m_colorRenderBuffer) {
+        LOGW("Driver doesn't support GL_OES_rgb8_rgba8");
+        LOGW("Falling back to color texture attachment");
+        m_colorRenderBuffer = false;
+    }
+
+    GL::genFramebuffers(1, &m_glFrameBufferHandle);
+
+    _rs.framebuffer(m_glFrameBufferHandle);
+
+    // Setup color render target
+    if (m_colorRenderBuffer) {
+        GL::genRenderbuffers(1, &m_glColorRenderBufferHandle);
+        GL::bindRenderbuffer(GL_RENDERBUFFER, m_glColorRenderBufferHandle);
+        GL::renderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES,
+                                m_width, m_height);
+
+        GL::framebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                    GL_RENDERBUFFER, m_glColorRenderBufferHandle);
+    } else {
+        TextureOptions options =
+            {GL_RGBA, GL_RGBA,
+            {GL_NEAREST, GL_NEAREST},
+            {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE}
+        };
+
+        m_texture = std::make_unique<Texture>(m_width, m_height, options);
+        m_texture->update(_rs, 0);
+
+        GL::framebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
+                                 GL_TEXTURE_2D, m_texture->getGlHandle(), 0);
+    }
+
+    {
+        // Create depth render buffer
+        GL::genRenderbuffers(1, &m_glDepthRenderBufferHandle);
+        GL::bindRenderbuffer(GL_RENDERBUFFER, m_glDepthRenderBufferHandle);
+        GL::renderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT16,
+                                m_width, m_height);
+
+        GL::framebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT,
+                                    GL_RENDERBUFFER, m_glDepthRenderBufferHandle);
+    }
+
+    GLenum status = GL::checkFramebufferStatus(GL_FRAMEBUFFER);
+    GL_CHECK();
+
+    if (status != GL_FRAMEBUFFER_COMPLETE) {
+        LOGE("Framebuffer status is incomplete:");
+
+        switch (status) {
+            case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
+                LOGE("\tGL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
+                break;
+            case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
+                LOGE("\tGL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT");
+                break;
+            case GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS:
+                LOGE("\tGL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS");
+                break;
+            case GL_FRAMEBUFFER_UNSUPPORTED:
+                LOGE("\tGL_FRAMEBUFFER_UNSUPPORTED");
+                break;
+            default:
+                LOGE("\tUnknown framebuffer issue");
+                break;
+        }
+    } else {
+        m_valid = true;
+    }
+
+    m_disposer = Disposer(_rs);
+}
+
+FrameBuffer::~FrameBuffer() {
+
+    GLuint glHandle = m_glFrameBufferHandle;
+
+    m_disposer([=](RenderState& rs) {
+        rs.framebufferUnset(glHandle);
+
+        GL::deleteFramebuffers(1, &glHandle);
+    });
+}
+
+void FrameBuffer::drawDebug(RenderState& _rs, glm::vec2 _dim) {
+
+    if (m_texture) {
+        Primitives::drawTexture(_rs, *m_texture, glm::vec2{}, _dim);
+    }
+}
+
+}
diff --git a/core/src/gl/framebuffer.h b/core/src/gl/framebuffer.h
new file mode 100644 (file)
index 0000000..16864a6
--- /dev/null
@@ -0,0 +1,70 @@
+#pragma once
+
+#include <memory>
+#include <vector>
+
+#include "glm/vec4.hpp"
+#include "gl/disposer.h"
+#include "gl.h"
+
+namespace Tangram {
+
+class Texture;
+class RenderState;
+
+class FrameBuffer {
+
+public:
+
+    FrameBuffer(int _width, int _height, bool _colorRenderBuffer = true);
+
+    ~FrameBuffer();
+
+    bool applyAsRenderTarget(RenderState& _rs, glm::vec4 _clearColor = glm::vec4(0.0));
+
+    static void apply(RenderState& _rs, GLuint _handle, glm::vec2 _viewport, glm::vec4 _clearColor);
+
+    bool valid() const { return m_valid; }
+
+    int getWidth() const { return m_width; }
+
+    int getHeight() const { return m_height; }
+
+    void bind(RenderState& _rs) const;
+
+    GLuint readAt(float _normalizedX, float _normalizedY) const;
+
+    struct PixelRect {
+        std::vector<GLuint> pixels;
+        int32_t left = 0, bottom = 0, width = 0, height = 0;
+    };
+
+    PixelRect readRect(float _normalizedX, float _normalizedY, float _normalizedW, float _normalizedH) const;
+
+    void drawDebug(RenderState& _rs, glm::vec2 _dim);
+
+private:
+
+    void init(RenderState& _rs);
+
+    std::unique_ptr<Texture> m_texture;
+
+    Disposer m_disposer;
+
+    GLuint m_glFrameBufferHandle;
+
+    GLuint m_glDepthRenderBufferHandle;
+
+    GLuint m_glColorRenderBufferHandle;
+
+    bool m_valid;
+
+    bool m_colorRenderBuffer;
+
+    int m_width;
+
+    int m_height;
+
+};
+
+}
diff --git a/core/src/gl/glError.cpp b/core/src/gl/glError.cpp
new file mode 100644 (file)
index 0000000..c36e1d8
--- /dev/null
@@ -0,0 +1,45 @@
+#include "gl/glError.h"
+#include "log.h"
+
+namespace Tangram {
+
+std::unordered_map<GLenum, std::string> GLError::s_GlErrorCodesToStrings = {
+        {GL_NO_ERROR, "GL_NO_ERROR"},
+        {GL_INVALID_ENUM, "GL_INVALID_ENUM"},
+        {GL_INVALID_VALUE, "GL_INVALID_VALUE"},
+        {GL_INVALID_OPERATION, "GL_INVALID_OPERATION"},
+        {GL_OUT_OF_MEMORY, "GL_OUT_OF_MEMORY"},
+        {GL_INVALID_FRAMEBUFFER_OPERATION, "GL_INVALID_FRAMEBUFFER_OPERATION"}
+    };
+
+bool GLError::hadError(const std::string& _locationTag) {
+
+    GLenum error = GL::getError();
+
+    if (error != GL_NO_ERROR) {
+
+        std::string errorString = s_GlErrorCodesToStrings[error];
+
+        LOGE("%s at %s", errorString.c_str(), _locationTag.c_str());
+
+        return true;
+    }
+
+    return false;
+}
+
+void GLError::error(const char* stmt, const char* fname, int line) {
+    GLenum err = GL::getError();
+
+    while (err != GL_NO_ERROR) {
+        auto it = s_GlErrorCodesToStrings.find(err);
+
+        if (it != s_GlErrorCodesToStrings.end()) {
+            LOGE("OpenGL error %s, at %s:%i - for %s\n", it->second.c_str(), fname, line, stmt);
+        }
+
+        err = GL::getError();
+    }
+}
+
+}
diff --git a/core/src/gl/glError.h b/core/src/gl/glError.h
new file mode 100644 (file)
index 0000000..b3a0edb
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "gl.h"
+#include <string>
+#include <unordered_map>
+
+namespace Tangram {
+
+class GLError {
+
+public:
+
+    /*
+     * hadGlError - checks OpenGL for any recorded errors. If no errors are found, it returns false.
+     * If an error is found, it prints the GL error enum combined with the location tag passed in,
+     * then returns true. This is intended to be used infrequently, in places where errors are likely or known.
+     */
+    static bool hadError(const std::string& _locationTag);
+
+    static void error(const char* stmt, const char* fname, int line);
+
+private:
+
+    static std::unordered_map<GLenum, std::string> s_GlErrorCodesToStrings;
+
+};
+
+#ifdef DEBUG
+#define GL_CHECK(STMT) do { STMT; Tangram::GLError::error(#STMT, __FILE__, __LINE__); } while (0)
+#else
+#define GL_CHECK(STMT) do { STMT; } while (0)
+#endif
+
+}
diff --git a/core/src/gl/hardware.cpp b/core/src/gl/hardware.cpp
new file mode 100644 (file)
index 0000000..bdb2325
--- /dev/null
@@ -0,0 +1,82 @@
+#include "gl/hardware.h"
+
+#include "gl.h"
+#include "log.h"
+#include "platform.h"
+
+#include <cstring>
+#include <sstream>
+#include <algorithm>
+#include <iterator>
+
+namespace Tangram {
+namespace Hardware {
+
+bool supportsMapBuffer = false;
+bool supportsVAOs = false;
+bool supportsTextureNPOT = false;
+bool supportsGLRGBA8OES = false;
+
+uint32_t maxTextureSize = 0;
+uint32_t maxCombinedTextureUnits = 0;
+static char* s_glExtensions;
+
+bool isAvailable(std::string _extension) {
+    return bool(s_glExtensions)
+      ? strstr(s_glExtensions, _extension.c_str()) != nullptr
+      : false;
+}
+
+void printAvailableExtensions() {
+    if (s_glExtensions == NULL) {
+        LOGW("Extensions string is NULL");
+        return;
+    }
+
+    std::string exts(s_glExtensions);
+    std::stringstream ss(exts);
+
+    ss >> std::noskipws;
+    std::string extension;
+    LOGD("GL Extensions available: ");
+    while (std::getline(ss, extension, ' ')) {
+        LOGD("\t - %s", extension.c_str());
+    }
+}
+
+void loadExtensions() {
+    s_glExtensions = (char*) GL::getString(GL_EXTENSIONS);
+
+    if (s_glExtensions == NULL) {
+        LOGE("glGetString( GL_EXTENSIONS ) returned NULL");
+        return;
+    }
+
+    supportsMapBuffer = isAvailable("mapbuffer");
+    supportsVAOs = isAvailable("vertex_array_object");
+    supportsTextureNPOT = isAvailable("texture_non_power_of_two");
+    supportsGLRGBA8OES = isAvailable("rgb8_rgba8");
+
+    LOG("Driver supports map buffer: %d", supportsMapBuffer);
+    LOG("Driver supports vaos: %d", supportsVAOs);
+    LOG("Driver supports rgb8_rgba8: %d", supportsGLRGBA8OES);
+    LOG("Driver supports NPOT texture: %d", supportsTextureNPOT);
+
+    // find extension symbols if needed
+    initGLExtensions();
+}
+
+void loadCapabilities() {
+    int val;
+    GL::getIntegerv(GL_MAX_TEXTURE_SIZE, &val);
+    maxTextureSize = val;
+
+    GL::getIntegerv(GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS, &val);
+    maxCombinedTextureUnits = val;
+
+    LOG("Hardware max texture size %d", maxTextureSize);
+    LOG("Hardware max combined texture units %d", maxCombinedTextureUnits);
+}
+
+}
+}
diff --git a/core/src/gl/hardware.h b/core/src/gl/hardware.h
new file mode 100644 (file)
index 0000000..21aef16
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <string>
+
+namespace Tangram {
+namespace Hardware {
+
+extern bool supportsMapBuffer;
+extern bool supportsVAOs;
+extern bool supportsTextureNPOT;
+extern bool supportsGLRGBA8OES;
+extern uint32_t maxTextureSize;
+extern uint32_t maxCombinedTextureUnits;
+
+void loadCapabilities();
+void loadExtensions();
+bool isAvailable(std::string _extension);
+void printAvailableExtensions();
+
+}
+}
diff --git a/core/src/gl/mesh.cpp b/core/src/gl/mesh.cpp
new file mode 100644 (file)
index 0000000..f4a9393
--- /dev/null
@@ -0,0 +1,286 @@
+#include "gl/mesh.h"
+#include "gl/shaderProgram.h"
+#include "gl/renderState.h"
+#include "gl/hardware.h"
+#include "gl/glError.h"
+#include "platform.h"
+#include "log.h"
+
+namespace Tangram {
+
+
+MeshBase::MeshBase() {
+    m_drawMode = GL_TRIANGLES;
+    m_hint = GL_STATIC_DRAW;
+    m_glVertexBuffer = 0;
+    m_glIndexBuffer = 0;
+    m_nVertices = 0;
+    m_nIndices = 0;
+    m_dirtyOffset = 0;
+    m_dirtySize = 0;
+
+    m_dirty = false;
+    m_isUploaded = false;
+    m_isCompiled = false;
+}
+
+MeshBase::MeshBase(std::shared_ptr<VertexLayout> _vertexLayout, GLenum _drawMode, GLenum _hint)
+    : MeshBase()
+{
+    m_vertexLayout = _vertexLayout;
+    m_hint = _hint;
+
+    setDrawMode(_drawMode);
+}
+
+MeshBase::~MeshBase() {
+
+    auto vaos = m_vaos;
+    auto glVertexBuffer = m_glVertexBuffer;
+    auto glIndexBuffer = m_glIndexBuffer;
+
+    m_disposer([=](RenderState& rs) mutable {
+        // Deleting a index/array buffer being used ends up setting up the current vertex/index buffer to 0
+        // after the driver finishes using it, force the render state to be 0 for vertex/index buffer
+        if (glVertexBuffer) {
+            rs.vertexBufferUnset(glVertexBuffer);
+            GL::deleteBuffers(1, &glVertexBuffer);
+        }
+        if (glIndexBuffer) {
+            rs.indexBufferUnset(glIndexBuffer);
+            GL::deleteBuffers(1, &glIndexBuffer);
+        }
+        vaos.dispose();
+    });
+
+
+    if (m_glVertexData) {
+        delete[] m_glVertexData;
+    }
+
+    if (m_glIndexData) {
+        delete[] m_glIndexData;
+    }
+
+}
+
+void MeshBase::setVertexLayout(std::shared_ptr<VertexLayout> _vertexLayout) {
+    m_vertexLayout = _vertexLayout;
+}
+
+void MeshBase::setDrawMode(GLenum _drawMode) {
+    switch (_drawMode) {
+        case GL_POINTS:
+        case GL_LINE_STRIP:
+        case GL_LINE_LOOP:
+        case GL_LINES:
+        case GL_TRIANGLE_STRIP:
+        case GL_TRIANGLE_FAN:
+        case GL_TRIANGLES:
+            m_drawMode = _drawMode;
+            break;
+        default:
+            LOGW("Invalid draw mode for mesh! Defaulting to GL_TRIANGLES");
+            m_drawMode = GL_TRIANGLES;
+    }
+}
+
+void MeshBase::subDataUpload(RenderState& rs, GLbyte* _data) {
+
+    if (!m_dirty && _data == nullptr) { return; }
+
+    if (m_hint == GL_STATIC_DRAW) {
+        LOGW("Wrong usage hint provided to the Vbo");
+        assert(false);
+    }
+
+    GLbyte* data = _data ? _data : m_glVertexData;
+
+    rs.vertexBuffer(m_glVertexBuffer);
+
+    long vertexBytes = m_nVertices * m_vertexLayout->getStride();
+
+    // invalidate/orphane the data store on the driver
+    GL::bufferData(GL_ARRAY_BUFFER, vertexBytes, NULL, m_hint);
+
+    if (Hardware::supportsMapBuffer) {
+        GLvoid* dataStore = GL::mapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+        // write memory client side
+        std::memcpy(dataStore, data, vertexBytes);
+
+        GL::unmapBuffer(GL_ARRAY_BUFFER);
+    } else {
+
+        // if this buffer is still used by gpu on current frame this call will not wait
+        // for the frame to finish using the vbo but "directly" send command to upload the data
+        GL::bufferData(GL_ARRAY_BUFFER, vertexBytes, data, m_hint);
+    }
+
+    m_dirty = false;
+}
+
+void MeshBase::upload(RenderState& rs) {
+
+    // Generate vertex buffer, if needed
+    if (m_glVertexBuffer == 0) {
+        GL::genBuffers(1, &m_glVertexBuffer);
+    }
+
+    // Buffer vertex data
+    int vertexBytes = m_nVertices * m_vertexLayout->getStride();
+
+    rs.vertexBuffer(m_glVertexBuffer);
+    GL::bufferData(GL_ARRAY_BUFFER, vertexBytes, m_glVertexData, m_hint);
+
+    delete[] m_glVertexData;
+    m_glVertexData = nullptr;
+
+    if (m_glIndexData) {
+
+        if (m_glIndexBuffer == 0) {
+            GL::genBuffers(1, &m_glIndexBuffer);
+        }
+
+        // Buffer element index data
+        rs.indexBuffer(m_glIndexBuffer);
+
+        GL::bufferData(GL_ELEMENT_ARRAY_BUFFER, m_nIndices * sizeof(GLushort), m_glIndexData, m_hint);
+
+        delete[] m_glIndexData;
+        m_glIndexData = nullptr;
+    }
+
+    m_disposer = Disposer(rs);
+
+    m_isUploaded = true;
+}
+
+bool MeshBase::draw(RenderState& rs, ShaderProgram& _shader, bool _useVao) {
+    bool useVao = _useVao && Hardware::supportsVAOs;
+
+    if (!m_isCompiled) { return false; }
+    if (m_nVertices == 0) { return false; }
+
+    // Enable shader program
+    if (!_shader.use(rs)) {
+        return false;
+    }
+
+    // Ensure that geometry is buffered into GPU
+    if (!m_isUploaded) {
+        upload(rs);
+    } else if (m_dirty) {
+        subDataUpload(rs);
+    }
+
+    if (useVao) {
+        if (!m_vaos.isInitialized()) {
+            // Capture vao state
+            m_vaos.initialize(rs, _shader, m_vertexOffsets, *m_vertexLayout, m_glVertexBuffer, m_glIndexBuffer);
+        }
+    } else {
+        // Bind buffers for drawing
+        rs.vertexBuffer(m_glVertexBuffer);
+
+        if (m_nIndices > 0) {
+            rs.indexBuffer(m_glIndexBuffer);
+        }
+    }
+
+    size_t indiceOffset = 0;
+    size_t vertexOffset = 0;
+
+    for (size_t i = 0; i < m_vertexOffsets.size(); ++i) {
+        auto& o = m_vertexOffsets[i];
+        uint32_t nIndices = o.first;
+        uint32_t nVertices = o.second;
+
+        if (!useVao) {
+            // Enable vertex attribs via vertex layout object
+            size_t byteOffset = vertexOffset * m_vertexLayout->getStride();
+            m_vertexLayout->enable(rs,  _shader, byteOffset);
+        } else {
+            // Bind the corresponding vao relative to the current offset
+            m_vaos.bind(i);
+        }
+
+        // Draw as elements or arrays
+        if (nIndices > 0) {
+            GL::drawElements(m_drawMode, nIndices, GL_UNSIGNED_SHORT,
+                             (void*)(indiceOffset * sizeof(GLushort)));
+        } else if (nVertices > 0) {
+            GL::drawArrays(m_drawMode, 0, nVertices);
+        }
+
+        vertexOffset += nVertices;
+        indiceOffset += nIndices;
+    }
+
+    if (useVao) {
+        m_vaos.unbind();
+    }
+
+    return true;
+}
+
+size_t MeshBase::bufferSize() const {
+    return m_nVertices * m_vertexLayout->getStride() + m_nIndices * sizeof(GLushort);
+}
+
+// Add indices by collecting them into batches to draw as much as
+// possible in one draw call.  The indices must be shifted by the
+// number of vertices that are present in the current batch.
+size_t MeshBase::compileIndices(const std::vector<std::pair<uint32_t, uint32_t>>& _offsets,
+                                const std::vector<uint16_t>& _indices, size_t _offset) {
+
+
+    GLushort* dst = m_glIndexData + _offset;
+    size_t curVertices = 0;
+    size_t src = 0;
+
+    if (m_vertexOffsets.empty()) {
+        m_vertexOffsets.emplace_back(0, 0);
+    } else {
+        curVertices = m_vertexOffsets.back().second;
+    }
+
+    for (auto& p : _offsets) {
+        size_t nIndices = p.first;
+        size_t nVertices = p.second;
+
+        if (curVertices + nVertices > MAX_INDEX_VALUE) {
+            m_vertexOffsets.emplace_back(0, 0);
+            curVertices = 0;
+        }
+        for (size_t i = 0; i < nIndices; i++, dst++) {
+            *dst = _indices[src++] + curVertices;
+        }
+
+        auto& offset = m_vertexOffsets.back();
+        offset.first += nIndices;
+        offset.second += nVertices;
+
+        curVertices += nVertices;
+    }
+
+    return _offset + src;
+}
+
+void MeshBase::setDirty(GLintptr _byteOffset, GLsizei _byteSize) {
+
+    if (!m_dirty) {
+        m_dirty = true;
+
+        m_dirtySize = _byteSize;
+        m_dirtyOffset = _byteOffset;
+
+    } else {
+        size_t end = std::max(m_dirtyOffset + m_dirtySize, _byteOffset + _byteSize);
+
+        m_dirtyOffset = std::min(m_dirtyOffset, _byteOffset);
+        m_dirtySize = end - m_dirtyOffset;
+    }
+}
+
+}
diff --git a/core/src/gl/mesh.h b/core/src/gl/mesh.h
new file mode 100644 (file)
index 0000000..c318e3a
--- /dev/null
@@ -0,0 +1,299 @@
+#pragma once
+
+#include "gl.h"
+#include "gl/disposer.h"
+#include "gl/vertexLayout.h"
+#include "gl/vao.h"
+#include "style/style.h"
+#include "util/types.h"
+#include "platform.h"
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <cstring> // for memcpy
+#include <cassert>
+
+#define MAX_INDEX_VALUE 65535 // Maximum value of GLushort
+
+namespace Tangram {
+
+/*
+ * Mesh - Drawable collection of geometry contained in a vertex buffer and
+ * (optionally) an index buffer
+ */
+struct MeshBase {
+public:
+    /*
+     * Creates a Mesh for vertex data arranged in the structure described by
+     * _vertexLayout to be drawn using the OpenGL primitive type _drawMode
+     */
+    MeshBase(std::shared_ptr<VertexLayout> _vertexlayout, GLenum _drawMode = GL_TRIANGLES,
+             GLenum _hint = GL_STATIC_DRAW);
+
+    MeshBase();
+
+    MeshBase(const MeshBase&) = delete;
+    MeshBase(MeshBase&&) = delete;
+    MeshBase& operator=(const MeshBase&) = delete;
+    MeshBase& operator=(MeshBase&&) = delete;
+
+    virtual ~MeshBase();
+
+    /*
+     * Set Vertex Layout for the mesh object
+     */
+    void setVertexLayout(std::shared_ptr<VertexLayout> _vertexLayout);
+
+    /*
+     * Set Draw mode for the mesh object
+     */
+    void setDrawMode(GLenum _drawMode = GL_TRIANGLES);
+
+    /*
+     * Releases all OpenGL resources for this mesh
+     */
+    void dispose(RenderState& rs);
+
+    /*
+     * Copies all added vertices and indices into OpenGL buffer objects; After
+     * geometry is uploaded, no more vertices or indices can be added
+     */
+    virtual void upload(RenderState& rs);
+
+    /*
+     * Sub data upload of the mesh, returns true if this results in a buffer binding
+     */
+    void subDataUpload(RenderState& rs, GLbyte* _data = nullptr);
+
+    /*
+     * Renders the geometry in this mesh using the ShaderProgram _shader; if
+     * geometry has not already been uploaded it will be uploaded at this point
+     */
+    bool draw(RenderState& rs, ShaderProgram& _shader, bool _useVao = true);
+
+    size_t bufferSize() const;
+
+protected:
+
+    // Used in draw for legth and offsets: sumIndices, sumVertices
+    // needs to be set by compile()
+    std::vector<std::pair<uint32_t, uint32_t>> m_vertexOffsets;
+
+    std::shared_ptr<VertexLayout> m_vertexLayout;
+
+    size_t m_nVertices;
+    GLuint m_glVertexBuffer;
+
+    Vao m_vaos;
+
+    // Compiled vertices for upload
+    GLbyte* m_glVertexData = nullptr;
+
+    size_t m_nIndices;
+    GLuint m_glIndexBuffer;
+    // Compiled  indices for upload
+    GLushort* m_glIndexData = nullptr;
+
+    GLenum m_drawMode;
+    GLenum m_hint;
+
+    bool m_isUploaded;
+    bool m_isCompiled;
+    bool m_dirty;
+
+    GLsizei m_dirtySize;
+    GLintptr m_dirtyOffset;
+
+    Disposer m_disposer;
+
+    size_t compileIndices(const std::vector<std::pair<uint32_t, uint32_t>>& _offsets,
+                          const std::vector<uint16_t>& _indices, size_t _offset);
+
+    void setDirty(GLintptr _byteOffset, GLsizei _byteSize);
+};
+
+template<class T>
+struct MeshData {
+
+    MeshData() {}
+    MeshData(std::vector<uint16_t>&& _indices, std::vector<T>&& _vertices)
+        : indices(std::move(_indices)),
+          vertices(std::move(_vertices)) {
+        offsets.emplace_back(indices.size(), vertices.size());
+    }
+
+    std::vector<uint16_t> indices;
+    std::vector<T> vertices;
+    std::vector<std::pair<uint32_t, uint32_t>> offsets;
+
+    void clear() {
+        offsets.clear();
+        indices.clear();
+        vertices.clear();
+    }
+};
+
+template<class T>
+class Mesh : public StyledMesh, protected MeshBase {
+public:
+
+    Mesh(std::shared_ptr<VertexLayout> _vertexLayout, GLenum _drawMode,
+         GLenum _hint = GL_STATIC_DRAW)
+        : MeshBase(_vertexLayout, _drawMode, _hint) {};
+
+    virtual ~Mesh() {}
+
+    size_t bufferSize() const override {
+        return MeshBase::bufferSize();
+    }
+
+    bool draw(RenderState& rs, ShaderProgram& shader, bool useVao = true) override {
+        return MeshBase::draw(rs, shader, useVao);
+    }
+
+    void compile(const std::vector<MeshData<T>>& _meshes);
+
+    void compile(const MeshData<T>& _mesh);
+
+    /*
+     * Update _nVerts vertices in the mesh with the new T value _newVertexValue
+     * starting after _byteOffset in the mesh vertex data memory
+     */
+    void updateVertices(Range _vertexRange, const T& _newVertexValue);
+
+    /*
+     * Update _nVerts vertices in the mesh with the new attribute A
+     * _newAttributeValue starting after _byteOffset in the mesh vertex data
+     * memory
+     */
+    template<class A>
+    void updateAttribute(Range _vertexRange, const A& _newAttributeValue,
+                         size_t _attribOffset = 0);
+};
+
+
+template<class T>
+void Mesh<T>::compile(const std::vector<MeshData<T>>& _meshes) {
+
+    m_nVertices = 0;
+    m_nIndices = 0;
+
+    for (auto& m : _meshes) {
+        m_nVertices += m.vertices.size();
+        m_nIndices += m.indices.size();
+    }
+
+    int stride = m_vertexLayout->getStride();
+    m_glVertexData = new GLbyte[m_nVertices * stride];
+
+    size_t offset = 0;
+    for (auto& m : _meshes) {
+        size_t nBytes = m.vertices.size() * stride;
+        std::memcpy(m_glVertexData + offset,
+                    (const GLbyte*)m.vertices.data(),
+                    nBytes);
+
+        offset += nBytes;
+    }
+
+    assert(offset == m_nVertices * stride);
+
+    if (m_nIndices > 0) {
+        m_glIndexData = new GLushort[m_nIndices];
+
+        size_t offset = 0;
+        for (auto& m : _meshes) {
+            offset = compileIndices(m.offsets, m.indices, offset);
+        }
+        assert(offset == m_nIndices);
+    }
+
+    m_isCompiled = true;
+}
+
+template<class T>
+void Mesh<T>::compile(const MeshData<T>& _mesh) {
+
+    m_nVertices = _mesh.vertices.size();
+    m_nIndices = _mesh.indices.size();
+
+    int stride = m_vertexLayout->getStride();
+    m_glVertexData = new GLbyte[m_nVertices * stride];
+
+    std::memcpy(m_glVertexData,
+                (const GLbyte*)_mesh.vertices.data(),
+                m_nVertices * stride);
+
+    if (m_nIndices > 0) {
+        m_glIndexData = new GLushort[m_nIndices];
+        compileIndices(_mesh.offsets, _mesh.indices, 0);
+    }
+
+    m_isCompiled = true;
+}
+
+template<class T>
+template<class A>
+void Mesh<T>::updateAttribute(Range _vertexRange, const A& _newAttributeValue,
+                              size_t _attribOffset) {
+
+    if (m_glVertexData == nullptr) {
+        assert(false);
+        return;
+    }
+
+    const size_t aSize = sizeof(A);
+    const size_t tSize = sizeof(T);
+    static_assert(aSize <= tSize, "Invalid attribute size");
+
+    if (_vertexRange.start < 0 || _vertexRange.length < 1) {
+        return;
+    }
+    if (size_t(_vertexRange.start + _vertexRange.length) > m_nVertices) {
+        //LOGW("Invalid range");
+        return;
+    }
+    if (_attribOffset >= tSize) {
+        //LOGW("Invalid attribute offset");
+        return;
+    }
+
+    size_t start = _vertexRange.start * tSize + _attribOffset;
+    size_t end = start + _vertexRange.length * tSize;
+
+    // update the vertices attributes
+    for (size_t offset = start; offset < end; offset += tSize) {
+        std::memcpy(m_glVertexData + offset, &_newAttributeValue, aSize);
+    }
+
+    // set all modified vertices dirty
+    setDirty(start, (_vertexRange.length - 1) * tSize + aSize);
+}
+
+template<class T>
+void Mesh<T>::updateVertices(Range _vertexRange, const T& _newVertexValue) {
+    if (m_glVertexData == nullptr) {
+        assert(false);
+        return;
+    }
+
+    size_t tSize = sizeof(T);
+
+    if (_vertexRange.start + _vertexRange.length > int(m_nVertices)) {
+        return;
+    }
+
+
+    size_t start = _vertexRange.start * tSize;
+    size_t end = start + _vertexRange.length * tSize;
+
+    // update the vertices
+    for (size_t offset = start; offset < end; offset += tSize) {
+        std::memcpy(m_glVertexData + offset, &_newVertexValue, tSize);
+    }
+
+    setDirty(start, end - start);
+}
+
+}
diff --git a/core/src/gl/primitives.cpp b/core/src/gl/primitives.cpp
new file mode 100644 (file)
index 0000000..da262f4
--- /dev/null
@@ -0,0 +1,181 @@
+#include "primitives.h"
+
+#include "glm/mat4x4.hpp"
+#include "glm/gtc/matrix_transform.hpp"
+#include "gl/glError.h"
+#include "gl/shaderProgram.h"
+#include "gl/vertexLayout.h"
+#include "gl/renderState.h"
+#include "gl/texture.h"
+#include "log.h"
+
+#include "debugPrimitive_vs.h"
+#include "debugPrimitive_fs.h"
+
+#include "debugTexture_vs.h"
+#include "debugTexture_fs.h"
+
+namespace Tangram {
+
+namespace Primitives {
+
+static bool s_initialized;
+static std::unique_ptr<ShaderProgram> s_shader;
+static std::unique_ptr<VertexLayout> s_layout;
+
+static UniformLocation s_uColor{"u_color"};
+static UniformLocation s_uProj{"u_proj"};
+
+
+static std::unique_ptr<ShaderProgram> s_textureShader;
+static std::unique_ptr<VertexLayout> s_textureLayout;
+
+static UniformLocation s_uTextureProj{"u_proj"};
+
+void init() {
+
+    // lazy init
+    if (!s_initialized) {
+        s_shader = std::make_unique<ShaderProgram>();
+
+        s_shader->setShaderSource(SHADER_SOURCE(debugPrimitive_vs),
+                                  SHADER_SOURCE(debugPrimitive_fs));
+
+        s_layout = std::unique_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 2, GL_FLOAT, false, 0},
+        }));
+
+
+        s_textureShader = std::make_unique<ShaderProgram>();
+
+        s_textureShader->setShaderSource(SHADER_SOURCE(debugTexture_vs),
+                                         SHADER_SOURCE(debugTexture_fs));
+
+        s_textureLayout = std::unique_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 2, GL_FLOAT, false, 0},
+            {"a_uv", 2, GL_FLOAT, false, 0},
+        }));
+
+
+        s_initialized = true;
+        GL::lineWidth(1.5f);
+    }
+}
+
+void deinit() {
+
+    s_shader.reset(nullptr);
+    s_layout.reset(nullptr);
+    s_textureShader.reset(nullptr);
+    s_textureLayout.reset(nullptr);
+    s_initialized = false;
+
+}
+
+void drawLine(RenderState& rs, const glm::vec2& _origin, const glm::vec2& _destination) {
+
+    init();
+
+    glm::vec2 verts[2] = {
+        glm::vec2(_origin.x, _origin.y),
+        glm::vec2(_destination.x, _destination.y)
+    };
+
+    if (!s_shader->use(rs)) { return; }
+
+    GLint boundBuffer;
+    GL::getIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
+    rs.vertexBuffer(0);
+    rs.depthTest(GL_FALSE);
+
+    // enable the layout for the line vertices
+    s_layout->enable(rs, *s_shader, 0, &verts);
+
+    GL::drawArrays(GL_LINES, 0, 2);
+
+    rs.vertexBuffer(boundBuffer);
+}
+
+void drawRect(RenderState& rs, const glm::vec2& _origin, const glm::vec2& _destination) {
+    drawLine(rs, _origin, {_destination.x, _origin.y});
+    drawLine(rs, {_destination.x, _origin.y}, _destination);
+    drawLine(rs, _destination, {_origin.x, _destination.y});
+    drawLine(rs, {_origin.x,_destination.y}, _origin);
+}
+
+void drawPoly(RenderState& rs, const glm::vec2* _polygon, size_t _n) {
+    init();
+
+    if (!s_shader->use(rs)) { return; }
+
+    GLint boundBuffer;
+    GL::getIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
+    rs.vertexBuffer(0);
+    rs.depthTest(GL_FALSE);
+
+    // enable the layout for the _polygon vertices
+    s_layout->enable(rs, *s_shader, 0, (void*)_polygon);
+
+    GL::drawArrays(GL_LINE_LOOP, 0, _n);
+
+    rs.vertexBuffer(boundBuffer);
+}
+
+void drawTexture(RenderState& rs, Texture& _tex, glm::vec2 _pos, glm::vec2 _dim) {
+    init();
+
+    if (!s_textureShader->use(rs)) { return; }
+
+    GLint boundBuffer;
+    GL::getIntegerv(GL_ARRAY_BUFFER_BINDING, &boundBuffer);
+    rs.vertexBuffer(0);
+    rs.depthTest(GL_FALSE);
+
+    float w = _tex.getWidth();
+    float h = _tex.getHeight();
+
+    if (_dim != glm::vec2(0)) {
+        w = _dim.x;
+        h = _dim.y;
+    }
+    glm::vec4 vertices[6] = {
+        {_pos.x, _pos.y, 0, 1},
+        {_pos.x, _pos.y + h, 0, 0},
+        {_pos.x + w, _pos.y, 1, 1},
+
+        {_pos.x + w, _pos.y, 1, 1},
+        {_pos.x, _pos.y + h, 0, 0},
+        {_pos.x + w, _pos.y + h, 1, 0},
+    };
+
+    _tex.bind(rs, 0);
+
+    // enable the layout for the _polygon vertices
+    s_textureLayout->enable(rs, *s_textureShader, 0, (void*)vertices);
+
+    GL::drawArrays(GL_TRIANGLES, 0, 6);
+
+    rs.vertexBuffer(boundBuffer);
+}
+
+void setColor(RenderState& rs, unsigned int _color) {
+    init();
+
+    float r = (_color >> 16 & 0xff) / 255.0;
+    float g = (_color >> 8  & 0xff) / 255.0;
+    float b = (_color       & 0xff) / 255.0;
+
+    s_shader->setUniformf(rs, s_uColor, r, g, b);
+}
+
+void setResolution(RenderState& rs, float _width, float _height) {
+    init();
+
+    glm::mat4 proj = glm::ortho(0.f, _width, _height, 0.f, -1.f, 1.f);
+    s_shader->setUniformMatrix4f(rs, s_uProj, proj);
+    s_textureShader->setUniformMatrix4f(rs, s_uTextureProj, proj);
+}
+
+}
+
+}
diff --git a/core/src/gl/primitives.h b/core/src/gl/primitives.h
new file mode 100644 (file)
index 0000000..1e3388e
--- /dev/null
@@ -0,0 +1,34 @@
+#pragma once
+
+#include "glm/vec2.hpp"
+
+namespace Tangram {
+
+class RenderState;
+class Texture;
+
+namespace Primitives {
+
+void init();
+void deinit();
+
+/* Setup the debug resolution size */
+void setResolution(RenderState& rs, float _width, float _height);
+
+/* Sets the current primitive color */
+void setColor(RenderState& rs, unsigned int _color);
+
+/* Draws a line from _origin to _destination for the screen resolution _resolution */
+void drawLine(RenderState& rs, const glm::vec2& _origin, const glm::vec2& _destination);
+
+/* Draws a rect from _origin to _destination for the screen resolution _resolution */
+void drawRect(RenderState& rs, const glm::vec2& _origin, const glm::vec2& _destination);
+
+/* Draws a polyon of containing _n points in screen space for the screen resolution _resolution */
+void drawPoly(RenderState& rs, const glm::vec2* _polygon, size_t _n);
+
+void drawTexture(RenderState& rs, Texture& _tex, glm::vec2 _pos, glm::vec2 _dim);
+
+}
+
+}
diff --git a/core/src/gl/renderState.cpp b/core/src/gl/renderState.cpp
new file mode 100644 (file)
index 0000000..9088b68
--- /dev/null
@@ -0,0 +1,397 @@
+#include "gl/renderState.h"
+
+#include "gl/vertexLayout.h"
+#include "gl/glError.h"
+#include "gl/hardware.h"
+#include "gl/texture.h"
+#include "log.h"
+#include "platform.h"
+
+// Default point texture data is included as an array literal.
+#include "defaultPointTextureData.h"
+
+#include <limits>
+
+namespace Tangram {
+
+RenderState::RenderState() {
+
+    m_blending = { 0, false };
+    m_culling = { 0, false };
+    m_depthMask = { 0, false };
+    m_depthTest = { 0, false };
+    m_stencilTest = { 0, false };
+    m_blendingFunc = { 0, 0, false };
+    m_stencilMask = { 0, false };
+    m_stencilFunc = { 0, 0, 0, false };
+    m_stencilOp = { 0, 0, 0, false };
+    m_colorMask = { 0, 0, 0, 0, false };
+    m_frontFace = { 0, false };
+    m_cullFace = { 0, false };
+    m_vertexBuffer = { 0, false };
+    m_indexBuffer = { 0, false };
+    m_program = { 0, false };
+    m_clearColor = { 0., 0., 0., 0., false };
+    m_texture = { 0, 0, false };
+    m_textureUnit = { 0, false };
+    m_framebuffer = { 0, false };
+    m_viewport = { 0, 0, 0, 0, false };
+
+}
+
+GLuint RenderState::getTextureUnit(GLuint _unit) {
+    return GL_TEXTURE0 + _unit;
+}
+
+RenderState::~RenderState() {
+
+    deleteQuadIndexBuffer();
+    deleteDefaultPointTexture();
+
+    for (auto& s : vertexShaders) {
+        GL::deleteShader(s.second);
+    }
+    vertexShaders.clear();
+
+    for (auto& s : fragmentShaders) {
+        GL::deleteShader(s.second);
+    }
+    fragmentShaders.clear();
+}
+
+void RenderState::invalidate() {
+
+    m_blending.set = false;
+    m_blendingFunc.set = false;
+    m_clearColor.set = false;
+    m_colorMask.set = false;
+    m_cullFace.set = false;
+    m_culling.set = false;
+    m_depthTest.set = false;
+    m_depthMask.set = false;
+    m_frontFace.set = false;
+    m_stencilTest.set = false;
+    m_stencilMask.set = false;
+    m_program.set = false;
+    m_indexBuffer.set = false;
+    m_vertexBuffer.set = false;
+    m_texture.set = false;
+    m_textureUnit.set = false;
+    m_viewport.set = false;
+    m_framebuffer.set = false;
+
+    attributeBindings.fill(0);
+
+    GL::depthFunc(GL_LESS);
+    GL::clearDepth(1.0);
+    GL::depthRange(0.0, 1.0);
+
+    // No need to delete shaders after context loss
+    vertexShaders.clear();
+    fragmentShaders.clear();
+}
+
+void RenderState::cacheDefaultFramebuffer() {
+    GL::getIntegerv(GL_FRAMEBUFFER_BINDING, &m_defaultFramebuffer);
+}
+
+int RenderState::nextAvailableTextureUnit() {
+    if (m_nextTextureUnit >= Hardware::maxCombinedTextureUnits) {
+        LOGE("Too many combined texture units are being used");
+        LOGE("GPU supports %d combined texture units", Hardware::maxCombinedTextureUnits);
+    }
+
+    return ++m_nextTextureUnit;
+}
+
+void RenderState::releaseTextureUnit() {
+    m_nextTextureUnit--;
+}
+
+int RenderState::currentTextureUnit() {
+    return m_nextTextureUnit;
+}
+
+void RenderState::resetTextureUnit() {
+    m_nextTextureUnit = 0;
+}
+
+inline void setGlFlag(GLenum flag, GLboolean enable) {
+    if (enable) {
+        GL::enable(flag);
+    } else {
+        GL::disable(flag);
+    }
+}
+
+bool RenderState::blending(GLboolean enable) {
+    if (!m_blending.set || m_blending.enabled != enable) {
+        m_blending = { enable, true };
+        setGlFlag(GL_BLEND, enable);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::blendingFunc(GLenum sfactor, GLenum dfactor) {
+    if (!m_blendingFunc.set || m_blendingFunc.sfactor != sfactor || m_blendingFunc.dfactor != dfactor) {
+        m_blendingFunc = { sfactor, dfactor, true };
+        GL::blendFunc(sfactor, dfactor);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::clearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a) {
+    if (!m_clearColor.set || m_clearColor.r != r || m_clearColor.g != g || m_clearColor.b != b || m_clearColor.a != a) {
+        m_clearColor = { r, g, b, a, true };
+        GL::clearColor(r, g, b, a);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::colorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a) {
+    if (!m_colorMask.set || m_colorMask.r != r || m_colorMask.g != g || m_colorMask.b != b || m_colorMask.a != a) {
+        m_colorMask = { r, g, b, a, true };
+        GL::colorMask(r, g, b, a);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::cullFace(GLenum face) {
+    if (!m_cullFace.set || m_cullFace.face != face) {
+        m_cullFace = { face, true };
+        GL::cullFace(face);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::culling(GLboolean enable) {
+    if (!m_culling.set || m_culling.enabled != enable) {
+        m_culling = { enable, true };
+        setGlFlag(GL_CULL_FACE, enable);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::depthTest(GLboolean enable) {
+    if (!m_depthTest.set || m_depthTest.enabled != enable) {
+        m_depthTest = { enable, true };
+        setGlFlag(GL_DEPTH_TEST, enable);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::depthMask(GLboolean enable) {
+    if (!m_depthMask.set || m_depthMask.enabled != enable) {
+        m_depthMask = { enable, true };
+        GL::depthMask(enable);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::frontFace(GLenum face) {
+    if (!m_frontFace.set || m_frontFace.face != face) {
+        m_frontFace = { face, true };
+        GL::frontFace(face);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::stencilMask(GLuint mask) {
+    if (!m_stencilMask.set || m_stencilMask.mask != mask) {
+        m_stencilMask = { mask, true };
+        GL::stencilMask(mask);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::stencilFunc(GLenum func, GLint ref, GLuint mask) {
+    if (!m_stencilFunc.set || m_stencilFunc.func != func || m_stencilFunc.ref != ref || m_stencilFunc.mask != mask) {
+        m_stencilFunc = { func, ref, mask, true };
+        GL::stencilFunc(func, ref, mask);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::stencilOp(GLenum sfail, GLenum spassdfail, GLenum spassdpass) {
+    if (!m_stencilOp.set || m_stencilOp.sfail != sfail || m_stencilOp.spassdfail != spassdfail || m_stencilOp.spassdpass != spassdpass) {
+        m_stencilOp = { sfail, spassdfail, spassdpass, true };
+        GL::stencilOp(sfail, spassdfail, spassdpass);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::stencilTest(GLboolean enable) {
+    if (!m_stencilTest.set || m_stencilTest.enabled != enable) {
+        m_stencilTest = { enable, true };
+        setGlFlag(GL_STENCIL_TEST, enable);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::shaderProgram(GLuint program) {
+    if (!m_program.set || m_program.program != program) {
+        m_program = { program, true };
+        GL::useProgram(program);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::texture(GLenum target, GLuint handle) {
+    if (!m_texture.set || m_texture.target != target || m_texture.handle != handle) {
+        m_texture = { target, handle, true };
+        GL::bindTexture(target, handle);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::textureUnit(GLuint unit) {
+    if (!m_textureUnit.set || m_textureUnit.unit != unit) {
+        m_textureUnit = { unit, true };
+        // Our cached texture handle is irrelevant on the new unit, so unset it.
+        m_texture.set = false;
+        GL::activeTexture(getTextureUnit(unit));
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::vertexBuffer(GLuint handle) {
+    if (!m_vertexBuffer.set || m_vertexBuffer.handle != handle) {
+        m_vertexBuffer = { handle, true };
+        GL::bindBuffer(GL_ARRAY_BUFFER, handle);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::indexBuffer(GLuint handle) {
+    if (!m_indexBuffer.set || m_indexBuffer.handle != handle) {
+        m_indexBuffer = { handle, true };
+        GL::bindBuffer(GL_ELEMENT_ARRAY_BUFFER, handle);
+        return false;
+    }
+    return true;
+}
+
+void RenderState::vertexBufferUnset(GLuint handle) {
+    if (m_vertexBuffer.handle == handle) {
+        m_vertexBuffer.set = false;
+    }
+}
+
+void RenderState::indexBufferUnset(GLuint handle) {
+    if (m_indexBuffer.handle == handle) {
+        m_indexBuffer.set = false;
+    }
+}
+
+void RenderState::shaderProgramUnset(GLuint program) {
+    if (m_program.program == program) {
+        m_program.set = false;
+    }
+}
+
+void RenderState::textureUnset(GLenum target, GLuint handle) {
+    if (m_texture.handle == handle) {
+        m_texture.set = false;
+    }
+}
+
+void RenderState::framebufferUnset(GLuint handle) {
+    if (m_framebuffer.handle == handle) {
+        m_framebuffer.set = false;
+    }
+}
+
+GLuint RenderState::getQuadIndexBuffer() {
+    if (m_quadIndexBuffer == 0) {
+        generateQuadIndexBuffer();
+    }
+    return m_quadIndexBuffer;
+}
+
+void RenderState::deleteQuadIndexBuffer() {
+    indexBufferUnset(m_quadIndexBuffer);
+    GL::deleteBuffers(1, &m_quadIndexBuffer);
+    m_quadIndexBuffer = 0;
+}
+
+void RenderState::generateQuadIndexBuffer() {
+
+    std::vector<GLushort> indices;
+    indices.reserve(MAX_QUAD_VERTICES / 4 * 6);
+
+    for (size_t i = 0; i < MAX_QUAD_VERTICES; i += 4) {
+        indices.push_back(i + 2);
+        indices.push_back(i + 0);
+        indices.push_back(i + 1);
+        indices.push_back(i + 1);
+        indices.push_back(i + 3);
+        indices.push_back(i + 2);
+    }
+
+    GL::genBuffers(1, &m_quadIndexBuffer);
+    indexBuffer(m_quadIndexBuffer);
+    GL::bufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(GLushort),
+                   reinterpret_cast<GLbyte*>(indices.data()), GL_STATIC_DRAW);
+
+}
+
+Texture* RenderState::getDefaultPointTexture() {
+    if (m_defaultPointTexture == nullptr) {
+        generateDefaultPointTexture();
+    }
+    return m_defaultPointTexture;
+}
+
+void RenderState::deleteDefaultPointTexture() {
+    delete m_defaultPointTexture;
+    m_defaultPointTexture = nullptr;
+}
+
+void RenderState::generateDefaultPointTexture() {
+    TextureOptions options = { GL_RGBA, GL_RGBA, { GL_LINEAR, GL_LINEAR }, { GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE } };
+    std::vector<char> defaultPoint;
+    defaultPoint.insert(defaultPoint.begin(), default_point_texture_data, default_point_texture_data + default_point_texture_size);
+    m_defaultPointTexture = new Texture(defaultPoint, options, true);
+}
+
+bool RenderState::framebuffer(GLuint handle) {
+    if (!m_framebuffer.set || m_framebuffer.handle != handle) {
+        m_framebuffer = { handle, true };
+        GL::bindFramebuffer(GL_FRAMEBUFFER, handle);
+        return false;
+    }
+    return true;
+}
+
+bool RenderState::viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+    if (!m_viewport.set || m_viewport.x != x || m_viewport.y != y
+      || m_viewport.width != width || m_viewport.height != height) {
+        m_viewport = { x, y, width, height, true };
+        GL::viewport(x, y, width, height);
+        return false;
+    }
+    return true;
+}
+
+GLuint RenderState::defaultFrameBuffer() const {
+    return (GLuint)m_defaultFramebuffer;
+}
+
+} // namespace Tangram
diff --git a/core/src/gl/renderState.h b/core/src/gl/renderState.h
new file mode 100644 (file)
index 0000000..2baf8a1
--- /dev/null
@@ -0,0 +1,206 @@
+#pragma once
+
+#include "gl.h"
+#include "gl/disposer.h"
+#include "util/jobQueue.h"
+#include <array>
+#include <string>
+#include <unordered_map>
+
+namespace Tangram {
+
+class Disposer;
+class Texture;
+
+class RenderState {
+
+public:
+
+    static constexpr size_t MAX_ATTRIBUTES = 16;
+
+    static constexpr size_t MAX_QUAD_VERTICES = 16384;
+
+    RenderState();
+    ~RenderState();
+
+    RenderState(const RenderState&) = delete;
+    RenderState(RenderState&&) = delete;
+    RenderState& operator=(const RenderState&) = delete;
+    RenderState& operator=(RenderState&&) = delete;
+
+    // Reset the render states.
+    void invalidate();
+
+    // Get the texture slot from a texture unit from 0 to TANGRAM_MAX_TEXTURE_UNIT-1.
+    static GLuint getTextureUnit(GLuint _unit);
+
+    // Get the currently active texture unit.
+    int currentTextureUnit();
+
+    // Get the immediately next available texture unit and mark it unavailable.
+    int nextAvailableTextureUnit();
+
+    // Reset the currently used texture unit.
+    void resetTextureUnit();
+
+    // Release one texture unit slot.
+    void releaseTextureUnit();
+
+    bool blending(GLboolean enable);
+
+    bool blendingFunc(GLenum sfactor, GLenum dfactor);
+
+    bool clearColor(GLclampf r, GLclampf g, GLclampf b, GLclampf a);
+
+    bool colorMask(GLboolean r, GLboolean g, GLboolean b, GLboolean a);
+
+    bool cullFace(GLenum face);
+
+    bool culling(GLboolean enable);
+
+    bool depthTest(GLboolean enable);
+
+    bool depthMask(GLboolean enable);
+
+    bool frontFace(GLenum face);
+
+    bool stencilMask(GLuint mask);
+
+    bool stencilFunc(GLenum func, GLint ref, GLuint mask);
+
+    bool stencilOp(GLenum sfail, GLenum spassdfail, GLenum spassdpass);
+
+    bool stencilTest(GLboolean enable);
+
+    bool shaderProgram(GLuint program);
+
+    bool texture(GLenum target, GLuint handle);
+
+    bool textureUnit(GLuint unit);
+
+    bool vertexBuffer(GLuint handle);
+
+    bool indexBuffer(GLuint handle);
+
+    bool framebuffer(GLuint handle);
+
+    bool viewport(GLint x, GLint y, GLsizei width, GLsizei height);
+
+    void vertexBufferUnset(GLuint handle);
+
+    void indexBufferUnset(GLuint handle);
+
+    void shaderProgramUnset(GLuint program);
+
+    void textureUnset(GLenum target, GLuint handle);
+
+    void framebufferUnset(GLuint handle);
+
+    void cacheDefaultFramebuffer();
+
+    GLuint defaultFrameBuffer() const;
+
+    GLuint getQuadIndexBuffer();
+
+    Texture* getDefaultPointTexture();
+
+    std::array<GLuint, MAX_ATTRIBUTES> attributeBindings = { { 0 } };
+
+    JobQueue jobQueue;
+
+    std::unordered_map<std::string, GLuint> fragmentShaders;
+    std::unordered_map<std::string, GLuint> vertexShaders;
+
+private:
+
+    uint32_t m_nextTextureUnit = 0;
+
+    GLuint m_quadIndexBuffer = 0;
+    void deleteQuadIndexBuffer();
+    void generateQuadIndexBuffer();
+
+    Texture* m_defaultPointTexture = nullptr;
+    void deleteDefaultPointTexture();
+    void generateDefaultPointTexture();
+
+    struct {
+        GLboolean enabled;
+        bool set;
+    } m_blending, m_culling, m_depthMask, m_depthTest, m_stencilTest;
+
+    struct {
+        GLenum sfactor, dfactor;
+        bool set;
+    } m_blendingFunc;
+
+    struct {
+        GLuint mask;
+        bool set;
+    } m_stencilMask;
+
+    struct {
+        GLenum func;
+        GLint ref;
+        GLuint mask;
+        bool set;
+    } m_stencilFunc;
+
+    struct {
+        GLenum sfail, spassdfail, spassdpass;
+        bool set;
+    } m_stencilOp;
+
+    struct {
+        GLboolean r, g, b, a;
+        bool set;
+    } m_colorMask;
+
+    struct {
+        GLenum face;
+        bool set;
+    } m_frontFace, m_cullFace;
+
+    struct {
+        GLuint handle;
+        bool set;
+    } m_vertexBuffer, m_indexBuffer;
+
+    struct {
+        GLuint program;
+        bool set;
+    } m_program;
+
+    struct {
+        GLclampf r, g, b, a;
+        bool set;
+    } m_clearColor;
+
+    struct {
+        GLenum target;
+        GLuint handle;
+        bool set;
+    } m_texture;
+
+    struct {
+        GLuint unit;
+        bool set;
+    } m_textureUnit;
+
+    struct FrameBufferState {
+        GLuint handle;
+        bool set;
+    } m_framebuffer;
+
+    struct ViewportState {
+        GLint x;
+        GLint y;
+        GLsizei width;
+        GLsizei height;
+        bool set;
+    } m_viewport;
+
+    GLint m_defaultFramebuffer = 0;
+
+};
+
+}
diff --git a/core/src/gl/shaderProgram.cpp b/core/src/gl/shaderProgram.cpp
new file mode 100644 (file)
index 0000000..1843631
--- /dev/null
@@ -0,0 +1,351 @@
+#include "gl/shaderProgram.h"
+
+#include "gl/disposer.h"
+#include "gl/glError.h"
+#include "gl/renderState.h"
+#include "glm/gtc/type_ptr.hpp"
+#include "scene/light.h"
+#include "log.h"
+#include "platform.h"
+
+namespace Tangram {
+
+ShaderProgram::ShaderProgram() {
+    // Nothing to do.
+}
+
+ShaderProgram::~ShaderProgram() {
+
+    auto glProgram = m_glProgram;
+
+    m_disposer([=](RenderState& rs) {
+        if (glProgram != 0) {
+            GL::deleteProgram(glProgram);
+        }
+        // Deleting the shader program that is currently in-use sets the current shader program to 0
+        // so we un-set the current program in the render state.
+        rs.shaderProgramUnset(glProgram);
+    });
+}
+
+GLint ShaderProgram::getAttribLocation(const std::string& _attribName) {
+
+    auto it = m_attribMap.find(_attribName);
+
+    if (it == m_attribMap.end()) {
+        // If this is a new entry, get the actual location from OpenGL.
+        GLint location = GL::getAttribLocation(m_glProgram, _attribName.c_str());
+        m_attribMap[_attribName] = location;
+        return location;
+    } else {
+        return it->second;
+    }
+
+}
+
+GLint ShaderProgram::getUniformLocation(const UniformLocation& _uniform) {
+
+    if (_uniform.location == -2) {
+        _uniform.location = GL::getUniformLocation(m_glProgram, _uniform.name.c_str());
+    }
+    return _uniform.location;
+}
+
+bool ShaderProgram::use(RenderState& rs) {
+
+    if (m_needsBuild) {
+        build(rs);
+    }
+
+    if (isValid()) {
+        rs.shaderProgram(m_glProgram);
+        return true;
+    }
+
+    return false;
+}
+
+bool ShaderProgram::build(RenderState& rs) {
+
+    if (!m_needsBuild) { return false; }
+    m_needsBuild = false;
+
+    // Delete handle for old program; values of 0 are silently ignored
+    GL::deleteProgram(m_glProgram);
+    m_glProgram = 0;
+
+    auto& vertSrc = m_vertexShaderSource;
+    auto& fragSrc = m_fragmentShaderSource;
+
+    // Compile vertex and fragment shaders
+    GLint vertexShader = makeCompiledShader(rs, vertSrc, GL_VERTEX_SHADER);
+    if (vertexShader == 0) {
+        LOGE("Shader compilation failed for %s", m_description.c_str());
+        return false;
+    }
+
+    GLint fragmentShader = makeCompiledShader(rs, fragSrc, GL_FRAGMENT_SHADER);
+    if (fragmentShader == 0) {
+        LOGE("Shader compilation failed for %s", m_description.c_str());
+        return false;
+    }
+
+    // Link shaders into a program
+    GLint program = makeLinkedShaderProgram(fragmentShader, vertexShader);
+    if (program == 0) {
+        LOGE("Shader compilation failed for %s", m_description.c_str());
+        return false;
+    }
+
+    m_glProgram = program;
+
+    // Clear any cached shader locations
+    m_attribMap.clear();
+    m_disposer = Disposer(rs);
+
+    return true;
+}
+
+GLuint ShaderProgram::makeLinkedShaderProgram(GLint _fragShader, GLint _vertShader) {
+
+    GLuint program = GL::createProgram();
+
+    GL::attachShader(program, _fragShader);
+    GL::attachShader(program, _vertShader);
+    GL::linkProgram(program);
+
+    GLint isLinked;
+    GL::getProgramiv(program, GL_LINK_STATUS, &isLinked);
+
+    if (isLinked == GL_FALSE) {
+        GLint infoLength = 0;
+        GL::getProgramiv(program, GL_INFO_LOG_LENGTH, &infoLength);
+
+        if (infoLength > 1) {
+            std::vector<GLchar> infoLog(infoLength);
+            GL::getProgramInfoLog(program, infoLength, NULL, &infoLog[0]);
+            LOGE("linking program:\n%s", &infoLog[0]);
+        }
+
+        GL::deleteProgram(program);
+        return 0;
+    }
+
+    return program;
+}
+
+GLuint ShaderProgram::makeCompiledShader(RenderState& rs, const std::string& _src, GLenum _type) {
+
+    auto& cache = (_type == GL_VERTEX_SHADER) ? rs.vertexShaders : rs.fragmentShaders;
+
+    auto entry = cache.emplace(_src, 0);
+    if (!entry.second) {
+        return entry.first->second;
+    }
+
+    GLuint shader = GL::createShader(_type);
+
+    const GLchar* source = (const GLchar*) _src.c_str();
+    GL::shaderSource(shader, 1, &source, NULL);
+    GL::compileShader(shader);
+
+    GLint isCompiled;
+    GL::getShaderiv(shader, GL_COMPILE_STATUS, &isCompiled);
+
+    if (isCompiled == GL_FALSE) {
+        GLint infoLength = 0;
+        GL::getShaderiv(shader, GL_INFO_LOG_LENGTH, &infoLength);
+
+        if (infoLength > 1) {
+            std::string infoLog;
+            infoLog.resize(infoLength);
+
+            GL::getShaderInfoLog(shader, infoLength, NULL, static_cast<GLchar*>(&infoLog[0]));
+            LOGE("Shader compilation failed\n%s", infoLog.c_str());
+
+            std::stringstream sourceStream(source);
+            std::string item;
+            std::vector<std::string> sourceLines;
+            while (std::getline(sourceStream, item)) { sourceLines.push_back(item); }
+
+            // Print errors with context
+            std::string line;
+            std::stringstream logStream(infoLog);
+
+            while (std::getline(logStream, line)) {
+                if (line.length() < 2) { continue; }
+
+                int lineNum = 0;
+                if (!sscanf(line.c_str(), "%*d%*[(:]%d", &lineNum)) { continue; }
+                LOGE("\nError on line %d: %s", lineNum, line.c_str());
+
+                for (int i = std::max(0, lineNum-5); i < lineNum+5; i++) {
+                    if (size_t(i) >= sourceLines.size()) { break; }
+                    LOGE("%d: %s", i+1, sourceLines[i].c_str());
+                }
+            }
+
+            // Print full source with line numbers
+            LOGD("\n\n");
+            for (size_t i = 0; i < sourceLines.size(); i++) {
+                LOGD("%d: %s", i, sourceLines[i].c_str());
+            }
+        }
+
+        GL::deleteShader(shader);
+        return 0;
+    }
+
+    entry.first->second = shader;
+
+    return shader;
+}
+
+void ShaderProgram::setUniformi(RenderState& rs, const UniformLocation& _loc, int _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform1i(location, _value); }
+    }
+}
+
+void ShaderProgram::setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, glm::vec2(_value0, _value1));
+        if (!cached) { GL::uniform2i(location, _value0, _value1); }
+    }
+}
+
+void ShaderProgram::setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1, int _value2) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, glm::vec3(_value0, _value1, _value2));
+        if (!cached) { GL::uniform3i(location, _value0, _value1, _value2); }
+    }
+}
+
+void ShaderProgram::setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1, int _value2, int _value3) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, glm::vec4(_value0, _value1, _value2, _value3));
+        if (!cached) { GL::uniform4i(location, _value0, _value1, _value2, _value3); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, float _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform1f(location, _value); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1) {
+    setUniformf(rs, _loc, glm::vec2(_value0, _value1));
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1, float _value2) {
+    setUniformf(rs, _loc, glm::vec3(_value0, _value1, _value2));
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1, float _value2, float _value3) {
+    setUniformf(rs, _loc, glm::vec4(_value0, _value1, _value2, _value3));
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec2& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform2f(location, _value.x, _value.y); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec3& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform3f(location, _value.x, _value.y, _value.z); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec4& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform4f(location, _value.x, _value.y, _value.z, _value.w); }
+    }
+}
+
+void ShaderProgram::setUniformMatrix2f(RenderState& rs, const UniformLocation& _loc, const glm::mat2& _value, bool _transpose) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = !_transpose && getFromCache(location, _value);
+        if (!cached) { GL::uniformMatrix2fv(location, 1, _transpose, glm::value_ptr(_value)); }
+    }
+}
+
+void ShaderProgram::setUniformMatrix3f(RenderState& rs, const UniformLocation& _loc, const glm::mat3& _value, bool _transpose) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = !_transpose && getFromCache(location, _value);
+        if (!cached) { GL::uniformMatrix3fv(location, 1, _transpose, glm::value_ptr(_value)); }
+    }
+}
+
+void ShaderProgram::setUniformMatrix4f(RenderState& rs, const UniformLocation& _loc, const glm::mat4& _value, bool _transpose) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = !_transpose && getFromCache(location, _value);
+        if (!cached) { GL::uniformMatrix4fv(location, 1, _transpose, glm::value_ptr(_value)); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray1f& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform1fv(location, _value.size(), _value.data()); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray2f& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform2fv(location, _value.size(), (float*)_value.data()); }
+    }
+}
+
+void ShaderProgram::setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray3f& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform3fv(location, _value.size(), (float*)_value.data()); }
+    }
+}
+
+void ShaderProgram::setUniformi(RenderState& rs, const UniformLocation& _loc, const UniformTextureArray& _value) {
+    if (!use(rs)) { return; }
+    GLint location = getUniformLocation(_loc);
+    if (location >= 0) {
+        bool cached = getFromCache(location, _value);
+        if (!cached) { GL::uniform1iv(location, _value.slots.size(), _value.slots.data()); }
+    }
+}
+
+}
diff --git a/core/src/gl/shaderProgram.h b/core/src/gl/shaderProgram.h
new file mode 100644 (file)
index 0000000..da9cbbb
--- /dev/null
@@ -0,0 +1,127 @@
+#pragma once
+
+#include "gl.h"
+#include "gl/disposer.h"
+#include "gl/shaderSource.h"
+#include "gl/uniform.h"
+#include "util/fastmap.h"
+
+#include "glm/glm.hpp"
+
+#include <string>
+#include <vector>
+#include <memory>
+
+namespace Tangram {
+
+class RenderState;
+
+//
+// ShaderProgram - utility class representing an OpenGL shader program
+//
+class ShaderProgram {
+
+public:
+
+    ShaderProgram();
+    ~ShaderProgram();
+
+    void setShaderSource(const std::string& _vertSrc, const std::string& _fragSrc) {
+        m_fragmentShaderSource = _fragSrc;
+        m_vertexShaderSource = _vertSrc;
+        m_needsBuild = true;
+    }
+
+    // Apply all source blocks to the source strings for this shader and attempt to compile
+    // and then link the resulting vertex and fragment shaders; if compiling or linking fails
+    // this prints the compiler log, returns false, and keeps the program's previous state; if
+    // successful it returns true.
+    bool build(RenderState& rs);
+
+    // Getters
+    GLuint getGlProgram() const { return m_glProgram; };
+
+    std::string getDescription() const { return m_description; }
+
+    // Fetch the location of a shader attribute, caching the result.
+    GLint getAttribLocation(const std::string& _attribName);
+
+    // Fetch the location of a shader uniform, caching the result.
+    GLint getUniformLocation(const UniformLocation& _uniformName);
+
+    // Return true if this object represents a valid OpenGL shader program.
+    bool isValid() const { return m_glProgram != 0; };
+
+    // Bind the program in OpenGL if it is not already bound; If the shader sources
+    // have been modified since the last time build() was called, also calls build().
+    // Returns true if shader can be used (i.e. is valid).
+    bool use(RenderState& rs);
+
+    // Ensure the program is bound and then set the named uniform to the given value(s).
+    void setUniformi(RenderState& rs, const UniformLocation& _loc, int _value);
+    void setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1);
+    void setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1, int _value2);
+    void setUniformi(RenderState& rs, const UniformLocation& _loc, int _value0, int _value1, int _value2, int _value3);
+
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, float _value);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1, float _value2);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, float _value0, float _value1, float _value2, float _value3);
+
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec2& _value);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec3& _value);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const glm::vec4& _value);
+
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray1f& _value);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray2f& _value);
+    void setUniformf(RenderState& rs, const UniformLocation& _loc, const UniformArray3f& _value);
+    void setUniformi(RenderState& rs, const UniformLocation& _loc, const UniformTextureArray& _value);
+
+    // Ensure the program is bound and then set the named uniform to the values
+    // beginning at the pointer _value; 4 values are used for a 2x2 matrix, 9 values for a 3x3, etc.
+    void setUniformMatrix2f(RenderState& rs, const UniformLocation& _loc, const glm::mat2& _value, bool transpose = false);
+    void setUniformMatrix3f(RenderState& rs, const UniformLocation& _loc, const glm::mat3& _value, bool transpose = false);
+    void setUniformMatrix4f(RenderState& rs, const UniformLocation& _loc, const glm::mat4& _value, bool transpose = false);
+
+    void setDescription(std::string _description) { m_description = _description; }
+
+    static GLuint makeLinkedShaderProgram(GLint _fragShader, GLint _vertShader);
+    static GLuint makeCompiledShader(RenderState& rs, const std::string& _src, GLenum _type);
+
+    const std::string& vertexShaderSource() { return m_vertexShaderSource; }
+    const std::string& fragmentShaderSource() { return m_fragmentShaderSource; }
+
+private:
+
+    // Get a uniform value from the cache, and returns false when it's a cache miss
+    template <class T>
+    inline bool getFromCache(GLint _location, T _value) {
+        auto& v = m_uniformCache[_location];
+        if (v.is<T>()) {
+            T& value = v.get<T>();
+            if (value == _value) {
+                return true;
+            }
+        }
+        v = _value;
+        return false;
+    }
+
+    GLuint m_glProgram = 0;
+
+    fastmap<std::string, GLint> m_attribMap;
+    fastmap<GLint, UniformValue> m_uniformCache;
+
+    std::string m_fragmentShaderSource;
+    std::string m_vertexShaderSource;
+
+    // An optional shader description printed on compile failure
+    std::string m_description;
+
+    bool m_needsBuild = true;
+
+    Disposer m_disposer;
+
+};
+
+}
diff --git a/core/src/gl/shaderSource.cpp b/core/src/gl/shaderSource.cpp
new file mode 100644 (file)
index 0000000..f639b05
--- /dev/null
@@ -0,0 +1,118 @@
+#include "gl/shaderSource.h"
+#include "util/floatFormatter.h"
+
+#include <set>
+#include <sstream>
+
+#include "selection_fs.h"
+
+namespace Tangram {
+
+void ShaderSource::setSourceStrings(const std::string& _fragSrc, const std::string& _vertSrc){
+    m_fragmentShaderSource = std::string(_fragSrc);
+    m_vertexShaderSource = std::string(_vertSrc);
+}
+
+void ShaderSource::addSourceBlock(const std::string& _tagName, const std::string& _glslSource, bool _allowDuplicate){
+
+    if (!_allowDuplicate) {
+        for (auto& source : m_sourceBlocks[_tagName]) {
+            if (_glslSource == source) {
+                return;
+            }
+        }
+    }
+
+    size_t start = 0;
+    std::string sourceBlock = _glslSource;
+
+    // Certain graphics drivers have issues with shaders having line continuation backslashes "\".
+    // Example raster.glsl was having issues on s6 and note2 because of the "\"s in the glsl file.
+    // This also makes sure if any "\"s are present in the shaders coming from style sheet will be
+    // taken care of.
+
+    // Replace blackslash+newline with spaces (simplification of regex "\\\\\\s*\\n")
+    while ((start = sourceBlock.find("\\\n", start)) != std::string::npos) {
+        sourceBlock.replace(start, 2, "  ");
+        start += 2;
+    }
+
+    m_sourceBlocks[_tagName].push_back(sourceBlock);
+}
+
+std::string ShaderSource::applySourceBlocks(const std::string& _source, bool _fragShader, bool _selection) const {
+
+    std::stringstream sourceOut;
+    std::set<std::string> pragmas;
+
+    sourceOut << "#define TANGRAM_EPSILON 0.00001\n";
+    sourceOut << "#define TANGRAM_WORLD_POSITION_WRAP 100000.\n";
+
+    if (_fragShader) {
+        sourceOut << "#define TANGRAM_FRAGMENT_SHADER\n";
+    } else {
+        sourceOut << "#define TANGRAM_DEPTH_DELTA 0.00003052\n"; // 2^-15
+        sourceOut << "#define TANGRAM_VERTEX_SHADER\n";
+    }
+
+    if (_selection) {
+        sourceOut <<  "#define TANGRAM_FEATURE_SELECTION\n";
+    }
+
+    std::stringstream sourceIn(_source);
+    std::string line;
+
+    while (std::getline(sourceIn, line)) {
+        if (line.empty()) {
+            continue;
+        }
+
+        sourceOut << line << '\n';
+
+        char pragmaName[128];
+        // NB: The initial whitespace is to skip any number of whitespace chars
+        if (sscanf(line.c_str(), " #pragma tangram:%127s", pragmaName) == 0) {
+            continue;
+        }
+
+        auto block = m_sourceBlocks.find(pragmaName);
+        if (block == m_sourceBlocks.end()) {
+            continue;
+        }
+
+        bool unique;
+        std::tie(std::ignore, unique) = pragmas.emplace(pragmaName);
+        if (!unique) {
+            continue;
+        }
+
+        // insert blocks
+        for (auto& s : block->second) {
+            sourceOut << s << '\n';
+        }
+    }
+
+    // for (auto& block : m_sourceBlocks) {
+    //     if (pragmas.find(block.first) == pragmas.end()) {
+    //         logMsg("Warning: expected pragma '%s' in shader source\n",
+    //                block.first.c_str());
+    //     }
+    // }
+    return sourceOut.str();
+}
+
+void ShaderSource::addExtensionDeclaration(const std::string& _extension) {
+    std::ostringstream oss;
+    oss << "#if defined(GL_ES) == 0 || defined(GL_" << _extension << ")\n";
+    oss << "    #extension GL_" << _extension << " : enable\n";
+    oss << "    #define TANGRAM_EXTENSION_" << _extension << '\n';
+    oss << "#endif\n";
+
+    addSourceBlock("extensions", oss.str());
+}
+
+std::string ShaderSource::buildSelectionFragmentSource() const {
+    return SHADER_SOURCE(selection_fs);
+}
+
+}
diff --git a/core/src/gl/shaderSource.h b/core/src/gl/shaderSource.h
new file mode 100644 (file)
index 0000000..c70f567
--- /dev/null
@@ -0,0 +1,67 @@
+#pragma once
+
+#include <map>
+#include <string>
+#include <vector>
+
+#define SHADER_SOURCE(NAME) ShaderSource::shaderSourceBlock(NAME ## _data, NAME ## _size)
+
+namespace Tangram {
+
+class ShaderSource {
+public:
+
+    // Set the vertex and fragment shader GLSL source to the given strings/
+    void setSourceStrings(const std::string& _vertSrc, const std::string& _fragSrc);
+
+    // Add a block of GLSL to be injected at "#pragma tangram: [_tagName]" in the shader sources.
+    void addSourceBlock(const std::string& _tagName, const std::string& _glslSource,
+                        bool _allowDuplicate = true);
+
+    void addExtensionDeclaration(const std::string& _extension);
+
+    const auto& getSourceBlocks() const { return m_sourceBlocks; }
+
+    // Build vertex shader source
+    std::string buildVertexSource() const {
+        return applySourceBlocks(m_vertexShaderSource, false);
+    }
+
+    // Build fragment shader source
+    std::string buildFragmentSource() const {
+        return applySourceBlocks(m_fragmentShaderSource, true);
+    }
+
+    // Build selection vertex shader source
+    std::string buildSelectionVertexSource() const  {
+        return applySourceBlocks(m_vertexShaderSource, false, true);
+    }
+
+    // Build selection fragment shader source
+    std::string buildSelectionFragmentSource() const;
+
+
+    static std::string shaderSourceBlock(const unsigned char* data, size_t size) {
+        std::string block;
+        if (data[size - 1] == '\n') {
+            block.append(reinterpret_cast<const char*>(data), size);
+        } else {
+            block.reserve(size + 2);
+            block.append(reinterpret_cast<const char*>(data), size);
+            block += '\n';
+        }
+        return block;
+    }
+
+private:
+
+    std::string applySourceBlocks(const std::string& _source, bool _fragShader,
+                                  bool _selection = false) const;
+
+    std::map<std::string, std::vector<std::string>> m_sourceBlocks;
+
+    std::string m_vertexShaderSource = "";
+    std::string m_fragmentShaderSource = "";
+};
+
+}
diff --git a/core/src/gl/texture.cpp b/core/src/gl/texture.cpp
new file mode 100644 (file)
index 0000000..d7d4b2c
--- /dev/null
@@ -0,0 +1,360 @@
+#include "gl/texture.h"
+
+#include "gl/glError.h"
+#include "gl/renderState.h"
+#include "gl/hardware.h"
+#include "util/geom.h"
+#include "log.h"
+#include "platform.h"
+#include "tangram.h"
+
+// Enable only JPEG, PNG, GIF, TGA and PSD
+#define STBI_NO_BMP
+#define STBI_NO_HDR
+#define STBI_NO_PIC
+#define STBI_NO_PNM
+
+#define STB_IMAGE_IMPLEMENTATION
+#include "stb_image.h"
+
+#include <cstring> // for memset
+
+namespace Tangram {
+
+Texture::Texture(unsigned int _width, unsigned int _height, TextureOptions _options, bool _generateMipmaps)
+    : m_options(_options), m_generateMipmaps(_generateMipmaps) {
+
+    m_glHandle = 0;
+    m_shouldResize = false;
+    m_target = GL_TEXTURE_2D;
+    resize(_width, _height);
+}
+
+Texture::Texture(const std::vector<char>& _data, TextureOptions options, bool generateMipmaps)
+    : Texture(0u, 0u, options, generateMipmaps) {
+
+    loadImageFromMemory(_data);
+}
+
+Texture::~Texture() {
+
+    auto glHandle = m_glHandle;
+    auto target = m_target;
+
+    m_disposer([=](RenderState& rs) {
+        // If the currently-bound texture is deleted, the binding resets to 0
+        // according to the OpenGL spec, so unset this texture binding.
+        rs.textureUnset(target, glHandle);
+
+        GL::deleteTextures(1, &glHandle);
+    });
+}
+
+bool Texture::loadImageFromMemory(const std::vector<char>& _data) {
+    unsigned char* pixels = nullptr;
+    int width, height, comp;
+
+    if (_data.size() != 0) {
+        pixels = stbi_load_from_memory(reinterpret_cast<const stbi_uc*>(_data.data()), _data.size(), &width, &height, &comp, STBI_rgb_alpha);
+    }
+
+    if (pixels) {
+        // stbi_load_from_memory loads the image as a series of scanlines starting from
+        // the top-left corner of the image. This call flips the output such that the data
+        // begins at the bottom-left corner, as required for our OpenGL texture coordinates.
+        auto* rgbaPixels = reinterpret_cast<GLuint*>(pixels);
+
+        Texture::flipImageData(rgbaPixels, width, height);
+
+        resize(width, height);
+
+        setData(rgbaPixels, width * height);
+
+        stbi_image_free(pixels);
+
+        return true;
+    }
+    // Default inconsistent texture data is set to a 1*1 pixel texture
+    // This reduces inconsistent behavior when texture failed loading
+    // texture data but a Tangram style shader requires a shader sampler
+    GLuint blackPixel = 0x0000ff;
+
+    setData(&blackPixel, 1);
+
+    return false;
+}
+
+Texture::Texture(Texture&& _other) {
+    *this = std::move(_other);
+}
+
+Texture& Texture::operator=(Texture&& _other) {
+    m_glHandle = _other.m_glHandle;
+    _other.m_glHandle = 0;
+
+    m_options = _other.m_options;
+    m_data = std::move(_other.m_data);
+    m_dirtyRanges = std::move(_other.m_dirtyRanges);
+    m_shouldResize = _other.m_shouldResize;
+    m_width = _other.m_width;
+    m_height = _other.m_height;
+    m_target = _other.m_target;
+    m_generateMipmaps = _other.m_generateMipmaps;
+    m_disposer = std::move(_other.m_disposer);
+
+    return *this;
+}
+
+void Texture::setData(const GLuint* _data, unsigned int _dataSize) {
+
+    m_data.clear();
+
+    m_data.insert(m_data.begin(), _data, _data + _dataSize);
+
+    setDirty(0, m_height);
+}
+
+void Texture::setSubData(const GLuint* _subData, uint16_t _xoff, uint16_t _yoff,
+                         uint16_t _width, uint16_t _height, uint16_t _stride) {
+
+    size_t bpp = bytesPerPixel();
+    size_t divisor = sizeof(GLuint) / bpp;
+
+    // Init m_data if update() was not called after resize()
+    if (m_data.size() != (m_width * m_height) / divisor) {
+        m_data.resize((m_width * m_height) / divisor);
+    }
+
+    // update m_data with subdata
+    for (size_t row = 0; row < _height; row++) {
+
+        size_t pos = ((_yoff + row) * m_width + _xoff) / divisor;
+        size_t posIn = (row * _stride) / divisor;
+        std::memcpy(&m_data[pos], &_subData[posIn], _width * bpp);
+    }
+
+    setDirty(_yoff, _height);
+}
+
+void Texture::setDirty(size_t _yoff, size_t _height) {
+    // FIXME: check that dirty range is valid for texture size!
+    size_t max = _yoff + _height;
+    size_t min = _yoff;
+
+    if (m_dirtyRanges.empty()) {
+        m_dirtyRanges.push_back({min, max});
+        return;
+    }
+
+    auto n = m_dirtyRanges.begin();
+
+    // Find first overlap
+    while (n != m_dirtyRanges.end()) {
+        if (min > n->max) {
+            // this range is after current
+            ++n;
+            continue;
+        }
+        if (max < n->min) {
+            // this range is before current
+            m_dirtyRanges.insert(n, {min, max});
+            return;
+        }
+        // Combine with overlapping range
+        n->min = std::min(n->min, min);
+        n->max = std::max(n->max, max);
+        break;
+    }
+    if (n == m_dirtyRanges.end()) {
+        m_dirtyRanges.push_back({min, max});
+        return;
+    }
+
+    // Merge up to last overlap
+    auto it = n+1;
+    while (it != m_dirtyRanges.end() && max >= it->min) {
+        n->max = std::max(it->max, max);
+        it = m_dirtyRanges.erase(it);
+    }
+}
+
+void Texture::bind(RenderState& rs, GLuint _unit) {
+    rs.textureUnit(_unit);
+    rs.texture(m_target, m_glHandle);
+}
+
+void Texture::generate(RenderState& rs, GLuint _textureUnit) {
+    GL::genTextures(1, &m_glHandle);
+
+    bind(rs, _textureUnit);
+
+    GL::texParameteri(m_target, GL_TEXTURE_MIN_FILTER, m_options.filtering.min);
+    GL::texParameteri(m_target, GL_TEXTURE_MAG_FILTER, m_options.filtering.mag);
+
+    GL::texParameteri(m_target, GL_TEXTURE_WRAP_S, m_options.wrapping.wraps);
+    GL::texParameteri(m_target, GL_TEXTURE_WRAP_T, m_options.wrapping.wrapt);
+
+    m_disposer = Disposer(rs);
+}
+
+bool Texture::isValid() const {
+    return m_glHandle != 0;
+}
+
+void Texture::update(RenderState& rs, GLuint _textureUnit) {
+
+    if (!m_shouldResize && m_dirtyRanges.empty()) {
+        return;
+    }
+
+    if (m_glHandle == 0) {
+        if (m_data.size() == 0) {
+            size_t divisor = sizeof(GLuint) / bytesPerPixel();
+            m_data.resize((m_width * m_height) / divisor, 0);
+        }
+    }
+
+    GLuint* data = m_data.size() > 0 ? m_data.data() : nullptr;
+
+    update(rs, _textureUnit, data);
+
+    m_data.clear();
+}
+
+void Texture::update(RenderState& rs, GLuint _textureUnit, const GLuint* data) {
+
+    if (!m_shouldResize && m_dirtyRanges.empty()) {
+        return;
+    }
+
+    if (m_glHandle == 0) {
+        // texture hasn't been initialized yet, generate it
+        generate(rs, _textureUnit);
+    } else {
+        bind(rs, _textureUnit);
+    }
+
+    // resize or push data
+    if (m_shouldResize) {
+        if (Hardware::maxTextureSize < m_width || Hardware::maxTextureSize < m_height) {
+            LOGW("The hardware maximum texture size is currently reached");
+        }
+
+        GL::texImage2D(m_target, 0, m_options.internalFormat,
+                       m_width, m_height, 0, m_options.format,
+                       GL_UNSIGNED_BYTE, data);
+
+        if (data && m_generateMipmaps) {
+            // generate the mipmaps for this texture
+            GL::generateMipmap(m_target);
+        }
+        m_shouldResize = false;
+        m_dirtyRanges.clear();
+        return;
+    }
+    size_t bpp = bytesPerPixel();
+    size_t divisor = sizeof(GLuint) / bpp;
+
+    for (auto& range : m_dirtyRanges) {
+        size_t offset =  (range.min * m_width) / divisor;
+        GL::texSubImage2D(m_target, 0, 0, range.min, m_width, range.max - range.min,
+                          m_options.format, GL_UNSIGNED_BYTE,
+                          data + offset);
+    }
+    m_dirtyRanges.clear();
+}
+
+void Texture::resize(const unsigned int _width, const unsigned int _height) {
+    m_width = _width;
+    m_height = _height;
+
+    if (!(Hardware::supportsTextureNPOT) &&
+        !(isPowerOfTwo(m_width) && isPowerOfTwo(m_height)) &&
+        (m_generateMipmaps || isRepeatWrapping(m_options.wrapping))) {
+        LOGW("OpenGL ES doesn't support texture repeat wrapping for NPOT textures nor mipmap textures");
+        LOGW("Falling back to LINEAR Filtering");
+        m_options.filtering = {GL_LINEAR, GL_LINEAR};
+        m_generateMipmaps = false;
+    }
+
+    m_shouldResize = true;
+    m_dirtyRanges.clear();
+}
+
+bool Texture::isRepeatWrapping(TextureWrapping _wrapping) {
+    return _wrapping.wraps == GL_REPEAT || _wrapping.wrapt == GL_REPEAT;
+}
+
+size_t Texture::bytesPerPixel() {
+    switch (m_options.internalFormat) {
+        case GL_ALPHA:
+        case GL_LUMINANCE:
+            return 1;
+        case GL_LUMINANCE_ALPHA:
+            return 2;
+        case GL_RGB:
+            return 3;
+        default:
+            return 4;
+    }
+}
+
+void Texture::flipImageData(unsigned char *result, int w, int h, int depth) {
+
+    assert(depth > 0 && w > 0 && h > 0 && bool(result));
+
+    const int step = 512;
+    unsigned char temp[step];
+
+    const int stride = w * depth;
+    const int end = stride % step;
+
+    for (int row = 0; row < h/2; row++) {
+        unsigned char* upper = result + row * stride;
+        unsigned char* lower = result + (h - row - 1) * stride;
+
+        for (int col = 0; col + step <= stride; col += step) {
+            std::copy(upper, upper + step, temp);
+            std::copy(lower, lower + step, upper);
+            std::copy(temp, temp + step, lower);
+            upper += step;
+            lower += step;
+        }
+        if (end != 0) {
+            std::copy(upper, upper + end, temp);
+            std::copy(lower, lower + end, upper);
+            std::copy(temp, temp + end, lower);
+        }
+    }
+}
+
+void Texture::flipImageData(GLuint *result, int w, int h) {
+
+    assert(w > 0 && h > 0 && bool(result));
+
+    const int step = 512;
+    GLuint temp[step];
+
+    const int stride = w;
+    const int end = stride % step;
+
+    for (int row = 0; row < h/2; row++) {
+        GLuint* upper = result + row * stride;
+        GLuint* lower = result + (h - row - 1) * stride;
+
+        for (int col = 0; col + step <= stride; col += step) {
+            std::copy(upper, upper + step, temp);
+            std::copy(lower, lower + step, upper);
+            std::copy(temp, temp + step, lower);
+            upper += step;
+            lower += step;
+        }
+        if (end != 0) {
+            std::copy(upper, upper + end, temp);
+            std::copy(lower, lower + end, upper);
+            std::copy(temp, temp + end, lower);
+        }
+    }
+}
+
+}
diff --git a/core/src/gl/texture.h b/core/src/gl/texture.h
new file mode 100644 (file)
index 0000000..ae13529
--- /dev/null
@@ -0,0 +1,125 @@
+#pragma once
+
+#include "gl.h"
+#include "gl/disposer.h"
+
+#include <vector>
+#include <memory>
+#include <string>
+
+namespace Tangram {
+
+class RenderState;
+
+struct TextureFiltering {
+    GLenum min;
+    GLenum mag;
+};
+
+struct TextureWrapping {
+    GLenum wraps;
+    GLenum wrapt;
+};
+
+struct TextureOptions {
+    GLenum internalFormat;
+    GLenum format;
+    TextureFiltering filtering;
+    TextureWrapping wrapping;
+};
+
+#define DEFAULT_TEXTURE_OPTION \
+    {GL_ALPHA, GL_ALPHA, \
+    {GL_LINEAR, GL_LINEAR}, \
+    {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE}}
+
+class Texture {
+
+public:
+
+    Texture(unsigned int _width, unsigned int _height,
+            TextureOptions _options = DEFAULT_TEXTURE_OPTION,
+            bool _generateMipmaps = false);
+
+    Texture(const std::vector<char>& _data,
+            TextureOptions _options = DEFAULT_TEXTURE_OPTION,
+            bool _generateMipmaps = false);
+
+    Texture(Texture&& _other);
+    Texture& operator=(Texture&& _other);
+
+    virtual ~Texture();
+
+    /* Perform texture updates, should be called at least once and after adding data or resizing */
+    virtual void update(RenderState& rs, GLuint _textureSlot);
+
+    virtual void update(RenderState& rs, GLuint _textureSlot, const GLuint* data);
+
+    /* Resize the texture */
+    void resize(const unsigned int _width, const unsigned int _height);
+
+    /* Width and Height texture getters */
+    unsigned int getWidth() const { return m_width; }
+    unsigned int getHeight() const { return m_height; }
+
+    void bind(RenderState& rs, GLuint _unit);
+
+    void setDirty(size_t yOffset, size_t height);
+
+    GLuint getGlHandle() { return m_glHandle; }
+
+    /* Sets texture data
+     *
+     * Has less priority than set sub data
+     */
+    void setData(const GLuint* _data, unsigned int _dataSize);
+
+    /* Update a region of the texture */
+    void setSubData(const GLuint* _subData, uint16_t _xoff, uint16_t _yoff,
+                    uint16_t _width, uint16_t _height, uint16_t _stride);
+
+    /* Checks whether the texture has valid data and has been successfully uploaded to GPU */
+    bool isValid() const;
+
+    typedef std::pair<GLuint, GLuint> TextureSlot;
+
+    static void invalidateAllTextures();
+
+    static bool isRepeatWrapping(TextureWrapping _wrapping);
+
+    bool loadImageFromMemory(const std::vector<char>& _data);
+
+    static void flipImageData(unsigned char *result, int w, int h, int depth);
+    static void flipImageData(GLuint *result, int w, int h);
+
+protected:
+
+    void generate(RenderState& rs, GLuint _textureUnit);
+
+    TextureOptions m_options;
+    std::vector<GLuint> m_data;
+    GLuint m_glHandle;
+
+    struct DirtyRange {
+        size_t min;
+        size_t max;
+    };
+    std::vector<DirtyRange> m_dirtyRanges;
+
+    bool m_shouldResize;
+
+    unsigned int m_width;
+    unsigned int m_height;
+
+    GLenum m_target;
+
+    Disposer m_disposer;
+
+private:
+
+    size_t bytesPerPixel();
+
+    bool m_generateMipmaps;
+};
+
+}
diff --git a/core/src/gl/uniform.h b/core/src/gl/uniform.h
new file mode 100644 (file)
index 0000000..ab0769e
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "util/variant.h"
+
+#include "glm/glm.hpp"
+#include "platform.h"
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class ShaderProgram;
+
+struct UniformTextureArray {
+    std::vector<std::string> names;
+    std::vector<int> slots;
+
+    inline bool operator==(const UniformTextureArray& uta) {
+        return uta.slots.size() == slots.size() && uta.slots == slots;
+    };
+};
+
+using UniformArray1f = std::vector<float>;
+using UniformArray2f = std::vector<glm::vec2>;
+using UniformArray3f = std::vector<glm::vec3>;
+
+/* Style Block Uniform types */
+using UniformValue = variant<none_type, bool, std::string, float, int, glm::vec2, glm::vec3, glm::vec4,
+    glm::mat2, glm::mat3, glm::mat4, UniformArray1f, UniformArray2f, UniformArray3f, UniformTextureArray>;
+
+
+class UniformLocation {
+
+public:
+    UniformLocation(const std::string& _name) : name(_name) {}
+
+private:
+    const std::string name;
+
+    mutable int location = -2;
+
+    friend class ShaderProgram;
+};
+
+}
diff --git a/core/src/gl/vao.cpp b/core/src/gl/vao.cpp
new file mode 100644 (file)
index 0000000..7200dd3
--- /dev/null
@@ -0,0 +1,72 @@
+#include "gl/vao.h"
+#include "gl/glError.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "gl/vertexLayout.h"
+#include <unordered_map>
+
+namespace Tangram {
+
+void Vao::initialize(RenderState& rs, ShaderProgram& _program, const VertexOffsets& _vertexOffsets,
+                     VertexLayout& _layout, GLuint _vertexBuffer, GLuint _indexBuffer) {
+
+    m_glVAOs.resize(_vertexOffsets.size());
+
+    GL::genVertexArrays(m_glVAOs.size(), m_glVAOs.data());
+
+    fastmap<std::string, GLuint> locations;
+
+    // FIXME (use a bindAttrib instead of getLocation) to make those locations shader independent
+    for (auto& attrib : _layout.getAttribs()) {
+        GLint location = _program.getAttribLocation(attrib.name);
+        locations[attrib.name] = location;
+    }
+
+    rs.vertexBuffer(_vertexBuffer);
+
+    int vertexOffset = 0;
+    for (size_t i = 0; i < _vertexOffsets.size(); ++i) {
+        auto vertexIndexOffset = _vertexOffsets[i];
+        int nVerts = vertexIndexOffset.second;
+        GL::bindVertexArray(m_glVAOs[i]);
+
+        // ELEMENT_ARRAY_BUFFER must be bound after bindVertexArray to be used by VAO
+        if (_indexBuffer != 0) {
+            rs.indexBufferUnset(_indexBuffer);
+            rs.indexBuffer(_indexBuffer);
+        }
+
+        // Enable vertex layout on the specified locations
+        _layout.enable(locations, vertexOffset * _layout.getStride());
+
+        vertexOffset += nVerts;
+    }
+
+    GL::bindVertexArray(0);
+
+    rs.vertexBuffer(0);
+    rs.indexBuffer(0);
+}
+
+bool Vao::isInitialized() {
+    return !m_glVAOs.empty();
+}
+
+void Vao::bind(unsigned int _index) {
+    if (_index < m_glVAOs.size()) {
+        GL::bindVertexArray(m_glVAOs[_index]);
+    }
+}
+
+void Vao::unbind() {
+    GL::bindVertexArray(0);
+}
+
+void Vao::dispose() {
+    if (!m_glVAOs.empty()) {
+        GL::deleteVertexArrays(m_glVAOs.size(), m_glVAOs.data());
+        m_glVAOs.clear();
+    }
+}
+
+}
diff --git a/core/src/gl/vao.h b/core/src/gl/vao.h
new file mode 100644 (file)
index 0000000..47c8e13
--- /dev/null
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "gl.h"
+#include <vector>
+#include <string>
+
+namespace Tangram {
+
+class RenderState;
+class ShaderProgram;
+class VertexLayout;
+
+using VertexOffsets = std::vector<std::pair<uint32_t, uint32_t>>;
+
+class Vao {
+
+public:
+
+    void initialize(RenderState& rs, ShaderProgram& _program, const VertexOffsets& _vertexOffsets,
+                    VertexLayout& _layout, GLuint _vertexBuffer, GLuint _indexBuffer);
+    bool isInitialized();
+    void bind(unsigned int _index);
+    void unbind();
+    void dispose();
+
+private:
+    std::vector<GLuint> m_glVAOs;
+
+};
+
+}
+
diff --git a/core/src/gl/vertexLayout.cpp b/core/src/gl/vertexLayout.cpp
new file mode 100644 (file)
index 0000000..01b8bed
--- /dev/null
@@ -0,0 +1,107 @@
+#include "gl/vertexLayout.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "gl/glError.h"
+#include "log.h"
+
+namespace Tangram {
+
+VertexLayout::VertexLayout(std::vector<VertexAttrib> _attribs) : m_attribs(_attribs) {
+
+    m_stride = 0;
+
+    for (auto& attrib : m_attribs) {
+
+        // Set the offset of this vertex attribute: The stride at this point denotes the number
+        // of bytes into the vertex by which this attribute is offset, but we must cast the number
+        // as a void* to use with glVertexAttribPointer; We use reinterpret_cast to avoid warnings
+        attrib.offset = m_stride;
+
+        GLint byteSize = attrib.size;
+
+        switch (attrib.type) {
+            case GL_FLOAT:
+            case GL_INT:
+            case GL_UNSIGNED_INT:
+                byteSize *= 4; // 4 bytes for floats, ints, and uints
+                break;
+            case GL_SHORT:
+            case GL_UNSIGNED_SHORT:
+                byteSize *= 2; // 2 bytes for shorts and ushorts
+                break;
+        }
+
+        m_stride += byteSize;
+
+        // TODO: Automatically add padding or warn if attributes are not byte-aligned
+
+    }
+}
+
+size_t VertexLayout::getOffset(std::string _attribName) {
+
+    for (auto& attrib : m_attribs) {
+        if (attrib.name == _attribName) {
+            return attrib.offset;
+        }
+    }
+
+    LOGE("No such attribute %s", _attribName.c_str());
+    return 0;
+}
+
+void VertexLayout::enable(const fastmap<std::string, GLuint>& _locations, size_t _byteOffset) {
+
+    for (auto& attrib : m_attribs) {
+        auto it = _locations.find(attrib.name);
+
+        if (it == _locations.end()) {
+            continue;
+        }
+
+        GLint location = it->second;;
+
+        if (location != -1) {
+            void* offset = ((unsigned char*) attrib.offset) + _byteOffset;
+            GL::enableVertexAttribArray(location);
+            GL::vertexAttribPointer(location, attrib.size, attrib.type, attrib.normalized, m_stride, offset);
+        }
+    }
+
+}
+
+void VertexLayout::enable(RenderState& rs, ShaderProgram& _program, size_t _byteOffset, void* _ptr) {
+
+    GLuint glProgram = _program.getGlProgram();
+
+    // Enable all attributes for this layout
+    for (auto& attrib : m_attribs) {
+
+        GLint location = _program.getAttribLocation(attrib.name);
+
+        if (location != -1) {
+            auto& loc = rs.attributeBindings[location];
+            // Track currently enabled attribs by the program to which they are bound
+            if (loc != glProgram) {
+                GL::enableVertexAttribArray(location);
+                loc = glProgram;
+            }
+
+            void* data = (unsigned char*)_ptr + attrib.offset + _byteOffset;
+            GL::vertexAttribPointer(location, attrib.size, attrib.type, attrib.normalized, m_stride, data);
+        }
+    }
+
+    // Disable previously bound and now-unneeded attributes
+    for (size_t i = 0; i < RenderState::MAX_ATTRIBUTES; ++i) {
+
+        GLuint& boundProgram = rs.attributeBindings[i];
+
+        if (boundProgram != glProgram && boundProgram != 0) {
+            GL::disableVertexAttribArray(i);
+            boundProgram = 0;
+        }
+    }
+}
+
+}
diff --git a/core/src/gl/vertexLayout.h b/core/src/gl/vertexLayout.h
new file mode 100644 (file)
index 0000000..f9b9d72
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "gl.h"
+
+#include "util/fastmap.h"
+
+#include <vector>
+#include <memory>
+#include <string>
+
+namespace Tangram {
+
+class RenderState;
+class ShaderProgram;
+
+class VertexLayout {
+
+public:
+
+    struct VertexAttrib {
+        std::string name;
+        GLint size;
+        GLenum type;
+        GLboolean normalized;
+        size_t offset; // Can be left as zero; value is overwritten in constructor of VertexLayout
+    };
+
+    VertexLayout(std::vector<VertexAttrib> _attribs);
+
+    void enable(RenderState& rs, ShaderProgram& _program, size_t _byteOffset, void* _ptr = nullptr);
+
+    void enable(const fastmap<std::string, GLuint>& _locations, size_t _bytOffset);
+
+    GLint getStride() const { return m_stride; };
+
+    const std::vector<VertexAttrib> getAttribs() const { return m_attribs; }
+
+    size_t getOffset(std::string _attribName);
+
+private:
+
+    std::vector<VertexAttrib> m_attribs;
+    GLint m_stride;
+
+};
+
+}
diff --git a/core/src/labels/curvedLabel.cpp b/core/src/labels/curvedLabel.cpp
new file mode 100644 (file)
index 0000000..1c00704
--- /dev/null
@@ -0,0 +1,288 @@
+#include "labels/curvedLabel.h"
+
+#include "gl/dynamicQuadMesh.h"
+#include "labels/obbBuffer.h"
+#include "labels/screenTransform.h"
+#include "log.h"
+#include "style/textStyle.h"
+#include "text/fontContext.h"
+#include "textLabels.h"
+#include "util/geom.h"
+#include "util/lineSampler.h"
+#include "view/view.h"
+
+#include <glm/gtx/norm.hpp>
+
+namespace Tangram {
+
+void CurvedLabel::applyAnchor(LabelProperty::Anchor _anchor) {
+
+    using namespace TextLabelProperty;
+
+    if (m_preferedAlignment == Align::none) {
+        Align newAlignment = alignFromAnchor(_anchor);
+        m_textRangeIndex = int(newAlignment);
+    } else {
+        m_textRangeIndex = int(m_preferedAlignment);
+    }
+
+    if (m_textRanges[m_textRangeIndex].length == 0) {
+        m_textRangeIndex = 0;
+    }
+
+    glm::vec2 offset = m_dim;
+    if (isChild()) { offset += m_relative->dimension(); }
+
+    m_anchor = LabelProperty::anchorDirection(_anchor) * offset * 0.5f;
+}
+
+bool CurvedLabel::updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                                        const AABB* _bounds, ScreenTransform& _transform) {
+
+    glm::vec2 min(-m_dim.y);
+    glm::vec2 max(_viewState.viewportSize + m_dim.y);
+
+    bool clipped = false;
+    bool inside = false;
+
+    LineSampler<ScreenTransform> sampler { _transform };
+
+    for (auto& p : m_modelTransform) {
+        glm::vec2 sp = worldToScreenSpace(_mvp, glm::vec4(p, 0.0, 1.0),
+                                          _viewState.viewportSize, clipped);
+
+        if (clipped) { return false; }
+
+        sampler.add(sp);
+
+        if (!inside) {
+            if ((sp.x > min.x && sp.x < max.x &&
+                 sp.y > min.y && sp.y < max.y)) {
+                inside = true;
+            }
+        }
+    }
+
+    if (!inside || sampler.sumLength() < m_dim.x) {
+        sampler.clearPoints();
+        return false;
+    }
+
+    auto center = sampler.point(m_anchorPoint);
+
+    // Set center for repeatGroup distance calculations
+    m_screenCenter = glm::vec2(center);
+    m_screenAnchorPoint = m_anchorPoint;
+
+    // Chord length for minimal ~120 degree inner angles (squared)
+    // sin(60)*2
+    const float sqDirLimit = powf(1.7f, 2);
+    // Range to check for angle changes
+    const float sampleWindow = 20;
+
+    float width = m_dim.x;
+    float start = sampler.point(m_anchorPoint).z - width * 0.5f;
+
+    if (start < 0 || start + width > sampler.sumLength()) {
+        sampler.clearPoints();
+        return false;
+    }
+
+    // Sets current segment to the segment on which the text starts.
+    glm::vec2 startPos, r;
+    sampler.sample(start, startPos, r);
+    size_t startSegment = sampler.curSegment();
+
+    glm::vec2 dir = sampler.segmentDirection(startSegment);
+
+    // Cannot reverse the direction when some glyphs must be
+    // placed in forward direction and vice versa.
+    const float flipTolerance = sin(DEG_TO_RAD * 45);
+    bool mustForward = dir.x > flipTolerance;
+    bool mustReverse = dir.x < -flipTolerance;
+
+    for (size_t i = startSegment + 1; i < _transform.size(); i++) {
+        float currLength = sampler.point(i).z;
+        dir = sampler.segmentDirection(i);
+
+        if (dir.x > flipTolerance) {
+            mustForward = true;
+        }
+        if (dir.x < -flipTolerance) {
+            mustReverse = true;
+        }
+
+        if (mustForward && mustReverse) {
+            sampler.clearPoints();
+            return false;
+        }
+
+        // Go back within window to check for hard direction changes
+        for (int k = i - 1; k >= int(startSegment); k--) {
+            if (glm::length2(sampler.segmentDirection(k) + dir) < sqDirLimit) {
+                sampler.clearPoints();
+                return false;
+            }
+            if (sampler.point(k).z < sampler.point(i).z - sampleWindow) {
+                break;
+            }
+        }
+        if (currLength > start + width) {
+            break;
+        }
+    }
+
+    if (!mustReverse) {
+        // TODO use better heuristic to decide flipping
+        glm::vec2 endPos;
+        sampler.sample(start + width, endPos, r);
+        if (startPos.x > endPos.x) {
+            mustReverse = true;
+        }
+    }
+
+    if (mustReverse) {
+        sampler.reversePoints();
+        m_screenAnchorPoint = _transform.size() - m_anchorPoint - 1;
+    }
+
+    return true;
+}
+
+void CurvedLabel::obbs(ScreenTransform& _transform, OBBBuffer& _obbs) {
+
+    glm::vec2 dim = m_dim - m_options.buffer;
+
+    if (m_occludedLastFrame) { dim += Label::activation_distance_threshold; }
+
+    // TODO: Remove - Only for testing
+    if (state() == State::dead) { dim -= 4; }
+
+    float width = dim.x;
+    LineSampler<ScreenTransform> sampler { _transform };
+
+    auto center = sampler.point(m_screenAnchorPoint).z;
+    //auto center = sampler.sumLength() * 0.5;
+
+    auto start = center - width * 0.5f;
+
+    glm::vec2 p1, p2, rotation;
+    sampler.sample(start, p1, rotation);
+
+    float prevLength = start;
+
+    int count = 0;
+    for (size_t i = sampler.curSegment()+1; i < _transform.size(); i++) {
+
+        float currLength = sampler.point(i).z;
+        float segmentLength = currLength - prevLength;
+        count++;
+
+        if (start + width > currLength) {
+            p2 = glm::vec2(sampler.point(i));
+
+            rotation = sampler.segmentDirection(i-1);
+            _obbs.append({(p1 + p2) * 0.5f, rotation, segmentLength, dim.y});
+            prevLength = currLength;
+            p1 = p2;
+
+        } else {
+
+            segmentLength = (start + width) - prevLength;
+            sampler.sample(start + width, p2, rotation);
+            _obbs.append({(p1 + p2) * 0.5f, rotation, segmentLength, dim.y});
+            break;
+        }
+    }
+}
+
+void CurvedLabel::addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) {
+    if (!visibleState()) { return; }
+
+    TextVertex::State state {
+        m_fontAttrib.selectionColor,
+        m_fontAttrib.fill,
+        m_fontAttrib.stroke,
+        uint16_t(m_alpha * TextVertex::alpha_scale),
+        uint16_t(m_fontAttrib.fontScale),
+    };
+
+    auto it = m_textLabels.quads.begin() + m_textRanges[m_textRangeIndex].start;
+    auto end = it + m_textRanges[m_textRangeIndex].length;
+    auto& style = m_textLabels.style;
+
+    auto& meshes = style.getMeshes();
+
+    glm::vec2 rotation;
+    LineSampler<ScreenTransform> sampler { _transform };
+
+    float width = m_dim.x;
+
+    if (sampler.sumLength() < width) { return; }
+
+    float center = sampler.point(m_screenAnchorPoint).z;
+
+    std::array<glm::i16vec2, 4> vertexPosition;
+
+    glm::i16vec2 min(-m_dim.y * TextVertex::position_scale);
+    glm::i16vec2 max((_screenSize + m_dim.y) * TextVertex::position_scale);
+
+    for (; it != end; ++it) {
+        auto quad = *it;
+
+        glm::vec2 origin = {(quad.quad[0].pos.x + quad.quad[2].pos.x) * 0.5f, 0 };
+        glm::vec2 point, p1, p2, r1, r2;
+
+        auto xStart = quad.quad[0].pos.x * TextVertex::position_inv_scale;
+        auto xEnd = quad.quad[2].pos.x * TextVertex::position_inv_scale;
+
+        float px = origin.x * TextVertex::position_inv_scale;
+        if (!sampler.sample(center + px, point, rotation)) {
+            continue;
+        }
+
+        bool ok1 = sampler.sample(center + xStart, p1, r1);
+        bool ok2 = sampler.sample(center + xEnd, p2, r2);
+        if (ok1 && ok2) {
+            if (r1 == r2) {
+                rotation = r1;
+            } else {
+                rotation = glm::normalize(p2 - p1);
+            }
+            //point = (p1 + p2) * 0.5f;
+            point = point * 0.5f + (p1 + p2) * 0.25f;
+        }
+
+        glm::i16vec2 p(point * TextVertex::position_scale);
+
+        rotation = {rotation.x, -rotation.y};
+
+        bool visible = false;
+
+        for (int i = 0; i < 4; i++) {
+
+            vertexPosition[i] = p + glm::i16vec2{rotateBy(glm::vec2(quad.quad[i].pos) - origin, rotation)};
+
+            if (!visible &&
+                vertexPosition[i].x > min.x &&
+                vertexPosition[i].x < max.x &&
+                vertexPosition[i].y > min.y &&
+                vertexPosition[i].y < max.y) {
+                visible = true;
+            }
+        }
+
+        if (!visible) { continue; }
+
+        auto* quadVertices = meshes[it->atlas]->pushQuad();
+
+        for (int i = 0; i < 4; i++) {
+            TextVertex& v = quadVertices[i];
+            v.pos = vertexPosition[i];
+            v.uv = quad.quad[i].uv;
+            v.state = state;
+        }
+    }
+}
+
+}
diff --git a/core/src/labels/curvedLabel.h b/core/src/labels/curvedLabel.h
new file mode 100644 (file)
index 0000000..c87f6c0
--- /dev/null
@@ -0,0 +1,69 @@
+#pragma once
+
+#include "labels/label.h"
+#include "labels/textLabel.h"
+
+#include <glm/glm.hpp>
+
+namespace Tangram {
+
+class TextLabels;
+class TextStyle;
+
+class CurvedLabel : public TextLabel {
+
+public:
+
+    struct VertexAttributes {
+        uint32_t fill;
+        uint32_t stroke;
+        uint8_t fontScale;
+        uint32_t selectionColor;
+    };
+
+    using ModelTransform = std::vector<glm::vec2>;
+
+    CurvedLabel(ModelTransform _modelTransform, Label::Options _options, float _prio,
+                TextLabel::VertexAttributes _attrib, glm::vec2 _dim,
+                TextLabels& _labels, TextRange _textRanges,
+                TextLabelProperty::Align _preferedAlignment, size_t _anchorPoint)
+
+        : TextLabel({{}}, Label::Type::curved, _options, _attrib,
+                    _dim, _labels, _textRanges, _preferedAlignment),
+          m_modelTransform(std::move(_modelTransform)),
+          m_anchorPoint(_anchorPoint),
+          m_screenAnchorPoint(_anchorPoint),
+          m_prio(_prio) {
+
+        applyAnchor(m_options.anchors[0]);
+    }
+
+    bool updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                               const AABB* _bounds, ScreenTransform& _transform) override;
+
+    void obbs(ScreenTransform& _transform, OBBBuffer& _obbs) override;
+
+    void addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) override;
+
+    void applyAnchor(LabelProperty::Anchor _anchor) override;
+
+    float candidatePriority() const override {
+        return m_prio;
+    }
+
+    glm::vec2 modelCenter() const override {
+        return m_modelTransform[m_anchorPoint];
+    }
+
+protected:
+
+    const std::vector<glm::vec2> m_modelTransform;
+
+    const size_t m_anchorPoint;
+
+    size_t m_screenAnchorPoint;
+
+    float m_prio = 0;
+};
+
+}
diff --git a/core/src/labels/fadeEffect.h b/core/src/labels/fadeEffect.h
new file mode 100644 (file)
index 0000000..7fce72a
--- /dev/null
@@ -0,0 +1,58 @@
+#pragma once
+
+#include <cmath>
+
+namespace Tangram {
+
+struct FadeEffect {
+
+public:
+
+    enum Interpolation {
+        linear = 0,
+        pow,
+        sine
+    };
+
+    FadeEffect() {}
+
+    FadeEffect(bool _in, Interpolation _interpolation, float _duration)
+        : m_interpolation(_interpolation), m_duration(_duration), m_in(_in) {}
+
+    float update(float _dt) {
+        m_step += _dt;
+        float st = m_step / m_duration;
+
+        switch (m_interpolation) {
+            case Interpolation::linear:
+                return m_in ? st : -st + 1;
+            case Interpolation::pow:
+                return m_in ? st * st : -(st * st) + 1;
+            case Interpolation::sine:
+                return m_in ? sin(st * M_PI * 0.5) : cos(st * M_PI * 0.5);
+        }
+
+        return st;
+    }
+
+    void reset(bool _in, Interpolation _interpolation, float _duration) {
+        m_in = _in;
+        m_interpolation = _interpolation;
+        m_duration = _duration;
+        m_step = 0.f;
+    }
+
+    bool isFinished() {
+        return m_step > m_duration;
+    }
+
+private:
+
+    Interpolation m_interpolation = Interpolation::linear;
+    float m_duration = 0.0f;
+    float m_step = 0.0f;
+    bool m_in = false;
+};
+
+}
+
diff --git a/core/src/labels/label.cpp b/core/src/labels/label.cpp
new file mode 100644 (file)
index 0000000..0a51336
--- /dev/null
@@ -0,0 +1,223 @@
+#include "labels/label.h"
+
+#include "log.h"
+#include "platform.h"
+#include "tile/tile.h"
+#include "util/geom.h"
+#include "util/mapProjection.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+const float Label::activation_distance_threshold = 2;
+
+Label::Label(glm::vec2 _size, Type _type, Options _options)
+    : m_type(_type),
+      m_dim(_size + _options.buffer),
+      m_options(_options),
+      m_state(State::none) {
+
+    if (m_type == Type::debug) {
+        m_options.collide = false;
+    }
+
+    if (m_options.collide) {
+        enterState(State::none, 0.0);
+    } else {
+        enterState(State::visible, 1.0);
+    }
+
+    m_occludedLastFrame = false;
+    m_occluded = false;
+    m_relative = nullptr;
+    m_anchorIndex = 0;
+}
+
+Label::~Label() {}
+
+void Label::setRelative(Label& _relative, bool _definePriority, bool _defineCollide) {
+    m_relative = &_relative;
+
+    if (_definePriority) {
+        m_options.priority = _relative.options().priority + 0.5f;
+    }
+
+    if (_defineCollide) {
+        m_options.collide = _relative.options().collide;
+    }
+
+    applyAnchor(m_options.anchors[m_anchorIndex]);
+}
+
+bool Label::visibleState() const {
+    int visibleFlags = (State::visible |
+                        State::fading_in |
+                        State::fading_out |
+                        State::skip_transition);
+
+    return (visibleFlags & m_state);
+}
+
+void Label::skipTransitions() {
+    enterState(State::skip_transition, 0.0);
+}
+
+void Label::enterState(const State& _state, float _alpha) {
+    if (m_state == State::dead) { return; }
+
+    m_state = _state;
+    setAlpha(_alpha);
+
+    if (m_state == State::sleep) {
+        // Reset anchor fallback index
+        m_anchorIndex = 0;
+    }
+}
+
+void Label::setAlpha(float _alpha) {
+    m_alpha = CLAMP(_alpha, 0.0, 1.0);
+}
+
+void Label::resetState() {
+
+    if (m_state == State::dead) { return; }
+
+    m_occludedLastFrame = false;
+    m_occluded = false;
+    m_anchorIndex = 0;
+    enterState(State::none, 0.0);
+}
+
+void Label::print() const {
+    LOG("Label - %p", this);
+    LOG("\tm_occludedLastFrame: %d", m_occludedLastFrame);
+    LOG("\tm_occluded: %d", m_occluded);
+    std::string state;
+    switch (m_state) {
+        case State::none: state = "none"; break;
+        case State::visible: state = "visible"; break;
+        case State::fading_in: state = "fading_in"; break;
+        case State::fading_out: state = "fading_out"; break;
+        case State::skip_transition: state = "skip_transition"; break;
+        case State::sleep: state = "sleep"; break;
+        case State::dead: state = "dead"; break;
+        case State::out_of_screen: state = "out_of_screen"; break;
+    }
+    LOG("\tm_state: %s", state.c_str());
+    LOG("\tm_anchorIndex: %d", m_anchorIndex);
+}
+
+bool Label::nextAnchor() {
+    int index = m_anchorIndex;
+    setAnchorIndex((index + 1) % m_options.anchors.count);
+
+    return m_anchorIndex != index;
+}
+
+bool Label::setAnchorIndex(int _index) {
+    if (_index >= int(m_options.anchors.count) || _index < 0) {
+        return false;
+    }
+    m_anchorIndex = _index;
+
+    applyAnchor(m_options.anchors[m_anchorIndex]);
+
+    return true;
+}
+
+bool Label::update(const glm::mat4& _mvp, const ViewState& _viewState,
+                   const AABB* _bounds, ScreenTransform& _transform) {
+
+    m_occludedLastFrame = m_occluded;
+    m_occluded = false;
+
+    bool valid = updateScreenTransform(_mvp, _viewState, _bounds, _transform);
+    if (!valid) {
+        enterState(State::sleep, 0.0);
+        return false;
+    }
+
+    return true;
+}
+
+bool Label::evalState(float _dt) {
+
+#ifdef DEBUG
+    if (Tangram::getDebugFlag(DebugFlags::draw_all_labels)) {
+        enterState(State::visible, 1.0);
+        return false;
+    }
+#endif
+
+    switch (m_state) {
+        case State::none:
+        case State::sleep:
+            if (m_occluded) {
+                enterState(State::sleep, 0.0);
+                return false;
+            }
+            if (m_options.showTransition.time == 0.f) {
+                enterState(State::visible, 1.0);
+                return false;
+            }
+            m_fade.reset(true, m_options.showTransition.ease,
+                         m_options.showTransition.time);
+            enterState(State::fading_in, 0.0);
+            return true;
+
+        case State::visible:
+            if (!m_occluded) { return false; }
+
+            if (m_options.hideTransition.time == 0.f) {
+                enterState(State::sleep, 0.0);
+                return false;
+            }
+            m_fade.reset(false, m_options.hideTransition.ease,
+                         m_options.hideTransition.time);
+
+            enterState(State::fading_out, 1.0);
+            return true;
+
+        case State::fading_in:
+            if (m_occluded) {
+                enterState(State::sleep, 0.0);
+                return false;
+            }
+            setAlpha(m_fade.update(_dt));
+            if (m_fade.isFinished()) {
+                enterState(State::visible, 1.0);
+                return false;
+            }
+            return true;
+
+        case State::fading_out:
+            // if (!m_occluded) {
+            //     enterState(State::fading_in, m_transform.state.alpha);
+            //     m_fade.reset(false, m_options.hideTransition.ease,
+            //                  m_options.showTransition.time);
+            //     return true;
+            // }
+            setAlpha(m_fade.update(_dt));
+            if (m_fade.isFinished()) {
+                enterState(State::sleep, 0.0);
+                return false;
+            }
+            return true;
+
+        case State::skip_transition:
+            if (m_occluded) {
+                enterState(State::sleep, 0.0);
+            } else {
+                enterState(State::visible, 1.0);
+            }
+            return true;
+
+        case State::dead:
+        case State::out_of_screen:
+            break;
+    }
+
+    return false;
+}
+
+}
diff --git a/core/src/labels/label.h b/core/src/labels/label.h
new file mode 100644 (file)
index 0000000..6f64501
--- /dev/null
@@ -0,0 +1,205 @@
+#pragma once
+
+#include "labels/fadeEffect.h"
+#include "labels/labelProperty.h"
+#include "tangram.h"
+#include "util/types.h"
+#include "util/hash.h"
+
+#include "glm/vec2.hpp"
+#include "glm/vec3.hpp"
+#include "glm/mat4x4.hpp"
+#include <climits> // needed in aabb.h
+#include "aabb.h"
+#include "obb.h"
+#include <string>
+#include <limits>
+#include <memory>
+
+namespace Tangram {
+
+struct ScreenTransform;
+struct ViewState;
+struct OBBBuffer;
+
+class Label {
+
+public:
+
+    using OBB = isect2d::OBB<glm::vec2>;
+    using AABB = isect2d::AABB<glm::vec2>;
+
+    enum class Type {
+        point,
+        line,
+        curved,
+        debug
+    };
+
+    enum State {
+        none            = 1 << 0,
+        fading_in       = 1 << 1,
+        fading_out      = 1 << 2,
+        visible         = 1 << 3,
+        sleep           = 1 << 4,
+        out_of_screen   = 1 << 5,
+        skip_transition = 1 << 6,
+        dead            = 1 << 7,
+    };
+
+    struct Transition {
+        FadeEffect::Interpolation ease = FadeEffect::Interpolation::linear;
+        float time = 0.0;
+    };
+
+    struct Options {
+        glm::vec2 offset;
+        glm::vec2 buffer;
+        float priority = std::numeric_limits<float>::max();
+        bool collide = true;
+        Transition selectTransition;
+        Transition hideTransition;
+        Transition showTransition;
+        size_t repeatGroup = 0;
+        float repeatDistance = 0;
+        size_t paramHash = 0; // the label hash based on its styling parameters
+        LabelProperty::Anchors anchors;
+        bool optional = false;
+        bool flat = false;
+        float angle = 0.f;
+        uint32_t featureId = 0;
+    };
+
+    static const float activation_distance_threshold;
+
+    Label(glm::vec2 _size, Type _type, Options _options);
+
+    virtual ~Label();
+
+    // Add vertices for this label to its Style's shared Mesh
+    virtual void addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) = 0;
+
+    virtual LabelType renderType() const = 0;
+
+    virtual uint32_t selectionColor() = 0;
+
+    virtual glm::vec2 modelCenter() const = 0;
+
+    // Returns the candidate priority for a feature with multiple labels
+    virtual float candidatePriority() const { return 0; }
+
+    bool update(const glm::mat4& _mvp, const ViewState& _viewState,
+                const AABB* _bounds, ScreenTransform& _transform);
+
+    bool evalState(float _dt);
+
+    // Update the screen position of the label
+    virtual bool updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                                       const AABB* _bounds, ScreenTransform& _transform) = 0;
+
+    // Current screen position of the label anchor
+    glm::vec2 screenCenter() const { return m_screenCenter; }
+
+    // Occlude the label
+    void occlude(bool _occlusion = true) { m_occluded = _occlusion; }
+
+    // Checks whether the label is in a state where it can occlusion
+    bool canOcclude() const { return m_options.collide; }
+
+    void skipTransitions();
+
+    size_t hash() const { return m_options.paramHash; }
+
+    glm::vec2 dimension() const { return m_dim; }
+
+    // Gets for label options: color and offset
+    const Options& options() const { return m_options; }
+
+    // Adds the oriented bounding boxes of the label to _obbs, updates Range
+    virtual void obbs(ScreenTransform& _transform, OBBBuffer& _obbs) = 0;
+
+    State state() const { return m_state; }
+
+    bool isOccluded() const { return m_occluded; }
+
+    bool occludedLastFrame() const { return m_occludedLastFrame; }
+
+    Label* relative() const { return m_relative; }
+    bool isChild() const { return bool(m_relative); }
+    bool isSibling() const { return bool(m_relative) && bool(m_relative->relative()); }
+
+    void setRelative(Label& _relative, bool _definePriority, bool _defineCollide);
+
+    LabelProperty::Anchor anchorType() const {
+        return m_options.anchors[m_anchorIndex];
+    }
+
+    int anchorIndex() { return m_anchorIndex; }
+
+    bool nextAnchor();
+
+    bool setAnchorIndex(int _index);
+
+    void enterState(const State& _state, float _alpha = 1.0f);
+
+    void resetState();
+
+    // Checks whether the label is in a visible state
+    bool visibleState() const;
+
+    Type type() const { return m_type; }
+
+    void print() const;
+
+    void setAlpha(float _alpha);
+
+protected:
+
+    virtual void applyAnchor(LabelProperty::Anchor _anchor) = 0;
+
+    const Type m_type;
+    const glm::vec2 m_dim;
+
+    Options m_options;
+
+    Label* m_relative;
+
+    State m_state;
+    FadeEffect m_fade;
+
+    int m_anchorIndex;
+    glm::vec2 m_anchor;
+
+    bool m_occludedLastFrame;
+    bool m_occluded;
+
+    glm::vec2 m_screenCenter;
+    float m_alpha;
+};
+
+}
+
+namespace std {
+    template <>
+    struct hash<Tangram::Label::Options> {
+        size_t operator() (const Tangram::Label::Options& o) const {
+            std::size_t seed = 0;
+            hash_combine(seed, o.offset.x);
+            hash_combine(seed, o.offset.y);
+            hash_combine(seed, o.priority);
+            hash_combine(seed, o.collide);
+            hash_combine(seed, o.repeatDistance);
+            hash_combine(seed, o.repeatGroup);
+            hash_combine(seed, (int)o.selectTransition.ease);
+            hash_combine(seed, o.selectTransition.time);
+            hash_combine(seed, (int)o.hideTransition.ease);
+            hash_combine(seed, o.hideTransition.time);
+            hash_combine(seed, (int)o.showTransition.ease);
+            hash_combine(seed, o.showTransition.time);
+            for (int i = 0; i < o.anchors.count; ++i) {
+                hash_combine(seed, (int)o.anchors[i]);
+            }
+            return seed;
+        }
+    };
+}
diff --git a/core/src/labels/labelCollider.cpp b/core/src/labels/labelCollider.cpp
new file mode 100644 (file)
index 0000000..c625163
--- /dev/null
@@ -0,0 +1,303 @@
+#include "labels/labelCollider.h"
+
+#include "labels/curvedLabel.h"
+#include "labels/labelSet.h"
+#include "labels/obbBuffer.h"
+#include "view/view.h" // ViewState
+
+#include "glm/gtc/matrix_transform.hpp"
+#include "glm/gtx/norm.hpp"
+
+namespace Tangram {
+
+void LabelCollider::addLabels(std::vector<std::unique_ptr<Label>>& _labels) {
+
+    for (auto& label : _labels) {
+        if (label->canOcclude()) {
+            m_labels.push_back(label.get());
+        }
+    }
+}
+
+size_t LabelCollider::filterRepeatGroups(size_t startPos, size_t curPos) {
+
+    size_t endGroup = m_labels[curPos].label->options().repeatGroup;
+    size_t endPos = curPos;
+
+    for (size_t pos = startPos; pos <= curPos; pos = endPos + 1) {
+        size_t repeatGroup = m_labels[pos].label->options().repeatGroup;
+        float  threshold2 = pow(m_labels[pos].label->options().repeatDistance, 2);
+
+        // Find end of the current repeatGroup
+        endPos = pos;
+
+        for (;endPos < m_labels.size()-1; endPos++) {
+            if (m_labels[endPos+1].label->options().repeatGroup != repeatGroup) {
+                break;
+            }
+        }
+
+        for (size_t i = pos; i < endPos; i++) {
+            Label* l1 = m_labels[i].label;
+            if (l1->isOccluded()) { continue; }
+
+            for (size_t j = i+1; j <= endPos; j++) {
+                Label* l2 = m_labels[j].label;
+                if (l2->isOccluded()) { continue; }
+
+                float d2 = distance2(l1->screenCenter(), l2->screenCenter());
+                if (d2 < threshold2) {
+                    l2->occlude();
+                }
+            }
+        }
+        if (repeatGroup == endGroup) { break; }
+    }
+    return endPos;
+}
+
+void LabelCollider::process(TileID _tileID, float _tileInverseScale, float _tileSize) {
+
+    // Sort labels so that all labels of one repeat group are next to each other
+    std::sort(m_labels.begin(), m_labels.end(),
+              [](auto& e1, auto& e2) {
+                  auto* l1 = e1.label;
+                  auto* l2 = e2.label;
+
+                  if (l1->options().priority != l2->options().priority) {
+                      // lower numeric priority means higher priority
+                      return l1->options().priority < l2->options().priority;
+                  }
+                  if (l1->options().repeatGroup != l2->options().repeatGroup) {
+                      return l1->options().repeatGroup < l2->options().repeatGroup;
+                  }
+
+                  if (l1->type() == l2->type()) {
+                      return l1->candidatePriority() < l2->candidatePriority();
+                  }
+
+                  return l1->hash() < l2->hash();
+              });
+
+    // Set view parameters so that the tile is rendererd at
+    // style-zoom-level + 2. (scaled up by factor 4). This
+    // filters out labels that are unlikely to become visible
+    // within the tiles zoom-range.
+    int overzoom = 2;
+    float tileScale = pow(2, _tileID.s - _tileID.z + overzoom);
+    glm::vec2 screenSize{ _tileSize * tileScale };
+
+    // Project tile to NDC (-1 to 1, y-up)
+    glm::mat4 mvp{1};
+    mvp[0][0] = 1.0f;
+    mvp[1][1] = -1.f;
+    // Place tile centered
+    mvp[3][0] = -0.5f;
+    mvp[3][1] = 0.5f;
+
+    ViewState viewState {
+        nullptr, // mapProjection (unused)
+        false, // changedOnLastUpdate (unused)
+        glm::dvec2{}, // center (unused)
+        0.f, // zoom (unused)
+        powf(2.f, _tileID.s + overzoom), // zoomScale
+        0.f, // fractZoom
+        screenSize, // viewPortSize
+        _tileSize, // screenTileSize
+    };
+
+    m_obbs.clear();
+    m_transforms.clear();
+
+    for (auto it = m_labels.begin(); it != m_labels.end(); ) {
+        auto& entry = *it;
+        auto* label = entry.label;
+        ScreenTransform transform { m_transforms, entry.transform };
+        if (label->updateScreenTransform(mvp, viewState, nullptr, transform)) {
+
+            OBBBuffer obbs { m_obbs, entry.obbs };
+
+            label->obbs(transform, obbs);
+
+            auto aabb = m_obbs[entry.obbs.start].getExtent();
+            for (int i = entry.obbs.start+1; i < entry.obbs.end(); i++) {
+                aabb = unionAABB(aabb, m_obbs[i].getExtent());
+            }
+
+            m_aabbs.push_back(aabb);
+            it++;
+        } else {
+            it = m_labels.erase(it);
+        }
+    }
+
+    if (m_labels.empty()) { return; }
+
+    m_isect2d.resize({screenSize.x / 128, screenSize.y / 128}, screenSize);
+
+    m_isect2d.intersect(m_aabbs);
+
+    // Set the first item to be the one with higher priority
+    for (auto& pair : m_isect2d.pairs) {
+
+        auto& e1 = m_labels[pair.first];
+        auto& e2 = m_labels[pair.second];
+        auto* l1 = e1.label;
+        auto* l2 = e2.label;
+
+        if (l1->options().priority > l2->options().priority) {
+            std::swap(pair.first, pair.second);
+
+            // Note: Mark the label to be potentially occluded
+            l2->enterState(Label::State::sleep, 0.0f);
+        } else {
+            l1->enterState(Label::State::sleep, 0.0f);
+        }
+    }
+
+    // Sort by priority on the first item
+    std::sort(m_isect2d.pairs.begin(), m_isect2d.pairs.end(),
+              [&](auto& a, auto& b) {
+
+                  if (a.first == b.first) { return a.second < b.second; }
+
+                  auto* l1 = m_labels[a.first].label;
+                  auto* l2 = m_labels[b.first].label;
+
+                  if (l1->options().priority != l2->options().priority) {
+                      // lower numeric priority means higher priority
+                      return l1->options().priority < l2->options().priority;
+                  }
+
+                  // Required ordering for 'filterRepeatGroups()'
+                  if (l1->options().repeatGroup != l2->options().repeatGroup) {
+                      return l1->options().repeatGroup < l2->options().repeatGroup;
+                  }
+
+                  if (l1->type() == l2->type() &&
+                      l1->candidatePriority() != l2->candidatePriority()) {
+                      return l1->candidatePriority() < l2->candidatePriority();
+                  }
+
+                  if (l1->hash() != l2->hash()) {
+                      return (l1->hash() < l2->hash());
+                  }
+
+                  // just so it is consistent between two instances
+                  return a.first < b.first;
+              });
+
+    // The collision pairs are sorted in a way that:
+    // - The first item may occlude the second it (but not the other way round!)
+    // At each iteration where the priority decreases:
+    // - the first item of the collision pair has a higher priority
+    // - all items of following collision pairs have a lower priority
+    // -> all labels of repeatGroups with higher priority have been added
+    //    when reaching a collision pair with lower priority
+    // This allows to remove repeated labels before they occlude other candidates
+
+    size_t repeatGroup = 0;
+    size_t lastFilteredLabelIndex = 0;
+
+    // Narrow Phase, resolve conflicts
+    for (auto& pair : m_isect2d.pairs) {
+
+        auto& e1 = m_labels[pair.first];
+        auto& e2 = m_labels[pair.second];
+        auto* l1 = e1.label;
+        auto* l2 = e2.label;
+
+        // Occlude labels within repeat group so that they don't occlude other labels
+        if (repeatGroup != l1->options().repeatGroup) {
+            repeatGroup = l1->options().repeatGroup;
+
+            if (repeatGroup != 0) {
+                lastFilteredLabelIndex = filterRepeatGroups(lastFilteredLabelIndex, pair.first);
+            }
+        }
+
+        // Dont let relatives occlude their child
+        if (l1->relative() == l2 || l2->relative() == l1) {
+            continue;
+        }
+        if (l1->isChild() && l1->relative()->isOccluded()) {
+            l1->occlude();
+        }
+        if (l2->isChild() && l2->relative()->isOccluded()) {
+            l2->occlude();
+        }
+
+        if (l1->isOccluded() || l2->isOccluded()) {
+            // One of this pair is already occluded.
+            // => conflict solved
+            continue;
+        }
+
+        bool intersection = false;
+        for (int i = e1.obbs.start; i < e1.obbs.end(); i++) {
+            for (int j = e2.obbs.start; j < e2.obbs.end(); j++) {
+
+                if (intersect(m_obbs[i], m_obbs[j])) {
+                    intersection = true;
+
+                    // break out of outer loop
+                    i = e1.obbs.end();
+                    break;
+                }
+            }
+        }
+        if (!intersection) { continue; }
+
+        if (l1->options().priority != l2->options().priority) {
+            // lower numeric priority means higher priority
+            if(l1->options().priority > l2->options().priority) {
+                l1->occlude();
+            } else {
+                l2->occlude();
+            }
+        } else {
+            if (l1->type() == l2->type()) {
+                if (l1->candidatePriority() > l2->candidatePriority()) {
+                    l1->occlude();
+                } else {
+                    l2->occlude();
+                }
+            }
+
+            // just so it is consistent between two instances
+            if (l1->hash() < l2->hash()) {
+                l1->occlude();
+            } else {
+                l2->occlude();
+            }
+        }
+    }
+
+    filterRepeatGroups(lastFilteredLabelIndex, m_labels.size()-1);
+
+    for (auto& entry : m_labels) {
+        auto* label = entry.label;
+
+        // Manage link occlusion (unified icon labels)
+        if (label->relative()) {
+            // First check if the child is required is occluded
+            if (label->relative()->isOccluded()) {
+                label->occlude();
+            } else if (!label->options().optional && label->isOccluded()) {
+                label->relative()->occlude();
+                label->relative()->enterState(Label::State::dead, 0.0f);
+            }
+        }
+
+        if (label->isOccluded()) {
+            label->enterState(Label::State::dead, 0.0f);
+        } else {
+            label->enterState(Label::State::none, 0.0f);
+        }
+    }
+
+    m_labels.clear();
+    m_aabbs.clear();
+}
+
+}
diff --git a/core/src/labels/labelCollider.h b/core/src/labels/labelCollider.h
new file mode 100644 (file)
index 0000000..1513ec8
--- /dev/null
@@ -0,0 +1,60 @@
+#pragma once
+
+#include "labels/label.h"
+#include "labels/screenTransform.h"
+#include "util/mapProjection.h"
+#include "util/types.h"
+
+#include "isect2d.h"
+#include "glm_vec.h" // for isect2d.h
+#include <memory>
+#include <vector>
+
+namespace Tangram {
+
+class Label;
+struct ViewState;
+
+class LabelCollider {
+
+public:
+
+
+    void addLabels(std::vector<std::unique_ptr<Label>>& _labels);
+
+    void process(TileID _tileID, float _tileInverseScale, float _tileSize);
+
+private:
+
+    size_t filterRepeatGroups(size_t startPos, size_t curPos);
+
+    using AABB = isect2d::AABB<glm::vec2>;
+    using OBB = isect2d::OBB<glm::vec2>;
+    using CollisionPairs = std::vector<isect2d::ISect2D<glm::vec2>::Pair>;
+
+    struct LabelEntry {
+
+        LabelEntry(Label* _label)
+            : label(_label),
+              priority(_label->options().priority) {}
+
+        Label* label;
+
+        float priority;
+
+        Range obbs;
+        Range transform;
+    };
+
+    // Parallel vectors
+
+    std::vector<LabelEntry> m_labels;
+    std::vector<AABB> m_aabbs;
+    std::vector<OBB> m_obbs;
+
+    isect2d::ISect2D<glm::vec2> m_isect2d;
+
+    ScreenTransform::Buffer m_transforms;
+};
+
+}
diff --git a/core/src/labels/labelProperty.cpp b/core/src/labels/labelProperty.cpp
new file mode 100644 (file)
index 0000000..ea2cbd5
--- /dev/null
@@ -0,0 +1,96 @@
+#include "labels/labelProperty.h"
+
+#include <map>
+
+namespace Tangram {
+namespace LabelProperty {
+
+const std::map<std::string, Placement> s_PlacementMap = {
+    {"vertex", Placement::vertex},
+    {"midpoint", Placement::midpoint},
+    {"spaced", Placement::spaced},
+    {"centroid", Placement::centroid},
+};
+
+const std::map<std::string, Anchor> s_AnchorMap = {
+    {"center", Anchor::center},
+    {"top", Anchor::top},
+    {"bottom", Anchor::bottom},
+    {"left", Anchor::left},
+    {"right", Anchor::right},
+    {"top-left", Anchor::top_left},
+    {"top-right", Anchor::top_right},
+    {"bottom-left", Anchor::bottom_left},
+    {"bottom-right", Anchor::bottom_right},
+};
+
+bool anchor(const std::string& _anchor, Anchor& _out) {
+    return tryFind(s_AnchorMap, _anchor, _out);
+}
+
+bool placement(const std::string& placement, Placement& out) {
+    return tryFind(s_PlacementMap, placement, out);
+}
+
+glm::vec2 anchorDirection(Anchor _anchor) {
+    glm::vec2 direction;
+
+    switch (_anchor) {
+        case top: direction = glm::vec2(0.0, -1.0); break;
+        case bottom: direction = glm::vec2(0.0, 1.0); break;
+        case left: direction = glm::vec2(-1.0, 0.0); break;
+        case right: direction = glm::vec2(1.0, 0.0); break;
+        case top_left: direction = glm::vec2(-1.0, -1.0); break;
+        case top_right: direction = glm::vec2(1.0, -1.0); break;
+        case bottom_left: direction = glm::vec2(-1.0, 1.0); break;
+        case bottom_right: direction = glm::vec2(1.0, 1.0); break;
+        case center: direction = glm::vec2(0.0, 0.0); break;
+    }
+
+    return direction;
+}
+
+} // LabelProperty
+
+namespace TextLabelProperty {
+
+const std::map<std::string, Transform> s_TransformMap = {
+    {"none", Transform::none},
+    {"capitalize", Transform::capitalize},
+    {"uppercase", Transform::uppercase},
+    {"lowercase", Transform::lowercase},
+};
+
+const std::map<std::string, Align> s_AlignMap = {
+    {"right", Align::right},
+    {"left", Align::left},
+    {"center", Align::center},
+};
+
+bool transform(const std::string& _transform, Transform& _out) {
+    return tryFind(s_TransformMap, _transform, _out);
+}
+
+bool align(const std::string& _align, Align& _out) {
+    return tryFind(s_AlignMap, _align, _out);
+}
+
+Align alignFromAnchor(LabelProperty::Anchor _anchor) {
+    switch(_anchor) {
+        case LabelProperty::Anchor::top_left:
+        case LabelProperty::Anchor::left:
+        case LabelProperty::Anchor::bottom_left:
+            return TextLabelProperty::Align::right;
+        case LabelProperty::Anchor::top_right:
+        case LabelProperty::Anchor::right:
+        case LabelProperty::Anchor::bottom_right:
+            return TextLabelProperty::Align::left;
+        case LabelProperty::Anchor::top:
+        case LabelProperty::Anchor::bottom:
+        case LabelProperty::Anchor::center:;
+    }
+    return TextLabelProperty::Align::center;
+}
+
+} // TextLabelProperty
+} // Tangram
diff --git a/core/src/labels/labelProperty.h b/core/src/labels/labelProperty.h
new file mode 100644 (file)
index 0000000..a1e78ae
--- /dev/null
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "util/util.h"
+
+#include "aabb.h"
+#include "glm/vec2.hpp"
+#include <string>
+#include <array>
+
+namespace Tangram {
+
+namespace LabelProperty {
+
+enum Placement : uint8_t {
+    vertex = 0,
+    midpoint,
+    spaced,
+    centroid,
+};
+
+enum Anchor : uint8_t {
+    center = 0,
+    top,
+    bottom,
+    left,
+    right,
+    top_left,
+    top_right,
+    bottom_left,
+    bottom_right,
+};
+
+constexpr int max_anchors = 9;
+
+struct Anchors {
+
+    Anchors() {}
+
+    Anchors(LabelProperty::Anchor _anchor) {
+        anchor[0] = _anchor;
+        count = 1;
+    }
+
+    std::array<LabelProperty::Anchor, LabelProperty::max_anchors> anchor;
+    int count = 0;
+
+    LabelProperty::Anchor operator[](size_t _pos) const {
+        return anchor[_pos];
+    }
+
+    bool operator==(const Anchors& _other) const {
+        return anchor == _other.anchor && count == _other.count;
+    }
+
+    isect2d::AABB<glm::vec2> extents(glm::vec2 size) {
+
+        glm::vec2 min{0};
+        glm::vec2 max{0};
+
+        for (int i = 0; i < count; i++) {
+            switch(anchor[i]) {
+            case center:
+                min.x = std::min(min.x, -0.5f);
+                min.y = std::min(min.y, -0.5f);
+                max.x = std::max(max.x, 0.5f);
+                max.y = std::max(max.y, 0.5f);
+                break;
+            case top:
+                min.x = std::min(min.x, -0.5f);
+                min.y = -1.0f;
+                max.x = std::max(max.x, 0.5f);
+                break;
+            case bottom:
+                min.x = std::min(min.x, -0.5f);
+                max.x = std::max(max.x, 0.5f);
+                max.y = 1.0f;
+                break;
+            case left:
+                min.x = -1.0f;
+                min.y = std::min(min.y, -0.5f);
+                max.y = std::max(max.y, 0.5f);
+                break;
+            case right:
+                min.y = std::min(min.y, -0.5f);
+                max.x = 1.0f;
+                max.y = std::max(max.y, 0.5f);
+                break;
+            case top_left:
+                min.x = -1.0f;
+                min.y = -1.0f;
+                break;
+            case top_right:
+                min.y = -1.0f;
+                max.x = 1.0f;
+                break;
+            case bottom_left:
+                min.x = -1.0f;
+                max.y = 1.0f;
+                break;
+            case bottom_right:
+                max.x = 1.0f;
+                max.y = 1.0f;
+                break;
+            }
+        }
+        // TODO add AABB constructor to pass min/max
+        return isect2d::AABB<glm::vec2>(min.x * size.x, min.y * size.y,
+                                        max.x * size.x, max.y * size.y);
+    }
+};
+
+bool anchor(const std::string& _transform, Anchor& _out);
+bool placement(const std::string& placement, Placement& out);
+
+glm::vec2 anchorDirection(Anchor _anchor);
+
+} // LabelProperty
+
+namespace TextLabelProperty {
+
+enum class Transform {
+    none,
+    capitalize,
+    uppercase,
+    lowercase,
+};
+
+enum class Align {
+    none   = -1,
+    right  = 0,
+    left   = 1,
+    center = 2,
+};
+
+bool transform(const std::string& _transform, Transform& _out);
+bool align(const std::string& _transform, Align& _out);
+Align alignFromAnchor(LabelProperty::Anchor _anchor);
+
+} // TextLabelProperty
+} // Tangram
diff --git a/core/src/labels/labelSet.cpp b/core/src/labels/labelSet.cpp
new file mode 100644 (file)
index 0000000..072043c
--- /dev/null
@@ -0,0 +1,23 @@
+#include "labels/labelSet.h"
+
+namespace Tangram {
+
+LabelSet::~LabelSet() {}
+
+void LabelSet::reset() {
+    for (auto& label : m_labels) {
+        label->resetState();
+    }
+}
+
+void LabelSet::setLabels(std::vector<std::unique_ptr<Label>>& _labels) {
+    typedef std::vector<std::unique_ptr<Label>>::iterator iter_t;
+    m_labels.clear();
+    m_labels.insert(m_labels.end(),
+                    std::move_iterator<iter_t>(_labels.begin()),
+                    std::move_iterator<iter_t>(_labels.end()));
+
+    _labels.clear();
+}
+
+}
diff --git a/core/src/labels/labelSet.h b/core/src/labels/labelSet.h
new file mode 100644 (file)
index 0000000..b3cd51e
--- /dev/null
@@ -0,0 +1,31 @@
+#pragma once
+
+#include "labels/label.h"
+#include "style/style.h"
+
+#include <vector>
+#include <memory>
+
+namespace Tangram {
+
+class LabelSet : public StyledMesh {
+public:
+
+    const auto& getLabels() const { return m_labels; }
+    auto& getLabels() { return m_labels; }
+
+    virtual ~LabelSet();
+
+    bool draw(RenderState& rs, ShaderProgram& _shader, bool _useVao = true) override { return true; }
+
+    size_t bufferSize() const override { return 0; }
+
+    void setLabels(std::vector<std::unique_ptr<Label>>& _labels);
+
+    void reset();
+
+protected:
+    std::vector<std::unique_ptr<Label>> m_labels;
+};
+
+}
diff --git a/core/src/labels/labels.cpp b/core/src/labels/labels.cpp
new file mode 100644 (file)
index 0000000..63784a3
--- /dev/null
@@ -0,0 +1,598 @@
+#include "labels/labels.h"
+
+#include "data/tileSource.h"
+#include "gl/primitives.h"
+#include "gl/shaderProgram.h"
+#include "labels/curvedLabel.h"
+#include "labels/labelSet.h"
+#include "labels/obbBuffer.h"
+#include "labels/textLabel.h"
+#include "marker/marker.h"
+#include "platform.h"
+#include "scene/scene.h"
+#include "style/pointStyle.h"
+#include "style/style.h"
+#include "style/textStyle.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "tile/tileCache.h"
+#include "tile/tileManager.h"
+#include "view/view.h"
+
+#include "glm/glm.hpp"
+#include "glm/gtc/matrix_transform.hpp"
+#include "glm/gtx/rotate_vector.hpp"
+#include "glm/gtx/norm.hpp"
+
+#include <cassert>
+
+namespace Tangram {
+
+Labels::Labels()
+    : m_needUpdate(false),
+      m_lastZoom(0.0f) {}
+
+Labels::~Labels() {}
+
+void Labels::processLabelUpdate(const ViewState& viewState,
+                                StyledMesh* mesh, Tile* tile,
+                                const glm::mat4& mvp,
+                                float dt, bool drawAll,
+                                bool onlyRender, bool isProxy) {
+
+    if (!mesh) { return; }
+    auto labelMesh = dynamic_cast<const LabelSet*>(mesh);
+    if (!labelMesh) { return; }
+
+    // TODO appropriate buffer to filter out-of-screen labels
+    float border = 256.0f;
+    AABB extendedBounds(-border, -border,
+                        viewState.viewportSize.x + border,
+                        viewState.viewportSize.y + border);
+
+    AABB screenBounds(0, 0,
+                      viewState.viewportSize.x,
+                      viewState.viewportSize.y);
+
+    for (auto& label : labelMesh->getLabels()) {
+        if (!drawAll && (label->state() == Label::State::dead) ) {
+            continue;
+        }
+
+        Range transformRange;
+        ScreenTransform transform { m_transforms, transformRange };
+
+        // Use extendedBounds when labels take part in collision detection.
+        auto bounds = (onlyRender || !label->canOcclude())
+            ? screenBounds
+            : extendedBounds;
+
+        if (!label->update(mvp, viewState, &bounds, transform)) {
+            continue;
+        }
+
+
+        if (onlyRender) {
+            if (label->occludedLastFrame()) { label->occlude(); }
+
+            if (label->visibleState() || !label->canOcclude()) {
+                m_needUpdate |= label->evalState(dt);
+                label->addVerticesToMesh(transform, viewState.viewportSize);
+            }
+        } else if (label->canOcclude()) {
+            m_labels.emplace_back(label.get(), tile, isProxy, transformRange);
+        } else {
+            m_needUpdate |= label->evalState(dt);
+            label->addVerticesToMesh(transform, viewState.viewportSize);
+        }
+        if (label->selectionColor()) {
+            m_selectionLabels.emplace_back(label.get(), tile, isProxy, transformRange);
+        }
+    }
+}
+
+std::pair<Label*, Tile*> Labels::getLabel(uint32_t _selectionColor) const {
+
+    for (auto& entry : m_selectionLabels) {
+
+        if (entry.label->visibleState() &&
+            entry.label->selectionColor() == _selectionColor) {
+
+            return { entry.label, entry.tile };
+        }
+    }
+    return {nullptr, nullptr};
+}
+
+void Labels::updateLabels(const ViewState& _viewState, float _dt,
+                          const std::vector<std::unique_ptr<Style>>& _styles,
+                          const std::vector<std::shared_ptr<Tile>>& _tiles,
+                          const std::vector<std::unique_ptr<Marker>>& _markers,
+                          bool _onlyRender) {
+
+    if (!_onlyRender) { m_labels.clear(); }
+
+    m_selectionLabels.clear();
+
+    m_needUpdate = false;
+
+    // int lodDiscard = LODDiscardFunc(View::s_maxZoom, _view.getZoom());
+
+    bool drawAllLabels = Tangram::getDebugFlag(DebugFlags::draw_all_labels);
+
+    for (const auto& tile : _tiles) {
+
+        //LOG("tile: %d/%d z:%d,%d", tile->getID().x, tile->getID().y, tile->getID().z, tile->getID().s);
+
+        // discard based on level of detail
+        // if ((zoom - tile->getID().z) > lodDiscard) {
+        //     continue;
+        // }
+
+        bool proxyTile = tile->isProxy();
+
+        glm::mat4 mvp = tile->mvp();
+
+        for (const auto& style : _styles) {
+            const auto& mesh = tile->getMesh(*style);
+            processLabelUpdate(_viewState, mesh.get(), tile.get(), mvp,
+                               _dt, drawAllLabels, _onlyRender, proxyTile);
+        }
+    }
+
+    for (const auto& marker : _markers) {
+
+        if (!marker->isVisible() || !marker->mesh()) { continue; }
+
+        for (const auto& style : _styles) {
+
+            if (marker->styleId() != style->getID()) { continue; }
+
+            const auto& mesh = marker->mesh();
+
+            processLabelUpdate(_viewState, mesh, nullptr,
+                               marker->modelViewProjectionMatrix(),
+                               _dt, drawAllLabels, _onlyRender, false);
+        }
+    }
+}
+
+void Labels::skipTransitions(const std::vector<const Style*>& _styles, Tile& _tile, Tile& _proxy) const {
+
+    for (const auto& style : _styles) {
+
+        auto* mesh0 = dynamic_cast<const LabelSet*>(_tile.getMesh(*style).get());
+        if (!mesh0) { continue; }
+
+        auto* mesh1 = dynamic_cast<const LabelSet*>(_proxy.getMesh(*style).get());
+        if (!mesh1) { continue; }
+
+        for (auto& l0 : mesh0->getLabels()) {
+            if (!l0->canOcclude()) { continue; }
+            if (l0->state() != Label::State::none) { continue; }
+
+            for (auto& l1 : mesh1->getLabels()) {
+                if (!l1->visibleState()) { continue; }
+                if (!l1->canOcclude()) { continue;}
+
+                // Using repeat group to also handle labels with dynamic style properties
+                if (l0->options().repeatGroup != l1->options().repeatGroup) { continue; }
+                // if (l0->hash() != l1->hash()) { continue; }
+
+                float d2 = glm::distance2(l0->screenCenter(), l1->screenCenter());
+
+                // The new label lies within the circle defined by the bbox of l0
+                if (sqrt(d2) < std::max(l0->dimension().x, l0->dimension().y)) {
+                    l0->skipTransitions();
+                }
+            }
+        }
+    }
+}
+
+std::shared_ptr<Tile> findProxy(int32_t _sourceID, const TileID& _proxyID,
+                                const std::vector<std::shared_ptr<Tile>>& _tiles,
+                                TileCache& _cache) {
+
+    auto proxy = _cache.contains(_sourceID, _proxyID);
+    if (proxy) { return proxy; }
+
+    for (auto& tile : _tiles) {
+        if (tile->getID() == _proxyID && tile->sourceID() == _sourceID) {
+            return tile;
+        }
+    }
+    return nullptr;
+}
+
+void Labels::skipTransitions(const std::shared_ptr<Scene>& _scene,
+                             const std::vector<std::shared_ptr<Tile>>& _tiles,
+                             TileManager& _tileManager, float _currentZoom) const {
+
+    std::vector<const Style*> styles;
+
+    for (const auto& style : _scene->styles()) {
+        if (dynamic_cast<const TextStyle*>(style.get()) ||
+            dynamic_cast<const PointStyle*>(style.get())) {
+            styles.push_back(style.get());
+        }
+    }
+
+    for (const auto& tile : _tiles) {
+        TileID tileID = tile->getID();
+        std::shared_ptr<Tile> proxy;
+
+        auto source = _scene->getTileSource(tile->sourceID());
+        if (!source) {
+            source = _tileManager.getClientTileSource(tile->sourceID());
+            // If tiles for this source exist, this source must exist (either tile or client source)
+            assert(source);
+            continue;
+        }
+
+        if (m_lastZoom < _currentZoom) {
+            // zooming in, add the one cached parent tile
+            proxy = findProxy(tile->sourceID(), tileID.getParent(source->zoomBias()), _tiles,
+                              *_tileManager.getTileCache());
+            if (proxy) { skipTransitions(styles, *tile, *proxy); }
+        } else {
+            // zooming out, add the 4 cached children tiles
+            for (int i = 0; i < 4; i++) {
+                proxy = findProxy(tile->sourceID(), tileID.getChild(i, source->maxZoom()), _tiles,
+                                  *_tileManager.getTileCache());
+                if (proxy) { skipTransitions(styles, *tile, *proxy); }
+            }
+        }
+    }
+}
+
+bool Labels::labelComparator(const LabelEntry& _a, const LabelEntry& _b) {
+    if (_a.proxy != _b.proxy) {
+        return _b.proxy;
+    }
+    if (_a.priority != _b.priority) {
+        return _a.priority < _b.priority;
+    }
+    if (!_a.tile || !_b.tile) {
+        return (bool)_a.tile;
+    }
+    if (_a.tile->getID().z != _b.tile->getID().z) {
+        return _a.tile->getID().z > _b.tile->getID().z;
+    }
+
+    auto l1 = _a.label;
+    auto l2 = _b.label;
+
+    // Note: This causes non-deterministic placement, i.e. depending on
+    // navigation history.
+    if (l1->occludedLastFrame() != l2->occludedLastFrame()) {
+        return l2->occludedLastFrame();
+    }
+    // This prefers labels within screen over out_of_screen.
+    // Important for repeat groups!
+    if (l1->visibleState() != l2->visibleState()) {
+        return l1->visibleState();
+    }
+
+    if (l1->options().repeatGroup != l2->options().repeatGroup) {
+        return l1->options().repeatGroup < l2->options().repeatGroup;
+    }
+
+    if (l1->type() == l2->type()) {
+        return l1->candidatePriority() < l2->candidatePriority();
+    }
+
+    if (l1->hash() != l2->hash()) {
+        return l1->hash() < l2->hash();
+    }
+
+    return l1 < l2;
+}
+
+void Labels::sortLabels() {
+    // Use stable sort so that relative ordering of markers is preserved.
+    std::stable_sort(m_labels.begin(), m_labels.end(), Labels::labelComparator);
+}
+
+void Labels::handleOcclusions(const ViewState& _viewState) {
+
+    m_isect2d.clear();
+    m_repeatGroups.clear();
+
+    using iterator = decltype(m_labels)::const_iterator;
+
+    // Find the label to which the obb belongs
+    auto findLabel = [](iterator begin, iterator end, int obb) {
+        for (auto it = begin; it != end; it++) {
+            if (obb >= it->obbsRange.start && obb < it->obbsRange.end()) {
+                return it->label;
+            }
+        }
+        assert(false);
+        return static_cast<Label*>(nullptr);
+    };
+
+    for (auto it = m_labels.begin(); it != m_labels.end(); ++it) {
+        auto& entry = *it;
+        auto* l = entry.label;
+
+        ScreenTransform transform { m_transforms, entry.transformRange };
+        OBBBuffer obbs { m_obbs, entry.obbsRange };
+
+        l->obbs(transform, obbs);
+
+        // Parent must have been processed earlier so at this point its
+        // occlusion and anchor position is determined for the current frame.
+        if (l->isChild()) {
+            if (l->relative()->isOccluded()) {
+                l->occlude();
+                continue;
+            }
+        }
+
+        // Skip label if another label of this repeatGroup is
+        // within repeatDistance.
+        if (l->options().repeatDistance > 0.f) {
+            if (withinRepeatDistance(l)) {
+                l->occlude();
+                // If this label is not marked optional, then mark the relative label as occluded
+                if (l->relative() && !l->options().optional) {
+                    l->relative()->occlude();
+                }
+                continue;
+            }
+        }
+
+        int anchorIndex = l->anchorIndex();
+
+        // For each anchor
+        do {
+            if (l->isOccluded()) {
+                // Update OBB for anchor fallback
+                obbs.clear();
+
+                l->obbs(transform, obbs);
+
+                if (anchorIndex == l->anchorIndex()) {
+                    // Reached first anchor again
+                    break;
+                }
+            }
+
+            l->occlude(false);
+
+            // Occlude label when its obbs intersect with a previous label.
+            for (auto& obb : obbs) {
+                m_isect2d.intersect(obb.getExtent(), [&](auto& a, auto& b) {
+                        size_t other = reinterpret_cast<size_t>(b.m_userData);
+
+                        if (!intersect(obb, m_obbs[other])) {
+                            return true;
+                        }
+                        // Ignore intersection with relative label
+                        if (l->relative() && l->relative() == findLabel(std::begin(m_labels), it, other)) {
+                            return true;
+                        }
+                        l->occlude();
+                        return false;
+
+                    }, false);
+
+                if (l->isOccluded()) { break; }
+            }
+        } while (l->isOccluded() && l->nextAnchor());
+
+        // At this point, the label has a relative that is visible,
+        // if it is not an optional label, turn the relative to occluded
+        if (l->isOccluded()) {
+            if (l->relative() && !l->options().optional) {
+                l->relative()->occlude();
+            }
+        } else {
+            // Insert into ISect2D grid
+            int obbPos = entry.obbsRange.start;
+            for (auto& obb : obbs) {
+                auto aabb = obb.getExtent();
+                aabb.m_userData = reinterpret_cast<void*>(obbPos++);
+                m_isect2d.insert(aabb);
+            }
+
+            if (l->options().repeatDistance > 0.f) {
+                m_repeatGroups[l->options().repeatGroup].push_back(l);
+            }
+        }
+    }
+}
+
+bool Labels::withinRepeatDistance(Label *_label) {
+    float threshold2 = pow(_label->options().repeatDistance, 2);
+
+    auto it = m_repeatGroups.find(_label->options().repeatGroup);
+    if (it != m_repeatGroups.end()) {
+        for (auto* ll : it->second) {
+            float d2 = glm::distance2(_label->screenCenter(), ll->screenCenter());
+            if (d2 < threshold2) {
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+void Labels::updateLabelSet(const ViewState& _viewState, float _dt,
+                            const std::shared_ptr<Scene>& _scene,
+                            const std::vector<std::shared_ptr<Tile>>& _tiles,
+                            const std::vector<std::unique_ptr<Marker>>& _markers,
+                            TileManager& _tileManager) {
+
+    m_transforms.clear();
+    m_obbs.clear();
+
+    /// Collect and update labels from visible tiles
+    updateLabels(_viewState, _dt, _scene->styles(), _tiles, _markers, false);
+
+    sortLabels();
+
+    /// Mark labels to skip transitions
+
+    if (int(m_lastZoom) != int(_viewState.zoom)) {
+        skipTransitions(_scene, _tiles, _tileManager, _viewState.zoom);
+        m_lastZoom = _viewState.zoom;
+    }
+
+    m_isect2d.resize({_viewState.viewportSize.x / 256, _viewState.viewportSize.y / 256},
+                     {_viewState.viewportSize.x, _viewState.viewportSize.y});
+
+    handleOcclusions(_viewState);
+
+    Label::AABB screenBounds{0, 0, _viewState.viewportSize.x, _viewState.viewportSize.y};
+
+    // Update label meshes
+    for (auto& entry : m_labels) {
+        ScreenTransform transform { m_transforms, entry.transformRange };
+
+        m_needUpdate |= entry.label->evalState(_dt);
+
+        if (entry.label->visibleState()) {
+            for (auto& obb : OBBBuffer{ m_obbs, entry.obbsRange }) {
+
+                if (obb.getExtent().intersect(screenBounds)) {
+                    entry.label->addVerticesToMesh(transform, _viewState.viewportSize);
+                    break;
+                }
+            }
+        }
+    }
+}
+
+void Labels::drawDebug(RenderState& rs, const View& _view) {
+
+    if (!Tangram::getDebugFlag(Tangram::DebugFlags::labels)) {
+        return;
+    }
+
+    for (auto& entry : m_labels) {
+        auto* label = entry.label;
+
+        if (label->type() == Label::Type::debug) { continue; }
+
+        glm::vec2 sp = label->screenCenter();
+
+        // draw bounding box
+        switch (label->state()) {
+        case Label::State::sleep:
+            Primitives::setColor(rs, 0x0000ff);
+            break;
+        case Label::State::visible:
+            Primitives::setColor(rs, 0x000000);
+            break;
+        case Label::State::none:
+            Primitives::setColor(rs, 0x0000ff);
+            break;
+        case Label::State::dead:
+            Primitives::setColor(rs, 0xff00ff);
+            break;
+        case Label::State::fading_in:
+            Primitives::setColor(rs, 0xffff00);
+            break;
+        case Label::State::fading_out:
+            Primitives::setColor(rs, 0xff0000);
+            break;
+        default:
+            Primitives::setColor(rs, 0x999999);
+        }
+
+#if DEBUG_OCCLUSION
+        if (label->isOccluded()) {
+            Primitives::setColor(rs, 0xff0000);
+            if (label->occludedLastFrame()) {
+                Primitives::setColor(rs, 0xffff00);
+            }
+        } else if (label->occludedLastFrame()) {
+            Primitives::setColor(rs, 0x00ff00);
+        } else {
+            Primitives::setColor(rs, 0x000000);
+        }
+#endif
+
+        for (auto& obb : OBBBuffer{ m_obbs, entry.obbsRange }) {
+            Primitives::drawPoly(rs, &(obb.getQuad())[0], 4);
+        }
+
+        if (label->relative() && label->relative()->visibleState() && !label->relative()->isOccluded()) {
+            Primitives::setColor(rs, 0xff0000);
+            Primitives::drawLine(rs, m_obbs[entry.obbsRange.start].getCentroid(),
+                                 label->relative()->screenCenter());
+        }
+
+        if (label->type() == Label::Type::curved) {
+            //for (int i = entry.transform.start; i < entry.transform.end()-2; i++) {
+            for (int i = entry.transformRange.start; i < entry.transformRange.end()-1; i++) {
+                if (i % 2 == 0) {
+                    Primitives::setColor(rs, 0xff0000);
+                } else {
+                    Primitives::setColor(rs, 0x0000ff);
+
+                }
+                Primitives::drawLine(rs, glm::vec2(m_transforms.points[i]),
+                                     glm::vec2(m_transforms.points[i+1]));
+            }
+        }
+#if 0
+        // draw offset
+        glm::vec2 rot = label->screenTransform().rotation;
+        glm::vec2 offset = label->options().offset;
+        if (label->relative()) { offset += label->relative()->options().offset; }
+        offset = rotateBy(offset, rot);
+
+        Primitives::setColor(rs, 0x000000);
+        Primitives::drawLine(rs, sp, sp - glm::vec2(offset.x, -offset.y));
+#endif
+
+        // draw projected anchor point
+        Primitives::setColor(rs, 0x0000ff);
+        Primitives::drawRect(rs, sp - glm::vec2(1.f), sp + glm::vec2(1.f));
+
+#if 0
+        if (label->options().repeatGroup != 0 && label->state() == Label::State::visible) {
+            size_t seed = 0;
+            hash_combine(seed, label->options().repeatGroup);
+            float repeatDistance = label->options().repeatDistance;
+
+            Primitives::setColor(rs, seed);
+            Primitives::drawLine(rs, label->screenCenter(),
+                                 glm::vec2(repeatDistance, 0.f) + label->screenCenter());
+
+            float off = M_PI / 6.f;
+            for (float pad = 0.f; pad < M_PI * 2.f; pad += off) {
+                glm::vec2 p0 = glm::vec2(cos(pad), sin(pad)) * repeatDistance
+                    + label->screenCenter();
+                glm::vec2 p1 = glm::vec2(cos(pad + off), sin(pad + off)) * repeatDistance
+                    + label->screenCenter();
+                Primitives::drawLine(rs, p0, p1);
+            }
+        }
+#endif
+    }
+
+    glm::vec2 split(_view.getWidth() / 256, _view.getHeight() / 256);
+    glm::vec2 res(_view.getWidth(), _view.getHeight());
+    const short xpad = short(ceilf(res.x / split.x));
+    const short ypad = short(ceilf(res.y / split.y));
+
+    Primitives::setColor(rs, 0x7ef586);
+    short x = 0, y = 0;
+    for (int j = 0; j < split.y; ++j) {
+        for (int i = 0; i < split.x; ++i) {
+            AABB cell(x, y, x + xpad, y + ypad);
+            Primitives::drawRect(rs, {x, y}, {x + xpad, y + ypad});
+            x += xpad;
+            if (x >= res.x) {
+                x = 0;
+                y += ypad;
+            }
+        }
+    }
+}
+
+}
diff --git a/core/src/labels/labels.h b/core/src/labels/labels.h
new file mode 100644 (file)
index 0000000..32869f5
--- /dev/null
@@ -0,0 +1,117 @@
+#pragma once
+
+#include "data/properties.h"
+#include "labels/label.h"
+#include "labels/screenTransform.h"
+#include "labels/spriteLabel.h"
+#include "tile/tileID.h"
+
+#include "glm_vec.h" // for isect2d.h
+#include "isect2d.h"
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <set>
+#include <unordered_map>
+#include <vector>
+
+#define PERF_TRACE __attribute__ ((noinline))
+
+namespace Tangram {
+
+class FontContext;
+class Marker;
+class Tile;
+class Style;
+class Scene;
+class TileManager;
+
+class Labels {
+
+public:
+    Labels();
+
+    virtual ~Labels();
+
+    void drawDebug(RenderState& rs, const View& _view);
+
+    void updateLabelSet(const ViewState& _viewState, float _dt,
+                        const std::shared_ptr<Scene>& _scene,
+                        const std::vector<std::shared_ptr<Tile>>& _tiles,
+                        const std::vector<std::unique_ptr<Marker>>& _markers,
+                        TileManager& tileManager);
+
+    /* onlyRender: when the view and tiles have not changed one does not need to update the set of
+     * active labels. We just need to render these the labels in this case
+     */
+    PERF_TRACE void updateLabels(const ViewState& _viewState, float _dt,
+                                 const std::vector<std::unique_ptr<Style>>& _styles,
+                                 const std::vector<std::shared_ptr<Tile>>& _tiles,
+                                 const std::vector<std::unique_ptr<Marker>>& _markers,
+                                 bool _onlyRender = true);
+
+    bool needUpdate() const { return m_needUpdate; }
+
+    std::pair<Label*, Tile*> getLabel(uint32_t _selectionColor) const;
+
+protected:
+
+    using AABB = isect2d::AABB<glm::vec2>;
+    using OBB = isect2d::OBB<glm::vec2>;
+    using CollisionPairs = std::vector<isect2d::ISect2D<glm::vec2>::Pair>;
+
+
+    void skipTransitions(const std::shared_ptr<Scene>& _scene,
+                         const std::vector<std::shared_ptr<Tile>>& _tiles,
+                         TileManager& _tileManager, float _currentZoom) const;
+
+    PERF_TRACE void skipTransitions(const std::vector<const Style*>& _styles, Tile& _tile, Tile& _proxy) const;
+
+    PERF_TRACE void sortLabels();
+
+    PERF_TRACE void handleOcclusions(const ViewState& _viewState);
+
+    PERF_TRACE bool withinRepeatDistance(Label *_label);
+
+    void processLabelUpdate(const ViewState& viewState, StyledMesh* mesh, Tile* tile,
+                            const glm::mat4& mvp, float dt, bool drawAll,
+                            bool onlyRender, bool isProxy);
+
+    bool m_needUpdate;
+
+    isect2d::ISect2D<glm::vec2> m_isect2d;
+
+    struct LabelEntry {
+
+        LabelEntry(Label* _label, Tile* _tile, bool _proxy, Range _screenTransform)
+            : label(_label),
+              tile(_tile),
+              priority(_label->options().priority),
+              proxy(_proxy),
+              transformRange(_screenTransform) {}
+
+        Label* label;
+        Tile* tile;
+        float priority;
+        bool proxy;
+
+        Range transformRange;
+        Range obbsRange;
+    };
+
+    static bool labelComparator(const LabelEntry& _a, const LabelEntry& _b);
+
+    std::vector<OBB> m_obbs;
+    ScreenTransform::Buffer m_transforms;
+
+    std::vector<LabelEntry> m_labels;
+    std::vector<LabelEntry> m_selectionLabels;
+
+    std::unordered_map<size_t, std::vector<Label*>> m_repeatGroups;
+
+    float m_lastZoom;
+};
+
+}
+
diff --git a/core/src/labels/obbBuffer.h b/core/src/labels/obbBuffer.h
new file mode 100644 (file)
index 0000000..7a0e2f1
--- /dev/null
@@ -0,0 +1,36 @@
+#pragma once
+
+#include "obb.h"
+#include "util/types.h"
+
+namespace Tangram {
+
+struct OBBBuffer {
+
+    OBBBuffer(std::vector<isect2d::OBB<glm::vec2>>& _obbs, Range& _range)
+        : obbs(_obbs), range(_range) {
+        if (!range.length) {
+            range.start = obbs.size();
+        }
+    }
+
+    auto begin() { return obbs.begin() + range.start; }
+    auto end() { return obbs.begin() + range.end(); }
+
+    void clear() {
+        range.length = 0;
+        obbs.resize(range.start);
+    }
+
+    void append(isect2d::OBB<glm::vec2> _obb) {
+        obbs.push_back(_obb);
+        range.length += 1;
+    }
+
+private:
+    std::vector<isect2d::OBB<glm::vec2>>& obbs;
+    Range& range;
+
+};
+
+}
diff --git a/core/src/labels/screenTransform.h b/core/src/labels/screenTransform.h
new file mode 100644 (file)
index 0000000..2e0932c
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "glm/vec2.hpp"
+
+namespace Tangram {
+
+// ScreenTransform is a view into ScreenTransform::Buffer
+struct ScreenTransform {
+
+    // ScreenTransform::Buffer holds screen space coordinates of multiple labels
+    // (used by LabelCollider and Labels class)
+    struct Buffer {
+        std::vector<glm::vec3> points;
+        std::vector<glm::vec2> path;
+        void clear() {
+            points.clear();
+            path.clear();
+        }
+    };
+
+    ScreenTransform(Buffer& _transformBuffer, Range& _range)
+        : buffer(_transformBuffer),
+          points(_transformBuffer.points),
+          range(_range) {
+
+        if (!range.length) {
+            range.start = points.size();
+        }
+    }
+
+    auto begin() { return points.begin() + range.start; }
+    auto end() { return points.begin() + range.end(); }
+
+    bool empty() const { return range.length == 0; }
+    size_t size() const { return range.length; }
+    void clear() {
+        range.length = 0;
+        points.resize(range.start);
+    }
+
+    auto operator[](size_t _pos) const { return points[range.start + _pos]; }
+
+    void push_back(glm::vec3 _p) {
+        points.push_back(_p);
+        range.length += 1;
+    }
+
+    void push_back(glm::vec2 _p) {
+        points.emplace_back(_p, 0);
+        range.length += 1;
+    }
+
+    // Get a temporary coordinate buffer (used for curved labels line smoothing)
+    std::vector<glm::vec2>& scratchBuffer() {
+        buffer.path.clear();
+        return buffer.path;
+    }
+
+private:
+    Buffer &buffer;
+    std::vector<glm::vec3>& points;
+    Range& range;
+};
+
+}
diff --git a/core/src/labels/spriteLabel.cpp b/core/src/labels/spriteLabel.cpp
new file mode 100644 (file)
index 0000000..0e036a4
--- /dev/null
@@ -0,0 +1,285 @@
+#include "labels/spriteLabel.h"
+
+#include "gl/dynamicQuadMesh.h"
+#include "labels/screenTransform.h"
+#include "labels/obbBuffer.h"
+#include "log.h"
+#include "scene/spriteAtlas.h"
+#include "style/pointStyle.h"
+#include "util/geom.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+using namespace LabelProperty;
+
+const float SpriteVertex::alpha_scale = 65535.0f;
+const float SpriteVertex::texture_scale = 65535.0f;
+
+struct BillboardTransform {
+    ScreenTransform& m_transform;
+
+    BillboardTransform(ScreenTransform& _transform)
+        : m_transform(_transform) {}
+
+    void set(glm::vec2 _position, glm::vec3 _projected, glm::vec2 _screenSize, float _fractZoom) {
+
+        m_transform.push_back(_position);
+        m_transform.push_back(_projected);
+        m_transform.push_back(glm::vec3(_screenSize, _fractZoom));
+    }
+
+    glm::vec2 position() const { return glm::vec2(m_transform[0]); }
+    glm::vec3 projected() const { return m_transform[1]; }
+    glm::vec2 screenSize() const { return glm::vec2(m_transform[2]); }
+    float fractZoom() const { return m_transform[2].z; }
+};
+
+struct FlatTransform {
+    ScreenTransform& m_transform;
+
+    FlatTransform(ScreenTransform& _transform)
+        : m_transform(_transform) {}
+
+    void set(const std::array<glm::vec2, 4>& _position,
+             const std::array<glm::vec3, 4>& _projected) {
+        for (size_t i = 0; i < 4; i++) {
+            m_transform.push_back(_position[i]);
+        }
+        for (size_t i = 0; i < 4; i++) {
+            m_transform.push_back(_projected[i]);
+        }
+    }
+
+    glm::vec2 position(size_t i) const { return glm::vec2(m_transform[i]); }
+    glm::vec3 projected(size_t i) const { return m_transform[4+i]; }
+};
+
+SpriteLabel::SpriteLabel(Coordinates _coordinates, glm::vec2 _size, Label::Options _options,
+                         SpriteLabel::VertexAttributes _attrib, Texture* _texture,
+                         SpriteLabels& _labels, size_t _labelsPos)
+    : Label(_size, Label::Type::point, _options),
+      m_coordinates(_coordinates),
+      m_labels(_labels),
+      m_labelsPos(_labelsPos),
+      m_texture(_texture),
+      m_vertexAttrib(_attrib) {
+
+    applyAnchor(m_options.anchors[0]);
+}
+
+void SpriteLabel::applyAnchor(LabelProperty::Anchor _anchor) {
+
+    m_anchor = LabelProperty::anchorDirection(_anchor) * m_dim * 0.5f;
+}
+
+bool SpriteLabel::updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                                        const AABB* _bounds, ScreenTransform& _transform) {
+
+    glm::vec2 halfScreen = glm::vec2(_viewState.viewportSize * 0.5f);
+    glm::vec2 p0 = m_coordinates;
+
+    if (m_options.flat) {
+
+        std::array<glm::vec2, 4> positions;
+        std::array<glm::vec3, 4> projected;
+
+        float sourceScale = pow(2, m_coordinates.z);
+
+        float scale = float(sourceScale / (_viewState.zoomScale * _viewState.tileSize));
+        float zoomFactor = m_vertexAttrib.extrudeScale * _viewState.fractZoom;
+
+        glm::vec2 dim = (m_dim + zoomFactor) * scale;
+
+        // Center around 0,0
+        dim *= 0.5f;
+
+        positions[0] = -dim;
+        positions[1] = glm::vec2(dim.x, -dim.y);
+        positions[2] = glm::vec2(-dim.x, dim.y);
+        positions[3] = dim;
+
+        // Rotate in clockwise order on the ground plane
+        if (m_options.angle != 0.f) {
+            glm::vec2 rotation(cos(DEG_TO_RAD * m_options.angle),
+                               sin(DEG_TO_RAD * m_options.angle));
+
+            for (size_t i = 0; i < 4; i++) {
+                positions[i] = rotateBy(positions[i], rotation);
+            }
+        }
+
+        AABB aabb;
+        for (size_t i = 0; i < 4; i++) {
+
+            positions[i] += p0;
+
+            glm::vec4 proj = worldToClipSpace(_mvp, glm::vec4(positions[i], 0.f, 1.f));
+            if (proj.w <= 0.0f) { return false; }
+
+            projected[i] = glm::vec3(proj) / proj.w;
+
+            // from normalized device coordinates to screen space coordinate system
+            // top-left screen axis, y pointing down
+            positions[i].x = 1 + projected[i].x;
+            positions[i].y = 1 - projected[i].y;
+            positions[i] *= halfScreen;
+
+            aabb.include(positions[i].x, positions[i].y);
+        }
+
+        if (_bounds) {
+            if (!aabb.intersect(*_bounds)) { return false; }
+        }
+
+        FlatTransform(_transform).set(positions, projected);
+
+        {
+            glm::vec4 projected = worldToClipSpace(_mvp, glm::vec4(p0, 0.f, 1.f));
+            if (projected.w <= 0.0f) { return false; }
+
+            projected /= projected.w;
+
+            glm::vec2 position;
+            position.x = 1 + projected.x;
+            position.y = 1 - projected.y;
+            position *= halfScreen;
+            position += m_options.offset;
+            m_screenCenter = position;
+        }
+    } else {
+
+        glm::vec4 projected = worldToClipSpace(_mvp, glm::vec4(p0, 0.f, 1.f));
+        if (projected.w <= 0.0f) { return false; }
+
+        projected /= projected.w;
+
+        glm::vec2 position;
+        position.x = 1 + projected.x;
+        position.y = 1 - projected.y;
+        position *= halfScreen;
+        position += m_options.offset;
+
+        if (_bounds) {
+            auto aabb = m_options.anchors.extents(m_dim);
+            aabb.min += position + m_options.offset;
+            aabb.max += position + m_options.offset;
+            if (!aabb.intersect(*_bounds)) { return false; }
+        }
+
+        m_screenCenter = position;
+
+        BillboardTransform(_transform).set(position, glm::vec3(projected),
+                                           _viewState.viewportSize, _viewState.fractZoom);
+    }
+
+    return true;
+}
+
+void SpriteLabel::obbs(ScreenTransform& _transform, OBBBuffer& _obbs) {
+    OBB obb;
+
+    if (m_options.flat) {
+        const float infinity = std::numeric_limits<float>::infinity();
+        float minx = infinity, miny = infinity;
+        float maxx = -infinity, maxy = -infinity;
+
+        for (int i = 0; i < 4; ++i) {
+
+            const auto& position = _transform[i];
+            minx = std::min(minx, position.x);
+            miny = std::min(miny, position.y);
+            maxx = std::max(maxx, position.x);
+            maxy = std::max(maxy, position.y);
+        }
+
+        glm::vec2 dim = glm::vec2(maxx - minx, maxy - miny);
+
+        if (m_occludedLastFrame) { dim += Label::activation_distance_threshold; }
+
+        glm::vec2 obbCenter = glm::vec2((minx + maxx) * 0.5f, (miny + maxy) * 0.5f);
+
+        obb = OBB(obbCenter, {1, 0}, dim.x, dim.y);
+    } else {
+
+        BillboardTransform pointTransform(_transform);
+
+        glm::vec2 dim = m_dim + glm::vec2(m_vertexAttrib.extrudeScale * pointTransform.fractZoom());
+
+        if (m_occludedLastFrame) { dim += Label::activation_distance_threshold; }
+
+        obb = OBB(pointTransform.position() + m_anchor, {1, 0}, dim.x, dim.y);
+    }
+
+    _obbs.append(obb);
+}
+
+void SpriteLabel::addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) {
+
+    if (!visibleState()) { return; }
+
+    // TODO
+    // if (a_extrude.x != 0.0) {
+    //     float dz = u_map_position.z - abs(u_tile_origin.z);
+    //     vertex_pos.xy += clamp(dz, 0.0, 1.0) * UNPACK_EXTRUDE(a_extrude.xy);
+    // }
+
+    auto& quad = m_labels.quads[m_labelsPos];
+
+    SpriteVertex::State state {
+        m_vertexAttrib.selectionColor,
+        m_vertexAttrib.color,
+        uint16_t(m_alpha * SpriteVertex::alpha_scale),
+        0,
+    };
+
+    auto& style = m_labels.m_style;
+
+    // Before pushing our geometry to the mesh, we push the texture that should be
+    // used to draw this label. We check a few potential textures in order of priority.
+    Texture* tex = nullptr;
+    if (m_texture) { tex = m_texture; }
+    else if (style.texture()) { tex = style.texture().get(); }
+    else if (style.spriteAtlas()) { tex = style.spriteAtlas()->texture(); }
+
+    // If tex is null, the mesh will use the default point texture.
+    style.getMesh()->pushTexture(tex);
+
+    auto* quadVertices = style.getMesh()->pushQuad();
+
+    if (m_options.flat) {
+        FlatTransform transform(_transform);
+
+        for (int i = 0; i < 4; i++) {
+            SpriteVertex& vertex = quadVertices[i];
+
+            vertex.pos = transform.projected(i);
+            vertex.uv = quad.quad[i].uv;
+            vertex.state = state;
+        }
+
+    } else {
+        BillboardTransform transform(_transform);
+
+        glm::vec2 pos = glm::vec2(transform.projected());
+        glm::vec2 scale = 2.0f / transform.screenSize();
+        scale.y *= -1;
+
+        pos += m_options.offset * scale;
+        pos += m_anchor * scale;
+
+        for (int i = 0; i < 4; i++) {
+            SpriteVertex& vertex = quadVertices[i];
+            glm::vec2 coord = pos + quad.quad[i].pos * scale;
+
+            vertex.pos.x = coord.x;
+            vertex.pos.y = coord.y;
+            vertex.pos.z = 0;
+
+            vertex.uv = quad.quad[i].uv;
+            vertex.state = state;
+        }
+    }
+}
+
+}
diff --git a/core/src/labels/spriteLabel.h b/core/src/labels/spriteLabel.h
new file mode 100644 (file)
index 0000000..c8a3e9f
--- /dev/null
@@ -0,0 +1,97 @@
+#pragma once
+
+#include "labels/label.h"
+#include "labels/labelSet.h"
+
+#include <array>
+
+namespace Tangram {
+
+class SpriteLabels;
+class PointStyle;
+class Texture;
+
+struct SpriteVertex {
+    glm::vec3 pos;
+    glm::u16vec2 uv;
+    struct State {
+        uint32_t selection;
+        uint32_t color;
+        uint16_t alpha;
+        uint16_t scale;
+    } state;
+
+    static const float alpha_scale;
+    static const float texture_scale;
+};
+
+class SpriteLabel : public Label {
+public:
+
+    struct VertexAttributes {
+        uint32_t color;
+        uint32_t selectionColor;
+        float extrudeScale;
+    };
+
+    using Coordinates = glm::vec3;
+
+    SpriteLabel(Coordinates _coordinates, glm::vec2 _size, Label::Options _options,
+                SpriteLabel::VertexAttributes _attrib, Texture* _texture,
+                SpriteLabels& _labels, size_t _labelsPos);
+
+    LabelType renderType() const override { return LabelType::icon; }
+
+    bool updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                               const AABB* _bounds, ScreenTransform& _transform) override;
+
+    void obbs(ScreenTransform& _transform, OBBBuffer& _obbs) override;
+
+    void addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) override;
+
+    void applyAnchor(LabelProperty::Anchor _anchor) override;
+
+    uint32_t selectionColor() override {
+        return m_vertexAttrib.selectionColor;
+    }
+
+    glm::vec2 modelCenter() const override {
+        return glm::vec2(m_coordinates);
+    }
+
+private:
+
+    const Coordinates m_coordinates;
+
+    // Back-pointer to owning container and position
+    const SpriteLabels& m_labels;
+    const size_t m_labelsPos;
+
+    // Non-owning reference to a texture that is specific to this label.
+    // If non-null, this indicates a custom texture for a marker.
+    Texture* m_texture;
+
+    VertexAttributes m_vertexAttrib;
+};
+
+struct SpriteQuad {
+    struct {
+        glm::vec2 pos;
+        glm::u16vec2 uv;
+    } quad[4];
+};
+
+class SpriteLabels : public LabelSet {
+public:
+    SpriteLabels(const PointStyle& _style) : m_style(_style) {}
+
+    void setQuads(std::vector<SpriteQuad>&& _quads) {
+        quads = std::move(_quads);
+    }
+
+    // TODO: hide within class if needed
+    const PointStyle& m_style;
+    std::vector<SpriteQuad> quads;
+};
+
+}
diff --git a/core/src/labels/textLabel.cpp b/core/src/labels/textLabel.cpp
new file mode 100644 (file)
index 0000000..4684ffe
--- /dev/null
@@ -0,0 +1,274 @@
+#include "labels/textLabel.h"
+
+#include "gl/dynamicQuadMesh.h"
+#include "labels/obbBuffer.h"
+#include "labels/textLabels.h"
+#include "labels/screenTransform.h"
+#include "log.h"
+#include "style/textStyle.h"
+#include "text/fontContext.h"
+#include "util/geom.h"
+#include "view/view.h"
+
+#include "glm/gtx/norm.hpp"
+
+namespace Tangram {
+
+using namespace LabelProperty;
+using namespace TextLabelProperty;
+
+const float TextVertex::position_scale = 4.0f;
+const float TextVertex::position_inv_scale = 0.25f;
+const float TextVertex::alpha_scale = 65535.0f;
+
+struct PointTransform {
+    ScreenTransform& m_transform;
+
+    PointTransform(ScreenTransform& _transform)
+        : m_transform(_transform) {}
+
+    void set(glm::vec2 _position, glm::vec2 _rotation) {
+        m_transform.push_back(_position);
+        m_transform.push_back(_rotation);
+    }
+
+    glm::vec2 position() const { return glm::vec2(m_transform[0]); }
+    glm::vec2 rotation() const { return glm::vec2(m_transform[1]); }
+};
+
+TextLabel::TextLabel(Coordinates _coordinates, Type _type, Label::Options _options,
+                     TextLabel::VertexAttributes _attrib, glm::vec2 _dim,
+                     TextLabels& _labels, TextRange _textRanges, Align _preferedAlignment)
+    : Label(_dim, _type, _options),
+      m_coordinates(_coordinates),
+      m_textLabels(_labels),
+      m_textRanges(_textRanges),
+      m_fontAttrib(_attrib),
+      m_preferedAlignment(_preferedAlignment) {
+
+    applyAnchor(m_options.anchors[0]);
+}
+
+void TextLabel::applyAnchor(Anchor _anchor) {
+
+    if (m_preferedAlignment == Align::none) {
+        Align newAlignment = alignFromAnchor(_anchor);
+        m_textRangeIndex = int(newAlignment);
+    } else {
+        m_textRangeIndex = int(m_preferedAlignment);
+    }
+
+    if (m_textRanges[m_textRangeIndex].length == 0) {
+        m_textRangeIndex = 0;
+    }
+
+    glm::vec2 offset = m_dim;
+    if (isChild()) { offset += m_relative->dimension(); }
+
+    m_anchor = LabelProperty::anchorDirection(_anchor) * offset * 0.5f;
+}
+
+bool TextLabel::updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                                      const AABB* _bounds, ScreenTransform& _transform) {
+
+    bool clipped = false;
+
+    switch(m_type) {
+        case Type::debug:
+        case Type::point: {
+
+            glm::vec2 p0 = m_coordinates[0];
+
+            glm::vec2 screenPosition = worldToScreenSpace(_mvp, glm::vec4(p0, 0.0, 1.0),
+                                                          _viewState.viewportSize, clipped);
+
+            if (clipped) { return false; }
+
+            if (_bounds) {
+                auto aabb = m_options.anchors.extents(m_dim);
+                aabb.min += screenPosition + m_options.offset;
+                aabb.max += screenPosition + m_options.offset;
+                if (!aabb.intersect(*_bounds)) { return false; }
+            }
+
+            m_screenCenter = screenPosition;
+
+            PointTransform(_transform).set(screenPosition + m_options.offset, glm::vec2{1, 0});
+
+            return true;
+        }
+        case Type::line: {
+
+            glm::vec2 rotation = {1, 0};
+
+            // project label position from mercator world space to screen
+            // coordinates
+            glm::vec2 p0 = m_coordinates[0];
+            glm::vec2 p2 = m_coordinates[1];
+
+            glm::vec2 ap0 = worldToScreenSpace(_mvp, glm::vec4(p0, 0.0, 1.0),
+                                               _viewState.viewportSize, clipped);
+            glm::vec2 ap2 = worldToScreenSpace(_mvp, glm::vec4(p2, 0.0, 1.0),
+                                               _viewState.viewportSize, clipped);
+
+            // check whether the label is behind the camera using the
+            // perspective division factor
+            if (clipped) { return false; }
+
+            if (_bounds) {
+                AABB aabb;
+                aabb.include(ap0.x, ap0.y);
+                aabb.include(ap2.x, ap2.y);
+                if (!aabb.intersect(*_bounds)) { return false; }
+            }
+
+            float length = glm::length(ap2 - ap0);
+
+            // default heuristic : allow label to be 30% wider than segment
+            float minLength = m_dim.x * 0.7;
+
+            if (length < minLength) { return false; }
+
+            glm::vec2 p1 = glm::vec2(p2 + p0) * 0.5f;
+
+            // Keep screen position center at world center (less sliding in tilted view)
+            glm::vec2 screenPosition = worldToScreenSpace(_mvp, glm::vec4(p1, 0.0, 1.0),
+                                                          _viewState.viewportSize, clipped);
+
+            auto offset = m_options.offset;
+
+            bool flip = ap0.x > ap2.x;
+
+            if (flip) {
+                rotation = (ap0 - ap2) / length;
+            } else {
+                rotation = (ap2 - ap0) / length;
+            }
+
+            if (m_options.anchors.anchor[0] == LabelProperty::Anchor::bottom) {
+                offset.y += m_dim.y * 0.5f;
+                if (flip) { offset = -offset; }
+            } else if (m_options.anchors.anchor[0] == LabelProperty::Anchor::top) {
+                offset.y += m_dim.y * 0.5f;
+                if (!flip) { offset = -offset; }
+            }
+
+            rotation = glm::vec2{ rotation.x, - rotation.y };
+
+            m_screenCenter = screenPosition;
+
+            PointTransform(_transform).set(screenPosition + rotateBy(offset, rotation), rotation);
+
+            return true;
+        }
+        default:
+            break;
+    }
+
+    return false;
+}
+
+float TextLabel::candidatePriority() const {
+    if (m_type != Type::line) { return 0.f; }
+
+    return 1.f / (glm::length2(m_coordinates[0] - m_coordinates[1]));
+}
+
+void TextLabel::obbs(ScreenTransform& _transform, OBBBuffer& _obbs) {
+
+    glm::vec2 dim = m_dim;
+
+    if (m_occludedLastFrame) { dim += Label::activation_distance_threshold; }
+
+    PointTransform pointTransform(_transform);
+    auto rotation = pointTransform.rotation();
+
+    auto position = pointTransform.position();
+    if (m_type != Type::line) { position += m_anchor; }
+
+    auto obb = OBB(position, glm::vec2{rotation.x, -rotation.y}, dim.x, dim.y);
+
+    _obbs.append(obb);
+
+}
+
+void TextLabel::addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) {
+    if (!visibleState()) { return; }
+
+    TextVertex::State state {
+        m_fontAttrib.selectionColor,
+        m_fontAttrib.fill,
+        m_fontAttrib.stroke,
+        uint16_t(m_alpha * TextVertex::alpha_scale),
+        uint16_t(m_fontAttrib.fontScale),
+    };
+
+    auto it = m_textLabels.quads.begin() + m_textRanges[m_textRangeIndex].start;
+    auto end = it + m_textRanges[m_textRangeIndex].length;
+    auto& style = m_textLabels.style;
+
+    auto& meshes = style.getMeshes();
+
+    PointTransform transform(_transform);
+
+    glm::vec2 rotation = transform.rotation();
+    bool rotate = (rotation.x != 1.f);
+
+    glm::vec2 screenPosition = transform.position();
+    if (m_type != Type::line) { screenPosition += m_anchor; }
+
+    glm::i16vec2 sp = glm::i16vec2(screenPosition * TextVertex::position_scale);
+    std::array<glm::i16vec2, 4> vertexPosition;
+
+    // Expand screen bounding box by text height
+    // TODO: Better approximation.
+    glm::i16vec2 min(-m_dim.y * TextVertex::position_scale);
+    glm::i16vec2 max((_screenSize + m_dim.y) * TextVertex::position_scale);
+
+    for (; it != end; ++it) {
+        auto quad = *it;
+        bool visible = false;
+
+        if (rotate) {
+            for (int i = 0; i < 4; i++) {
+                vertexPosition[i] = sp + glm::i16vec2{rotateBy(quad.quad[i].pos, rotation)};
+            }
+        } else {
+            for (int i = 0; i < 4; i++) {
+                vertexPosition[i] = sp + quad.quad[i].pos;
+            }
+        }
+
+        for (int i = 0; i < 4; i++) {
+            if (!visible &&
+                vertexPosition[i].x > min.x &&
+                vertexPosition[i].x < max.x &&
+                vertexPosition[i].y > min.y &&
+                vertexPosition[i].y < max.y) {
+                visible = true;
+            }
+        }
+        if (!visible) { continue; }
+
+        auto* quadVertices = meshes[it->atlas]->pushQuad();
+
+        for (int i = 0; i < 4; i++) {
+            TextVertex& v = quadVertices[i];
+            v.pos = vertexPosition[i];
+            v.uv = quad.quad[i].uv;
+            v.state = state;
+        }
+    }
+}
+
+TextLabels::~TextLabels() {
+    style.context()->releaseAtlas(m_atlasRefs);
+}
+
+void TextLabels::setQuads(std::vector<GlyphQuad>&& _quads, std::bitset<FontContext::max_textures> _atlasRefs) {
+    quads = std::move(_quads);
+    m_atlasRefs = _atlasRefs;
+
+}
+
+}
diff --git a/core/src/labels/textLabel.h b/core/src/labels/textLabel.h
new file mode 100644 (file)
index 0000000..fcd7309
--- /dev/null
@@ -0,0 +1,104 @@
+#pragma once
+
+#include "labels/label.h"
+
+#include <glm/glm.hpp>
+
+namespace Tangram {
+
+class TextLabels;
+class TextStyle;
+
+struct GlyphQuad {
+    size_t atlas;
+    struct {
+        glm::i16vec2 pos;
+        glm::u16vec2 uv;
+    } quad[4];
+};
+
+using TextRange = std::array<Range, 3>;
+
+struct TextVertex {
+    glm::i16vec2 pos;
+    glm::u16vec2 uv;
+    struct State {
+        uint32_t selection;
+        uint32_t color;
+        uint32_t stroke;
+        uint16_t alpha;
+        uint16_t scale;
+    } state;
+
+    const static float position_scale;
+    const static float position_inv_scale;
+    const static float alpha_scale;
+};
+
+class TextLabel : public Label {
+
+public:
+
+    struct VertexAttributes {
+        uint32_t fill;
+        uint32_t stroke;
+        uint8_t fontScale;
+        uint32_t selectionColor;
+    };
+
+    using Coordinates = std::array<glm::vec2, 2>;
+
+    TextLabel(Coordinates _coordinates, Type _type, Label::Options _options,
+              TextLabel::VertexAttributes _attrib,
+              glm::vec2 _dim, TextLabels& _labels, TextRange _textRanges,
+              TextLabelProperty::Align _preferedAlignment);
+
+    LabelType renderType() const override { return LabelType::text; }
+
+    bool updateScreenTransform(const glm::mat4& _mvp, const ViewState& _viewState,
+                               const AABB* _bounds, ScreenTransform& _transform) override;
+
+    void obbs(ScreenTransform& _transform, OBBBuffer& _obbs) override;
+
+    void addVerticesToMesh(ScreenTransform& _transform, const glm::vec2& _screenSize) override;
+
+    void applyAnchor(LabelProperty::Anchor _anchor) override;
+
+    TextRange& textRanges() {
+        return m_textRanges;
+    }
+
+    uint32_t selectionColor() override {
+        return m_fontAttrib.selectionColor;
+    }
+
+    glm::vec2 modelCenter() const override {
+        if (m_type == Label::Type::line) {
+            return (m_coordinates[0] + m_coordinates[1]) * 0.5f;
+        } else {
+            return m_coordinates[0];
+        }
+    }
+
+    float candidatePriority() const override;
+
+protected:
+
+    const Coordinates m_coordinates;
+
+    // Back-pointer to owning container
+    const TextLabels& m_textLabels;
+
+    // first vertex and count in m_textLabels quads (left,right,center)
+    TextRange m_textRanges;
+
+    // TextRange currently used for drawing
+    int m_textRangeIndex;
+
+    VertexAttributes m_fontAttrib;
+
+    // The text LAbel prefered alignment
+    TextLabelProperty::Align m_preferedAlignment;
+};
+
+}
diff --git a/core/src/labels/textLabels.h b/core/src/labels/textLabels.h
new file mode 100644 (file)
index 0000000..58b89fa
--- /dev/null
@@ -0,0 +1,30 @@
+#pragma once
+
+#include "labels/labelSet.h"
+#include "labels/textLabel.h"
+#include "text/fontContext.h"
+
+#include <bitset>
+#include <vector>
+
+namespace Tangram {
+
+class TextLabels : public LabelSet {
+
+public:
+
+    TextLabels(const TextStyle& _style) : style(_style) {}
+
+    ~TextLabels() override;
+
+    void setQuads(std::vector<GlyphQuad>&& _quads, std::bitset<FontContext::max_textures> _atlasRefs);
+
+    std::vector<GlyphQuad> quads;
+    const TextStyle& style;
+
+private:
+
+    std::bitset<FontContext::max_textures> m_atlasRefs;
+};
+
+}
diff --git a/core/src/marker/marker.cpp b/core/src/marker/marker.cpp
new file mode 100644 (file)
index 0000000..378204d
--- /dev/null
@@ -0,0 +1,182 @@
+#include "marker/marker.h"
+
+#include "data/tileData.h"
+#include "gl/texture.h"
+#include "scene/dataLayer.h"
+#include "scene/drawRule.h"
+#include "scene/scene.h"
+#include "style/style.h"
+#include "view/view.h"
+
+#include "glm/gtc/matrix_transform.hpp"
+#include "glm/gtx/transform.hpp"
+
+namespace Tangram {
+
+Marker::Marker(MarkerID id) : m_id(id) {
+    m_drawRuleSet.reset(new DrawRuleMergeSet());
+}
+
+Marker::~Marker() {
+}
+
+void Marker::setBounds(BoundingBox bounds) {
+    m_bounds = bounds;
+    m_origin = bounds.min; // South-West corner
+}
+
+void Marker::setFeature(std::unique_ptr<Feature> feature) {
+    m_feature = std::move(feature);
+}
+
+void Marker::setStyling(std::string styling, bool isPath) {
+    m_styling.string = styling;
+    m_styling.isPath = isPath;
+}
+
+bool Marker::evaluateRuleForContext(StyleContext& ctx) {
+    return m_drawRuleSet->evaluateRuleForContext(*drawRule(), ctx);
+}
+
+void Marker::setDrawRuleData(std::unique_ptr<DrawRuleData> drawRuleData) {
+    m_drawRuleData = std::move(drawRuleData);
+    m_drawRule = std::make_unique<DrawRule>(*m_drawRuleData, "", 0);
+}
+
+void Marker::mergeRules(const SceneLayer& layer) {
+    m_drawRuleSet->mergeRules(layer);
+}
+
+bool Marker::finalizeRuleMergingForName(const std::string& name) {
+    bool found = false;
+    for (auto& rule : m_drawRuleSet->matchedRules()) {
+        if (name == *rule.name) {
+            m_drawRule = std::make_unique<DrawRule>(rule);
+            found = true;
+            break;
+        }
+    }
+    if (found) {
+        // Clear leftover data (outside the loop so we don't invalidate iterators).
+        m_drawRuleData.reset(nullptr);
+        m_drawRuleSet->matchedRules().clear();
+    }
+    return found;
+}
+
+void Marker::setMesh(uint32_t styleId, uint32_t zoom, std::unique_ptr<StyledMesh> mesh) {
+    m_mesh = std::move(mesh);
+    m_styleId = styleId;
+    m_builtZoomLevel = zoom;
+
+    float scale;
+    if (m_feature && m_feature->geometryType == GeometryType::points) {
+        scale = (MapProjection::HALF_CIRCUMFERENCE * 2) / (1 << zoom);
+    } else {
+        scale = extent();
+    }
+    m_modelMatrix = glm::scale(glm::vec3(scale));
+}
+
+void Marker::setTexture(std::unique_ptr<Texture> texture) {
+    m_texture = std::move(texture);
+}
+
+void Marker::setEase(const glm::dvec2& dest, float duration, EaseType e) {
+    auto origin = m_origin;
+    auto cb = [=](float t) { m_origin = { ease(origin.x, dest.x, t, e), ease(origin.y, dest.y, t, e) }; };
+    m_ease = { duration, cb };
+}
+
+void Marker::update(float dt, const View& view) {
+    // Update easing
+    if (!m_ease.finished()) { m_ease.update(dt); }
+    // Apply marker-view translation to the model matrix
+    const auto& viewOrigin = view.getPosition();
+    m_modelMatrix[3][0] = m_origin.x - viewOrigin.x;
+    m_modelMatrix[3][1] = m_origin.y - viewOrigin.y;
+
+    m_modelViewProjectionMatrix = view.getViewProjectionMatrix() * m_modelMatrix;
+}
+
+void Marker::setVisible(bool visible) {
+    m_visible = visible;
+}
+
+void Marker::setDrawOrder(int drawOrder) {
+    m_drawOrder = drawOrder;
+}
+
+void Marker::setSelectionColor(uint32_t selectionColor) {
+    m_selectionColor = selectionColor;
+}
+
+int Marker::builtZoomLevel() const {
+    return m_builtZoomLevel;
+}
+
+int Marker::drawOrder() const {
+    return m_drawOrder;
+}
+
+MarkerID Marker::id() const {
+    return m_id;
+}
+
+uint32_t Marker::styleId() const {
+    return m_styleId;
+}
+
+float Marker::extent() const {
+    return glm::max(m_bounds.width(), m_bounds.height());
+}
+
+Feature* Marker::feature() const {
+    return m_feature.get();
+}
+
+DrawRule* Marker::drawRule() const {
+    return m_drawRule.get();
+}
+
+StyledMesh* Marker::mesh() const {
+    return m_mesh.get();
+}
+
+Texture* Marker::texture() const {
+    return m_texture.get();
+}
+
+const BoundingBox& Marker::bounds() const {
+    return m_bounds;
+}
+
+const glm::dvec2& Marker::origin() const {
+    return m_origin;
+}
+
+const glm::mat4& Marker::modelMatrix() const {
+    return m_modelMatrix;
+}
+
+const glm::mat4& Marker::modelViewProjectionMatrix() const {
+    return m_modelViewProjectionMatrix;
+}
+
+bool Marker::isEasing() const {
+    return !m_ease.finished();
+}
+
+bool Marker::isVisible() const {
+    return m_visible;
+}
+
+uint32_t Marker::selectionColor() const {
+    return m_selectionColor;
+}
+
+bool Marker::compareByDrawOrder(const std::unique_ptr<Marker>& lhs, const std::unique_ptr<Marker>& rhs) {
+    return lhs->m_drawOrder < rhs->m_drawOrder;
+}
+
+} // namespace Tangram
diff --git a/core/src/marker/marker.h b/core/src/marker/marker.h
new file mode 100644 (file)
index 0000000..2122d2b
--- /dev/null
@@ -0,0 +1,170 @@
+#pragma once
+
+#include "util/ease.h"
+#include "util/geom.h"
+#include "util/types.h"
+
+#include "glm/mat4x4.hpp"
+#include "glm/vec2.hpp"
+#include <memory>
+#include <string>
+
+namespace Tangram {
+
+class SceneLayer;
+class DrawRuleMergeSet;
+class MapProjection;
+class Scene;
+class StyleContext;
+class Texture;
+class View;
+struct DrawRule;
+struct DrawRuleData;
+struct Feature;
+struct StyledMesh;
+
+class Marker {
+
+    struct Styling {
+        std::string string;
+        bool isPath = false; // True if styling string is a path to a draw rule.
+    };
+
+public:
+
+    // Create an empty marker with the given ID. An ID of 0 indicates an invalid marker.
+    Marker(MarkerID id);
+
+    ~Marker();
+
+    // Set the axis-aligned bounding box for the feature geometry in Mercator meters;
+    // The points in the feature for this Marker should be made relative to a coordinate system
+    // whose origin is the South-West corner of the bounds and whose unit length is the
+    // maximum dimension (extent) of the bounds.
+    void setBounds(BoundingBox bounds);
+
+    // Set the feature whose geometry will be used to build the marker.
+    void setFeature(std::unique_ptr<Feature> feature);
+
+    // Sets the styling struct for the marker
+    void setStyling(std::string styling, bool isPath);
+
+    // Set the new draw rule data that will be used to build the marker.
+    void setDrawRuleData(std::unique_ptr<DrawRuleData> drawRuleData);
+
+    // Merge draw rules from the given layer into the internal draw rule set.
+    void mergeRules(const SceneLayer& layer);
+
+    // From the set of merged draw rules, set the one with the given name as the
+    // Marker's draw rule and clear the internal draw rule set. Returns true if
+    // the named rule was found.
+    bool finalizeRuleMergingForName(const std::string& name);
+
+    // Set the styled mesh for this marker with the associated style id and zoom level.
+    void setMesh(uint32_t styleId, uint32_t zoom, std::unique_ptr<StyledMesh> mesh);
+
+    void setTexture(std::unique_ptr<Texture> texture);
+
+    // Set an ease for the origin of this marker in Mercator meters.
+    void setEase(const glm::dvec2& destination, float duration, EaseType ease);
+
+    void setSelectionColor(uint32_t selectionColor);
+
+    // Set the model matrix for the marker using the current view and update any eases.
+    void update(float dt, const View& view);
+
+    // Set whether this marker should be visible.
+    void setVisible(bool visible);
+
+    // Set the ordering of this marker relative to other markers.
+    // Markers with higher values are drawn 'above' those with lower values.
+    void setDrawOrder(int drawOrder);
+
+    // Get the unique identifier for this marker. An ID of 0 indicates an invalid marker.
+    MarkerID id() const;
+
+    // Get the ID of the style that should draw the mesh for this marker.
+    uint32_t styleId() const;
+
+    // Get the zoom level at which the mesh for this marker was built.
+    int builtZoomLevel() const;
+
+    // Get the ordering of this marker relative to other markers.
+    int drawOrder() const;
+
+    // Get the length of the maximum dimension of the bounds of this marker. This is used as
+    // the scale in the model matrix.
+    float extent() const;
+
+    StyledMesh* mesh() const;
+
+    DrawRule* drawRule() const;
+
+    Feature* feature() const;
+
+    Texture* texture() const;
+
+    const BoundingBox& bounds() const;
+
+    // Get the origin of the geometry for this marker, i.e. the South-West corner of the bounds.
+    // This is used as the origin in the model matrix.
+    const glm::dvec2& origin() const;
+
+    const glm::mat4& modelMatrix() const;
+
+    const glm::mat4& modelViewProjectionMatrix() const;
+
+    const Styling& styling() const { return m_styling; }
+
+    bool evaluateRuleForContext(StyleContext& ctx);
+
+    bool isEasing() const;
+
+    bool isVisible() const;
+
+    uint32_t selectionColor() const;
+
+    static bool compareByDrawOrder(const std::unique_ptr<Marker>& lhs, const std::unique_ptr<Marker>& rhs);
+
+protected:
+
+    std::unique_ptr<Feature> m_feature;
+    std::unique_ptr<StyledMesh> m_mesh;
+    std::unique_ptr<Texture> m_texture;
+    std::unique_ptr<DrawRuleMergeSet> m_drawRuleSet;
+    std::unique_ptr<DrawRuleData> m_drawRuleData;
+    std::unique_ptr<DrawRule> m_drawRule;
+
+    Styling m_styling;
+
+    MarkerID m_id = 0;
+
+    uint32_t m_styleId = 0;
+
+    int m_builtZoomLevel = 0;
+
+    uint32_t m_selectionColor = 0;
+
+    int m_drawOrder = 0;
+
+    // Origin of marker geometry relative to global projection space.
+    glm::dvec2 m_origin;
+
+    // Bounding box in global projection space which describes the origin and extent of the coordinates in the Feature
+    BoundingBox m_bounds;
+
+    // Matrix relating marker-local coordinates to global projection space coordinates;
+    // Note that this matrix does not contain the relative translation from the global origin to the marker origin.
+    // Distances from the global origin are too large to represent precisely in 32-bit floats, so we only apply the
+    // relative translation from the view origin to the model origin immediately before drawing the marker.
+    glm::mat4 m_modelMatrix;
+
+    glm::mat4 m_modelViewProjectionMatrix;
+
+    Ease m_ease;
+
+    bool m_visible = true;
+
+};
+
+} // namespace Tangram
diff --git a/core/src/marker/markerManager.cpp b/core/src/marker/markerManager.cpp
new file mode 100644 (file)
index 0000000..aa518f9
--- /dev/null
@@ -0,0 +1,459 @@
+#include "marker/markerManager.h"
+
+#include "data/tileData.h"
+#include "gl/texture.h"
+#include "marker/marker.h"
+#include "scene/sceneLoader.h"
+#include "scene/dataLayer.h"
+#include "scene/styleContext.h"
+#include "style/style.h"
+#include "labels/labelSet.h"
+#include "log.h"
+#include "selection/featureSelection.h"
+
+#include <algorithm>
+
+namespace Tangram {
+
+MarkerManager::MarkerManager() {}
+
+MarkerManager::~MarkerManager() {}
+
+void MarkerManager::setScene(std::shared_ptr<Scene> scene) {
+
+    m_scene = scene;
+    m_mapProjection = scene->mapProjection().get();
+
+    m_styleContext = std::make_unique<StyleContext>();
+    m_styleContext->initFunctions(*scene);
+
+    // Initialize StyleBuilders.
+    m_styleBuilders.clear();
+    for (auto& style : scene->styles()) {
+        m_styleBuilders[style->getName()] = style->createBuilder();
+    }
+
+    removeAll();
+}
+
+MarkerID MarkerManager::add() {
+
+    // Add a new empty marker object to the list of markers.
+    auto id = ++m_idCounter;
+    m_markers.push_back(std::make_unique<Marker>(id));
+
+    // Sort the marker list by draw order.
+    std::stable_sort(m_markers.begin(), m_markers.end(), Marker::compareByDrawOrder);
+
+    // Return a handle for the marker.
+    return id;
+
+}
+
+bool MarkerManager::remove(MarkerID markerID) {
+    for (auto it = m_markers.begin(), end = m_markers.end(); it != end; ++it) {
+        if (it->get()->id() == markerID) {
+            m_markers.erase(it);
+            return true;
+        }
+    }
+    return false;
+}
+
+bool MarkerManager::setStylingFromString(MarkerID markerID, const char* styling) {
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    marker->setStyling(std::string(styling), false);
+
+    // Create a draw rule from the styling string.
+    if (!buildStyling(*marker)) { return false; }
+
+    // Build the feature mesh for the marker's current geometry.
+    buildGeometry(*marker, m_zoom);
+
+    return true;
+}
+
+bool MarkerManager::setStylingFromPath(MarkerID markerID, const char* path) {
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    marker->setStyling(std::string(path), true);
+
+    // Create a draw rule from the styling string.
+    if (!buildStyling(*marker)) { return false; }
+
+    // Build the feature mesh for the marker's current geometry.
+    buildGeometry(*marker, m_zoom);
+
+    return true;
+}
+
+bool MarkerManager::setBitmap(MarkerID markerID, int width, int height, const unsigned int* bitmapData) {
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    TextureOptions options = { GL_RGBA, GL_RGBA, { GL_LINEAR, GL_LINEAR }, { GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE } };
+    auto texture = std::make_unique<Texture>(width, height, options);
+    unsigned int size = width * height;
+    texture->setData(bitmapData, size);
+
+    marker->setTexture(std::move(texture));
+
+    // The geometry is unchanged, but the mesh must be rebuilt because DynamicQuadMesh contains
+    // texture batches as part of its data.
+    buildGeometry(*marker, m_zoom);
+
+    return true;
+}
+
+bool MarkerManager::setVisible(MarkerID markerID, bool visible) {
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    marker->setVisible(visible);
+    return true;
+}
+
+bool MarkerManager::setDrawOrder(MarkerID markerID, int drawOrder) {
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    marker->setDrawOrder(drawOrder);
+
+    // Sort the marker list by draw order.
+    std::stable_sort(m_markers.begin(), m_markers.end(), Marker::compareByDrawOrder);
+    return true;
+}
+
+bool MarkerManager::setPoint(MarkerID markerID, LngLat lngLat) {
+
+    if (!m_scene) { return false; }
+
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    // If the marker does not have a 'point' feature mesh built, build it.
+    if (!marker->mesh() || !marker->feature() || marker->feature()->geometryType != GeometryType::points) {
+        auto feature = std::make_unique<Feature>();
+        feature->geometryType = GeometryType::points;
+        feature->points.emplace_back();
+        marker->setFeature(std::move(feature));
+        buildGeometry(*marker, m_zoom);
+    }
+
+    // Update the marker's bounds to the given coordinates.
+    auto origin = m_mapProjection->LonLatToMeters({ lngLat.longitude, lngLat.latitude });
+    marker->setBounds({ origin, origin });
+
+    return true;
+}
+
+bool MarkerManager::setPointEased(MarkerID markerID, LngLat lngLat, float duration, EaseType ease) {
+
+    if (!m_scene) { return false; }
+
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+
+    // If the marker does not have a 'point' feature built, set that point immediately.
+    if (!marker->mesh() || !marker->feature() || marker->feature()->geometryType != GeometryType::points) {
+        return setPoint(markerID, lngLat);
+    }
+
+    auto dest = m_mapProjection->LonLatToMeters({ lngLat.longitude, lngLat.latitude });
+    marker->setEase(dest, duration, ease);
+
+    return true;
+}
+
+bool MarkerManager::setPolyline(MarkerID markerID, LngLat* coordinates, int count) {
+
+    if (!m_scene) { return false; }
+
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+    if (!coordinates || count < 2) { return false; }
+
+    // Build a feature for the new set of polyline points.
+    auto feature = std::make_unique<Feature>();
+    feature->geometryType = GeometryType::lines;
+    feature->lines.emplace_back();
+    auto& line = feature->lines.back();
+
+    // Determine the bounds of the polyline.
+    BoundingBox bounds;
+    bounds.min = { coordinates[0].longitude, coordinates[0].latitude };
+    bounds.max = bounds.min;
+    for (int i = 0; i < count; ++i) {
+        bounds.expand(coordinates[i].longitude, coordinates[i].latitude);
+    }
+    bounds.min = m_mapProjection->LonLatToMeters(bounds.min);
+    bounds.max = m_mapProjection->LonLatToMeters(bounds.max);
+
+    // Update the marker's bounds.
+    marker->setBounds(bounds);
+
+    float scale = 1.f / marker->extent();
+
+    // Project and offset the coordinates into the marker-local coordinate system.
+    auto origin = marker->origin(); // SW corner.
+    for (int i = 0; i < count; ++i) {
+        auto degrees = glm::dvec2(coordinates[i].longitude, coordinates[i].latitude);
+        auto meters = m_mapProjection->LonLatToMeters(degrees);
+        line.emplace_back((meters.x - origin.x) * scale, (meters.y - origin.y) * scale, 0.f);
+    }
+
+    // Update the feature data for the marker.
+    marker->setFeature(std::move(feature));
+
+    // Build a new mesh for the marker.
+    buildGeometry(*marker, m_zoom);
+
+    return true;
+}
+
+bool MarkerManager::setPolygon(MarkerID markerID, LngLat* coordinates, int* counts, int rings) {
+
+    if (!m_scene) { return false; }
+
+    Marker* marker = getMarkerOrNull(markerID);
+    if (!marker) { return false; }
+    if (!coordinates || !counts || rings < 1) { return false; }
+
+    // Build a feature for the new set of polygon points.
+    auto feature = std::make_unique<Feature>();
+    feature->geometryType = GeometryType::polygons;
+    feature->polygons.emplace_back();
+    auto& polygon = feature->polygons.back();
+
+    // Determine the bounds of the polygon.
+    BoundingBox bounds;
+    LngLat* ring = coordinates;
+    for (int i = 0; i < rings; ++i) {
+        int count = counts[i];
+        for (int j = 0; j < count; ++j) {
+            if (i == 0 && j == 0) {
+                bounds.min = { ring[0].longitude, ring[0].latitude };
+                bounds.max = bounds.min;
+            }
+            bounds.expand(ring[j].longitude, ring[j].latitude);
+        }
+        ring += count;
+    }
+    bounds.min = m_mapProjection->LonLatToMeters(bounds.min);
+    bounds.max = m_mapProjection->LonLatToMeters(bounds.max);
+
+    // Update the marker's bounds.
+    marker->setBounds(bounds);
+
+    float scale = 1.f / marker->extent();
+
+    // Project and offset the coordinates into the marker-local coordinate system.
+    auto origin = marker->origin(); // SW corner.
+    ring = coordinates;
+    for (int i = 0; i < rings; ++i) {
+        int count = counts[i];
+        polygon.emplace_back();
+        auto& line = polygon.back();
+        for (int j = 0; j < count; ++j) {
+            auto degrees = glm::dvec2(ring[j].longitude, ring[j].latitude);
+            auto meters = m_mapProjection->LonLatToMeters(degrees);
+            line.emplace_back((meters.x - origin.x) * scale, (meters.y - origin.y) * scale, 0.f);
+        }
+        ring += count;
+    }
+
+    // Update the feature data for the marker.
+    marker->setFeature(std::move(feature));
+
+    // Build a new mesh for the marker.
+    buildGeometry(*marker, m_zoom);
+
+    return true;
+}
+
+bool MarkerManager::update(int zoom) {
+
+    if (zoom == m_zoom) {
+         return false;
+    }
+    bool rebuilt = false;
+    for (auto& marker : m_markers) {
+        if (zoom != marker->builtZoomLevel()) {
+            buildGeometry(*marker, zoom);
+            rebuilt = true;
+        }
+    }
+    m_zoom = zoom;
+    return rebuilt;
+}
+
+void MarkerManager::removeAll() {
+
+    m_markers.clear();
+
+}
+
+void MarkerManager::rebuildAll() {
+
+    for (auto& entry : m_markers) {
+        buildStyling(*entry);
+        buildGeometry(*entry, m_zoom);
+    }
+
+}
+
+const std::vector<std::unique_ptr<Marker>>& MarkerManager::markers() const {
+    return m_markers;
+}
+
+bool MarkerManager::buildStyling(Marker& marker) {
+
+    if (!m_scene) { return false; }
+
+    std::vector<StyleParam> params;
+
+    const auto& markerStyling = marker.styling();
+
+    // If the Marker styling is a path, find the layers it specifies.
+    if (markerStyling.isPath) {
+        auto path = markerStyling.string;
+        // The DELIMITER used by layers is currently ":", but Marker paths use "." (scene.h).
+        std::replace(path.begin(), path.end(), '.', DELIMITER[0]);
+        // Start iterating over the delimited path components.
+        size_t start = 0, end = 0;
+        end = path.find(DELIMITER[0], start);
+        if (path.compare(start, end - start, "layers") != 0) {
+            // If the path doesn't begin with 'layers' it isn't a layer heirarchy.
+            return false;
+        }
+        // Find the DataLayer named in our path.
+        const SceneLayer* currentLayer = nullptr;
+        size_t layerStart = end + 1;
+        start = end + 1;
+        end = path.find(DELIMITER[0], start);
+        for (const auto& layer : m_scene->layers()) {
+            if (path.compare(layerStart, end - layerStart, layer.name()) == 0) {
+                currentLayer = &layer;
+                marker.mergeRules(layer);
+                break;
+            }
+        }
+        // Search sublayers recursively until we can't find another token or layer.
+        while (end != std::string::npos && currentLayer != nullptr) {
+            start = end + 1;
+            end = path.find(DELIMITER[0], start);
+            const auto& layers = currentLayer->sublayers();
+            currentLayer = nullptr;
+            for (const auto& layer : layers) {
+                if (path.compare(layerStart, end - layerStart, layer.name()) == 0) {
+                    currentLayer = &layer;
+                    marker.mergeRules(layer);
+                    break;
+                }
+            }
+        }
+        // The last token found should have been "draw".
+        if (path.compare(start, end - start, "draw") != 0) {
+            return false;
+        }
+        // The draw group name should come next.
+        start = end + 1;
+        end = path.find(DELIMITER[0], start);
+        // Find the rule in the merged set whose name matches the final token.
+        return marker.finalizeRuleMergingForName(path.substr(start, end - start));
+    }
+
+    // If the styling is not a path, try to load it as a string of YAML.
+    const auto& sceneJsFnList = m_scene->functions();
+    auto jsFnIndex = sceneJsFnList.size();
+
+    try {
+        YAML::Node node = YAML::Load(markerStyling.string);
+        // Parse style parameters from the YAML node.
+        SceneLoader::parseStyleParams(node, m_scene, "", params);
+    } catch (YAML::Exception e) {
+        LOG("Invalid marker styling '%s', %s", markerStyling.string.c_str(), e.what());
+        return false;
+    }
+    // Compile any new JS functions used for styling.
+    for (auto i = jsFnIndex; i < sceneJsFnList.size(); ++i) {
+        m_styleContext->addFunction(sceneJsFnList[i]);
+    }
+
+    marker.setDrawRuleData(std::make_unique<DrawRuleData>("", 0, std::move(params)));
+
+    return true;
+}
+
+bool MarkerManager::buildGeometry(Marker& marker, int zoom) {
+
+    auto feature = marker.feature();
+    auto rule = marker.drawRule();
+    if (!feature || !rule) { return false; }
+
+    StyleBuilder* styler = nullptr;
+    {
+        auto name = rule->getStyleName();
+        auto it = m_styleBuilders.find(name);
+        if (it != m_styleBuilders.end()) {
+            styler = it->second.get();
+        } else {
+            LOGN("Invalid style %s", name.c_str());
+            return false;
+        }
+    }
+
+    // Apply defaul draw rules defined for this style
+    styler->style().applyDefaultDrawRules(*rule);
+
+    m_styleContext->setKeywordZoom(zoom);
+
+    bool valid = marker.evaluateRuleForContext(*m_styleContext);
+
+    if (!valid) { return false; }
+
+    styler->setup(marker, zoom);
+
+    uint32_t selectionColor = 0;
+    bool interactive = false;
+    if (rule->get(StyleParamKey::interactive, interactive) && interactive) {
+        if (selectionColor == 0) {
+            selectionColor = m_scene->featureSelection()->nextColorIdentifier();
+        }
+        rule->selectionColor = selectionColor;
+    } else {
+        rule->selectionColor = 0;
+    }
+
+    if (!styler->addFeature(*feature, *rule)) { return false; }
+
+    marker.setSelectionColor(selectionColor);
+    marker.setMesh(styler->style().getID(), zoom, styler->build());
+
+    setVisible(marker.id(), marker.isVisible());
+
+    return true;
+}
+
+const Marker* MarkerManager::getMarkerOrNullBySelectionColor(uint32_t selectionColor) const {
+    for (const auto& marker : m_markers) {
+        if (marker->isVisible() && marker->selectionColor() == selectionColor) {
+            return marker.get();
+        }
+    }
+
+    return nullptr;
+}
+
+Marker* MarkerManager::getMarkerOrNull(MarkerID markerID) {
+    if (!markerID) { return nullptr; }
+    for (const auto& entry : m_markers) {
+        if (entry->id() == markerID) { return entry.get(); }
+    }
+    return nullptr;
+}
+
+} // namespace Tangram
diff --git a/core/src/marker/markerManager.h b/core/src/marker/markerManager.h
new file mode 100644 (file)
index 0000000..c6bf40d
--- /dev/null
@@ -0,0 +1,95 @@
+#pragma once
+
+#include "scene/drawRule.h"
+#include "util/ease.h"
+#include "util/fastmap.h"
+#include "util/types.h"
+
+#include <memory>
+#include <vector>
+
+namespace Tangram {
+
+class MapProjection;
+class Marker;
+class Scene;
+class StyleBuilder;
+class StyleContext;
+
+class MarkerManager {
+
+public:
+
+    MarkerManager();
+    ~MarkerManager();
+    // Set the Scene object whose styling information will be used to build markers.
+    void setScene(std::shared_ptr<Scene> scene);
+
+    // Create a new, empty marker and return its ID. An ID of 0 indicates an invalid marker.
+    MarkerID add();
+
+    // Try to remove the marker with the given ID; returns true if the marker was found and removed.
+    bool remove(MarkerID markerID);
+
+    // Set the styling for a marker using a YAML string; returns true if the marker was found and updated.
+    bool setStylingFromString(MarkerID markerID, const char* styling);
+
+    // Set the styling for a marker using a scene path; returns true is the marker was found and update.
+    bool setStylingFromPath(MarkerID markerID, const char* path);
+
+    bool setBitmap(MarkerID markerID, int width, int height, const unsigned int* bitmapData);
+
+    // Set whether a marker should be visible; returns true if the marker was found and updated.
+    bool setVisible(MarkerID markerID, bool visible);
+
+    // Set the ordering of this marker relative to other markers. Higher values are drawn 'above' others.
+    bool setDrawOrder(MarkerID markerID, int drawOrder);
+
+    // Set a marker to a point feature at the given position; returns true if the marker was found and updated.
+    bool setPoint(MarkerID markerID, LngLat lngLat);
+
+    // Set a marker to a point feature at the given position; if the marker was previously set to a point, this
+    // eases from the old position to the new one over the given duration with the given ease type; returns true if
+    // the marker was found and updated.
+    bool setPointEased(MarkerID markerID, LngLat lngLat, float duration, EaseType ease);
+
+    // Set a marker to a polyline feature at the given position; returns true if the marker was found and updated.
+    bool setPolyline(MarkerID markerID, LngLat* coordinates, int count);
+
+    // Set a marker to a polygon feature at the given position; returns true if the marker was found and updated.
+    bool setPolygon(MarkerID markerID, LngLat* coordinates, int* counts, int rings);
+
+    // Update the zoom level for all markers; markers are built for one zoom level at a time so when the current zoom
+    // changes, all marker meshes are rebuilt.
+    bool update(int zoom);
+
+    // Remove and destroy all markers.
+    void removeAll();
+
+    // Rebuild all markers.
+    void rebuildAll();
+
+    const std::vector<std::unique_ptr<Marker>>& markers() const;
+
+    const Marker* getMarkerOrNullBySelectionColor(uint32_t selectionColor) const;
+
+private:
+
+    Marker* getMarkerOrNull(MarkerID markerID);
+
+    bool buildStyling(Marker& marker);
+    bool buildGeometry(Marker& marker, int zoom);
+
+    std::unique_ptr<StyleContext> m_styleContext;
+    std::shared_ptr<Scene> m_scene;
+    std::vector<std::unique_ptr<Marker>> m_markers;
+    std::vector<std::string> m_jsFnList;
+    fastmap<std::string, std::unique_ptr<StyleBuilder>> m_styleBuilders;
+    MapProjection* m_mapProjection = nullptr;
+
+    uint32_t m_idCounter = 0;
+    int m_zoom = 0;
+
+};
+
+} // namespace Tangram
diff --git a/core/src/platform.cpp b/core/src/platform.cpp
new file mode 100644 (file)
index 0000000..a3c09b6
--- /dev/null
@@ -0,0 +1,84 @@
+#include "platform.h"
+#include "log.h"
+
+#include <fstream>
+#include <string>
+
+namespace Tangram {
+
+Platform::Platform() : m_continuousRendering(false) {}
+
+Platform::~Platform() {}
+
+void Platform::setContinuousRendering(bool _isContinuous) {
+    m_continuousRendering = _isContinuous;
+}
+
+bool Platform::isContinuousRendering() const {
+    return m_continuousRendering;
+}
+
+std::string Platform::resolveAssetPath(const std::string& path) const {
+    return path;
+};
+
+bool Platform::bytesFromFileSystem(const char* _path, std::function<char*(size_t)> _allocator) const {
+    std::ifstream resource(_path, std::ifstream::ate | std::ifstream::binary);
+
+    if(!resource.is_open()) {
+        LOGW("Failed to read file at path: %s", _path);
+        return false;
+    }
+
+    size_t size = resource.tellg();
+    char* cdata = _allocator(size);
+
+    resource.seekg(std::ifstream::beg);
+    resource.read(cdata, size);
+    resource.close();
+
+    return true;
+}
+
+std::string Platform::stringFromFile(const char* _path) const {
+    std::string out;
+    if (!_path || strlen(_path) == 0) { return out; }
+
+    std::string data;
+
+    auto allocator = [&](size_t size) {
+        data.resize(size);
+        return &data[0];
+    };
+
+    bytesFromFileSystem(_path, allocator);
+
+    return data;
+}
+
+std::vector<char> Platform::bytesFromFile(const char* _path) const {
+    if (!_path || strlen(_path) == 0) { return {}; }
+
+    std::vector<char> data;
+
+    auto allocator = [&](size_t size) {
+        data.resize(size);
+        return data.data();
+    };
+
+    bytesFromFileSystem(_path, allocator);
+
+    return data;
+}
+
+std::vector<char> Platform::systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const {
+    // No-op by default
+    return {};
+}
+
+std::vector<FontSourceHandle> Platform::systemFontFallbacksHandle() const {
+    // No-op by default
+    return {};
+}
+
+} // namespace Tangram
diff --git a/core/src/scene/ambientLight.cpp b/core/src/scene/ambientLight.cpp
new file mode 100644 (file)
index 0000000..3b133e7
--- /dev/null
@@ -0,0 +1,56 @@
+#include "scene/ambientLight.h"
+
+#include "gl/shaderProgram.h"
+#include "ambientLight_glsl.h"
+
+#include "glm/gtx/string_cast.hpp"
+
+namespace Tangram {
+
+std::string AmbientLight::s_typeName = "AmbientLight";
+
+AmbientLight::AmbientLight(const std::string& _name, bool _dynamic) :
+    Light(_name, _dynamic) {
+
+    m_type = LightType::ambient;
+
+}
+
+AmbientLight::~AmbientLight() {}
+
+std::unique_ptr<LightUniforms> AmbientLight::getUniforms() {
+
+    if (!m_dynamic) { return nullptr; }
+
+    return std::make_unique<LightUniforms>(getUniformName());
+}
+
+void AmbientLight::setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                                LightUniforms& _uniforms) {
+    Light::setupProgram(rs, _view, _shader, _uniforms);
+}
+
+std::string AmbientLight::getClassBlock() {
+    return SHADER_SOURCE(ambientLight_glsl);
+}
+
+std::string AmbientLight::getInstanceDefinesBlock() {
+    //  Ambient lights don't have defines.... yet.
+    return "\n";
+}
+
+std::string AmbientLight::getInstanceAssignBlock() {
+    std::string block = Light::getInstanceAssignBlock();
+    if (!m_dynamic) {
+        block += ")";
+    }
+    return block;
+}
+
+const std::string& AmbientLight::getTypeName() {
+
+    return s_typeName;
+
+}
+
+}
diff --git a/core/src/scene/ambientLight.h b/core/src/scene/ambientLight.h
new file mode 100644 (file)
index 0000000..53d5b95
--- /dev/null
@@ -0,0 +1,32 @@
+#pragma once
+
+#include "scene/light.h"
+
+namespace Tangram {
+
+class AmbientLight : public Light {
+public:
+
+    AmbientLight(const std::string& _name, bool _dynamic = false);
+    virtual ~AmbientLight();
+
+    virtual void setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms) override;
+
+    std::unique_ptr<LightUniforms> getUniforms() override;
+
+protected:
+
+    /*  GLSL block code with structs and need functions for this light type */
+    virtual std::string getClassBlock() override;
+    virtual std::string getInstanceDefinesBlock() override;
+    virtual std::string getInstanceAssignBlock() override;
+    virtual const std::string& getTypeName() override;
+
+private:
+
+    static std::string s_typeName;
+
+};
+
+}
diff --git a/core/src/scene/asset.cpp b/core/src/scene/asset.cpp
new file mode 100644 (file)
index 0000000..a7b55c6
--- /dev/null
@@ -0,0 +1,185 @@
+#include "scene/asset.h"
+#include "platform.h"
+#include "log.h"
+
+// Define MINIZ_NO_ZLIB_APIS to remove all ZLIB-style compression/decompression API's.
+#define MINIZ_NO_ZLIB_APIS
+// Define MINIZ_NO_ZLIB_COMPATIBLE_NAME to disable zlib names, to prevent conflicts against stock zlib.
+#define MINIZ_NO_ZLIB_COMPATIBLE_NAMES
+
+#include <miniz.h>
+
+#include <unordered_map>
+#include <tuple>
+
+namespace Tangram {
+
+struct ZipHandle {
+    ~ZipHandle();
+    std::unique_ptr<mz_zip_archive> archiveHandle;
+    std::unordered_map<std::string, std::pair<unsigned int, size_t>> fileInfo;
+
+    // Path to the zip bundle (helps in resolving zip resource path)
+    std::string bundlePath = "";
+    std::vector<char> data;
+};
+
+ZipHandle::~ZipHandle() {
+    if (archiveHandle) {
+        mz_zip_reader_end(archiveHandle.get());
+    }
+}
+
+
+/* Asset Class Implementation */
+Asset::Asset(std::string name) : m_name(name) {}
+
+std::vector<char> Asset::readBytesFromAsset(const std::shared_ptr<Platform> &platform) const {
+    return platform->bytesFromFile(m_name.c_str());
+}
+
+std::string Asset::readStringFromAsset(const std::shared_ptr<Platform> &platform) const {
+    return platform->stringFromFile(m_name.c_str());
+}
+
+
+/* ZippedAsset Class Implementation */
+ZippedAsset::ZippedAsset(std::string name, std::shared_ptr<ZipHandle> zipHandle, std::vector<char> zippedData) :
+        Asset(name),
+        m_zipHandle(zipHandle) {
+
+    buildZipHandle(zippedData);
+}
+
+bool ZippedAsset::isBaseSceneYaml(const std::string& filePath) const {
+    auto extLoc = filePath.find(".yaml");
+    if (extLoc == std::string::npos) { return false; }
+
+    auto slashLoc = filePath.find("/");
+    if (slashLoc != std::string::npos) { return false; }
+    return true;
+}
+
+void ZippedAsset::buildZipHandle(std::vector<char>& zipData) {
+
+    if (zipData.empty()) { return; }
+
+    m_zipHandle = std::make_shared<ZipHandle>();
+    m_zipHandle->archiveHandle.reset(new mz_zip_archive());
+    m_zipHandle->data.swap(zipData);
+
+    mz_zip_archive* zip = m_zipHandle->archiveHandle.get();
+    memset(zip, 0, sizeof(mz_zip_archive));
+    if (!mz_zip_reader_init_mem(zip, m_zipHandle->data.data(), m_zipHandle->data.size(), 0)) {
+        LOGE("ZippedAssetPackage: Could not open archive: %s", m_name.c_str());
+        m_zipHandle.reset();
+        return;
+    }
+
+    auto lastPathSegment = m_name.rfind('/');
+    m_zipHandle->bundlePath = (lastPathSegment == std::string::npos) ? "" : m_name.substr(0, lastPathSegment+1);
+
+    /* Instead of using mz_zip_reader_locate_file, maintaining a map of file name to index,
+     * for performance reasons.
+     * https://www.ncbi.nlm.nih.gov/IEB/ToolBox/CPP_DOC/lxr/source/src/util/compress/api/miniz/miniz.c
+     */
+    const auto& numFiles = mz_zip_reader_get_num_files(zip);
+    for (unsigned int i = 0; i < numFiles; i++) {
+        mz_zip_archive_file_stat st;
+        if (!mz_zip_reader_file_stat(zip, i, &st)) {
+            LOGE("ZippedAssetPackage: Could not read file stats: %s", st.m_filename);
+            continue;
+        }
+        if (isBaseSceneYaml(st.m_filename)) {
+            m_name = m_zipHandle->bundlePath + st.m_filename;
+        }
+        m_zipHandle->fileInfo[st.m_filename] = std::pair<unsigned int, size_t>(i, st.m_uncomp_size);
+    }
+}
+
+bool ZippedAsset::bytesFromAsset(const std::string& filePath, std::function<char*(size_t)> allocator) const{
+
+    auto pos = filePath.find(m_zipHandle->bundlePath);
+    if (pos != 0) {
+        LOGE("Invalid asset path: %s", m_name.c_str());
+        return false;
+    }
+
+    auto resourcePath = filePath.substr(m_zipHandle->bundlePath.size());
+    if (*resourcePath.begin() == '/') { resourcePath.erase(resourcePath.begin()); }
+
+    if (m_zipHandle->archiveHandle) {
+        mz_zip_archive* zip = m_zipHandle->archiveHandle.get();
+        auto it = m_zipHandle->fileInfo.find(resourcePath);
+
+        if (it != m_zipHandle->fileInfo.end()) {
+            std::size_t elementSize = it->second.second;
+            char* elementData = allocator(elementSize);
+
+            /* read file data directly to memory */
+            if (mz_zip_reader_extract_to_mem(zip, it->second.first, elementData, elementSize, 0)) {
+                if (!elementData) {
+                    LOGE("ZippedAssetPackage::loadAsset: Could not load archive asset: %s", filePath.c_str());
+                    return false;
+                }
+                return true;
+            }
+        }
+    }
+    return false;
+
+}
+
+std::vector<char> ZippedAsset::readBytesFromAsset(const std::shared_ptr<Platform>& platform,
+                                                  const std::string& filePath) const {
+
+    if (!m_zipHandle) { return {}; }
+
+    std::vector<char> fileData;
+
+    auto allocator = [&](size_t size) {
+        fileData.resize(size);
+        return fileData.data();
+    };
+
+    bytesFromAsset(filePath, allocator);
+
+    if (fileData.empty()) {
+        LOGE("Asset \"%s\" read resulted in no data read. Verify the path in the scene.", filePath.c_str());
+    }
+
+    return fileData;
+}
+
+std::vector<char> ZippedAsset::readBytesFromAsset(const std::shared_ptr<Platform> &platform) const {
+    return readBytesFromAsset(platform, m_name);
+}
+
+std::string ZippedAsset::readStringFromAsset(const std::shared_ptr<Platform>& platform,
+                                             const std::string& filePath) const {
+
+    if (!m_zipHandle) { return ""; }
+
+    std::string fileData;
+
+    auto allocator = [&](size_t size) {
+        fileData.resize(size);
+        return &fileData[0];
+    };
+
+    bytesFromAsset(filePath, allocator);
+
+    if (fileData.empty()) {
+        LOGE("Asset \"%s\" read resulted in no data read. Verify the path in the scene.", m_name.c_str());
+    }
+
+    return fileData;
+}
+
+
+std::string ZippedAsset::readStringFromAsset(const std::shared_ptr<Platform> &platform) const {
+    return readStringFromAsset(platform, m_name);
+}
+
+
+}
diff --git a/core/src/scene/asset.h b/core/src/scene/asset.h
new file mode 100644 (file)
index 0000000..eb4b62d
--- /dev/null
@@ -0,0 +1,73 @@
+#pragma once
+
+#include <string>
+#include <vector>
+#include <memory>
+#include <functional>
+
+namespace Tangram {
+
+class Platform;
+struct ZipHandle;
+
+/*
+ * An Asset class representing every asset loaded via the scene file
+ */
+class Asset {
+public:
+    Asset(std::string name);
+
+    const std::string& name() const { return m_name; }
+
+    // Non zipped asset
+    virtual std::shared_ptr<ZipHandle> zipHandle() const { return nullptr; }
+
+    // returns the string from file
+    virtual std::string readStringFromAsset(const std::shared_ptr<Platform>& platform) const;
+
+    // returns the raw bytes from file
+    virtual std::vector<char> readBytesFromAsset(const std::shared_ptr<Platform>& platform) const;
+
+protected:
+    // Name of an asset (resolved path with respect to the parent scene file to which this asset belongs)
+    // Also used to read contents of the asset
+    std::string m_name;
+};
+
+
+/*
+ * A specialized asset representation for assets within a zip bundle
+ */
+class ZippedAsset : public Asset {
+public:
+    ZippedAsset(std::string name, std::shared_ptr<ZipHandle> zipHandle = nullptr, std::vector<char> zippedData = {});
+
+    std::shared_ptr<ZipHandle> zipHandle() const override { return m_zipHandle; }
+
+    // builds zipHandle (if not already built, from raw Data)
+    void buildZipHandle(std::vector<char>& zippedData);
+
+    // returns the string from resource from asset's path (relative to zip bundle path) in zip archive
+    std::string readStringFromAsset(const std::shared_ptr<Platform>& platform) const override;
+
+    // returns the raw bytes from resource from asset's path (relative to zip bundle path) in zip archive
+    std::vector<char> readBytesFromAsset(const std::shared_ptr<Platform>& platform) const override;
+
+    // returns the string from file bundled within the zip archive
+    std::string readStringFromAsset(const std::shared_ptr<Platform>& platform, const std::string& filename) const;
+
+    // returns the bytes from file bundled within the zip archive
+    std::vector<char> readBytesFromAsset(const std::shared_ptr<Platform>& platform, const std::string& filename) const;
+
+private:
+    std::shared_ptr<ZipHandle> m_zipHandle = nullptr;
+
+    // Check if the filePath is the base scene yaml
+    bool isBaseSceneYaml(const std::string& filePath) const ;
+
+    // read raw bytes from a bundled file
+    bool bytesFromAsset(const std::string& filename, std::function<char*(size_t)> _allocator) const ;
+
+};
+
+}
diff --git a/core/src/scene/dataLayer.cpp b/core/src/scene/dataLayer.cpp
new file mode 100644 (file)
index 0000000..07b3ff9
--- /dev/null
@@ -0,0 +1,10 @@
+#include "scene/dataLayer.h"
+
+namespace Tangram {
+
+DataLayer::DataLayer(SceneLayer _layer, const std::string& _source, const std::vector<std::string>& _collections) :
+    SceneLayer(std::move(_layer)),
+    m_source(_source),
+    m_collections(_collections) {}
+
+}
diff --git a/core/src/scene/dataLayer.h b/core/src/scene/dataLayer.h
new file mode 100644 (file)
index 0000000..0c2a7d0
--- /dev/null
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "scene/sceneLayer.h"
+
+#include <string>
+
+namespace Tangram {
+
+// DataLayer represents a top-level layer in the stylesheet, distinct from
+// SceneLayer by its association with a collection within a TileSource
+class DataLayer : public SceneLayer {
+
+    std::string m_source;
+    std::vector<std::string> m_collections;
+
+public:
+
+    DataLayer(SceneLayer _layer, const std::string& _source, const std::vector<std::string>& _collections);
+
+    const auto& source() const { return m_source; }
+    const auto& collections() const { return m_collections; }
+
+};
+
+}
diff --git a/core/src/scene/directionalLight.cpp b/core/src/scene/directionalLight.cpp
new file mode 100644 (file)
index 0000000..8f4569a
--- /dev/null
@@ -0,0 +1,70 @@
+#include "scene/directionalLight.h"
+
+#include "gl/shaderProgram.h"
+#include "directionalLight_glsl.h"
+#include "platform.h"
+#include "util/floatFormatter.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+std::string DirectionalLight::s_typeName = "DirectionalLight";
+
+DirectionalLight::DirectionalLight(const std::string& _name, bool _dynamic) :
+    Light(_name, _dynamic),
+    m_direction(1.0,0.0,0.0) {
+
+    m_type = LightType::directional;
+}
+
+DirectionalLight::~DirectionalLight() {}
+
+void DirectionalLight::setDirection(const glm::vec3 &_dir) {
+    m_direction = glm::normalize(_dir);
+}
+
+std::unique_ptr<LightUniforms> DirectionalLight::getUniforms() {
+
+    if (!m_dynamic) { return nullptr; }
+
+    return std::make_unique<Uniforms>(getUniformName());
+}
+
+void DirectionalLight::setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                                    LightUniforms& _uniforms) {
+
+    glm::vec3 direction = m_direction;
+    if (m_origin == LightOrigin::world) {
+        direction = _view.getNormalMatrix() * direction;
+    }
+
+    Light::setupProgram(rs, _view, _shader, _uniforms);
+
+    auto& u = static_cast<DirectionalLight::Uniforms&>(_uniforms);
+    _shader.setUniformf(rs, u.direction, direction);
+}
+
+std::string DirectionalLight::getClassBlock() {
+    return SHADER_SOURCE(directionalLight_glsl);
+}
+
+std::string DirectionalLight::getInstanceDefinesBlock() {
+    // Directional lights don't have defines.... yet.
+    return "\n";
+}
+
+std::string DirectionalLight::getInstanceAssignBlock() {
+    std::string block = Light::getInstanceAssignBlock();
+    if (!m_dynamic) {
+        block += ", " + ff::to_string(m_direction) + ")";
+    }
+    return block;
+}
+
+const std::string& DirectionalLight::getTypeName() {
+
+    return s_typeName;
+
+}
+
+}
diff --git a/core/src/scene/directionalLight.h b/core/src/scene/directionalLight.h
new file mode 100644 (file)
index 0000000..30557c5
--- /dev/null
@@ -0,0 +1,50 @@
+#pragma once
+
+#include "scene/light.h"
+
+#include "glm/vec3.hpp"
+
+namespace Tangram {
+
+
+class DirectionalLight : public Light {
+public:
+
+    DirectionalLight(const std::string& _name, bool _dynamic = false);
+    virtual ~DirectionalLight();
+
+    /* Set the direction of the light */
+    virtual void setDirection(const glm::vec3& _dir);
+
+    virtual void setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms) override;
+
+    struct Uniforms : public LightUniforms {
+
+        Uniforms(const std::string& _name)
+            : LightUniforms(_name),
+              direction(_name+".direction") {}
+
+        UniformLocation direction;
+    };
+
+
+    std::unique_ptr<LightUniforms> getUniforms() override;
+
+protected:
+
+    /*  GLSL block code with structs and need functions for this light type */
+    virtual std::string getClassBlock() override;
+    virtual std::string getInstanceDefinesBlock() override;
+    virtual std::string getInstanceAssignBlock() override;
+    virtual const std::string& getTypeName() override;
+
+    glm::vec3 m_direction;
+
+private:
+
+    static std::string s_typeName;
+
+};
+
+}
diff --git a/core/src/scene/drawRule.cpp b/core/src/scene/drawRule.cpp
new file mode 100644 (file)
index 0000000..2628c35
--- /dev/null
@@ -0,0 +1,210 @@
+#include "scene/drawRule.h"
+
+#include "drawRuleWarnings.h"
+#include "log.h"
+#include "platform.h"
+#include "scene/scene.h"
+#include "scene/sceneLayer.h"
+#include "scene/stops.h"
+#include "scene/styleContext.h"
+#include "style/style.h"
+#include "tile/tileBuilder.h"
+#include "util/hash.h"
+
+#include <algorithm>
+
+namespace Tangram {
+
+DrawRuleData::DrawRuleData(std::string _name, int _id,
+                           std::vector<StyleParam> _parameters)
+    : parameters(std::move(_parameters)),
+      name(std::move(_name)),
+      id(_id) {}
+
+std::string DrawRuleData::toString() const {
+    std::string str = "{\n";
+    for (auto& p : parameters) {
+         str += " { "
+             + std::to_string(static_cast<int>(p.key))
+             + ", "
+             + p.toString()
+             + " }\n";
+    }
+    str += "}\n";
+
+    return str;
+}
+
+DrawRule::DrawRule(const DrawRuleData& _ruleData, const std::string& _layerName, size_t _layerDepth) :
+    name(&_ruleData.name),
+    id(_ruleData.id) {
+
+    for (const auto& param : _ruleData.parameters) {
+        auto key = static_cast<uint8_t>(param.key);
+        active[key] = true;
+        params[key] = { &param, _layerName.c_str(), _layerDepth };
+    }
+}
+
+void DrawRule::merge(const DrawRuleData& _ruleData, const SceneLayer& _layer) {
+
+    evalConflict(*this, _ruleData, _layer);
+
+    const auto depthNew = _layer.depth();
+    const char* layerNew = _layer.name().c_str();
+
+    for (const auto& paramNew : _ruleData.parameters) {
+
+        auto key = static_cast<uint8_t>(paramNew.key);
+        auto& param = params[key];
+
+        if (!active[key] || depthNew > param.depth ||
+            (depthNew == param.depth && strcmp(layerNew, param.name) > 0)) {
+            param = { &paramNew, layerNew, depthNew };
+            active[key] = true;
+        }
+    }
+}
+
+bool DrawRule::contains(StyleParamKey _key) const {
+    return findParameter(_key) != false;
+}
+
+const StyleParam& DrawRule::findParameter(StyleParamKey _key) const {
+    static const StyleParam NONE;
+
+    uint8_t key = static_cast<uint8_t>(_key);
+    if (!active[key]) { return NONE; }
+    return *params[key].param;
+}
+
+const std::string& DrawRule::getStyleName() const {
+
+    const auto& style = findParameter(StyleParamKey::style);
+
+    if (style) {
+        return style.value.get<std::string>();
+    } else {
+        return *name;
+    }
+}
+
+const char* DrawRule::getLayerName(StyleParamKey _key) const {
+    return params[static_cast<uint8_t>(_key)].name;
+}
+
+size_t DrawRule::getParamSetHash() const {
+    size_t seed = 0;
+    for (size_t i = 0; i < StyleParamKeySize; i++) {
+        if (active[i]) { hash_combine(seed, params[i].name); }
+    }
+    return seed;
+}
+
+void DrawRule::logGetError(StyleParamKey _expectedKey, const StyleParam& _param) const {
+    LOGE("wrong type '%d'for StyleParam '%d'", _param.value.which(), _expectedKey);
+}
+
+bool DrawRuleMergeSet::match(const Feature& _feature, const SceneLayer& _layer, StyleContext& _ctx) {
+
+    _ctx.setFeature(_feature);
+    m_matchedRules.clear();
+    m_queuedLayers.clear();
+
+    // If uber layer is marked not visible return immediately
+    if (!_layer.enabled()) {
+        return false;
+    }
+
+    // If the first filter doesn't match, return immediately
+    if (!_layer.filter().eval(_feature, _ctx)) { return false; }
+
+    m_queuedLayers.push_back(&_layer);
+
+    // Iterate depth-first over the layer hierarchy
+    while (!m_queuedLayers.empty()) {
+
+        // Pop a layer off the top of the stack
+        const auto& layer = *m_queuedLayers.back();
+        m_queuedLayers.pop_back();
+
+        // Merge rules from layer into accumulated set
+        mergeRules(layer);
+
+        // Push each of the layer's matching sublayers onto the stack
+        for (const auto& sublayer : layer.sublayers()) {
+            // Skip matching this sublayer if marked not visible
+            if (!sublayer.enabled()) {
+                continue;
+            }
+
+            if (sublayer.filter().eval(_feature, _ctx)) {
+                m_queuedLayers.push_back(&sublayer);
+            }
+        }
+    }
+
+    return true;
+}
+
+bool DrawRuleMergeSet::evaluateRuleForContext(DrawRule& rule, StyleContext& ctx) {
+
+    bool visible;
+    if (rule.get(StyleParamKey::visible, visible) && !visible) {
+        return false;
+    }
+
+    bool valid = true;
+    for (size_t i = 0; i < StyleParamKeySize; ++i) {
+
+        if (!rule.active[i]) {
+            rule.params[i].param = nullptr;
+            continue;
+        }
+
+        auto*& param = rule.params[i].param;
+
+        // Evaluate JS functions and Stops
+        if (param->function >= 0) {
+
+            // Copy param into 'evaluated' and point param to the evaluated StyleParam.
+            m_evaluated[i] = *param;
+            param = &m_evaluated[i];
+
+            if (!ctx.evalStyle(param->function, param->key, m_evaluated[i].value)) {
+                if (StyleParam::isRequired(param->key)) {
+                    valid = false;
+                    break;
+                } else {
+                    rule.active[i] = false;
+                }
+            }
+        } else if (param->stops) {
+            m_evaluated[i] = *param;
+            param = &m_evaluated[i];
+
+            Stops::eval(*param->stops, param->key, ctx.getKeywordZoom(), m_evaluated[i].value);
+        }
+    }
+
+    return valid;
+}
+
+void DrawRuleMergeSet::mergeRules(const SceneLayer& _layer) {
+
+    size_t pos, end = m_matchedRules.size();
+
+    for (const auto& rule : _layer.rules()) {
+        for (pos = 0; pos < end; pos++) {
+            if (m_matchedRules[pos].id == rule.id) { break; }
+        }
+
+        if (pos == end) {
+            m_matchedRules.emplace_back(rule, _layer.name(), _layer.depth());
+        } else {
+            m_matchedRules[pos].merge(rule, _layer);
+        }
+    }
+}
+
+}
diff --git a/core/src/scene/drawRule.h b/core/src/scene/drawRule.h
new file mode 100644 (file)
index 0000000..71c1b34
--- /dev/null
@@ -0,0 +1,142 @@
+#pragma once
+
+#include "scene/styleParam.h"
+
+#include <bitset>
+#include <vector>
+#include <set>
+
+namespace Tangram {
+
+struct Feature;
+class TileBuilder;
+class Scene;
+class SceneLayer;
+class StyleContext;
+class FeatureSelection;
+
+/*
+ * A draw rule is a named collection of style parameters. When a draw rule is found to match a
+ * feature, the feature's geometry is built into drawable buffers using a style determined from the
+ * rule with the parameters contained in the rule.
+ *
+ * Draw rules are represented in two ways: by a DrawRuleData and by a DrawRule.
+ *
+ * DrawRuleData represents a named set of style parameters *as they are written in the layer*.
+ * This is different from the set of style parameters that is applied to a feature after matching
+ * and merging; the merged set of style parameters is represented by DrawRule.
+ *
+ * DrawRule is a temporary object and only contains style parameters that are defined in at least
+ * one DrawRuleData, so it can safely reference any needed parameters by pointers to the original.
+ * However, style parameters that need to be evaluated per-feature must also have space to store
+ * their evaluated values.
+ *
+ * When matching and merging draw rules, the name of the rule is frequently copied and compared. To
+ * make this process faster, each string used as the name of a draw rule is assigned to an integer
+ * index within the scene object and then stored as the id of a draw rule.
+ */
+
+struct DrawRuleData {
+
+    // https://github.com/tangrams/tangram-docs/blob/gh-pages/pages/draw.md#style-parameters
+    std::vector<StyleParam> parameters;
+
+    // draw-rule name (and assigned id)
+    // https://github.com/tangrams/tangram-docs/blob/gh-pages/pages/draw.md#draw-rule
+    std::string name;
+    int id;
+
+    DrawRuleData(std::string _name, int _id, std::vector<StyleParam> _parameters);
+
+    std::string toString() const;
+
+};
+
+struct DrawRule {
+
+    // Map of StypeParamKey => StyleParam pointer
+    // of the matched SceneLayer or the evaluated
+    // Function/Stops in DrawRuleMergeset.
+    struct {
+        const StyleParam* param;
+        // SceneLayer name and depth
+        const char* name;
+        size_t depth;
+
+    } params[StyleParamKeySize];
+
+    // A mask to indicate which parameters are set.
+    // 'active' MUST be checked before accessing 'params'
+    // This is cheaper to zero out 4 byte than
+    // 480 (on 32bit arch) or 980 byte for params array.
+    std::bitset<StyleParamKeySize> active = { 0 };
+
+
+    // draw-style name and id
+    const std::string* name = nullptr;
+    int id;
+    bool isOutlineOnly = false;
+    uint32_t selectionColor = 0;
+    FeatureSelection* featureSelection = nullptr;
+
+    DrawRule(const DrawRuleData& _ruleData, const std::string& _layerName, size_t _layerDepth);
+
+    void merge(const DrawRuleData& _ruleData, const SceneLayer& _layer);
+
+    bool isJSFunction(StyleParamKey _key) const;
+
+    bool contains(StyleParamKey _key) const;
+
+    const std::string& getStyleName() const;
+
+    const char* getLayerName(StyleParamKey _key) const;
+
+    size_t getParamSetHash() const;
+
+    const StyleParam& findParameter(StyleParamKey _key) const;
+
+    template<typename T>
+    bool get(StyleParamKey _key, T& _value) const {
+        if (auto& param = findParameter(_key)) {
+            return StyleParam::Value::visit(param.value, StyleParam::visitor<T>{ _value });
+        }
+        return false;
+    }
+
+    template<typename T>
+    const T* get(StyleParamKey _key) const {
+        if (auto& param = findParameter(_key)) {
+            return StyleParam::Value::visit(param.value, StyleParam::visitor_ptr<T>{});
+        }
+        return nullptr;
+    }
+
+private:
+    void logGetError(StyleParamKey _expectedKey, const StyleParam& _param) const;
+
+};
+
+class DrawRuleMergeSet {
+
+public:
+    bool evaluateRuleForContext(DrawRule& rule, StyleContext& ctx);
+
+    // internal
+    bool match(const Feature& _feature, const SceneLayer& _layer, StyleContext& _ctx);
+
+    // internal
+    void mergeRules(const SceneLayer& _layer);
+
+    auto& matchedRules() { return m_matchedRules; }
+
+private:
+    // Reusable containers 'matchedRules' and 'queuedLayers'
+    std::vector<DrawRule> m_matchedRules;
+    std::vector<const SceneLayer*> m_queuedLayers;
+
+    // Container for dynamically-evaluated parameters
+    StyleParam m_evaluated[StyleParamKeySize];
+
+};
+
+}
diff --git a/core/src/scene/drawRuleWarnings.h b/core/src/scene/drawRuleWarnings.h
new file mode 100644 (file)
index 0000000..4141268
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+#if defined(TANGRAM_WARN_ON_RULE_CONFLICT)
+
+#include <mutex>
+#include <set>
+
+namespace Tangram {
+
+static std::set<std::string> log;
+static std::mutex logMutex;
+
+void evalConflict(const DrawRule& rule, const DrawRuleData& data, const SceneLayer& layer) {
+
+    for (const auto& param : data.parameters) {
+
+        auto k = static_cast<uint8_t>(param.key);
+
+        if (rule.depths[k] == layer.depth()) {
+
+            std::lock_guard<std::mutex> lock(logMutex);
+
+            std::string logString = "Draw parameter '" + StyleParam::keyName(param.key) + "' in rule '" +
+                data.name + "' in layer '" + layer.name() + "' conflicts with layer '" + rule.layers[k] + "'";
+
+            if (log.insert(logString).second) {
+                LOGW("%s", logString.c_str());
+            }
+        }
+
+    }
+
+}
+
+}
+
+#else
+
+namespace Tangram {
+
+void evalConflict(const DrawRule& rule, const DrawRuleData& data, const SceneLayer& layer) {}
+
+}
+
+#endif
diff --git a/core/src/scene/filters.cpp b/core/src/scene/filters.cpp
new file mode 100644 (file)
index 0000000..f476d9f
--- /dev/null
@@ -0,0 +1,386 @@
+#include "scene/filters.h"
+
+#include "data/tileData.h"
+#include "platform.h"
+#include "scene/styleContext.h"
+
+#include <cmath>
+
+namespace Tangram {
+
+void Filter::print(int _indent) const {
+
+    switch (data.which()) {
+
+    case Data::type<OperatorAny>::value: {
+        logMsg("%*s any\n", _indent, "");
+        for (const auto& filt : data.get<OperatorAny>().operands) {
+            filt.print(_indent + 2);
+        }
+        break;
+    }
+    case Data::type<OperatorAll>::value: {
+        logMsg("%*s all\n", _indent, "");
+        for (const auto& filt : data.get<OperatorAll>().operands) {
+            filt.print(_indent + 2);
+        }
+        break;
+    }
+    case Data::type<OperatorNone>::value: {
+        logMsg("%*s none\n", _indent, "");
+        for (const auto& filt : data.get<OperatorNone>().operands) {
+            filt.print(_indent + 2);
+        }
+        break;
+    }
+    case Data::type<Existence>::value: {
+        auto& f = data.get<Existence>();
+        logMsg("%*s existence - key:%s\n", _indent, "", f.key.c_str());
+        break;
+    }
+    case Data::type<EqualitySet>::value: {
+        auto& f = data.get<EqualitySet>();
+        if (f.values[0].is<std::string>()) {
+            logMsg("%*s equality set - keyword:%d key:%s val:%s\n", _indent, "",
+                   f.keyword != FilterKeyword::undefined,
+                   f.key.c_str(),
+                   f.values[0].get<std::string>().c_str());
+        }
+        if (f.values[0].is<double>()) {
+            logMsg("%*s equality - keyword:%d key:%s val:%f\n", _indent, "",
+                   f.keyword != FilterKeyword::undefined,
+                   f.key.c_str(),
+                   f.values[0].get<double>());
+        }
+        break;
+    }
+    case Data::type<Equality>::value: {
+        auto& f = data.get<Equality>();
+        if (f.value.is<std::string>()) {
+            logMsg("%*s equality - keyword:%d key:%s val:%s\n", _indent, "",
+                   f.keyword != FilterKeyword::undefined,
+                   f.key.c_str(),
+                   f.value.get<std::string>().c_str());
+        }
+        if (f.value.is<double>()) {
+            logMsg("%*s equality - keyword:%d key:%s val:%f\n", _indent, "",
+                   f.keyword != FilterKeyword::undefined,
+                   f.key.c_str(),
+                   f.value.get<double>());
+        }
+        break;
+    }
+    case Data::type<Range>::value: {
+        auto& f = data.get<Range>();
+        logMsg("%*s range - keyword:%d key:%s min:%f max:%f\n", _indent, "",
+               f.keyword != FilterKeyword::undefined,
+               f.key.c_str(), f.min, f.max);
+        return;
+    }
+    case Data::type<Function>::value: {
+        logMsg("%*s function\n", _indent, "");
+        break;
+    }
+    default:
+        break;
+    }
+
+}
+
+
+int Filter::filterCost() const {
+    // Add some extra penalty for set vs simple filters
+    int sum = 100;
+
+    switch (data.which()) {
+    case Data::type<OperatorAny>::value:
+        for (auto& f : operands()) { sum += f.filterCost(); }
+        return sum;
+
+    case Data::type<OperatorAll>::value:
+        for (auto& f : operands()) { sum += f.filterCost(); }
+        return sum;
+
+    case Data::type<OperatorNone>::value:
+        for (auto& f : operands()) { sum += f.filterCost(); }
+        return sum;
+
+    case Data::type<Existence>::value:
+        // Equality and Range are more specific for increasing
+        // the chance to fail early check them before Existence
+        return 20;
+
+    case Data::type<EqualitySet>::value:
+        return data.get<EqualitySet>().keyword == FilterKeyword::undefined ? 10 : 1;
+
+    case Data::type<Equality>::value:
+        return data.get<Equality>().keyword == FilterKeyword::undefined ? 10 : 1;
+
+    case Data::type<Filter::Range>::value:
+        return data.get<Range>().keyword == FilterKeyword::undefined ? 10 : 1;
+
+    case Data::type<Function>::value:
+        // Most expensive filter should be checked last
+        return 1000;
+    }
+    return 0;
+}
+
+const std::string& Filter::key() const {
+    static const std::string empty = "";
+
+    switch (data.which()) {
+
+    case Data::type<Existence>::value:
+        return data.get<Existence>().key;
+
+    case Data::type<EqualitySet>::value:
+        return data.get<EqualitySet>().key;
+
+    case Data::type<Equality>::value:
+        return data.get<Equality>().key;
+
+    case Data::type<Filter::Range>::value:
+        return data.get<Range>().key;
+
+    default:
+        break;
+    }
+    return empty;
+}
+
+const std::vector<Filter>& Filter::operands() const {
+    static const std::vector<Filter> empty;
+
+    switch (data.which()) {
+    case Data::type<OperatorAny>::value:
+        return data.get<OperatorAny>().operands;
+
+    case Data::type<OperatorAll>::value:
+        return data.get<OperatorAll>().operands;
+
+    case Data::type<OperatorNone>::value:
+        return data.get<OperatorNone>().operands;
+
+    default:
+        break;
+    }
+    return empty;
+}
+
+bool Filter::isOperator() const {
+
+    switch (data.which()) {
+    case Data::type<OperatorAny>::value:
+        return true;
+
+    case Data::type<OperatorAll>::value:
+        return true;
+
+    case Data::type<OperatorNone>::value:
+        return true;
+
+    default:
+        break;
+    }
+    return false;
+}
+
+int compareSetFilter(const Filter& a, const Filter& b) {
+    auto& oa = a.operands();
+    auto& ob = b.operands();
+
+    if (oa.size() != ob.size()) { return oa.size() < ob.size(); }
+
+    if (oa[0].data.is<Filter::Range>() &&
+        ob[0].data.is<Filter::Range>() &&
+        oa[0].key() == ob[0].key()) {
+        // take the one with more restrictive range
+        auto ra = oa[0].data.get<Filter::Range>();
+        auto rb = ob[0].data.get<Filter::Range>();
+
+        if (std::isinf(ra.max) && std::isinf(rb.max)) {
+            return rb.min - ra.min;
+        }
+    }
+
+    return 0;
+}
+
+
+void Filter::sort(std::vector<Filter>& _filters) {
+    std::sort(_filters.begin(), _filters.end(),
+              [](Filter& a, Filter& b) {
+
+                  // Sort simple filters by eval cost
+                  int ma = a.filterCost();
+                  int mb = b.filterCost();
+
+                  if (!a.isOperator() && !b.isOperator()) {
+                      int diff = ma - mb;
+                      if (diff != 0) {
+                          return diff < 0;
+                      }
+
+                      // just for consistent ordering
+                      // (and using > to prefer $zoom over $geom)
+                      return a.key() > b.key();
+                  }
+
+                  // When one is a simple Filter and the other is a operaor
+                  // or both are operators prefer the one with the cheaper
+                  // filter(s).
+                  if (ma != mb) {
+                      return ma < mb;
+                  }
+
+                  return compareSetFilter(a, b) < 0;
+              });
+}
+
+
+struct string_matcher {
+    using result_type = bool;
+    const std::string& str;
+
+    template <typename T>
+    bool operator()(T v) const { return false; }
+    bool operator()(const std::string& v) const {
+        return str == v;
+    }
+};
+
+struct number_matcher {
+    using result_type = bool;
+    double num;
+
+    template <typename T>
+    bool operator()(T v) const { return false; }
+    bool operator()(const double& v) const {
+        if (num == v) { return true; }
+        return std::fabs(num - v) <= std::numeric_limits<double>::epsilon();
+    }
+};
+
+struct match_equal_set {
+    using result_type = bool;
+    const std::vector<Value>& values;
+
+    template <typename T>
+    bool operator()(T) const { return false; }
+
+    bool operator()(const double& num) const {
+        number_matcher m{num};
+        for (const auto& v : values) {
+            if (Value::visit(v, m)) {
+                return true;
+            }
+        }
+        return false;
+    }
+    bool operator()(const std::string& str) const {
+        string_matcher m{str};
+
+        for (const auto& v : values) {
+            if (Value::visit(v, m)) {
+                return true;
+            }
+        }
+        return false;
+    }
+};
+
+struct match_equal {
+    using result_type = bool;
+    const Value& value;
+
+    template <typename T>
+    bool operator()(T) const { return false; }
+
+    bool operator()(const double& num) const {
+        return Value::visit(value, number_matcher{num});
+    }
+    bool operator()(const std::string& str) const {
+        return Value::visit(value, string_matcher{str});
+    }
+};
+
+struct match_range {
+    const Filter::Range& f;
+    double scale;
+
+    bool operator() (const double& num) const {
+        return num >= f.min * scale && num < f.max * scale;
+    }
+    bool operator() (const std::string&) const { return false; }
+    bool operator() (const none_type&) const { return false; }
+};
+
+struct matcher {
+    using result_type = bool;
+
+    matcher(const Feature& feat, StyleContext& ctx) :
+        props(feat.props), ctx(ctx) {}
+
+    const Properties& props;
+    StyleContext& ctx;
+
+    bool eval(const Filter::Data& data) const {
+        return Filter::Data::visit(data, *this);
+    }
+
+    bool operator() (const Filter::OperatorAny& f) const {
+        for (const auto& filt : f.operands) {
+            if (eval(filt.data)) { return true; }
+        }
+        return false;
+    }
+    bool operator() (const Filter::OperatorAll& f) const {
+        for (const auto& filt : f.operands) {
+            if (!eval(filt.data)) { return false; }
+        }
+        return true;
+    }
+    bool operator() (const Filter::OperatorNone& f) const {
+        for (const auto& filt : f.operands) {
+            if (eval(filt.data)) { return false; }
+        }
+        return true;
+    }
+    bool operator() (const Filter::Existence& f) const {
+        return f.exists == props.contains(f.key);
+    }
+    bool operator() (const Filter::EqualitySet& f) const {
+        auto& value = (f.keyword == FilterKeyword::undefined)
+            ? props.get(f.key)
+            : ctx.getKeyword(f.keyword);
+
+        return Value::visit(value, match_equal_set{f.values});
+    }
+    bool operator() (const Filter::Equality& f) const {
+        auto& value = (f.keyword == FilterKeyword::undefined)
+            ? props.get(f.key)
+            : ctx.getKeyword(f.keyword);
+
+        return Value::visit(value, match_equal{f.value});
+    }
+    bool operator() (const Filter::Range& f) const {
+        auto scale = (f.hasPixelArea) ? ctx.getPixelAreaScale() : 1.f;
+        auto& value = (f.keyword == FilterKeyword::undefined)
+            ? props.get(f.key)
+            : ctx.getKeyword(f.keyword);
+        return Value::visit(value, match_range{f, scale});
+    }
+    bool operator() (const Filter::Function& f) const {
+        return ctx.evalFilter(f.id);
+    }
+    bool operator() (const none_type& f) const {
+        return true;
+    }
+};
+
+bool Filter::eval(const Feature& feat, StyleContext& ctx) const {
+    return Data::visit(data, matcher(feat, ctx));
+}
+
+}
diff --git a/core/src/scene/filters.h b/core/src/scene/filters.h
new file mode 100644 (file)
index 0000000..4bcf501
--- /dev/null
@@ -0,0 +1,124 @@
+#pragma once
+
+#include "util/variant.h"
+
+#include <memory>
+#include <vector>
+
+namespace Tangram {
+
+class StyleContext;
+struct Feature;
+
+enum class FilterKeyword : uint8_t {
+    undefined,
+    zoom,
+    geometry,
+};
+
+struct Filter {
+    struct OperatorAll {
+        std::vector<Filter> operands;
+    };
+    struct OperatorAny {
+        std::vector<Filter> operands;
+    };
+    struct OperatorNone {
+        std::vector<Filter> operands;
+    };
+
+    struct EqualitySet {
+        std::string key;
+        std::vector<Value> values;
+        FilterKeyword keyword;
+    };
+    struct Equality {
+        std::string key;
+        Value value;
+        FilterKeyword keyword;
+    };
+    struct Range {
+        std::string key;
+        float min;
+        float max;
+        FilterKeyword keyword;
+        bool hasPixelArea;
+    };
+    struct Existence {
+        std::string key;
+        bool exists;
+    };
+    struct Function {
+        uint32_t id;
+    };
+    using Data = variant<none_type,
+                         OperatorAll,
+                         OperatorNone,
+                         OperatorAny,
+                         EqualitySet,
+                         Equality,
+                         Range,
+                         Existence,
+                         Function>;
+    Data data;
+
+    Filter() : data(none_type{}) {}
+    Filter(Data _data) : data(std::move(_data)) {}
+
+    bool eval(const Feature& feat, StyleContext& ctx) const;
+
+    // Create an 'any', 'all', or 'none' filter
+    inline static Filter MatchAny(std::vector<Filter> filters) {
+        sort(filters);
+        return { OperatorAny{ std::move(filters) }};
+    }
+    inline static Filter MatchAll(std::vector<Filter> filters) {
+        sort(filters);
+        return { OperatorAll{ std::move(filters) }};
+    }
+    inline static Filter MatchNone(std::vector<Filter> filters) {
+        sort(filters);
+        return { OperatorNone{ std::move(filters) }};
+    }
+    // Create an 'equality' filter
+    inline static Filter MatchEquality(const std::string& k, const std::vector<Value>& vals) {
+        if (vals.size() == 1) {
+            return { Equality{ k, vals[0], keywordType(k) }};
+        } else {
+            return { EqualitySet{ k, vals, keywordType(k) }};
+        }
+    }
+    // Create a 'range' filter
+    inline static Filter MatchRange(const std::string& k, float min, float max, bool sqA) {
+        return { Range{ k, min, max, keywordType(k), sqA }};
+    }
+    // Create an 'existence' filter
+    inline static Filter MatchExistence(const std::string& k, bool ex) {
+        return { Existence{ k, ex }};
+    }
+    // Create an 'function' filter with reference to Scene function id
+    inline static Filter MatchFunction(uint32_t id) {
+        return { Function{ id }};
+    }
+
+    static FilterKeyword keywordType(const std::string& _key) {
+        if (_key == "$geometry") {
+            return FilterKeyword::geometry;
+        } else if (_key == "$zoom") {
+            return  FilterKeyword::zoom;
+        }
+        return  FilterKeyword::undefined;
+    }
+
+    /* Public for testing */
+    static void sort(std::vector<Filter>& filters);
+    void print(int _indent = 0) const;
+    int filterCost() const;
+    bool isOperator() const;
+    const std::string& key() const;
+    const std::vector<Filter>& operands() const;
+
+    bool isValid() const { return !data.is<none_type>(); }
+    operator bool() const { return isValid(); }
+};
+}
diff --git a/core/src/scene/importer.cpp b/core/src/scene/importer.cpp
new file mode 100644 (file)
index 0000000..d4112da
--- /dev/null
@@ -0,0 +1,383 @@
+#include "scene/importer.h"
+
+#include "log.h"
+#include "platform.h"
+#include "scene/sceneLoader.h"
+
+#include "yaml-cpp/yaml.h"
+#include <cassert>
+
+using YAML::Node;
+using YAML::NodeType;
+
+namespace Tangram {
+
+std::atomic_uint Importer::progressCounter(0);
+
+Node Importer::applySceneImports(const std::shared_ptr<Platform>& platform,
+        std::shared_ptr<Scene>& scene) {
+
+    const Url& scenePath = scene->path();
+    const Url& resourceRoot = scene->resourceRoot();
+
+    Url path;
+    Url rootScenePath = scenePath.resolved(resourceRoot);
+
+    // Asset fills the m_path of the yaml asset with the yaml file in the zip bundle
+    scene->createSceneAsset(platform, rootScenePath, Url(""), Url(""));
+
+    m_sceneQueue.push_back(rootScenePath);
+
+
+    while (true) {
+        {
+            std::unique_lock<std::mutex> lock(sceneMutex);
+
+            m_condition.wait(lock, [&, this]{
+                    if (m_sceneQueue.empty()) {
+                        // Not busy at all?
+                        if (progressCounter == 0) { return true; }
+                    } else {
+                        // More work and not completely busy?
+                        if (progressCounter < MAX_SCENE_DOWNLOAD) { return true; }
+                    }
+
+                    return false;
+                });
+
+
+            if (m_sceneQueue.empty()) {
+                if (progressCounter == 0) {
+                    break;
+                }
+                continue;
+            }
+
+            path = m_sceneQueue.back();
+            m_sceneQueue.pop_back();
+
+            if (m_scenes.find(path) != m_scenes.end()) { continue; }
+        }
+
+        bool isZipped = (Url::getPathExtension(path.path()) == "zip");
+        auto& asset = scene->assets()[path.string()];
+        // An asset at this path must have been created by now.
+        assert(asset);
+
+        if (path.hasHttpScheme() && !asset->zipHandle()) {
+            progressCounter++;
+            platform->startUrlRequest(path.string(), [&, isZipped, path](std::vector<char>&& rawData) {
+                if (!rawData.empty()) {
+                    std::unique_lock<std::mutex> lock(sceneMutex);
+                    auto& asset = scene->assets()[path.string()];
+                    if (isZipped) {
+                        auto& zippedAsset = static_cast<ZippedAsset&>(*asset);
+                        zippedAsset.buildZipHandle(rawData);
+                        processScene(platform, scene, path, asset->readStringFromAsset(platform));
+                    } else {
+                        processScene(platform, scene, path, std::string(rawData.data(), rawData.size()));
+                    }
+                }
+                progressCounter--;
+                m_condition.notify_all();
+            });
+        } else {
+            std::unique_lock<std::mutex> lock(sceneMutex);
+            processScene(platform, scene, path, getSceneString(platform, path, asset));
+        }
+    }
+
+    Node root = Node();
+
+    LOGD("Processing scene import Stack:");
+    std::vector<Url> sceneStack;
+    importScenesRecursive(platform, scene, root, rootScenePath, sceneStack);
+
+    return root;
+}
+
+void Importer::processScene(const std::shared_ptr<Platform>& platform, std::shared_ptr<Scene>& scene,
+        const Url& scenePath, const std::string &sceneString) {
+
+    LOGD("Process: '%s'", scenePath.string().c_str());
+
+    // Don't load imports twice
+    if (m_scenes.find(scenePath) != m_scenes.end()) {
+        return;
+    }
+
+    try {
+        auto sceneNode = YAML::Load(sceneString);
+
+        m_scenes[scenePath] = sceneNode;
+
+        for (const auto& import : getResolvedImportUrls(platform, scene, sceneNode, scenePath)) {
+            m_sceneQueue.push_back(import);
+            m_condition.notify_all();
+        }
+    } catch (YAML::ParserException e) {
+        LOGE("Parsing scene config '%s'", e.what());
+    }
+}
+
+bool nodeIsPotentialUrl(const Node& node) {
+    // Check that the node is scalar and not null.
+    if (!node || !node.IsScalar()) { return false; }
+
+    // Check that the node does not contain a 'global' reference.
+    if (node.Scalar().compare(0, 7, "global.") == 0) { return false; }
+
+    return true;
+}
+
+bool nodeIsTextureUrl(const Node& node, const Node& textures) {
+
+    if (!nodeIsPotentialUrl(node)) { return false; }
+
+    // Check that the node is not a number or a boolean.
+    bool booleanValue = false;
+    double numberValue = 0.;
+    if (YAML::convert<bool>::decode(node, booleanValue)) { return false; }
+    if (YAML::convert<double>::decode(node, numberValue)) { return false; }
+
+    // Check that the node does not name a scene texture.
+    if (textures[node.Scalar()]) { return false; }
+
+    return true;
+}
+
+void Importer::resolveSceneUrls(const std::shared_ptr<Platform>& platform, Scene& scene, Node& root, const Url& base) {
+
+    // Resolve global texture URLs.
+    std::string relativeUrl = "";
+
+    Node textures = root["textures"];
+
+    if (textures) {
+        for (auto texture : textures) {
+            if (Node textureUrlNode = texture.second["url"]) {
+                if (nodeIsPotentialUrl(textureUrlNode)) {
+                    relativeUrl = textureUrlNode.Scalar();
+                    textureUrlNode = Url(textureUrlNode.Scalar()).resolved(base).string();
+                    scene.createSceneAsset(platform, textureUrlNode.Scalar(), relativeUrl, base);
+                }
+            }
+        }
+    }
+
+    // Resolve inline texture URLs.
+
+    if (Node styles = root["styles"]) {
+
+        for (auto entry : styles) {
+
+            Node style = entry.second;
+            if (!style.IsMap()) { continue; }
+
+            //style->texture
+            if (Node texture = style["texture"]) {
+                if (nodeIsTextureUrl(texture, textures)) {
+                    relativeUrl = texture.Scalar();
+                    texture = Url(texture.Scalar()).resolved(base).string();
+                    scene.createSceneAsset(platform, texture.Scalar(), relativeUrl, base);
+                }
+            }
+
+            //style->material->texture
+            if (Node material = style["material"]) {
+                if (!material.IsMap()) { continue; }
+                for (auto& prop : {"emission", "ambient", "diffuse", "specular", "normal"}) {
+                    if (Node propNode = material[prop]) {
+                        if (!propNode.IsMap()) { continue; }
+                        if (Node matTexture = propNode["texture"]) {
+                            if (nodeIsTextureUrl(matTexture, textures)) {
+                                relativeUrl = matTexture.Scalar();
+                                matTexture = Url(matTexture.Scalar()).resolved(base).string();
+                                scene.createSceneAsset(platform, matTexture.Scalar(), relativeUrl, base);
+                            }
+                        }
+                    }
+                }
+            }
+
+            //style->shader->uniforms->texture
+            if (Node shaders = style["shaders"]) {
+                if (!shaders.IsMap()) { continue; }
+                if (Node uniforms = shaders["uniforms"]) {
+                    for (auto uniformEntry : uniforms) {
+                        Node uniformValue = uniformEntry.second;
+                        if (nodeIsTextureUrl(uniformValue, textures)) {
+                            relativeUrl = uniformValue.Scalar();
+                            uniformValue = Url(uniformValue.Scalar()).resolved(base).string();
+                            scene.createSceneAsset(platform, uniformValue.Scalar(), relativeUrl, base);
+                        } else if (uniformValue.IsSequence()) {
+                            for (Node u : uniformValue) {
+                                if (nodeIsTextureUrl(u, textures)) {
+                                    relativeUrl = u.Scalar();
+                                    u = Url(u.Scalar()).resolved(base).string();
+                                    scene.createSceneAsset(platform, u.Scalar(), relativeUrl, base);
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    // Resolve data source URLs.
+
+    // TODO: create assets for sources
+    if (Node sources = root["sources"]) {
+        for (auto source : sources) {
+            if (!source.second.IsMap()) { continue; }
+            if (Node sourceUrl = source.second["url"]) {
+                if (nodeIsPotentialUrl(sourceUrl)) {
+                    auto resolvedUrl = Url(sourceUrl.Scalar()).resolved(base);
+                    sourceUrl = (resolvedUrl.isAbsolute()) ?
+                            resolvedUrl.string() : platform->resolveAssetPath(resolvedUrl.string());
+                }
+            }
+        }
+    }
+
+    // Resolve font URLs.
+
+    if (Node fonts = root["fonts"]) {
+        if (fonts.IsMap()) {
+            for (const auto& font : fonts) {
+                if (font.second.IsMap()) {
+                    auto urlNode = font.second["url"];
+                    if (nodeIsPotentialUrl(urlNode)) {
+                        relativeUrl = urlNode.Scalar();
+                        urlNode = Url(urlNode.Scalar()).resolved(base).string();
+                        scene.createSceneAsset(platform, urlNode.Scalar(), relativeUrl, base);
+                    }
+                } else if (font.second.IsSequence()) {
+                    for (auto& fontNode : font.second) {
+                        auto urlNode = fontNode["url"];
+                        if (nodeIsPotentialUrl(urlNode)) {
+                            relativeUrl = urlNode.Scalar();
+                            urlNode = Url(urlNode.Scalar()).resolved(base).string();
+                            scene.createSceneAsset(platform, urlNode.Scalar(), relativeUrl, base);
+                        }
+                    }
+                }
+            }
+        }
+    }
+}
+
+std::string Importer::getSceneString(const std::shared_ptr<Platform>& platform,
+        const Url& scenePath, const std::shared_ptr<Asset>& asset) {
+    if (!asset) { return "";}
+
+    return asset->readStringFromAsset(platform);
+}
+
+std::vector<Url> Importer::getResolvedImportUrls(const std::shared_ptr<Platform>& platform,
+        std::shared_ptr<Scene>& scene, const Node& sceneNode, const Url& base) {
+
+    std::vector<Url> scenePaths;
+
+    if (const Node& import = sceneNode["import"]) {
+        if (import.IsScalar()) {
+            auto resolvedUrl = Url(import.Scalar()).resolved(base);
+            scene->createSceneAsset(platform, resolvedUrl, import.Scalar(), base);
+            scenePaths.push_back(resolvedUrl);
+        } else if (import.IsSequence()) {
+            for (const auto& path : import) {
+                if (path.IsScalar()) {
+                    auto resolvedUrl = Url(path.Scalar()).resolved(base);
+                    scene->createSceneAsset(platform, resolvedUrl, path.Scalar(), base);
+                    scenePaths.push_back(resolvedUrl);
+                }
+            }
+        }
+    }
+
+    return scenePaths;
+}
+
+void Importer::importScenesRecursive(const std::shared_ptr<Platform>& platform,
+        std::shared_ptr<Scene>& scene, Node& root, const Url& scenePath, std::vector<Url>& sceneStack) {
+
+    LOGD("Starting importing Scene: %s", scenePath.string().c_str());
+
+    for (const auto& s : sceneStack) {
+        if (scenePath == s) {
+            LOGE("%s will cause a cyclic import. Stopping this scene from being imported",
+                    scenePath.string().c_str());
+            return;
+        }
+    }
+
+    sceneStack.push_back(scenePath);
+
+    auto sceneNode = m_scenes[scenePath];
+
+    if (sceneNode.IsNull()) { return; }
+    if (!sceneNode.IsMap()) { return; }
+
+    auto imports = getResolvedImportUrls(platform, scene, sceneNode, scenePath);
+
+    // Don't want to merge imports, so remove them here.
+    sceneNode.remove("import");
+
+    for (const auto& url : imports) {
+
+        importScenesRecursive(platform, scene, root, url, sceneStack);
+
+    }
+
+    sceneStack.pop_back();
+
+    mergeMapFields(root, sceneNode);
+
+    resolveSceneUrls(platform, *scene, root, scenePath);
+}
+
+void Importer::mergeMapFields(Node& target, const Node& import) {
+
+    for (const auto& entry : import) {
+
+        const auto& key = entry.first.Scalar();
+        const auto& source = entry.second;
+        auto dest = target[key];
+
+        if (!dest) {
+            dest = source;
+            continue;
+        }
+
+        if (dest.Type() != source.Type()) {
+            LOGN("Merging different node types: '%s'\n'%s'\n<==\n'%s'",
+                 key.c_str(), Dump(dest).c_str(), Dump(source).c_str());
+        }
+
+        switch(dest.Type()) {
+            case NodeType::Null:
+            case NodeType::Scalar:
+            case NodeType::Sequence:
+                dest = source;
+                break;
+
+            case NodeType::Map: {
+                auto newTarget = dest;
+                if (source.IsMap()) {
+                    mergeMapFields(newTarget, source);
+                } else {
+                    dest = source;
+                }
+                break;
+            }
+            default:
+                // NodeType::Undefined is handled above by checking (!dest).
+                // All types are handled, so this should never be reached.
+                assert(false);
+                break;
+        }
+    }
+}
+
+}
diff --git a/core/src/scene/importer.h b/core/src/scene/importer.h
new file mode 100644 (file)
index 0000000..7cc1b95
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "util/url.h"
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+#include "yaml-cpp/yaml.h"
+#include "scene/scene.h"
+
+namespace Tangram {
+
+class Platform;
+class Asset;
+
+class Importer {
+
+public:
+
+    using Node = YAML::Node;
+
+    // Loads the main scene with deep merging dependent imported scenes.
+    Node applySceneImports(const std::shared_ptr<Platform>& platform, std::shared_ptr<Scene>& scene);
+
+    void resolveSceneUrls(const std::shared_ptr<Platform>& platform, Scene& scene, Node& root, const Url& base);
+
+// protected for testing purposes, else could be private
+protected:
+    // Overriden in unit testing
+    virtual std::string getSceneString(const std::shared_ptr<Platform>& platform,
+            const Url& scenePath, const std::shared_ptr<Asset>& asset = nullptr);
+
+    void processScene(const std::shared_ptr<Platform>& platform, std::shared_ptr<Scene>& scene,
+            const Url& scenePath, const std::string& sceneString);
+
+    // Get the sequence of scene names that are designated to be imported into the
+    // input scene node by its 'import' fields.
+    std::vector<Url> getResolvedImportUrls(const std::shared_ptr<Platform>& platform,
+            std::shared_ptr<Scene>& scene, const Node& sceneNode, const Url& base);
+
+    // loads all the imported scenes and the master scene and returns a unified YAML root node.
+    void importScenesRecursive(const std::shared_ptr<Platform>& platform, std::shared_ptr<Scene>& scene,
+            Node& root, const Url& scenePath, std::vector<Url>& sceneStack);
+
+    void mergeMapFields(Node& target, const Node& import);
+
+private:
+    // import scene to respective root nodes
+    std::unordered_map<Url, Node> m_scenes;
+
+    std::vector<Url> m_sceneQueue;
+
+    static std::atomic_uint progressCounter;
+    std::mutex sceneMutex;
+    std::condition_variable m_condition;
+
+    const unsigned int MAX_SCENE_DOWNLOAD = 4;
+};
+
+}
diff --git a/core/src/scene/light.cpp b/core/src/scene/light.cpp
new file mode 100644 (file)
index 0000000..101d9a0
--- /dev/null
@@ -0,0 +1,158 @@
+#include "scene/light.h"
+
+#include "gl/shaderProgram.h"
+#include "lights_glsl.h"
+#include "platform.h"
+#include "util/floatFormatter.h"
+
+#include <set>
+#include <sstream>
+
+namespace Tangram {
+
+Light::Light(const std::string& _name, bool _dynamic):
+    m_name(_name),
+    m_ambient(0.0f),
+    m_diffuse(1.0f),
+    m_specular(0.0f),
+    m_type(LightType::ambient),
+    m_origin(LightOrigin::camera),
+    m_dynamic(_dynamic) {
+}
+
+Light::~Light() {
+
+}
+
+void Light::setInstanceName(const std::string &_name) {
+    m_name = _name;
+}
+
+void Light::setAmbientColor(const glm::vec4 _ambient) {
+    m_ambient = _ambient;
+}
+
+void Light::setDiffuseColor(const glm::vec4 _diffuse) {
+    m_diffuse = _diffuse;
+}
+
+void Light::setSpecularColor(const glm::vec4 _specular) {
+    m_specular = _specular;
+}
+
+void Light::setOrigin(LightOrigin origin) {
+    m_dynamic = true;
+    m_origin = origin;
+}
+
+
+void Light::setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                         LightUniforms& _uniforms) {
+    _shader.setUniformf(rs, _uniforms.ambient, m_ambient);
+    _shader.setUniformf(rs, _uniforms.diffuse, m_diffuse);
+    _shader.setUniformf(rs, _uniforms.specular, m_specular);
+}
+
+auto Light::assembleLights(const std::vector<std::unique_ptr<Light>>& _lights) ->
+    std::map<std::string, std::string> {
+
+    // Create strings to contain the assembled lighting source code
+    std::stringstream lighting;
+
+    std::map<std::string, std::string> sourceBlocks;
+
+    std::set<std::string> lightClasses;
+    std::set<std::string> lightDefines;
+    std::set<std::string> lightSetup;
+
+    for (auto& light : _lights) {
+        lightDefines.insert(light->getInstanceDefinesBlock());
+        lightClasses.insert(light->getClassBlock());
+        if (light->isDynamic()) {
+            lightSetup.insert(light->getInstanceName() + " = " + light->getUniformName() + ";");
+        }
+    }
+
+    for (auto& string: lightClasses) {
+        lighting << '\n' << string;
+    }
+
+    std::stringstream definesBlock;
+    for (auto& string: lightDefines) {
+        definesBlock << '\n' << string;
+    }
+    sourceBlocks["defines"] = definesBlock.str();
+
+    std::stringstream setupBlock;
+    for (auto& string: lightSetup) {
+        setupBlock << '\n' << string;
+    }
+    sourceBlocks["setup"] = setupBlock.str();
+
+    for (auto& light : _lights) {
+        lighting << '\n' << light->getInstanceBlock();
+    }
+    // After lights definitions are all added, add the main lighting functions
+    std::string lightingBlock = SHADER_SOURCE(lights_glsl);
+
+    // The main lighting functions each contain a tag where all light instances should be computed;
+    std::stringstream lights;
+    for (auto& light : _lights) {
+        lights << '\n' << light->getInstanceComputeBlock();
+    }
+
+    const std::string tag = "#pragma tangram: lights_to_compute";
+    size_t pos = lightingBlock.find(tag) + tag.length();
+    lightingBlock.insert(pos, lights.str());
+
+    // Place our assembled lighting source code back into the map of "source blocks";
+    // The assembled strings will then be injected into a shader at the "vertex_lighting"
+    // and "fragment_lighting" tags
+    sourceBlocks["lighting"] = lighting.str() + lightingBlock;
+
+    return sourceBlocks;
+}
+
+LightType Light::getType() {
+    return m_type;
+}
+
+std::string Light::getUniformName() {
+       return "u_" + m_name;
+}
+
+std::string Light::getInstanceName() {
+    return m_name;
+}
+
+std::string Light::getInstanceBlock() {
+    std::string block = "";
+    const std::string& typeName = getTypeName();
+    if (m_dynamic) {
+        //  If is dynamic, define the uniform and copy it to the global instance of the light struct
+        block += "uniform " + typeName + " " + getUniformName() + ";\n";
+        block += typeName + " " + getInstanceName() + ";\n";
+    } else {
+        //  If is not dynamic define the global instance of the light struct and fill the variables
+        block += typeName + " " + getInstanceName() + getInstanceAssignBlock() +";\n";
+    }
+    return block;
+}
+
+std::string Light::getInstanceAssignBlock() {
+
+    std::string block = "";
+    const std::string& typeName = getTypeName();
+    if (!m_dynamic) {
+        block += " = " + typeName + "(" + ff::to_string(m_ambient);
+        block += ", " + ff::to_string(m_diffuse);
+        block += ", " + ff::to_string(m_specular);
+    }
+    return block;
+}
+
+std::string Light::getInstanceComputeBlock() {
+    return  "calculateLight(" + getInstanceName() + ", _eyeToPoint, _normal);\n";
+}
+
+}
diff --git a/core/src/scene/light.h b/core/src/scene/light.h
new file mode 100644 (file)
index 0000000..8d390f8
--- /dev/null
@@ -0,0 +1,143 @@
+#pragma once
+
+#include "gl/uniform.h"
+
+#include "glm/vec4.hpp"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class RenderState;
+class ShaderProgram;
+class View;
+
+enum class LightType {
+    ambient,
+    directional,
+    point,
+    spot
+};
+
+enum class LightOrigin {
+    camera,
+    ground,
+    world
+};
+
+static inline std::string lightOriginString(LightOrigin origin) {
+    switch(origin) {
+        case LightOrigin::camera: return "camera";
+        case LightOrigin::ground: return "ground";
+        case LightOrigin::world: return "world";
+        default: return "undefined";
+    }
+}
+
+struct LightUniforms {
+    LightUniforms(const std::string& _name)
+        : ambient(_name+".ambient"),
+          diffuse(_name+".diffuse"),
+          specular(_name+".specular") {}
+
+    virtual ~LightUniforms() {}
+
+    UniformLocation ambient;
+    UniformLocation diffuse;
+    UniformLocation specular;
+};
+
+/*  This is the abstract class that other type of lights can extend from it.
+ *  Another possible aproach could be something like the vertexLayout but this one
+ *  let you define specific methods for subclassed lights.
+ */
+class Light {
+public:
+
+    /* All lights have a name*/
+    Light(const std::string& _name, bool _dynamic = false);
+
+    virtual ~Light();
+
+    /*  This name is used to construct the uniform name to be pass to the shader */
+    virtual void setInstanceName(const std::string &_name);
+
+    /*  Set Ambient Color. Which is constant across the scene */
+    virtual void setAmbientColor(const glm::vec4 _ambient);
+
+    /*  Set Diffuse Color. What we generaly understand for color of a light */
+    virtual void setDiffuseColor(const glm::vec4 _diffuse);
+
+    /*  Set Specular Color. This are the intense reflections of a light. AKA shinny spot */
+    virtual void setSpecularColor(const glm::vec4 _specular);
+
+    /*  Set the origin relative to which this light will be positioned */
+    void setOrigin(LightOrigin origin);
+
+    /*  Get the origin relative to which this light is positioned */
+    LightOrigin getOrigin() const { return m_origin; }
+
+    /*  Get the instances light name defined on the shader */
+    virtual std::string getInstanceName();
+
+    /*  Get the type of light, especially to identify the class and specific methods to it. */
+    virtual LightType getType();
+
+    /*  GLSL line to compute the specific light instance */
+    virtual std::string getInstanceComputeBlock();
+
+    /*
+     * Inject the needed lines of GLSL code on the shader to make this light work
+     * Returns LightUniforms for passing to setupProgram if this light is dynamic
+     */
+    virtual std::unique_ptr<LightUniforms> getUniforms() = 0;
+
+    /*  Pass the uniforms for this particular DYNAMICAL light on the passed shader */
+    virtual void setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms);
+
+    /*  STATIC Function that compose sourceBlocks with Lights on a ProgramShader */
+    static std::map<std::string, std::string>  assembleLights(const std::vector<std::unique_ptr<Light>>& _lights);
+
+    bool isDynamic() const { return m_dynamic; }
+protected:
+
+    /*  Get the uniform name of the DYNAMICAL light */
+    virtual std::string getUniformName();
+
+    /*  Get the struct and function to compute a light */
+    virtual std::string getClassBlock() = 0;
+
+    /*  Get the instances GLSL block where the light is defined inside the shader */
+    virtual std::string getInstanceBlock();
+
+    /*  Get the instances GLSL block where NON DYNAMICAL light values are assigned inside the shader */
+    virtual std::string getInstanceAssignBlock();
+
+    /*  GLSL #defines flags for the instance of this light */
+    virtual std::string getInstanceDefinesBlock() = 0;
+
+    /* Get the string name of the type of this light (as it would be declared in GLSL) */
+    virtual const std::string& getTypeName() = 0;
+
+    /*  The name reference to the uniform on the shader.  */
+    std::string m_name;
+
+    /* Light Colors */
+    glm::vec4 m_ambient;
+    glm::vec4 m_diffuse;
+    glm::vec4 m_specular;
+
+    /*  This is use to identify the type of light after been pull inside a vector of uniq_ptr of this abstract class*/
+    LightType m_type;
+
+    /*  This determines if postion and direction of the light is related to the camera, ground or world */
+    LightOrigin m_origin;
+
+    bool m_dynamic;
+
+};
+
+}
diff --git a/core/src/scene/lights.h b/core/src/scene/lights.h
new file mode 100644 (file)
index 0000000..73aa049
--- /dev/null
@@ -0,0 +1,19 @@
+#pragma once
+
+/* LIGHTS 
+-------------------------------
+This openGL Lights implementation follows from the WebGL version of Tangram 
+( https://github.com/tangrams/tangram/wiki/Lights-Overview )
+
+Lights work together with the Materials to inject different lighting functions 
+into the style shaders.
+*/
+
+/* Abstract Class */
+#include "scene/light.h"
+
+/* Lights Types */
+#include "scene/ambientLight.h"
+#include "scene/directionalLight.h"
+#include "scene/pointLight.h"
+#include "scene/spotLight.h"
diff --git a/core/src/scene/pointLight.cpp b/core/src/scene/pointLight.cpp
new file mode 100644 (file)
index 0000000..2ed265e
--- /dev/null
@@ -0,0 +1,144 @@
+#include "scene/pointLight.h"
+
+#include "gl/shaderProgram.h"
+#include "platform.h"
+#include "pointLight_glsl.h"
+#include "util/floatFormatter.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+std::string PointLight::s_typeName = "PointLight";
+
+PointLight::PointLight(const std::string& _name, bool _dynamic) :
+    Light(_name, _dynamic),
+    m_attenuation(0.0),
+    m_innerRadius(0.0),
+    m_outerRadius(0.0) {
+
+    m_type = LightType::point;
+}
+
+PointLight::~PointLight() {}
+
+void PointLight::setPosition(UnitVec<glm::vec3> pos) {
+    m_position = pos;
+}
+
+void PointLight::setAttenuation(float _att) {
+    m_attenuation = _att;
+}
+
+void PointLight::setRadius(float _outer) {
+    m_innerRadius = 0.0;
+    m_outerRadius = _outer;
+}
+
+void PointLight::setRadius(float _inner, float _outer) {
+    m_innerRadius = _inner;
+    m_outerRadius = _outer;
+}
+
+std::unique_ptr<LightUniforms> PointLight::getUniforms() {
+
+    if (!m_dynamic) { return nullptr; }
+
+    return std::make_unique<Uniforms>(getUniformName());
+}
+
+void PointLight::setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms) {
+    Light::setupProgram(rs, _view, _shader, _uniforms);
+
+    glm::vec4 position = glm::vec4(m_position.value, 0.0);
+
+    if (m_origin == LightOrigin::world) {
+        // For world origin, format is: [longitude, latitude, meters (default) or pixels w/px units]
+        position[2] /= m_position.units[2] == Unit::pixel ? _view.pixelsPerMeter() : 1.0;
+
+        // Move light's world position into camera space
+        glm::dvec2 camSpace = _view.getMapProjection().LonLatToMeters(glm::dvec2(position.x, position.y));
+        position.x = camSpace.x - (_view.getPosition().x + _view.getEye().x);
+        position.y = camSpace.y - (_view.getPosition().y + _view.getEye().y);
+        position.z = position.z - _view.getEye().z;
+
+    } else if (m_origin == LightOrigin::ground || m_origin == LightOrigin::camera) {
+        for (int i = 0; i < 3; ++i) {
+            position[i] /= m_position.units[i] == Unit::pixel ? _view.pixelsPerMeter() : 1.0;
+        }
+
+        if (m_origin == LightOrigin::ground) {
+            // Move light position relative to the eye position in world space
+            position -= glm::vec4(_view.getEye(), 0.0);
+        }
+    }
+
+    if (m_origin == LightOrigin::world || m_origin == LightOrigin::ground) {
+        // Light position is a vector from the camera to the light in world space;
+        // we can transform this vector into camera space the same way we would with normals
+        position = _view.getViewMatrix() * position;
+    }
+
+    auto& u = static_cast<Uniforms&>(_uniforms);
+
+    _shader.setUniformf(rs, u.position, position);
+
+    if (m_attenuation != 0.0) {
+        _shader.setUniformf(rs, u.attenuation, m_attenuation);
+    }
+
+    if (m_innerRadius != 0.0) {
+        _shader.setUniformf(rs, u.innerRadius, m_innerRadius);
+    }
+
+    if (m_outerRadius != 0.0) {
+        _shader.setUniformf(rs, u.outerRadius, m_outerRadius);
+    }
+}
+
+std::string PointLight::getClassBlock() {
+    return SHADER_SOURCE(pointLight_glsl);
+}
+
+std::string PointLight::getInstanceDefinesBlock() {
+    std::string defines = "";
+
+    if (m_attenuation!=0.0) {
+        defines += "#define TANGRAM_POINTLIGHT_ATTENUATION_EXPONENT\n";
+    }
+
+    if (m_innerRadius!=0.0) {
+        defines += "#define TANGRAM_POINTLIGHT_ATTENUATION_INNER_RADIUS\n";
+    }
+
+    if (m_outerRadius!=0.0) {
+        defines += "#define TANGRAM_POINTLIGHT_ATTENUATION_OUTER_RADIUS\n";
+    }
+    return defines;
+}
+
+std::string PointLight::getInstanceAssignBlock() {
+    std::string block = Light::getInstanceAssignBlock();
+    if (!m_dynamic) {
+        block += ", " + ff::to_string(m_position.value);
+        if (m_attenuation!=0.0) {
+            block += ", " + ff::to_string(m_attenuation);
+        }
+        if (m_innerRadius!=0.0) {
+            block += ", " + ff::to_string(m_innerRadius);
+        }
+        if (m_outerRadius!=0.0) {
+            block += ", " + ff::to_string(m_outerRadius);
+        }
+        block += ")";
+    }
+    return block;
+}
+
+const std::string& PointLight::getTypeName() {
+
+    return s_typeName;
+
+}
+
+}
diff --git a/core/src/scene/pointLight.h b/core/src/scene/pointLight.h
new file mode 100644 (file)
index 0000000..0cad179
--- /dev/null
@@ -0,0 +1,65 @@
+#pragma once
+
+#include "scene/light.h"
+#include "scene/styleParam.h"
+
+namespace Tangram {
+
+class PointLight : public Light {
+public:
+
+    PointLight(const std::string& _name, bool _dynamic = false);
+    virtual ~PointLight();
+
+    /*  Set the position relative to the camera */
+    virtual void setPosition(UnitVec<glm::vec3> position);
+
+    /*  Set the constant attenuation */
+    virtual void setAttenuation(float _att);
+
+    /*  Set the constant outer radius or inner/outer radius*/
+    virtual void setRadius(float _outer);
+    virtual void setRadius(float _inner, float _outer);
+
+    virtual void setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms) override;
+
+    struct Uniforms : public LightUniforms {
+        Uniforms(const std::string& _name)
+            : LightUniforms(_name),
+              position(_name+".position"),
+              attenuation(_name+".attenuation"),
+              innerRadius(_name+".innerRadius"),
+              outerRadius(_name+".outerRadius") {}
+
+        UniformLocation position;
+        UniformLocation attenuation;
+        UniformLocation innerRadius;
+        UniformLocation outerRadius;
+    };
+
+    auto getPosition() const -> UnitVec<glm::vec3> { return m_position; }
+
+    std::unique_ptr<LightUniforms> getUniforms() override;
+
+protected:
+
+    /*  GLSL block code with structs and need functions for this light type */
+    virtual std::string getClassBlock() override;
+    virtual std::string getInstanceDefinesBlock() override;
+    virtual std::string getInstanceAssignBlock() override;
+    virtual const std::string& getTypeName() override;
+
+    UnitVec<glm::vec3> m_position;
+
+    float m_attenuation;
+    float m_innerRadius;
+    float m_outerRadius;
+
+private:
+
+    static std::string s_typeName;
+
+};
+
+}
diff --git a/core/src/scene/scene.cpp b/core/src/scene/scene.cpp
new file mode 100644 (file)
index 0000000..1c846bb
--- /dev/null
@@ -0,0 +1,203 @@
+#include "scene/scene.h"
+
+#include "data/tileSource.h"
+#include "gl/shaderProgram.h"
+#include "log.h"
+#include "platform.h"
+#include "scene/dataLayer.h"
+#include "scene/light.h"
+#include "scene/spriteAtlas.h"
+#include "scene/stops.h"
+#include "selection/featureSelection.h"
+#include "style/material.h"
+#include "style/style.h"
+#include "text/fontContext.h"
+#include "util/mapProjection.h"
+#include "util/util.h"
+#include "util/url.h"
+#include "view/view.h"
+
+#include <algorithm>
+#include <atomic>
+#include <regex>
+
+namespace Tangram {
+
+static std::atomic<int32_t> s_serial;
+
+Scene::Scene(std::shared_ptr<const Platform> _platform, const std::string& _path)
+    : id(s_serial++),
+      m_path(_path),
+      m_fontContext(std::make_shared<FontContext>(_platform)),
+      m_featureSelection(std::make_unique<FeatureSelection>()) {
+
+    std::regex r("^(http|https):/");
+    std::smatch match;
+
+    if (std::regex_search(_path, match, r)) {
+        m_resourceRoot = "";
+        m_path = _path;
+    } else {
+
+        auto split = _path.find_last_of("/");
+        if (split == std::string::npos) {
+            m_resourceRoot = "";
+            m_path = _path;
+        } else {
+            m_resourceRoot = _path.substr(0, split + 1);
+            m_path = _path.substr(split + 1);
+        }
+    }
+
+    LOGD("Scene '%s' => '%s' : '%s'", _path.c_str(), m_resourceRoot.c_str(), m_path.c_str());
+
+    m_fontContext->setSceneResourceRoot(m_resourceRoot);
+
+    // For now we only have one projection..
+    // TODO how to share projection with view?
+    m_mapProjection.reset(new MercatorProjection());
+}
+
+Scene::Scene(const Scene& _other)
+    : id(s_serial++),
+      m_featureSelection(std::make_unique<FeatureSelection>()) {
+
+    m_config = _other.m_config;
+    m_fontContext = _other.m_fontContext;
+
+    m_path = _other.m_path;
+    m_resourceRoot = _other.m_resourceRoot;
+
+    m_globalRefs = _other.m_globalRefs;
+
+    m_mapProjection.reset(new MercatorProjection());
+    m_assets = _other.assets();
+}
+
+Scene::~Scene() {}
+
+const Style* Scene::findStyle(const std::string& _name) const {
+
+    for (auto& style : m_styles) {
+        if (style->getName() == _name) { return style.get(); }
+    }
+    return nullptr;
+
+}
+
+Style* Scene::findStyle(const std::string& _name) {
+
+    for (auto& style : m_styles) {
+        if (style->getName() == _name) { return style.get(); }
+    }
+    return nullptr;
+}
+
+int Scene::addIdForName(const std::string& _name) {
+    int id = getIdForName(_name);
+
+    if (id < 0) {
+        m_names.push_back(_name);
+        return m_names.size() - 1;
+    }
+    return id;
+}
+
+int Scene::getIdForName(const std::string& _name) const {
+    auto it = std::find(m_names.begin(), m_names.end(), _name);
+    if (it == m_names.end()) {
+        return -1;
+    }
+    return it - m_names.begin();
+}
+
+int Scene::addJsFunction(const std::string& _function) {
+    for (size_t i = 0; i < m_jsFunctions.size(); i++) {
+        if (m_jsFunctions[i] == _function) { return i; }
+    }
+    m_jsFunctions.push_back(_function);
+    return m_jsFunctions.size()-1;
+}
+
+const Light* Scene::findLight(const std::string &_name) const {
+    for (auto& light : m_lights) {
+        if (light->getInstanceName() == _name) { return light.get(); }
+    }
+    return nullptr;
+}
+
+std::shared_ptr<Texture> Scene::getTexture(const std::string& textureName) const {
+    auto texIt = m_textures.find(textureName);
+    if (texIt == m_textures.end()) {
+        return nullptr;
+    }
+    return texIt->second;
+}
+
+std::shared_ptr<TileSource> Scene::getTileSource(int32_t id) {
+    auto it = std::find_if(m_tileSources.begin(), m_tileSources.end(),
+                           [&](auto& s){ return s->id() == id; });
+    if (it != m_tileSources.end()) {
+        return *it;
+    }
+    return nullptr;
+}
+
+std::shared_ptr<TileSource> Scene::getTileSource(const std::string& name) {
+    auto it = std::find_if(m_tileSources.begin(), m_tileSources.end(),
+                           [&](auto& s){ return s->name() == name; });
+    if (it != m_tileSources.end()) {
+        return *it;
+    }
+    return nullptr;
+}
+
+void Scene::setPixelScale(float _scale) {
+    m_pixelScale = _scale;
+    for (auto& style : m_styles) {
+        style->setPixelScale(_scale);
+    }
+    m_fontContext->setPixelScale(_scale);
+}
+
+void Scene::createSceneAsset(const std::shared_ptr<Platform>& platform, const Url& resolvedUrl,
+                                 const Url& relativeUrl, const Url& base) {
+
+    auto& resolvedStr = resolvedUrl.string();
+    auto& baseStr = base.string();
+    std::shared_ptr<Asset> asset;
+
+    if (m_assets.find(resolvedStr) != m_assets.end()) { return; }
+
+    if ( (Url::getPathExtension(resolvedUrl.path()) == "zip") ){
+        if (relativeUrl.hasHttpScheme() || (resolvedUrl.hasHttpScheme() && base.isEmpty())) {
+            // Data to be fetched later (and zipHandle created) in network callback
+            asset = std::make_shared<ZippedAsset>(resolvedStr);
+
+        } else if (relativeUrl.isAbsolute() || base.isEmpty()) {
+            asset = std::make_shared<ZippedAsset>(resolvedStr, nullptr, platform->bytesFromFile(resolvedStr.c_str()));
+        } else {
+            auto parentAsset = static_cast<ZippedAsset*>(m_assets[baseStr].get());
+            // Parent asset (for base Str) must have been created by now
+            assert(parentAsset);
+            asset = std::make_shared<ZippedAsset>(resolvedStr, nullptr,
+                                                                       parentAsset->readBytesFromAsset(platform, resolvedStr));
+        }
+    } else {
+        const auto& parentAsset = m_assets[baseStr];
+
+        if (relativeUrl.isAbsolute() || (parentAsset && !parentAsset->zipHandle())) {
+            // Make sure to first check for cases when the asset does not belong within a zipBundle
+            asset = std::make_shared<Asset>(resolvedStr);
+        } else if (parentAsset && parentAsset->zipHandle()) {
+            // Asset is in zip bundle
+            asset = std::make_shared<ZippedAsset>(resolvedStr, parentAsset->zipHandle());
+        } else {
+            asset = std::make_shared<Asset>(resolvedStr);
+        }
+    }
+
+    m_assets[resolvedStr] = asset;
+}
+
+}
diff --git a/core/src/scene/scene.h b/core/src/scene/scene.h
new file mode 100644 (file)
index 0000000..e1f674a
--- /dev/null
@@ -0,0 +1,194 @@
+#pragma once
+
+#include "scene/asset.h"
+#include "util/color.h"
+#include "util/fastmap.h"
+#include "view/view.h"
+
+#include <atomic>
+#include <list>
+#include <memory>
+#include <string>
+#include <vector>
+#include <tuple>
+#include <unordered_map>
+
+#include "glm/vec2.hpp"
+#include "yaml-cpp/yaml.h"
+#include "util/yamlHelper.h"
+
+
+namespace Tangram {
+
+class DataLayer;
+class FeatureSelection;
+class FontContext;
+class Light;
+class MapProjection;
+class Platform;
+class SceneLayer;
+class SpriteAtlas;
+class Style;
+class Texture;
+class TileSource;
+struct Stops;
+class Url;
+
+// Delimiter used in sceneloader for style params and layer-sublayer naming
+const std::string DELIMITER = ":";
+
+/* Singleton container of <Style> information
+ *
+ * Scene is a singleton containing the styles, lighting, and interactions defining a map scene
+ */
+
+class Scene {
+public:
+
+    struct Camera {
+        CameraType type = CameraType::perspective;
+
+        float maxTilt = 90.f;
+        std::shared_ptr<Stops> maxTiltStops;
+
+        // perspective
+        glm::vec2 vanishingPoint = {0, 0};
+        float fieldOfView = 0.25 * PI;
+        std::shared_ptr<Stops> fovStops;
+
+        // isometric
+        glm::vec2 obliqueAxis = {0, 1};
+    };
+
+    Camera m_camera;
+
+    enum animate {
+        yes, no, none
+    };
+
+    Scene(std::shared_ptr<const Platform> _platform, const std::string& _path = "");
+    Scene(const Scene& _other);
+    ~Scene();
+
+    auto& camera() { return m_camera; }
+
+    auto& resourceRoot() { return m_resourceRoot; }
+    auto& config() { return m_config; }
+    auto& tileSources() { return m_tileSources; };
+    auto& layers() { return m_layers; };
+    auto& styles() { return m_styles; };
+    auto& lights() { return m_lights; };
+    auto& lightBlocks() { return m_lightShaderBlocks; };
+    auto& textures() { return m_textures; };
+    auto& functions() { return m_jsFunctions; };
+    auto& assets() { return m_assets; };
+    auto& spriteAtlases() { return m_spriteAtlases; };
+    auto& stops() { return m_stops; }
+    auto& background() { return m_background; }
+    auto& fontContext() { return m_fontContext; }
+    auto& globalRefs() { return m_globalRefs; }
+    auto& featureSelection() { return m_featureSelection; }
+    Style* findStyle(const std::string& _name);
+
+    const auto& path() const { return m_path; }
+    const auto& resourceRoot() const { return m_resourceRoot; }
+    const auto& config() const { return m_config; }
+    const auto& tileSources() const { return m_tileSources; };
+    const auto& layers() const { return m_layers; };
+    const auto& styles() const { return m_styles; };
+    const auto& lights() const { return m_lights; };
+    const auto& lightBlocks() const { return m_lightShaderBlocks; };
+    const auto& functions() const { return m_jsFunctions; };
+    const auto& mapProjection() const { return m_mapProjection; };
+    const auto& fontContext() const { return m_fontContext; }
+    const auto& globalRefs() const { return m_globalRefs; }
+    const auto& featureSelection() const { return m_featureSelection; }
+    const auto& assets() const { return m_assets; };
+
+    void createSceneAsset(const std::shared_ptr<Platform>& platform, const Url& resolvedUrl, const Url& relativeUrl,
+                          const Url& base);
+
+    const Style* findStyle(const std::string& _name) const;
+
+    const Light* findLight(const std::string& _name) const;
+
+    void updateTime(float _dt) { m_time += _dt; }
+    float time() const { return m_time; }
+
+    int addIdForName(const std::string& _name);
+    int getIdForName(const std::string& _name) const;
+
+    int addJsFunction(const std::string& _function);
+
+    const int32_t id;
+
+    bool useScenePosition = true;
+    glm::dvec2 startPosition = { 0, 0 };
+    float startZoom = 0;
+
+    void animated(bool animated) { m_animated = animated ? yes : no; }
+    animate animated() const { return m_animated; }
+
+    std::shared_ptr<TileSource> getTileSource(int32_t id);
+    std::shared_ptr<TileSource> getTileSource(const std::string& name);
+
+    std::shared_ptr<Texture> getTexture(const std::string& name) const;
+
+    float pixelScale() { return m_pixelScale; }
+    void setPixelScale(float _scale);
+
+    std::atomic_ushort pendingTextures{0};
+    std::atomic_ushort pendingFonts{0};
+
+private:
+
+    // The file path from which this scene was loaded
+    std::string m_path;
+
+    std::string m_resourceRoot;
+
+    // The root node of the YAML scene configuration
+    YAML::Node m_config;
+
+    std::unique_ptr<MapProjection> m_mapProjection;
+
+    std::vector<DataLayer> m_layers;
+    std::vector<std::shared_ptr<TileSource>> m_tileSources;
+    std::vector<std::unique_ptr<Style>> m_styles;
+
+    std::vector<std::unique_ptr<Light>> m_lights;
+    std::map<std::string, std::string> m_lightShaderBlocks;
+
+    std::unordered_map<std::string, std::shared_ptr<Texture>> m_textures;
+    std::unordered_map<std::string, std::shared_ptr<SpriteAtlas>> m_spriteAtlases;
+
+    // path as key
+    fastmap<std::string, std::shared_ptr<Asset>> m_assets;
+
+    // Records the YAML Nodes for which global values have been swapped; keys are
+    // nodes that referenced globals, values are nodes of globals themselves.
+    std::vector<std::pair<YamlPath, YamlPath>> m_globalRefs;
+
+    // Container of all strings used in styling rules; these need to be
+    // copied and compared frequently when applying styling, so rules use
+    // integer indices into this container to represent strings
+    std::vector<std::string> m_names;
+
+    std::vector<std::string> m_jsFunctions;
+    std::list<Stops> m_stops;
+
+    Color m_background;
+
+    std::shared_ptr<FontContext> m_fontContext;
+
+    std::unique_ptr<FeatureSelection> m_featureSelection;
+
+    animate m_animated = none;
+
+    float m_pixelScale = 1.0f;
+
+    float m_time = 0.0;
+
+};
+
+}
diff --git a/core/src/scene/sceneLayer.cpp b/core/src/scene/sceneLayer.cpp
new file mode 100644 (file)
index 0000000..ac73333
--- /dev/null
@@ -0,0 +1,31 @@
+#include "scene/sceneLayer.h"
+
+#include <algorithm>
+
+namespace Tangram {
+
+SceneLayer::SceneLayer(std::string _name, Filter _filter,
+                       std::vector<DrawRuleData> _rules,
+                       std::vector<SceneLayer> _sublayers,
+                       bool _enabled) :
+    m_filter(std::move(_filter)),
+    m_name(_name),
+    m_rules(_rules),
+    m_sublayers(std::move(_sublayers)),
+    m_enabled(_enabled) {
+
+    setDepth(1);
+
+}
+
+void SceneLayer::setDepth(size_t _d) {
+
+    m_depth = _d;
+
+    for (auto& layer : m_sublayers) {
+        layer.setDepth(m_depth + 1);
+    }
+
+}
+
+}
diff --git a/core/src/scene/sceneLayer.h b/core/src/scene/sceneLayer.h
new file mode 100644 (file)
index 0000000..b6f53c9
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "scene/drawRule.h"
+#include "scene/filters.h"
+#include "scene/styleParam.h"
+
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+struct Feature;
+
+class SceneLayer {
+
+    Filter m_filter;
+    std::string m_name;
+    std::vector<DrawRuleData> m_rules;
+    std::vector<SceneLayer> m_sublayers;
+    size_t m_depth = 0;
+    bool m_enabled = true;
+
+public:
+
+    SceneLayer(std::string _name, Filter _filter,
+               std::vector<DrawRuleData> _rules,
+               std::vector<SceneLayer> _sublayers,
+               bool _enabled);
+
+    const auto& name() const { return m_name; }
+    const auto& filter() const { return m_filter; }
+    const auto& rules() const { return m_rules; }
+    const auto& sublayers() const { return m_sublayers; }
+    const auto& depth() const { return m_depth; }
+    const auto& enabled() const { return m_enabled; }
+
+    void setDepth(size_t _d);
+};
+
+}
+
diff --git a/core/src/scene/sceneLoader.cpp b/core/src/scene/sceneLoader.cpp
new file mode 100644 (file)
index 0000000..24dd5cd
--- /dev/null
@@ -0,0 +1,1821 @@
+#include "scene/sceneLoader.h"
+
+#include "data/clientGeoJsonSource.h"
+#include "data/memoryCacheDataSource.h"
+#include "data/mbtilesDataSource.h"
+#include "data/networkDataSource.h"
+#include "data/rasterSource.h"
+#include "data/tileSource.h"
+#include "gl/shaderSource.h"
+#include "log.h"
+#include "platform.h"
+#include "style/debugStyle.h"
+#include "style/debugTextStyle.h"
+#include "style/material.h"
+#include "style/polygonStyle.h"
+#include "style/polylineStyle.h"
+#include "style/textStyle.h"
+#include "style/pointStyle.h"
+#include "style/rasterStyle.h"
+#include "scene/dataLayer.h"
+#include "scene/filters.h"
+#include "scene/importer.h"
+#include "scene/scene.h"
+#include "scene/sceneLayer.h"
+#include "scene/spriteAtlas.h"
+#include "scene/lights.h"
+#include "scene/stops.h"
+#include "scene/styleMixer.h"
+#include "scene/styleParam.h"
+#include "util/base64.h"
+#include "util/floatFormatter.h"
+#include "util/yamlHelper.h"
+#include "view/view.h"
+
+#include "csscolorparser.hpp"
+#include <algorithm>
+#include <cassert>
+#include <iterator>
+#include <regex>
+#include <vector>
+
+using YAML::Node;
+using YAML::NodeType;
+using YAML::BadConversion;
+
+#define LOGNode(fmt, node, ...) LOGW(fmt ":\n'%s'\n", ## __VA_ARGS__, Dump(node).c_str())
+
+namespace Tangram {
+
+// TODO: make this configurable: 16MB default in-memory DataSource cache:
+constexpr size_t CACHE_SIZE = 16 * (1024 * 1024);
+
+static const std::string GLOBAL_PREFIX = "global.";
+
+std::mutex SceneLoader::m_textureMutex;
+
+bool SceneLoader::loadScene(const std::shared_ptr<Platform>& _platform, std::shared_ptr<Scene> _scene,
+                            const std::vector<SceneUpdate>& _updates, SceneUpdateErrorCallback _onSceneUpdateError) {
+
+    Importer sceneImporter;
+
+    _scene->config() = sceneImporter.applySceneImports(_platform, _scene);
+
+    if (!_scene->config()) {
+        return false;
+    }
+
+    if (!applyUpdates(_platform, *_scene, _updates, _onSceneUpdateError)) {
+        LOGW("Scene updates failed when loading scene");
+    }
+
+    // Load font resources
+    _scene->fontContext()->loadFonts();
+
+    applyConfig(_platform, _scene);
+
+    return true;
+}
+
+bool SceneLoader::applyUpdates(const std::shared_ptr<Platform>& platform, Scene& scene,
+                               const std::vector<SceneUpdate>& updates, SceneUpdateErrorCallback onSceneUpdateError) {
+    auto& root = scene.config();
+
+    for (const auto& update : updates) {
+        SceneUpdateError updateError;
+        bool hasError = false;
+        Node value;
+
+        try {
+            value = YAML::Load(update.value);
+        } catch (YAML::ParserException e) {
+            LOGE("Parsing scene update string failed. '%s'", e.what());
+            updateError = {update, Error::scene_update_value_yaml_syntax_error};
+            hasError = true;
+        }
+
+        if (!hasError && value) {
+            try {
+                // Dummy node to trigger YAML exception on YAML syntax errors
+                auto parse = YAML::Load(update.path);
+                Node node = YamlPath(update.path).get(root);
+
+                if (node && node.Scalar().empty() && node != root) {
+                    updateError = {update, Error::scene_update_path_not_found};
+                    hasError = true;
+                } else {
+                    node = value;
+                }
+            } catch(YAML::Exception e) {
+                LOGE("Parsing scene update string failed. %s '%s'", update.path.c_str(), e.what());
+                updateError = {update, Error::scene_update_path_yaml_syntax_error};
+                hasError = true;
+            }
+        }
+
+        if (hasError) {
+            if (onSceneUpdateError) {
+                onSceneUpdateError(updateError);
+            }
+
+            return false;
+        }
+    }
+
+    Importer importer;
+    importer.resolveSceneUrls(platform, scene, root, Url(scene.path()).resolved(Url(scene.resourceRoot())));
+
+    return true;
+}
+
+void printFilters(const SceneLayer& layer, int indent){
+    LOG("%*s >>> %s\n", indent, "", layer.name().c_str());
+    layer.filter().print(indent + 2);
+
+    for (auto& l : layer.sublayers()) {
+        printFilters(l, indent + 2);
+    }
+};
+
+void createGlobalRefs(const Node& node, Scene& scene, YamlPathBuffer& path) {
+    switch(node.Type()) {
+    case NodeType::Scalar: {
+            const auto& value = node.Scalar();
+            if (value.length() > 7 && value.compare(0, 7, GLOBAL_PREFIX) == 0) {
+                scene.globalRefs().emplace_back(path.toYamlPath(),
+                                                YamlPath(value.substr(GLOBAL_PREFIX.length())));
+            }
+        }
+        break;
+    case NodeType::Sequence: {
+            path.pushSequence();
+            for (const auto& entry : node) {
+                createGlobalRefs(entry, scene, path);
+                path.increment();
+            }
+            path.pop();
+        }
+        break;
+    case NodeType::Map:
+        for (const auto& entry : node) {
+            path.pushMap(&entry.first.Scalar());
+            createGlobalRefs(entry.second, scene, path);
+            path.pop();
+        }
+        break;
+    default:
+        break;
+    }
+}
+
+void SceneLoader::applyGlobals(Node root, Scene& scene) {
+
+    YamlPathBuffer path;
+    createGlobalRefs(root, scene, path);
+    const auto& globals = root["global"];
+    if (!scene.globalRefs().empty() && !globals.IsMap()) {
+        LOGW("Missing global references");
+    }
+
+    for (auto& globalRef : scene.globalRefs()) {
+        auto target = globalRef.first.get(root);
+        auto global = globalRef.second.get(globals);
+        if (target && global) {
+            target = global;
+        } else {
+            LOGW("Global reference is undefined: %s <= %s",
+                 globalRef.first.codedPath.c_str(),
+                 globalRef.second.codedPath.c_str());
+        }
+    }
+}
+
+bool SceneLoader::applyConfig(const std::shared_ptr<Platform>& _platform, const std::shared_ptr<Scene>& _scene) {
+
+    Node& config = _scene->config();
+
+    // Instantiate built-in styles
+    _scene->styles().emplace_back(new PolygonStyle("polygons"));
+    _scene->styles().emplace_back(new PolylineStyle("lines"));
+    _scene->styles().emplace_back(new DebugTextStyle("debugtext", std::make_shared<FontContext>(_platform), true));
+    _scene->styles().emplace_back(new TextStyle("text", _scene->fontContext(), true));
+    _scene->styles().emplace_back(new DebugStyle("debug"));
+    _scene->styles().emplace_back(new PointStyle("points", _scene->fontContext()));
+    _scene->styles().emplace_back(new RasterStyle("raster"));
+
+    if (config["global"]) {
+        applyGlobals(config, *_scene);
+    }
+
+
+    if (Node sources = config["sources"]) {
+        for (const auto& source : sources) {
+            std::string srcName = source.first.Scalar();
+            try { loadSource(_platform, srcName, source.second, sources, _scene); }
+            catch (YAML::RepresentationException e) {
+                LOGNode("Parsing sources: '%s'", source, e.what());
+            }
+        }
+    } else {
+        LOGW("No source defined in the yaml scene configuration.");
+    }
+
+    if (Node textures = config["textures"]) {
+        for (const auto& texture : textures) {
+            try { loadTexture(_platform, texture, _scene); }
+            catch (YAML::RepresentationException e) {
+                LOGNode("Parsing texture: '%s'", texture, e.what());
+            }
+        }
+    }
+
+    if (Node fonts = config["fonts"]) {
+        if (fonts.IsMap()) {
+            for (const auto& font : fonts) {
+                try { loadFont(_platform, font, _scene); }
+                catch (YAML::RepresentationException e) {
+                    LOGNode("Parsing font: '%s'", font, e.what());
+                }
+            }
+        }
+    }
+
+    if (Node styles = config["styles"]) {
+        StyleMixer mixer;
+        try {
+            mixer.mixStyleNodes(styles);
+        } catch (YAML::RepresentationException e) {
+            LOGNode("Mixing styles: '%s'", styles, e.what());
+        }
+        for (const auto& entry : styles) {
+            try {
+                auto name = entry.first.Scalar();
+                auto config = entry.second;
+                loadStyle(_platform, name, config, _scene);
+            }
+            catch (YAML::RepresentationException e) {
+                LOGNode("Parsing style: '%s'", entry, e.what());
+            }
+        }
+    }
+
+    // Styles that are opaque must be ordered first in the scene so that
+    // they are rendered 'under' styles that require blending
+    std::sort(_scene->styles().begin(), _scene->styles().end(), Style::compare);
+
+    // Post style sorting set their respective IDs=>vector indices
+    // These indices are used for style geometry lookup in tiles
+    auto& styles = _scene->styles();
+    for(uint32_t i = 0; i < styles.size(); i++) {
+        styles[i]->setID(i);
+    }
+
+    if (Node layers = config["layers"]) {
+        for (const auto& layer : layers) {
+            try { loadLayer(layer, _scene); }
+            catch (YAML::RepresentationException e) {
+                LOGNode("Parsing layer: '%s'", layer, e.what());
+            }
+        }
+    }
+
+    if (Node lights = config["lights"]) {
+        for (const auto& light : lights) {
+            try { loadLight(light, _scene); }
+            catch (YAML::RepresentationException e) {
+                LOGNode("Parsing light: '%s'", light, e.what());
+            }
+        }
+    }
+
+    if (_scene->lights().empty()) {
+        // Add an ambient light if nothing else is specified
+        std::unique_ptr<AmbientLight> amb(new AmbientLight("defaultLight"));
+        amb->setAmbientColor({ 1.f, 1.f, 1.f, 1.f });
+        _scene->lights().push_back(std::move(amb));
+    }
+
+    _scene->lightBlocks() = Light::assembleLights(_scene->lights());
+
+    if (Node camera = config["camera"]) {
+        try { loadCamera(camera, _scene); }
+        catch (YAML::RepresentationException e) {
+            LOGNode("Parsing camera: '%s'", camera, e.what());
+        }
+
+    } else if (Node cameras = config["cameras"]) {
+        try { loadCameras(cameras, _scene); }
+        catch (YAML::RepresentationException e) {
+            LOGNode("Parsing cameras: '%s'", cameras, e.what());
+        }
+    }
+
+    loadBackground(config["scene"]["background"], _scene);
+
+    Node animated = config["scene"]["animated"];
+    if (animated) {
+        _scene->animated(animated.as<bool>());
+    }
+
+    for (auto& style : _scene->styles()) {
+        style->build(*_scene);
+    }
+
+    return true;
+}
+
+void SceneLoader::loadShaderConfig(const std::shared_ptr<Platform>& platform, Node shaders, Style& style, const std::shared_ptr<Scene>& scene) {
+
+    if (!shaders) { return; }
+
+    auto& shader = style.getShaderSource();
+
+    if (Node extNode = shaders["extensions_mixed"]) {
+        if (extNode.IsScalar()) {
+            shader.addExtensionDeclaration(extNode.Scalar());
+        } else if (extNode.IsSequence()) {
+            for (const auto& e : extNode) {
+                shader.addExtensionDeclaration(e.Scalar());
+            }
+        }
+    }
+
+    if (Node definesNode = shaders["defines"]) {
+        for (const auto& define : definesNode) {
+            const std::string& name = define.first.Scalar();
+
+            // undefine any previous definitions
+            {
+                auto pos = name.find('(');
+                if (pos == std::string::npos) {
+                    shader.addSourceBlock("defines", "#undef " + name);
+                } else {
+                    shader.addSourceBlock("defines", "#undef " + name.substr(0, pos));
+                }
+            }
+            bool bValue;
+
+            if (getBool(define.second, bValue)) {
+                // specifying a define to be 'true' means that it is simply
+                // defined and has no value
+                if (bValue) {
+                    shader.addSourceBlock("defines", "#define " + name);
+                }
+            } else {
+                const std::string& value = define.second.Scalar();
+                shader.addSourceBlock("defines", "#define " + name + " " + value);
+            }
+        }
+    }
+
+    if (Node uniformsNode = shaders["uniforms"]) {
+        for (const auto& uniform : uniformsNode) {
+            const std::string& name = uniform.first.Scalar();
+            StyleUniform styleUniform;
+
+            if (parseStyleUniforms(platform, uniform.second, scene, styleUniform)) {
+                if (styleUniform.value.is<UniformArray1f>()) {
+                    UniformArray1f& array = styleUniform.value.get<UniformArray1f>();
+                    shader.addSourceBlock("uniforms", "uniform float " + name +
+                        "[" + std::to_string(array.size()) + "];");
+                } else if(styleUniform.value.is<UniformTextureArray>()) {
+                    UniformTextureArray& textureArray = styleUniform.value.get<UniformTextureArray>();
+                    shader.addSourceBlock("uniforms", "uniform " + styleUniform.type + " " + name +
+                        "[" + std::to_string(textureArray.names.size()) + "];");
+                } else {
+                    shader.addSourceBlock("uniforms", "uniform " + styleUniform.type + " " + name + ";");
+                }
+
+                style.styleUniforms().emplace_back(name, styleUniform.value);
+            } else {
+                LOGNode("Style uniform parsing failure", uniform.second);
+            }
+        }
+    }
+
+    if (Node blocksNode = shaders["blocks_mixed"]) {
+        for (const auto& block : blocksNode) {
+            const auto& name = block.first.Scalar();
+            const auto& value = block.second;
+            if (value.IsSequence()){
+                for (const auto& it : value) {
+                    shader.addSourceBlock(name, it.Scalar(), false);
+                }
+            } else if (value.IsScalar()) {
+                shader.addSourceBlock(name, value.Scalar(), false);
+            }
+        }
+    }
+}
+
+glm::vec4 parseMaterialVec(const Node& prop) {
+
+    switch (prop.Type()) {
+    case NodeType::Sequence:
+        return parseVec<glm::vec4>(prop);
+    case NodeType::Scalar: {
+        double value;
+        if (getDouble(prop, value)) {
+            return glm::vec4(value, value, value, 1.0);
+        } else {
+            return getColorAsVec4(prop);
+        }
+        break;
+    }
+    case NodeType::Map:
+        // Handled as texture
+        break;
+    default:
+        LOGNode("Invalid 'material'", prop);
+        break;
+    }
+    return glm::vec4(0.0);
+}
+
+void SceneLoader::loadMaterial(const std::shared_ptr<Platform>& platform, Node matNode, Material& material, const std::shared_ptr<Scene>& scene, Style& style) {
+    if (!matNode.IsMap()) { return; }
+
+    if (Node n = matNode["emission"]) {
+        if (n.IsMap()) {
+            material.setEmission(loadMaterialTexture(platform, n, scene, style));
+        } else {
+            material.setEmission(parseMaterialVec(n));
+        }
+    }
+    if (Node n = matNode["diffuse"]) {
+        if (n.IsMap()) {
+            material.setDiffuse(loadMaterialTexture(platform, n, scene, style));
+        } else {
+            material.setDiffuse(parseMaterialVec(n));
+        }
+    }
+    if (Node n = matNode["ambient"]) {
+        if (n.IsMap()) {
+            material.setAmbient(loadMaterialTexture(platform, n, scene, style));
+        } else {
+            material.setAmbient(parseMaterialVec(n));
+        }
+    }
+
+    if (Node n = matNode["specular"]) {
+        if (n.IsMap()) {
+            material.setSpecular(loadMaterialTexture(platform, n, scene, style));
+        } else {
+            material.setSpecular(parseMaterialVec(n));
+        }
+    }
+
+    if (Node shininess = matNode["shininess"]) {
+        double value;
+        if (getDouble(shininess, value, "shininess")) {
+            material.setShininess(value);
+        }
+    }
+
+    material.setNormal(loadMaterialTexture(platform, matNode["normal"], scene, style));
+}
+
+MaterialTexture SceneLoader::loadMaterialTexture(const std::shared_ptr<Platform>& platform, Node matCompNode, const std::shared_ptr<Scene>& scene, Style& style) {
+
+    if (!matCompNode) { return MaterialTexture{}; }
+
+    Node textureNode = matCompNode["texture"];
+    if (!textureNode) {
+        LOGNode("Expected a 'texture' parameter", matCompNode);
+
+        return MaterialTexture{};
+    }
+
+    const std::string& name = textureNode.Scalar();
+
+    MaterialTexture matTex;
+    {
+        std::lock_guard<std::mutex> lock(m_textureMutex);
+        matTex.tex = scene->textures()[name];
+    }
+
+    if (!matTex.tex) {
+        // Load inline material  textures
+        if (!loadTexture(platform, name, scene)) {
+            LOGW("Not able to load material texture: %s", name.c_str());
+            return MaterialTexture();
+        }
+    }
+
+    if (Node mappingNode = matCompNode["mapping"]) {
+        const std::string& mapping = mappingNode.Scalar();
+        if (mapping == "uv") {
+            matTex.mapping = MappingType::uv;
+
+            // Mark the style to generate texture coordinates
+            if (!style.genTexCoords()) {
+                LOGW("Style %s has option `texcoords: false` but material %s has uv mapping",
+                    style.getName().c_str(), name.c_str());
+                LOGW("Defaulting uvs generation to true for style %s",
+                    style.getName().c_str());
+            }
+
+            style.setTexCoordsGeneration(true);
+        } else if (mapping == "spheremap") {
+            matTex.mapping = MappingType::spheremap;
+        } else if (mapping == "planar") {
+            matTex.mapping = MappingType::planar;
+        } else if (mapping == "triplanar") {
+            matTex.mapping = MappingType::triplanar;
+        } else {
+            LOGW("Unrecognized texture mapping '%s'", mapping.c_str());
+        }
+    }
+
+    if (Node scaleNode = matCompNode["scale"]) {
+        if (scaleNode.IsSequence() && scaleNode.size() == 2) {
+            matTex.scale = { scaleNode[0].as<float>(), scaleNode[1].as<float>(), 1.f };
+        } else if (scaleNode.IsScalar()) {
+            matTex.scale = glm::vec3(scaleNode.as<float>());
+        } else {
+            LOGW("Unrecognized scale parameter in material");
+        }
+    }
+
+    if (Node amountNode = matCompNode["amount"]) {
+        if (amountNode.IsSequence() && amountNode.size() == 3) {
+            matTex.amount = { amountNode[0].as<float>(),
+                              amountNode[1].as<float>(),
+                              amountNode[2].as<float>() };
+        } else if (amountNode.IsScalar()) {
+            matTex.amount = glm::vec3(amountNode.as<float>());
+        } else {
+            LOGW("Unrecognized amount parameter in material");
+        }
+    }
+
+    return matTex;
+}
+
+bool SceneLoader::extractTexFiltering(Node& filtering, TextureFiltering& filter) {
+    const std::string& textureFiltering = filtering.Scalar();
+    if (textureFiltering == "linear") {
+        filter.min = filter.mag = GL_LINEAR;
+        return false;
+    } else if (textureFiltering == "mipmap") {
+        filter.min = GL_LINEAR_MIPMAP_LINEAR;
+        return true;
+    } else if (textureFiltering == "nearest") {
+        filter.min = filter.mag = GL_NEAREST;
+        return false;
+    } else {
+        return false;
+    }
+}
+
+void SceneLoader::updateSpriteNodes(const std::string& texName,
+        std::shared_ptr<Texture>& texture, const std::shared_ptr<Scene>& scene) {
+    auto& spriteAtlases = scene->spriteAtlases();
+    if (spriteAtlases.find(texName) != spriteAtlases.end()) {
+        auto& spriteAtlas = spriteAtlases[texName];
+        spriteAtlas->updateSpriteNodes(texture);
+    }
+}
+
+std::shared_ptr<Texture> SceneLoader::fetchTexture(const std::shared_ptr<Platform>& platform, const std::string& name, const std::string& url,
+        const TextureOptions& options, bool generateMipmaps, const std::shared_ptr<Scene>& scene) {
+
+    std::shared_ptr<Texture> texture;
+
+    std::regex r("^(http|https):/");
+    std::smatch match;
+
+    auto& asset = scene->assets()[url];
+    if (!asset) {
+        LOGE("Asset missing at path: %s.", url.c_str());
+        return texture;
+    }
+
+    // TODO: generalize using URI handlers
+    if (std::regex_search(url, match, r) && !asset->zipHandle()) {
+        scene->pendingTextures++;
+        platform->startUrlRequest(url, [=](std::vector<char>&& rawData) {
+                std::lock_guard<std::mutex> lock(m_textureMutex);
+                auto texture = scene->getTexture(name);
+                if (texture) {
+                    if (!texture->loadImageFromMemory(rawData)) {
+                        LOGE("Invalid texture data '%s'", url.c_str());
+                    }
+
+                    updateSpriteNodes(name, texture, scene);
+                    scene->pendingTextures--;
+                    if (scene->pendingTextures == 0) {
+                        platform->requestRender();
+                    }
+                }
+            });
+        std::vector<char> textureData = {};
+        texture = std::make_shared<Texture>(textureData, options, generateMipmaps);
+    } else {
+
+        if (url.substr(0, 22) == "data:image/png;base64,") {
+            // Skip data: prefix
+            auto data = url.substr(22);
+
+            std::vector<unsigned char> blob;
+
+            try {
+                blob = Base64::decode(data);
+            } catch(std::runtime_error e) {
+                LOGE("Can't decode Base64 texture '%s'", e.what());
+            }
+
+            if (blob.empty()) {
+                LOGE("Can't decode Base64 texture");
+                return nullptr;
+            }
+            texture = std::make_shared<Texture>(0, 0, options, generateMipmaps);
+
+            std::vector<char> textureData;
+            auto cdata = reinterpret_cast<char*>(blob.data());
+            textureData.insert(textureData.begin(), cdata, cdata + blob.size());
+            if (!texture->loadImageFromMemory(textureData)) {
+                LOGE("Invalid Base64 texture");
+            }
+
+        } else {
+
+            auto data = asset->readBytesFromAsset(platform);
+
+            if (data.size() == 0) {
+                LOGE("Can't load texture resource at url '%s'", url.c_str());
+                return nullptr;
+            }
+
+            texture = std::make_shared<Texture>(0, 0, options, generateMipmaps);
+            if (!texture->loadImageFromMemory(data)) {
+                LOGE("Invalid texture data '%s'", url.c_str());
+            }
+        }
+    }
+
+    return texture;
+}
+
+bool SceneLoader::loadTexture(const std::shared_ptr<Platform>& platform, const std::string& url, const std::shared_ptr<Scene>& scene) {
+    TextureOptions options = {GL_RGBA, GL_RGBA, {GL_LINEAR, GL_LINEAR}, {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE}};
+
+    auto texture = fetchTexture(platform, url, url, options, false, scene);
+    if (texture) {
+        std::lock_guard<std::mutex> lock(m_textureMutex);
+        scene->textures().emplace(url, texture);
+        return true;
+    }
+
+    LOGE("Missing texture %s", url.c_str());
+    return false;
+}
+
+void SceneLoader::loadTexture(const std::shared_ptr<Platform>& platform, const std::pair<Node, Node>& node, const std::shared_ptr<Scene>& scene) {
+
+    const std::string& name = node.first.Scalar();
+    Node textureConfig = node.second;
+
+    std::string file;
+    TextureOptions options = {GL_RGBA, GL_RGBA, {GL_LINEAR, GL_LINEAR}, {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE} };
+
+    if (Node url = textureConfig["url"]) {
+        file = url.as<std::string>();
+    } else {
+        LOGW("No url specified for texture '%s', skipping.", name.c_str());
+        return;
+    }
+
+    bool generateMipmaps = false;
+
+    if (Node filtering = textureConfig["filtering"]) {
+        if (extractTexFiltering(filtering, options.filtering)) {
+            generateMipmaps = true;
+        }
+    }
+
+    auto texture = fetchTexture(platform, name, file, options, generateMipmaps, scene);
+    if (!texture) {
+        LOGE("Missing texture %s", name.c_str());
+        return;
+    }
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+    if (Node sprites = textureConfig["sprites"]) {
+        std::shared_ptr<SpriteAtlas> atlas(new SpriteAtlas(texture));
+
+        for (auto it = sprites.begin(); it != sprites.end(); ++it) {
+
+            const Node sprite = it->second;
+            const std::string& spriteName = it->first.Scalar();
+
+            if (sprite) {
+                glm::vec4 desc = parseVec<glm::vec4>(sprite);
+                glm::vec2 pos = glm::vec2(desc.x, desc.y);
+                glm::vec2 size = glm::vec2(desc.z, desc.w);
+
+                atlas->addSpriteNode(spriteName, pos, size);
+            }
+        }
+        scene->spriteAtlases()[name] = atlas;
+    }
+    scene->textures().emplace(name, texture);
+}
+
+void loadFontDescription(const std::shared_ptr<Platform>& platform, const Node& node, const std::string& family, const std::shared_ptr<Scene>& scene) {
+    if (!node.IsMap()) {
+        LOGW("");
+        return;
+    }
+    std::string style = "normal", weight = "400", uri;
+
+    for (const auto& fontDesc : node) {
+        const std::string& key = fontDesc.first.Scalar();
+        if (key == "weight") {
+            weight = fontDesc.second.Scalar();
+        } else if (key == "style") {
+            style = fontDesc.second.Scalar();
+        } else if (key == "url") {
+            uri = fontDesc.second.Scalar();
+        } else if (key == "external") {
+            LOGW("external: within fonts: is a no-op in native version of tangram (%s)", family.c_str());
+        }
+    }
+
+    if (uri.empty()) {
+        LOGW("Empty url: block within fonts: (%s)", family.c_str());
+        return;
+    }
+
+    std::string familyNormalized, styleNormalized;
+
+    familyNormalized.resize(family.size());
+    styleNormalized.resize(style.size());
+
+    std::transform(family.begin(), family.end(), familyNormalized.begin(), ::tolower);
+    std::transform(style.begin(), style.end(), styleNormalized.begin(), ::tolower);
+
+    // Download/Load the font and add it to the context
+    FontDescription _ft(familyNormalized, styleNormalized, weight, uri);
+
+    std::regex regex("^(http|https):/");
+    std::smatch match;
+
+    auto& asset = scene->assets()[_ft.uri];
+    if (!asset) {
+        LOGE("Asset missing at path: %s.", _ft.uri.c_str());
+        return;
+    }
+
+    if (std::regex_search(uri, match, regex) && !asset->zipHandle()) {
+        // Load remote
+        scene->pendingFonts++;
+        platform->startUrlRequest(_ft.uri, [_ft, scene](std::vector<char>&& rawData) {
+            if (rawData.size() == 0) {
+                LOGE("Bad URL request for font %s at URL %s", _ft.alias.c_str(), _ft.uri.c_str());
+            } else {
+                scene->fontContext()->addFont(_ft, alfons::InputSource(std::move(rawData)));
+            }
+            scene->pendingFonts--;
+        });
+    } else {
+        auto data = asset->readBytesFromAsset(platform);
+
+        if (data.size() == 0) {
+            LOGW("Local font at path %s can't be found (%s)", _ft.uri.c_str(), _ft.bundleAlias.c_str());
+        } else {
+            LOGN("Adding local font %s (%s)", _ft.uri.c_str(), _ft.bundleAlias.c_str());
+            scene->fontContext()->addFont(_ft, alfons::InputSource(std::move(data)));
+        }
+    }
+}
+
+void SceneLoader::loadFont(const std::shared_ptr<Platform>& platform, const std::pair<Node, Node>& font, const std::shared_ptr<Scene>& scene) {
+    const std::string& family = font.first.Scalar();
+
+    if (font.second.IsMap()) {
+        loadFontDescription(platform, font.second, family, scene);
+    } else if (font.second.IsSequence()) {
+        for (const auto& node : font.second) {
+            loadFontDescription(platform, node, family, scene);
+        }
+    }
+}
+
+void SceneLoader::loadStyleProps(const std::shared_ptr<Platform>& platform, Style& style, Node styleNode, const std::shared_ptr<Scene>& scene) {
+
+    if (!styleNode) {
+        LOGW("Can not parse style parameters, bad style YAML Node");
+        return;
+    }
+
+    if (Node animatedNode = styleNode["animated"]) {
+        LOGW("'animated' property will be set but not yet implemented in styles"); // TODO
+        if (!animatedNode.IsScalar()) { LOGW("animated flag should be a scalar"); }
+        else {
+            bool animate;
+            if (getBool(animatedNode, animate, "animated")) {
+                style.setAnimated(animate);
+            }
+        }
+    }
+
+    if (Node blendNode = styleNode["blend"]) {
+        const std::string& blendMode = blendNode.Scalar();
+        if      (blendMode == "opaque")   { style.setBlendMode(Blending::opaque); }
+        else if (blendMode == "add")      { style.setBlendMode(Blending::add); }
+        else if (blendMode == "multiply") { style.setBlendMode(Blending::multiply); }
+        else if (blendMode == "overlay")  { style.setBlendMode(Blending::overlay); }
+        else if (blendMode == "inlay")    { style.setBlendMode(Blending::inlay); }
+        else { LOGW("Invalid blend mode '%s'", blendMode.c_str()); }
+    }
+
+    if (Node blendOrderNode = styleNode["blend_order"]) {
+        try {
+            auto blendOrder = blendOrderNode.as<int>();
+            style.setBlendOrder(blendOrder);
+        } catch (const BadConversion& e) {
+            LOGE("Integral value expected for blend_order style parameter.\n");
+        }
+    }
+
+    if (Node texcoordsNode = styleNode["texcoords"]) {
+        style.setTexCoordsGeneration(texcoordsNode.as<bool>());
+    }
+
+    if (Node dashNode = styleNode["dash"]) {
+        if (auto polylineStyle = dynamic_cast<PolylineStyle*>(&style)) {
+            if (dashNode.IsSequence()) {
+                std::vector<float> dashValues;
+                for (auto dashValue : dashNode) {
+                    dashValues.push_back(dashValue.as<float>());
+                }
+                polylineStyle->setDashArray(dashValues);
+                polylineStyle->setTexCoordsGeneration(true);
+            }
+        }
+    }
+
+    if (Node dashBackgroundColor = styleNode["dash_background_color"]) {
+        if (auto polylineStyle = dynamic_cast<PolylineStyle*>(&style)) {
+            glm::vec4 backgroundColor = getColorAsVec4(dashBackgroundColor);
+            polylineStyle->setDashBackgroundColor(backgroundColor);
+        }
+    }
+
+    if (Node shadersNode = styleNode["shaders"]) {
+        loadShaderConfig(platform, shadersNode, style, scene);
+    }
+
+    if (Node lightingNode = styleNode["lighting"]) {
+        const std::string& lighting = lightingNode.Scalar();
+        if (lighting == "fragment") { style.setLightingType(LightingType::fragment); }
+        else if (lighting == "vertex") { style.setLightingType(LightingType::vertex); }
+        else if (lighting == "false") { style.setLightingType(LightingType::none); }
+        else if (lighting == "true") { } // use default lighting
+        else { LOGW("Unrecognized lighting type '%s'", lighting.c_str()); }
+    }
+
+    if (Node textureNode = styleNode["texture"]) {
+        std::lock_guard<std::mutex> lock(m_textureMutex);
+        if (auto pointStyle = dynamic_cast<PointStyle*>(&style)) {
+            const std::string& textureName = textureNode.Scalar();
+            auto& atlases = scene->spriteAtlases();
+            auto atlasIt = atlases.find(textureName);
+            auto styleTexture = scene->getTexture(textureName);
+            if (atlasIt != atlases.end()) {
+                pointStyle->setSpriteAtlas(atlasIt->second);
+            } else if (styleTexture){
+                pointStyle->setTexture(styleTexture);
+            } else {
+                LOGW("Undefined texture name %s", textureName.c_str());
+            }
+        } else if (auto polylineStyle = dynamic_cast<PolylineStyle*>(&style)) {
+            const std::string& textureName = textureNode.Scalar();
+            auto texture = scene->getTexture(textureName);
+            if (texture) {
+                polylineStyle->setTexture(texture);
+                polylineStyle->setTexCoordsGeneration(true);
+            }
+        }
+    }
+
+    if (Node materialNode = styleNode["material"]) {
+        loadMaterial(platform, materialNode, style.getMaterial(), scene, style);
+    }
+
+    if (const Node& drawNode = styleNode["draw"]) {
+        std::vector<StyleParam> params;
+        int ruleID = scene->addIdForName(style.getName());
+        parseStyleParams(drawNode, scene, "", params);
+        /*Note:  ruleID and name is immaterial here, as these are only used for rule merging, but
+         * style's default styling rules are applied post rule merging for any style parameter which
+         * was not assigned during merging step.
+         */
+        auto rule = std::make_unique<DrawRuleData>(style.getName(), ruleID, std::move(params));
+        style.setDefaultDrawRule(std::move(rule));
+    }
+
+}
+
+bool SceneLoader::loadStyle(const std::shared_ptr<Platform>& platform, const std::string& name, Node config, const std::shared_ptr<Scene>& scene) {
+
+    const auto& builtIn = Style::builtInStyleNames();
+
+    if (std::find(builtIn.begin(), builtIn.end(), name) != builtIn.end()) {
+        LOGW("Cannot use built-in style name '%s' for new style", name.c_str());
+        return false;
+    }
+
+    Node baseNode = config["base"];
+    if (!baseNode) {
+        // No base style, this is an abstract style
+        return true;
+    }
+
+    // Construct style instance using the merged properties
+    std::unique_ptr<Style> style;
+    auto baseStyle = baseNode.Scalar();
+    if (baseStyle == "polygons") {
+        style = std::make_unique<PolygonStyle>(name);
+    } else if (baseStyle == "lines") {
+        style = std::make_unique<PolylineStyle>(name);
+    } else if (baseStyle == "text") {
+        style = std::make_unique<TextStyle>(name, scene->fontContext(), true);
+    } else if (baseStyle == "points") {
+        style = std::make_unique<PointStyle>(name, scene->fontContext());
+    } else if (baseStyle == "raster") {
+        style = std::make_unique<RasterStyle>(name);
+    } else {
+        LOGW("Base style '%s' not recognized, cannot instantiate.", baseStyle.c_str());
+        return false;
+    }
+
+    Node rasterNode = config["raster"];
+    if (rasterNode) {
+        const auto& raster = rasterNode.Scalar();
+        if (raster == "normal") {
+            style->setRasterType(RasterType::normal);
+        } else if (raster == "color") {
+            style->setRasterType(RasterType::color);
+        } else if (raster == "custom") {
+            style->setRasterType(RasterType::custom);
+        }
+    }
+
+    loadStyleProps(platform, *style.get(), config, scene);
+
+    scene->styles().push_back(std::move(style));
+
+    return true;
+}
+
+void SceneLoader::loadSource(const std::shared_ptr<Platform>& platform, const std::string& name,
+                             const Node& source, const Node& sources, const std::shared_ptr<Scene>& _scene) {
+    if (_scene->getTileSource(name)) {
+        LOGW("Duplicate TileSource: %s", name.c_str());
+        return;
+    }
+
+    std::string type;
+    std::string url;
+    std::string mbtiles;
+    std::vector<std::string> subdomains;
+
+    int32_t minDisplayZoom = -1;
+    int32_t maxDisplayZoom = -1;
+    int32_t maxZoom = 18;
+    int32_t zoomBias = 0;
+
+    if (auto typeNode = source["type"]) {
+        type = typeNode.Scalar();
+    }
+    if (auto urlNode = source["url"]) {
+        url = urlNode.Scalar();
+    }
+    if (auto minDisplayZoomNode = source["min_display_zoom"]) {
+        minDisplayZoom = minDisplayZoomNode.as<int32_t>(minDisplayZoom);
+    }
+    if (auto maxDisplayZoomNode = source["max_display_zoom"]) {
+        maxDisplayZoom = maxDisplayZoomNode.as<int32_t>(maxDisplayZoom);
+    }
+    if (auto maxZoomNode = source["max_zoom"]) {
+        maxZoom = maxZoomNode.as<int32_t>(maxZoom);
+    }
+    if (auto tileSizeNode = source["tile_size"]) {
+        zoomBias = TileSource::zoomBiasFromTileSize(tileSizeNode.as<int32_t>());
+    }
+
+    // Parse and append any URL parameters.
+    if (auto urlParamsNode = source["url_params"]) {
+        std::stringstream urlStream;
+        // Transform our current URL from "base[?query][#hash]" into "base?params[query][#hash]".
+        auto hashStart = std::min(url.find_first_of("#"), url.size());
+        auto queryStart = std::min(url.find_first_of("?"), url.size());
+        auto baseEnd = std::min(hashStart, queryStart + 1);
+        urlStream << url.substr(0, baseEnd);
+        if (queryStart == url.size()) {
+            urlStream << "?";
+        }
+        if (urlParamsNode.IsMap()) {
+            for (const auto& entry : urlParamsNode) {
+                if (entry.first.IsScalar() && entry.second.IsScalar()) {
+                    urlStream << entry.first.Scalar() << "=" << entry.second.Scalar() << "&";
+                } else {
+                    LOGW("Invalid url_params entry in source '%s', entries should be strings.", name.c_str());
+                }
+            }
+        } else {
+            LOGW("Expected a map of values for url_params in source '%s'.", name.c_str());
+        }
+        urlStream << url.substr(baseEnd);
+        url = urlStream.str();
+    }
+
+    // Apply URL subdomain configuration.
+    if (Node subDomainNode = source["url_subdomains"]) {
+        if (subDomainNode.IsSequence()) {
+            for (const auto& domain : subDomainNode) {
+                if (domain.IsScalar()) {
+                    subdomains.push_back(domain.Scalar());
+                }
+            }
+        }
+    }
+
+    // Check whether the URL template and subdomains make sense together, and warn if not.
+    bool hasSubdomainPlaceholder = (url.find("{s}") != std::string::npos);
+    if (hasSubdomainPlaceholder && subdomains.empty()) {
+        LOGW("The URL for source '%s' includes the subdomain placeholder '{s}', but no subdomains were given.", name.c_str());
+    }
+    if (!hasSubdomainPlaceholder && !subdomains.empty()) {
+        LOGW("The URL for source '%s' has subdomains specified, but does not include the subdomain placeholder '{s}'.", name.c_str());
+    }
+
+    // distinguish tiled and non-tiled sources by url
+    bool tiled = url.size() > 0 &&
+        url.find("{x}") != std::string::npos &&
+        url.find("{y}") != std::string::npos &&
+        url.find("{z}") != std::string::npos;
+
+    bool isMBTilesFile = false;
+    {
+        const char* extStr = ".mbtiles";
+        const size_t extLength = strlen(extStr);
+        const size_t urlLength = url.length();
+        isMBTilesFile = urlLength > extLength && (url.compare(urlLength - extLength, extLength, extStr) == 0);
+    }
+
+    auto rawSources = std::make_unique<MemoryCacheDataSource>();
+    rawSources->setCacheSize(CACHE_SIZE);
+
+    if (isMBTilesFile) {
+        // If we have MBTiles, we know the source is tiled.
+        tiled = true;
+        // Create an MBTiles data source from the file at the url and add it to the source chain.
+        rawSources->setNext(std::make_unique<MBTilesDataSource>(platform, name, url, ""));
+    } else if (tiled) {
+        rawSources->setNext(std::make_unique<NetworkDataSource>(platform, url, std::move(subdomains)));
+    }
+
+    std::shared_ptr<TileSource> sourcePtr;
+
+    if (type == "GeoJSON" && !tiled) {
+        sourcePtr = std::make_shared<ClientGeoJsonSource>(platform, name, url, minDisplayZoom, maxDisplayZoom, maxZoom, zoomBias);
+    } else if (type == "Raster") {
+        TextureOptions options = {GL_RGBA, GL_RGBA, {GL_LINEAR, GL_LINEAR}, {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE} };
+        bool generateMipmaps = false;
+        if (Node filtering = source["filtering"]) {
+            if (extractTexFiltering(filtering, options.filtering)) {
+                generateMipmaps = true;
+            }
+        }
+
+        sourcePtr = std::make_shared<RasterSource>(name, std::move(rawSources),
+                                                   minDisplayZoom, maxDisplayZoom, maxZoom, zoomBias,
+                                                   options, generateMipmaps);
+    } else {
+        sourcePtr = std::make_shared<TileSource>(name, std::move(rawSources),
+                                                 minDisplayZoom, maxDisplayZoom, maxZoom, zoomBias);
+
+        if (type == "GeoJSON") {
+            sourcePtr->setFormat(TileSource::Format::GeoJson);
+        } else if (type == "TopoJSON") {
+            sourcePtr->setFormat(TileSource::Format::TopoJson);
+        } else if (type == "MVT") {
+            sourcePtr->setFormat(TileSource::Format::Mvt);
+        } else {
+            LOGE("Source '%s' does not have a valid type. Valid types are 'GeoJSON', 'TopoJSON', and 'MVT'. " \
+                "This source will be ignored.", name.c_str());
+            return;
+        }
+    }
+
+    _scene->tileSources().push_back(sourcePtr);
+
+    if (auto rasters = source["rasters"]) {
+        loadSourceRasters(platform, sourcePtr, source["rasters"], sources, _scene);
+    }
+
+}
+
+void SceneLoader::loadSourceRasters(const std::shared_ptr<Platform>& platform, std::shared_ptr<TileSource> &source, Node rasterNode, const Node& sources,
+                                    const std::shared_ptr<Scene>& scene) {
+    if (rasterNode.IsSequence()) {
+        for (const auto& raster : rasterNode) {
+            std::string srcName = raster.Scalar();
+            try {
+                loadSource(platform, srcName, sources[srcName], sources, scene);
+            } catch (YAML::RepresentationException e) {
+                LOGNode("Parsing sources: '%s'", sources[srcName], e.what());
+                return;
+            }
+            source->addRasterSource(scene->getTileSource(srcName));
+        }
+    }
+}
+
+void SceneLoader::parseLightPosition(Node position, PointLight& light) {
+    if (position.IsSequence()) {
+        UnitVec<glm::vec3> lightPos;
+        std::string positionSequence;
+
+        // Evaluate sequence separated by ',' to parse with parseVec3
+        for (auto n : position) {
+            positionSequence += n.Scalar() + ",";
+        }
+
+        StyleParam::parseVec3(positionSequence, {Unit::meter, Unit::pixel}, lightPos);
+        light.setPosition(lightPos);
+    } else {
+        LOGNode("Wrong light position parameter", position);
+    }
+}
+
+void SceneLoader::loadLight(const std::pair<Node, Node>& node, const std::shared_ptr<Scene>& scene) {
+
+    const Node light = node.second;
+    const std::string& name = node.first.Scalar();
+    const std::string& type = light["type"].Scalar();
+
+    if (Node visible = light["visible"]) {
+        // If 'visible' is false, skip loading this light.
+        if (!visible.as<bool>(true)) { return; }
+    }
+
+    std::unique_ptr<Light> sceneLight;
+
+    if (type == "ambient") {
+        sceneLight = std::make_unique<AmbientLight>(name);
+
+    } else if (type == "directional") {
+        auto dLight(std::make_unique<DirectionalLight>(name));
+
+        if (Node direction = light["direction"]) {
+            dLight->setDirection(parseVec<glm::vec3>(direction));
+        }
+        sceneLight = std::move(dLight);
+
+    } else if (type == "point") {
+        auto pLight(std::make_unique<PointLight>(name));
+
+        if (Node position = light["position"]) {
+            parseLightPosition(position, *pLight);
+        }
+        if (Node radius = light["radius"]) {
+            if (radius.size() > 1) {
+                pLight->setRadius(radius[0].as<float>(), radius[1].as<float>());
+            } else {
+                pLight->setRadius(radius.as<float>());
+            }
+        }
+        if (Node att = light["attenuation"]) {
+            pLight->setAttenuation(att.as<float>());
+        }
+        sceneLight = std::move(pLight);
+
+    } else if (type == "spotlight") {
+        auto sLight(std::make_unique<SpotLight>(name));
+
+        if (Node position = light["position"]) {
+            parseLightPosition(position, *sLight);
+        }
+        if (Node direction = light["direction"]) {
+            sLight->setDirection(parseVec<glm::vec3>(direction));
+        }
+        if (Node radius = light["radius"]) {
+            if (radius.size() > 1) {
+                sLight->setRadius(radius[0].as<float>(), radius[1].as<float>());
+            } else {
+                sLight->setRadius(radius.as<float>());
+            }
+        }
+        if (Node angle = light["angle"]) {
+            sLight->setCutoffAngle(angle.as<float>());
+        }
+        if (Node exponent = light["exponent"]) {
+            sLight->setCutoffExponent(exponent.as<float>());
+        }
+        sceneLight = std::move(sLight);
+    }
+    if (Node origin = light["origin"]) {
+        const std::string& originStr = origin.Scalar();
+        if (originStr == "world") {
+            sceneLight->setOrigin(LightOrigin::world);
+        } else if (originStr == "camera") {
+            sceneLight->setOrigin(LightOrigin::camera);
+        } else if (originStr == "ground") {
+            sceneLight->setOrigin(LightOrigin::ground);
+        }
+    }
+    if (Node ambient = light["ambient"]) {
+        sceneLight->setAmbientColor(getColorAsVec4(ambient));
+    }
+    if (Node diffuse = light["diffuse"]) {
+        sceneLight->setDiffuseColor(getColorAsVec4(diffuse));
+    }
+    if (Node specular = light["specular"]) {
+        sceneLight->setSpecularColor(getColorAsVec4(specular));
+    }
+
+    // Verify that light position parameters are consistent with the origin type
+    if (sceneLight->getType() == LightType::point || sceneLight->getType() == LightType::spot) {
+        auto pLight = static_cast<PointLight&>(*sceneLight);
+        auto lightPosition = pLight.getPosition();
+        LightOrigin origin = pLight.getOrigin();
+
+        if (origin == LightOrigin::world) {
+            if (lightPosition.units[0] == Unit::pixel || lightPosition.units[1] == Unit::pixel) {
+                LOGW("Light position with attachment %s may not be used with unit of type %s",
+                    lightOriginString(origin).c_str(), unitString(Unit::pixel).c_str());
+                LOGW("Long/Lat expected in meters");
+            }
+        }
+    }
+
+    scene->lights().push_back(std::move(sceneLight));
+}
+
+void SceneLoader::loadCamera(const Node& _camera, const std::shared_ptr<Scene>& _scene) {
+
+    auto& camera = _scene->camera();
+
+    if (Node active = _camera["active"]) {
+        if (!active.as<bool>()) {
+            return;
+        }
+    }
+
+    auto type = _camera["type"].Scalar();
+    if (type == "perspective") {
+        camera.type = CameraType::perspective;
+
+        // Only one of focal length and FOV is applied;
+        // according to docs, focal length takes precedence.
+        if (Node focal = _camera["focal_length"]) {
+            if (focal.IsScalar()) {
+                float length = focal.as<float>();
+                camera.fieldOfView = View::focalLengthToFieldOfView(length);
+            } else if (focal.IsSequence()) {
+                camera.fovStops = std::make_shared<Stops>(Stops::Numbers(focal));
+                for (auto& f : camera.fovStops->frames) {
+                    f.value = View::focalLengthToFieldOfView(f.value.get<float>());
+                }
+            }
+        } else if (Node fov = _camera["fov"]) {
+            if (fov.IsScalar()) {
+                float degrees = fov.as<float>(camera.fieldOfView * RAD_TO_DEG);
+                camera.fieldOfView = degrees * DEG_TO_RAD;
+
+            } else if (fov.IsSequence()) {
+                camera.fovStops = std::make_shared<Stops>(Stops::Numbers(fov));
+                for (auto& f : camera.fovStops->frames) {
+                    f.value = float(f.value.get<float>() * DEG_TO_RAD);
+                }
+            }
+        }
+
+        if (Node vanishing = _camera["vanishing_point"]) {
+            if (vanishing.IsSequence() && vanishing.size() >= 2) {
+                // Values are pixels, unit strings are ignored.
+                float x = ff::stof(vanishing[0].Scalar());
+                float y = ff::stof(vanishing[1].Scalar());
+                camera.vanishingPoint = { x, y };
+            }
+        }
+    } else if (type == "isometric") {
+        camera.type = CameraType::isometric;
+
+        if (Node axis = _camera["axis"]) {
+            camera.obliqueAxis = { axis[0].as<float>(), axis[1].as<float>() };
+
+        }
+    } else if (type == "flat") {
+        camera.type = CameraType::flat;
+    }
+
+    // Default is world origin at 0 zoom
+    double x = 0;
+    double y = 0;
+    float z = 0;
+
+    if (Node position = _camera["position"]) {
+        x = position[0].as<double>();
+        y = position[1].as<double>();
+        if (position.size() > 2) {
+            z = position[2].as<float>();
+        }
+    }
+
+    if (Node zoom = _camera["zoom"]) {
+        z = zoom.as<float>();
+    }
+
+    if (Node maxTilt = _camera["max_tilt"]) {
+        if (maxTilt.IsSequence()) {
+            camera.maxTiltStops = std::make_shared<Stops>(Stops::Numbers(maxTilt));
+        } else if (maxTilt.IsScalar()) {
+            camera.maxTilt = maxTilt.as<float>(PI);
+        }
+    }
+
+    _scene->startPosition = glm::dvec2(x, y);
+    _scene->startZoom = z;
+}
+
+void SceneLoader::loadCameras(Node _cameras, const std::shared_ptr<Scene>& _scene) {
+
+    // To correctly match the behavior of the webGL library we'll need a place
+    // to store multiple view instances.  Since we only have one global view
+    // right now, we'll just apply the settings from the first active camera we
+    // find.
+
+    for (const auto& entry : _cameras) {
+        loadCamera(entry.second, _scene);
+    }
+}
+
+Filter SceneLoader::generateFilter(Node _filter, Scene& scene) {
+
+    switch (_filter.Type()) {
+    case NodeType::Scalar: {
+
+        const std::string& val = _filter.Scalar();
+        if (val.compare(0, 8, "function") == 0) {
+            return Filter::MatchFunction(scene.addJsFunction(val));
+        }
+        return Filter();
+    }
+    case NodeType::Sequence: {
+        return generateAnyFilter(_filter, scene);
+    }
+    case NodeType::Map: {
+        std::vector<Filter> filters;
+        for (const auto& filtItr : _filter) {
+            const std::string& key = filtItr.first.Scalar();
+            Node node = _filter[key];
+            Filter f;
+            if (key == "none") {
+                f = generateNoneFilter(node, scene);
+            } else if (key == "not") {
+                f = generateNoneFilter(node, scene);
+            } else if (key == "any") {
+                f = generateAnyFilter(node, scene);
+            } else if (key == "all") {
+                f = generateAllFilter(node, scene);
+            } else {
+                f = generatePredicate(node, key);
+            }
+
+            if (f.isValid()) { filters.push_back(std::move(f)); }
+        }
+
+        if (!filters.empty()) {
+            if (filters.size() == 1) { return filters.front(); }
+
+            return Filter::MatchAll(std::move(filters));
+        }
+        return Filter();
+    }
+    default:
+        return Filter();
+    }
+}
+
+Filter SceneLoader::generatePredicate(Node _node, std::string _key) {
+
+    switch (_node.Type()) {
+    case NodeType::Scalar: {
+        if (_node.Tag() == "tag:yaml.org,2002:str") {
+            // Node was explicitly tagged with '!!str' or the canonical tag
+            // 'tag:yaml.org,2002:str' yaml-cpp normalizes the tag value to the
+            // canonical form
+            return Filter::MatchEquality(_key, { Value(_node.as<std::string>()) });
+        }
+        double number;
+        if (getDouble(_node, number)) {
+            return Filter::MatchEquality(_key, { Value(number) });
+        }
+        bool existence;
+        if (getBool(_node, existence)) {
+            return Filter::MatchExistence(_key, existence);
+        }
+        const std::string& value = _node.Scalar();
+        return Filter::MatchEquality(_key, { Value(std::move(value)) });
+    }
+    case NodeType::Sequence: {
+        std::vector<Value> values;
+        for (const auto& valItr : _node) {
+            double number;
+            if (getDouble(valItr, number)) {
+                values.emplace_back(number);
+            } else {
+                const std::string& value = valItr.Scalar();
+                values.emplace_back(std::move(value));
+            }
+        }
+        return Filter::MatchEquality(_key, std::move(values));
+    }
+    case NodeType::Map: {
+        double minVal = -std::numeric_limits<double>::infinity();
+        double maxVal = std::numeric_limits<double>::infinity();
+        bool hasMinPixelArea = false;
+        bool hasMaxPixelArea = false;
+
+        for (const auto& n : _node) {
+            if (n.first.Scalar() == "min") {
+                if(!getFilterRangeValue(n.second, minVal, hasMinPixelArea)) {
+                    return Filter();
+                }
+            } else if (n.first.Scalar() == "max") {
+                if (!getFilterRangeValue(n.second, maxVal, hasMaxPixelArea)) {
+                    return Filter();
+                }
+            }
+        }
+
+        if (_node["max"].IsScalar() && _node["min"].IsScalar() &&
+                (hasMinPixelArea != hasMaxPixelArea)) { return Filter(); }
+
+        return Filter::MatchRange(_key, minVal, maxVal, hasMinPixelArea | hasMaxPixelArea);
+    }
+    default:
+        return Filter();
+    }
+}
+
+bool SceneLoader::getFilterRangeValue(const Node& node, double& val, bool& hasPixelArea) {
+    if (!getDouble(node, val)) {
+        auto strVal = node.Scalar();
+        auto n = strVal.find("px2");
+        if (n == std::string::npos) { return false; }
+        try {
+            val = ff::stof(std::string(strVal, 0, n));
+            hasPixelArea = true;
+        } catch (std::invalid_argument) { return false; }
+    }
+    return true;
+}
+
+Filter SceneLoader::generateAnyFilter(Node _filter, Scene& scene) {
+
+    if (_filter.IsSequence()) {
+        std::vector<Filter> filters;
+
+        for (const auto& filt : _filter) {
+            if (Filter f = generateFilter(filt, scene)) {
+                filters.push_back(std::move(f));
+            } else { return Filter(); }
+        }
+        return Filter::MatchAny(std::move(filters));
+    }
+    return Filter();
+}
+
+Filter SceneLoader::generateAllFilter(Node _filter, Scene& scene) {
+
+    if (_filter.IsSequence()) {
+        std::vector<Filter> filters;
+
+        for (const auto& filt : _filter) {
+            if (Filter f = generateFilter(filt, scene)) {
+                filters.push_back(std::move(f));
+            } else { return Filter(); }
+        }
+        return Filter::MatchAll(std::move(filters));
+    }
+    return Filter();
+}
+
+Filter SceneLoader::generateNoneFilter(Node _filter, Scene& scene) {
+
+    if (_filter.IsSequence()) {
+        std::vector<Filter> filters;
+
+        for (const auto& filt : _filter) {
+            if (Filter f = generateFilter(filt, scene)) {
+                filters.push_back(std::move(f));
+            } else { return Filter(); }
+        }
+        return Filter::MatchNone(std::move(filters));
+
+    } else if (_filter.IsMap() || _filter.IsScalar()) {
+        // 'not' case
+        if (Filter f = generateFilter(_filter, scene)) {
+            return Filter::MatchNone({std::move(f)});
+        }
+    }
+    return Filter();
+}
+
+void SceneLoader::parseStyleParams(Node params, const std::shared_ptr<Scene>& scene, const std::string& prefix,
+                                   std::vector<StyleParam>& out) {
+
+    for (const auto& prop : params) {
+
+        std::string key;
+        if (!prefix.empty()) {
+            key = prefix + DELIMITER + prop.first.Scalar();
+        } else {
+            key = prop.first.Scalar();
+        }
+        if (key == "transition" || key == "text:transition") {
+            parseTransition(prop.second, scene, key, out);
+            continue;
+        }
+
+        if (key == "text") {
+            // Add StyleParam to signify that icon uses text
+            out.push_back(StyleParam{ StyleParamKey::point_text, "" });
+        }
+
+        Node value = prop.second;
+
+        switch (value.Type()) {
+        case NodeType::Scalar: {
+            const std::string& val = value.Scalar();
+
+            if (val.compare(0, 8, "function") == 0) {
+                StyleParam param(key, "");
+                param.function = scene->addJsFunction(val);
+                out.push_back(std::move(param));
+            } else {
+                out.push_back(StyleParam{ key, val });
+            }
+            break;
+        }
+        case NodeType::Sequence: {
+            if (value[0].IsSequence()) {
+                auto styleKey = StyleParam::getKey(key);
+                if (styleKey != StyleParamKey::none) {
+
+                    if (StyleParam::isColor(styleKey)) {
+                        scene->stops().push_back(Stops::Colors(value));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    } else if (StyleParam::isSize(styleKey)) {
+                        scene->stops().push_back(Stops::Sizes(value, StyleParam::unitsForStyleParam(styleKey)));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    } else if (StyleParam::isWidth(styleKey)) {
+                        scene->stops().push_back(Stops::Widths(value, *scene->mapProjection(),
+                                                              StyleParam::unitsForStyleParam(styleKey)));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    } else if (StyleParam::isOffsets(styleKey)) {
+                        scene->stops().push_back(Stops::Offsets(value, StyleParam::unitsForStyleParam(styleKey)));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    } else if (StyleParam::isFontSize(styleKey)) {
+                        scene->stops().push_back(Stops::FontSize(value));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    } else if (StyleParam::isNumberType(styleKey)) {
+                        scene->stops().push_back(Stops::Numbers(value));
+                        out.push_back(StyleParam{ styleKey, &(scene->stops().back()) });
+                    }
+                } else {
+                    LOGW("Unknown style parameter %s", key.c_str());
+                }
+
+            } else {
+                // TODO optimize for color values
+                out.push_back(StyleParam{ key, parseSequence(value) });
+            }
+            break;
+        }
+        case NodeType::Map: {
+            // NB: Flatten parameter map
+            parseStyleParams(value, scene, key, out);
+
+            break;
+        }
+        default:
+            LOGW("Style parameter %s must be a scalar, sequence, or map.", key.c_str());
+        }
+    }
+}
+
+bool SceneLoader::parseStyleUniforms(const std::shared_ptr<Platform>& platform, const Node& value, const std::shared_ptr<Scene>& scene, StyleUniform& styleUniform) {
+    if (value.IsScalar()) { // float, bool or string (texture)
+        double fValue;
+        bool bValue;
+
+        if (getDouble(value, fValue)) {
+            styleUniform.type = "float";
+            styleUniform.value = (float)fValue;
+        } else if (getBool(value, bValue)) {
+            styleUniform.type = "bool";
+            styleUniform.value = (bool)bValue;
+        } else {
+            const std::string& strVal = value.Scalar();
+            styleUniform.type = "sampler2D";
+
+            if (scene) {
+                std::shared_ptr<Texture> texture = scene->getTexture(strVal);
+
+                if (!texture && !loadTexture(platform, strVal, scene)) {
+                    LOGW("Can't load texture with name %s", strVal.c_str());
+                    return false;
+                }
+            }
+
+            styleUniform.value = strVal;
+        }
+    } else if (value.IsSequence()) {
+        int size = value.size();
+        try {
+            switch (size) {
+                case 2:
+                    styleUniform.value = parseVec<glm::vec2>(value);
+                    break;
+                case 3:
+                    styleUniform.value = parseVec<glm::vec3>(value);
+                    break;
+                case 4:
+                    styleUniform.value = parseVec<glm::vec4>(value);
+                    break;
+                default:
+                    UniformArray1f uniformArray;
+                    for (const auto& val : value) {
+                        double fValue;
+                        if (getDouble(val, fValue)) {
+                            uniformArray.push_back(fValue);
+                        } else {
+                            return false;
+                        }
+                    }
+                    styleUniform.value = std::move(uniformArray);
+                    break;
+            }
+
+            styleUniform.type = "vec" + std::to_string(size);
+        } catch (const BadConversion& e) { // array of strings (textures)
+            UniformTextureArray textureArrayUniform;
+            textureArrayUniform.names.reserve(size);
+            styleUniform.type = "sampler2D";
+
+            for (const auto& strVal : value) {
+                const std::string& textureName = strVal.Scalar();
+                textureArrayUniform.names.push_back(textureName);
+
+                if (scene) {
+                    std::shared_ptr<Texture> texture = scene->getTexture(textureName);
+
+                    if (!texture && !loadTexture(platform, textureName, scene)) {
+                        LOGW("Can't load texture with name %s", textureName.c_str());
+                        return false;
+                    }
+                }
+            }
+
+            styleUniform.value = std::move(textureArrayUniform);
+        }
+    } else {
+        LOGW("Expected a scalar or sequence value for uniforms");
+        return false;
+    }
+
+    return true;
+}
+
+void SceneLoader::parseTransition(Node params, const std::shared_ptr<Scene>& scene, std::string _prefix, std::vector<StyleParam>& out) {
+
+    // First iterate over the mapping of 'events', we currently recognize 'hide', 'selected', and 'show'.
+    for (const auto& event : params) {
+        if (!event.first.IsScalar() || !event.second.IsMap()) {
+            LOGW("Can't parse 'transitions' entry, expected a mapping of strings to mappings at: %s", _prefix.c_str());
+            continue;
+        }
+
+        // Add the event to our key, so it's now 'transition:event'.
+        std::string transitionEvent = _prefix + DELIMITER + event.first.Scalar();
+
+        // Iterate over the parameters in the 'event', we currently only recognize 'time'.
+        for (const auto& param : event.second) {
+            if (!param.first.IsScalar() || !param.second.IsScalar()) {
+                LOGW("Expected a mapping of strings to strings or numbers in: %s", transitionEvent.c_str());
+                continue;
+            }
+            // Add the parameter to our key, so it's now 'transition:event:param'.
+            std::string transitionEventParam = transitionEvent + DELIMITER + param.first.Scalar();
+            // Create a style parameter from the key and value.
+            out.push_back(StyleParam{ transitionEventParam, param.second.Scalar() });
+        }
+    }
+}
+
+SceneLayer SceneLoader::loadSublayer(const Node& layer, const std::string& layerName, const std::shared_ptr<Scene>& scene) {
+
+    std::vector<SceneLayer> sublayers;
+    std::vector<DrawRuleData> rules;
+    Filter filter;
+    bool enabled = true;
+
+    for (const auto& member : layer) {
+
+        const std::string& key = member.first.Scalar();
+
+        if (key == "data") {
+            // Ignored for sublayers
+        } else if (key == "draw") {
+            // Member is a mapping of draw rules
+            for (auto& ruleNode : member.second) {
+
+                std::vector<StyleParam> params;
+                parseStyleParams(ruleNode.second, scene, "", params);
+
+                const std::string& ruleName = ruleNode.first.Scalar();
+                int ruleId = scene->addIdForName(ruleName);
+
+                rules.push_back({ ruleName, ruleId, std::move(params) });
+            }
+        } else if (key == "filter") {
+            filter = generateFilter(member.second, *scene);
+            if (!filter.isValid()) {
+                LOGNode("Invalid 'filter' in layer '%s'", member.second, layerName.c_str());
+                return { layerName, {}, {}, {}, false };
+            }
+        } else if (key == "visible") {
+            if (!layer["enabled"].IsDefined()) {
+                YAML::convert<bool>::decode(member.second, enabled);
+            }
+        } else if (key == "enabled") {
+            YAML::convert<bool>::decode(member.second, enabled);
+        } else {
+            // Member is a sublayer
+            sublayers.push_back(loadSublayer(member.second, (layerName + DELIMITER + key), scene));
+        }
+    }
+
+    return { layerName, std::move(filter), rules, std::move(sublayers), enabled };
+}
+
+void SceneLoader::loadLayer(const std::pair<Node, Node>& layer, const std::shared_ptr<Scene>& scene) {
+
+    const std::string& name = layer.first.Scalar();
+
+    std::string source;
+    std::vector<std::string> collections;
+
+    if (Node data = layer.second["data"]) {
+        if (Node data_source = data["source"]) {
+            if (data_source.IsScalar()) {
+                source = data_source.Scalar();
+                auto dataSource = scene->getTileSource(source);
+                if (dataSource) {
+                    dataSource->generateGeometry(true);
+                } else {
+                    LOGW("Can't find data source %s for layer %s", source.c_str(), name.c_str());
+                }
+            }
+        }
+
+        if (Node data_layer = data["layer"]) {
+            if (data_layer.IsScalar()) {
+                collections.push_back(data_layer.Scalar());
+            } else if (data_layer.IsSequence()) {
+                collections = data_layer.as<std::vector<std::string>>();
+            }
+        }
+    }
+
+    if (collections.empty()) {
+        collections.push_back(name);
+    }
+
+    auto sublayer = loadSublayer(layer.second, name, scene);
+
+    scene->layers().push_back({ std::move(sublayer), source, collections });
+}
+
+void SceneLoader::loadBackground(Node background, const std::shared_ptr<Scene>& scene) {
+
+    if (!background) { return; }
+
+    if (Node colorNode = background["color"]) {
+        std::string str;
+        if (colorNode.IsScalar()) {
+            str = colorNode.Scalar();
+        } else if (colorNode.IsSequence()) {
+            str = parseSequence(colorNode);
+        }
+        scene->background().abgr = StyleParam::parseColor(str);
+    }
+}
+
+}
diff --git a/core/src/scene/sceneLoader.h b/core/src/scene/sceneLoader.h
new file mode 100644 (file)
index 0000000..2f72375
--- /dev/null
@@ -0,0 +1,109 @@
+#pragma once
+
+#include "gl/uniform.h"
+#include "scene/scene.h"
+#include "tangram.h"
+
+#include <cassert>
+#include <memory>
+#include <mutex>
+#include <sstream>
+#include <string>
+#include <tuple>
+#include <vector>
+
+#include "yaml-cpp/yaml.h"
+#include "glm/vec2.hpp"
+#include "glm/vec3.hpp"
+#include "glm/vec4.hpp"
+
+namespace Tangram {
+
+class Material;
+class PointLight;
+class SceneLayer;
+class ShaderProgram;
+class Style;
+class TileManager;
+class TileSource;
+class View;
+struct Filter;
+struct MaterialTexture;
+struct StyleParam;
+struct TextureFiltering;
+struct TextureOptions;
+
+// 0: type, 1: values
+struct StyleUniform {
+    std::string type;
+    UniformValue value;
+};
+
+struct SceneLoader {
+    using Node = YAML::Node;
+
+    static bool loadScene(const std::shared_ptr<Platform>& _platform, std::shared_ptr<Scene> _scene,
+                          const std::vector<SceneUpdate>& updates = {}, SceneUpdateErrorCallback _onSceneUpdateError = nullptr);
+    static bool applyConfig(const std::shared_ptr<Platform>& platform, const std::shared_ptr<Scene>& scene);
+    static bool applyUpdates(const std::shared_ptr<Platform>& platform, Scene& scene,
+                             const std::vector<SceneUpdate>& updates, SceneUpdateErrorCallback onSceneUpdateError = nullptr);
+    static void applyGlobals(Node root, Scene& scene);
+
+    /*** all public for testing ***/
+
+    static void loadBackground(Node background, const std::shared_ptr<Scene>& scene);
+    static void loadSource(const std::shared_ptr<Platform>& platform, const std::string& name,
+                           const Node& source, const Node& sources, const std::shared_ptr<Scene>& scene);
+    static void loadSourceRasters(const std::shared_ptr<Platform>& platform, std::shared_ptr<TileSource>& source, Node rasterNode,
+                                  const Node& sources, const std::shared_ptr<Scene>& scene);
+    static void loadTexture(const std::shared_ptr<Platform>& platform, const std::pair<Node, Node>& texture, const std::shared_ptr<Scene>& scene);
+    static void loadLayer(const std::pair<Node, Node>& layer, const std::shared_ptr<Scene>& scene);
+    static void loadLight(const std::pair<Node, Node>& light, const std::shared_ptr<Scene>& scene);
+    static void loadCameras(Node cameras, const std::shared_ptr<Scene>& scene);
+    static void loadCamera(const Node& camera, const std::shared_ptr<Scene>& scene);
+    static void loadStyleProps(const std::shared_ptr<Platform>& platform, Style& style, Node styleNode, const std::shared_ptr<Scene>& scene);
+    static void loadMaterial(const std::shared_ptr<Platform>& platform, Node matNode, Material& material, const std::shared_ptr<Scene>& scene, Style& style);
+    static void loadShaderConfig(const std::shared_ptr<Platform>& platform, Node shaders, Style& style, const std::shared_ptr<Scene>& scene);
+    static void loadFont(const std::shared_ptr<Platform>& platform, const std::pair<Node, Node>& font, const std::shared_ptr<Scene>& scene);
+    static SceneLayer loadSublayer(const Node& layer, const std::string& name, const std::shared_ptr<Scene>& scene);
+    static Filter generateFilter(Node filter, Scene& scene);
+    static Filter generateAnyFilter(Node filter, Scene& scene);
+    static Filter generateAllFilter(Node filter, Scene& scene);
+    static Filter generateNoneFilter(Node filter, Scene& scene);
+    static Filter generatePredicate(Node filter, std::string _key);
+    static bool getFilterRangeValue(const Node& node, double& val, bool& hasPixelArea);
+    /* loads a texture with default texture properties */
+    static bool loadTexture(const std::shared_ptr<Platform>& platform, const std::string& url, const std::shared_ptr<Scene>& scene);
+    static std::shared_ptr<Texture> fetchTexture(const std::shared_ptr<Platform>& platform, const std::string& name, const std::string& url,
+            const TextureOptions& options, bool generateMipmaps, const std::shared_ptr<Scene>& scene);
+    static bool extractTexFiltering(Node& filtering, TextureFiltering& filter);
+
+    /*
+     * Sprite nodes are created using a default 1x1 black texture when sprite atlas is requested over the network.
+     * Once a sprite atlas has been fetched, sprite nodes need to be updated according to the width/height of the
+     * fetched sprite atlas.
+     */
+    static void updateSpriteNodes(const std::string& texName,
+            std::shared_ptr<Texture>& texture, const std::shared_ptr<Scene>& scene);
+
+    static MaterialTexture loadMaterialTexture(const std::shared_ptr<Platform>& platform, Node matCompNode,
+                                               const std::shared_ptr<Scene>& scene, Style& style);
+
+    static void parseStyleParams(Node params, const std::shared_ptr<Scene>& scene, const std::string& propPrefix,
+                                 std::vector<StyleParam>& out);
+    static void parseTransition(Node params, const std::shared_ptr<Scene>& scene, std::string _prefix, std::vector<StyleParam>& out);
+
+    static bool parseStyleUniforms(const std::shared_ptr<Platform>& platform, const Node& value,
+                                   const std::shared_ptr<Scene>& scene, StyleUniform& styleUniform);
+
+    static void parseLightPosition(Node position, PointLight& light);
+
+    static bool loadStyle(const std::shared_ptr<Platform>& platform, const std::string& styleName,
+                          Node config, const std::shared_ptr<Scene>& scene);
+
+    static std::mutex m_textureMutex;
+    SceneLoader() = delete;
+
+};
+
+}
diff --git a/core/src/scene/spotLight.cpp b/core/src/scene/spotLight.cpp
new file mode 100644 (file)
index 0000000..9360c04
--- /dev/null
@@ -0,0 +1,93 @@
+#include "scene/spotLight.h"
+
+#include "gl/shaderProgram.h"
+#include "platform.h"
+#include "spotLight_glsl.h"
+#include "util/floatFormatter.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+std::string SpotLight::s_typeName = "SpotLight";
+
+SpotLight::SpotLight(const std::string& _name, bool _dynamic) :
+    PointLight(_name, _dynamic),
+    m_direction(1.0,0.0,0.0),
+    m_spotExponent(0.0),
+    m_spotCutoff(0.0),
+    m_spotCosCutoff(0.0) {
+
+    m_type = LightType::spot;
+}
+
+SpotLight::~SpotLight() {}
+
+void SpotLight::setDirection(const glm::vec3 &_dir) {
+    m_direction = _dir;
+}
+
+void SpotLight::setCutoffAngle(float _cutoffAngle) {
+    m_spotCutoff = _cutoffAngle;
+    m_spotCosCutoff = cos(_cutoffAngle * 3.14159 / 180.0);
+}
+
+void SpotLight::setCutoffExponent(float _exponent) {
+    m_spotExponent = _exponent;
+}
+
+std::unique_ptr<LightUniforms> SpotLight::getUniforms() {
+
+    if (!m_dynamic) { return nullptr; }
+
+    return std::make_unique<Uniforms>(getUniformName());
+}
+
+void SpotLight::setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                             LightUniforms& _uniforms) {
+    PointLight::setupProgram(rs, _view, _shader, _uniforms);
+
+    glm::vec3 direction = m_direction;
+    if (m_origin == LightOrigin::world) {
+        direction = glm::normalize(_view.getNormalMatrix() * direction);
+    }
+
+    auto& u = static_cast<Uniforms&>(_uniforms);
+    _shader.setUniformf(rs, u.direction, direction);
+    _shader.setUniformf(rs, u.spotCosCutoff, m_spotCosCutoff);
+    _shader.setUniformf(rs, u.spotExponent, m_spotExponent);
+}
+
+std::string SpotLight::getClassBlock() {
+    return SHADER_SOURCE(spotLight_glsl);
+}
+
+std::string SpotLight::getInstanceAssignBlock() {
+    std::string block = Light::getInstanceAssignBlock();
+
+    if (!m_dynamic) {
+        block += ", " + ff::to_string(m_position.value);
+        if (m_attenuation!=0.0) {
+            block += ", " + ff::to_string(m_attenuation);
+        }
+        if (m_innerRadius!=0.0) {
+            block += ", " + ff::to_string(m_innerRadius);
+        }
+        if (m_outerRadius!=0.0) {
+            block += ", " + ff::to_string(m_outerRadius);
+        }
+
+        block += ", " + ff::to_string(m_direction);
+        block += ", " + ff::to_string(m_spotCosCutoff);
+        block += ", " + ff::to_string(m_spotExponent);
+        block += ")";
+    }
+    return block;
+}
+
+const std::string& SpotLight::getTypeName() {
+
+    return s_typeName;
+
+}
+
+}
diff --git a/core/src/scene/spotLight.h b/core/src/scene/spotLight.h
new file mode 100644 (file)
index 0000000..805c423
--- /dev/null
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "scene/pointLight.h"
+
+#include "glm/vec3.hpp"
+
+namespace Tangram {
+
+class SpotLight : public PointLight {
+public:
+
+    SpotLight(const std::string& _name, bool _dynamic = false);
+    virtual ~SpotLight();
+
+    /*  Set the direction of the light */
+    virtual void setDirection(const glm::vec3& _dir);
+
+    /*  Set the properties of the cutoff light cone */
+    virtual void setCutoffAngle(float _cutoffConeDegrees);
+
+    virtual void setCutoffExponent(float _exponent);
+
+    virtual void setupProgram(RenderState& rs, const View& _view, ShaderProgram& _shader,
+                              LightUniforms& _uniforms) override;
+
+    struct Uniforms : public PointLight::Uniforms {
+
+        Uniforms(const std::string& _name)
+            : PointLight::Uniforms(_name),
+            direction(_name+".direction"),
+            spotCosCutoff(_name+".spotCosCutoff"),
+            spotExponent(_name+".spotExponent") {}
+
+        UniformLocation direction;
+        UniformLocation spotCosCutoff;
+        UniformLocation spotExponent;
+    };
+
+    std::unique_ptr<LightUniforms> getUniforms() override;
+
+protected:
+    /*  GLSL block code with structs and need functions for this light type */
+    virtual std::string getClassBlock() override;
+    virtual std::string getInstanceAssignBlock() override;
+    virtual const std::string& getTypeName() override;
+
+    glm::vec3 m_direction;
+
+    float m_spotExponent;
+    float m_spotCutoff;
+    float m_spotCosCutoff;
+
+private:
+
+    static std::string s_typeName;
+
+};
+
+}
diff --git a/core/src/scene/spriteAtlas.cpp b/core/src/scene/spriteAtlas.cpp
new file mode 100644 (file)
index 0000000..ddde881
--- /dev/null
@@ -0,0 +1,44 @@
+#include "scene/spriteAtlas.h"
+
+#include "platform.h"
+
+namespace Tangram {
+
+SpriteAtlas::SpriteAtlas(std::shared_ptr<Texture> _texture) : m_texture(_texture) {}
+
+void SpriteAtlas::addSpriteNode(const std::string& _name, glm::vec2 _origin, glm::vec2 _size) {
+
+    float atlasWidth = m_texture->getWidth();
+    float atlasHeight = m_texture->getHeight();
+    float uvL = _origin.x / atlasWidth;
+    float uvR = uvL + _size.x / atlasWidth;
+    float uvB = 1.f - _origin.y / atlasHeight;
+    float uvT = uvB - _size.y / atlasHeight;
+
+    m_spritesNodes[_name] = SpriteNode { { uvL, uvB }, { uvR, uvT }, _size, _origin };
+}
+
+bool SpriteAtlas::getSpriteNode(const std::string& _name, SpriteNode& _node) const {
+    auto it = m_spritesNodes.find(_name);
+    if (it == m_spritesNodes.end()) {
+        return false;
+    }
+
+    _node = it->second;
+    return true;
+}
+
+void SpriteAtlas::updateSpriteNodes(std::shared_ptr<Texture> _texture) {
+    m_texture = _texture;
+    for (auto& spriteNode : m_spritesNodes) {
+        // Use the origin of the spriteNode set when the node was created
+        addSpriteNode(spriteNode.first.k, spriteNode.second.m_origin, spriteNode.second.m_size);
+    }
+}
+
+void SpriteAtlas::bind(RenderState& rs, GLuint _slot) {
+    m_texture->update(rs, _slot);
+    m_texture->bind(rs, _slot);
+}
+
+}
diff --git a/core/src/scene/spriteAtlas.h b/core/src/scene/spriteAtlas.h
new file mode 100644 (file)
index 0000000..d02bae8
--- /dev/null
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "gl/texture.h"
+#include "util/fastmap.h"
+
+#include "glm/glm.hpp"
+#include <map>
+#include <memory>
+
+namespace Tangram {
+
+struct SpriteNode {
+    glm::vec2 m_uvBL;
+    glm::vec2 m_uvTR;
+    glm::vec2 m_size;
+    glm::vec2 m_origin;
+};
+
+class SpriteAtlas {
+
+public:
+    SpriteAtlas(std::shared_ptr<Texture> _texture);
+
+    /* Creates a sprite node in the atlas located at _origin in the texture by a size in pixels _size */
+    void addSpriteNode(const std::string& _name, glm::vec2 _origin, glm::vec2 _size);
+    bool getSpriteNode(const std::string& _name, SpriteNode& _node) const;
+    void updateSpriteNodes(std::shared_ptr<Texture> _texture);
+
+    /* Bind the atlas in the driver */
+    void bind(RenderState& rs, GLuint _slot);
+
+    Texture* texture() { return m_texture.get(); }
+
+private:
+    fastmap<std::string, SpriteNode> m_spritesNodes;
+    std::shared_ptr<Texture> m_texture;
+};
+
+}
diff --git a/core/src/scene/stops.cpp b/core/src/scene/stops.cpp
new file mode 100644 (file)
index 0000000..b9754bf
--- /dev/null
@@ -0,0 +1,410 @@
+#include "scene/stops.h"
+
+#include "platform.h"
+#include "log.h"
+#include "scene/styleParam.h"
+#include "util/mapProjection.h"
+
+#include <algorithm>
+#include "csscolorparser.hpp"
+#include "yaml-cpp/yaml.h"
+
+namespace Tangram {
+
+auto Stops::Colors(const YAML::Node& _node) -> Stops {
+    Stops stops;
+    if (!_node.IsSequence()) { return stops; }
+
+    for (const auto& frameNode : _node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+        float key = frameNode[0].as<float>();
+
+        // parse color from sequence or string
+        Color color;
+        YAML::Node colorNode = frameNode[1];
+        if (colorNode.IsScalar()) {
+            color.abgr = CSSColorParser::parse(colorNode.as<std::string>()).getInt();
+        } else if (colorNode.IsSequence() && colorNode.size() >= 3) {
+            color.r = colorNode[0].as<float>() * 255.;
+            color.g = colorNode[1].as<float>() * 255.;
+            color.b = colorNode[2].as<float>() * 255.;
+            float alpha = colorNode.size() > 3 ? colorNode[3].as<float>() : 1.f;
+            color.a = alpha * 255.;
+        }
+        stops.frames.emplace_back(key, color);
+    }
+    return stops;
+}
+
+double widthMeterToPixel(float _zoom, double _tileSize, double _width) {
+    // pixel per meter at z == 0
+    double meterRes = _tileSize / (2.0 * MapProjection::HALF_CIRCUMFERENCE);
+    // pixel per meter at zoom
+    meterRes *= exp2(_zoom);
+
+    return _width * meterRes;
+}
+
+auto Stops::FontSize(const YAML::Node& _node) -> Stops {
+    Stops stops;
+
+    if (!_node.IsSequence()) {
+        return stops;
+    }
+
+    float lastKey = 0;
+    for (const auto& frameNode : _node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+        float key = frameNode[0].as<float>();
+
+        if (lastKey > key) {
+            LOGW("Invalid stop order: key %f > %f", lastKey, key);
+            continue;
+        }
+
+        lastKey = key;
+        float pixelSize;
+
+        if (StyleParam::parseFontSize(frameNode[1].Scalar(), pixelSize)) {
+            stops.frames.emplace_back(key, pixelSize);
+        } else {
+            LOGW("Error while parsing font size stops: %f %s", key, Dump(frameNode[1]).c_str());
+        }
+    }
+
+    return stops;
+}
+
+auto Stops::Sizes(const YAML::Node& _node, const std::vector<Unit>& _units) -> Stops {
+    Stops stops;
+    if (!_node.IsSequence()) {
+        return stops;
+    }
+
+    float lastKey = 0;
+
+    for (const auto& frameNode : _node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+        float key = frameNode[0].as<float>();
+
+        if (lastKey > key) {
+            LOGW("Invalid stop order: key %f > %f", lastKey, key);
+            continue;
+        }
+        lastKey = key;
+
+        if (frameNode[1].IsScalar()) {
+            StyleParam::ValueUnitPair sizeValue;
+            sizeValue.unit = Unit::pixel;
+            size_t start = 0;
+
+            if (StyleParam::parseValueUnitPair(frameNode[1].Scalar(), start, sizeValue)) {
+                for (auto& unit : _units) {
+                    if (sizeValue.unit != unit) {
+                        LOGW("Size StyleParam can only take in pixel values in: %s", Dump(_node).c_str());
+                    }
+                }
+
+                stops.frames.emplace_back(key, sizeValue.value);
+            } else {
+                LOGW("could not parse node %s\n", Dump(frameNode[1]).c_str());
+            }
+        } else if (frameNode[1].IsSequence()) {
+            std::vector<StyleParam::ValueUnitPair> sizeValues;
+
+            for (const auto& sequenceNode : frameNode[1]) {
+                StyleParam::ValueUnitPair sizeValue;
+                sizeValue.unit = Unit::pixel; // default to pixel
+                if (StyleParam::parseValueUnitPair(sequenceNode.Scalar(), 0, sizeValue)) {
+                    for (auto& unit : _units) {
+                        if (sizeValue.unit != unit) {
+                            LOGW("Size StyleParam can only take in pixel values in: %s", Dump(_node).c_str());
+                        }
+                    }
+                    sizeValues.push_back(sizeValue);
+                } else {
+                    LOGW("could not parse node %s\n", Dump(sequenceNode).c_str());
+                }
+            }
+            if (sizeValues.size() == 2) {
+                stops.frames.emplace_back(key, glm::vec2(sizeValues[0].value, sizeValues[1].value));
+            }
+        }
+    }
+    return stops;
+}
+
+auto Stops::Offsets(const YAML::Node& _node, const std::vector<Unit>& _units) -> Stops {
+    Stops stops;
+    if (!_node.IsSequence()) {
+        return stops;
+    }
+    float lastKey = 0;
+    for (const auto& frameNode : _node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+        float key = frameNode[0].as<float>();
+
+        if (lastKey > key) {
+            LOGW("Invalid stop order: key %f > %f", lastKey, key);
+            continue;
+        }
+        lastKey = key;
+
+        if (frameNode[1].IsSequence()) {
+            std::vector<StyleParam::ValueUnitPair> widths;
+            Unit lastUnit = Unit::pixel;
+
+            for (const auto& sequenceNode : frameNode[1]) {
+                StyleParam::ValueUnitPair width;
+                width.unit = Unit::pixel; // default to pixel
+                if (StyleParam::parseValueUnitPair(sequenceNode.Scalar(), 0, width)) {
+                    widths.push_back(width);
+                    if (lastUnit != width.unit) {
+                        LOGW("Mixed units not allowed for stop values", Dump(frameNode[1]).c_str());
+                    }
+                    lastUnit = width.unit;
+                } else {
+                    LOGW("could not parse node %s", Dump(sequenceNode).c_str());
+                }
+            }
+            if (widths.size() == 2) {
+                if (widths[0].unit != Unit::pixel || widths[1].unit != Unit::pixel) {
+                    LOGW("Non-pixel unit not allowed for multidimensionnal stop values");
+                }
+                stops.frames.emplace_back(key, glm::vec2(widths[0].value, widths[1].value));
+            }
+        }
+    }
+
+    return stops;
+}
+
+auto Stops::Widths(const YAML::Node& _node, const MapProjection& _projection, const std::vector<Unit>& _units) -> Stops {
+    Stops stops;
+    if (!_node.IsSequence()) { return stops; }
+
+    double tileSize = _projection.TileSize();
+
+    bool lastIsMeter = false;
+    float lastKey = 0;
+    float lastMeter = 0;
+
+    for (const auto& frameNode : _node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+        float key = frameNode[0].as<float>();
+
+        if (lastKey > key) {
+            LOGW("Invalid stop order: key %f > %f\n", lastKey, key);
+            continue;
+        }
+        lastKey = key;
+
+        StyleParam::ValueUnitPair width;
+        width.unit = Unit::meter;
+        size_t start = 0;
+
+        if (StyleParam::parseValueUnitPair(frameNode[1].Scalar(), start, width)) {
+            bool valid = false;
+            for (auto& unit : _units) {
+                if (width.unit == unit) {
+                    valid = true;
+                    break;
+                }
+            }
+
+            if (!valid) {
+                LOGW("Invalid unit is being used for stop %s", Dump(frameNode[1]).c_str());
+            }
+
+            if (width.unit == Unit::meter) {
+                float w = widthMeterToPixel(key, tileSize, width.value);
+                stops.frames.emplace_back(key, w);
+
+                lastIsMeter = true;
+                lastMeter = width.value;
+
+            } else {
+                stops.frames.emplace_back(key, width.value);
+                lastIsMeter = false;
+            }
+        } else {
+            LOGW("could not parse node %s\n", Dump(frameNode[1]).c_str());
+        }
+    }
+    // Append stop at max-zoom to continue scaling after the last stop
+    // TODO: define MAX_ZOOM == 24
+    if (lastIsMeter && lastKey < 24) {
+        float w = widthMeterToPixel(24, tileSize, lastMeter);
+        stops.frames.emplace_back(24, w);
+    }
+
+    return stops;
+}
+
+auto Stops::Numbers(const YAML::Node& node) -> Stops {
+    Stops stops;
+    if (!node.IsSequence()) { return stops; }
+
+    float lastKey = 0;
+
+    for (const auto frameNode : node) {
+        if (!frameNode.IsSequence() || frameNode.size() != 2) { continue; }
+
+        float key = frameNode[0].as<float>();
+        if (lastKey > key) {
+            LOGW("Invalid stop order: key %f > %f\n", lastKey, key);
+            continue;
+        }
+        lastKey = key;
+
+        float value = frameNode[1].as<float>();
+        stops.frames.emplace_back(key, value);
+    }
+
+    return stops;
+}
+
+auto Stops::evalExpFloat(float _key) const -> float {
+    if (frames.empty()) { return 0; }
+
+    auto upper = nearestHigherFrame(_key);
+    auto lower = upper - 1;
+
+    if (upper == frames.end())  {
+        return lower->value.get<float>();
+    }
+    if (lower < frames.begin()) {
+        return upper->value.get<float>();
+    }
+
+    if (upper->key <= _key) {
+        return upper->value.get<float>();
+    }
+    if (lower->key >= _key) {
+        return lower->value.get<float>();
+    }
+
+    double range = exp2(upper->key - lower->key) - 1.0;
+    double pos = exp2(_key - lower->key) - 1.0;
+
+    double lerp = pos / range;
+
+    return lower->value.get<float>() * (1 - lerp) + upper->value.get<float>() * lerp;
+}
+
+auto Stops::evalFloat(float _key) const -> float {
+    if (frames.empty()) { return 0; }
+
+    auto upper = nearestHigherFrame(_key);
+    auto lower = upper - 1;
+
+    if (upper == frames.end()) {
+        return lower->value.get<float>();
+    }
+    if (lower < frames.begin()) {
+        return upper->value.get<float>();
+    }
+
+    float lerp = (_key - lower->key) / (upper->key - lower->key);
+
+    return (lower->value.get<float>() * (1 - lerp) + upper->value.get<float>() * lerp);
+}
+
+auto Stops::evalColor(float _key) const -> uint32_t {
+    if (frames.empty()) { return 0; }
+
+    auto upper = nearestHigherFrame(_key);
+    auto lower = upper - 1;
+    if (upper == frames.end())  {
+        return lower->value.get<Color>().abgr;
+    }
+    if (lower < frames.begin()) {
+        return upper->value.get<Color>().abgr;
+    }
+
+    float lerp = (_key - lower->key) / (upper->key - lower->key);
+
+    return Color::mix(lower->value.get<Color>(), upper->value.get<Color>(), lerp).abgr;
+}
+
+auto Stops::evalExpVec2(float _key) const -> glm::vec2 {
+    if (frames.empty()) { return glm::vec2{0.f}; }
+
+    auto upper = nearestHigherFrame(_key);
+    auto lower = upper - 1;
+
+    if (upper == frames.end()) {
+        return lower->value.get<glm::vec2>();
+    }
+    if (lower < frames.begin()) {
+        return upper->value.get<glm::vec2>();
+    }
+
+    double range = exp2(upper->key - lower->key) - 1.0;
+    double pos = exp2(_key - lower->key) - 1.0;
+
+    double lerp = pos / range;
+
+    const glm::vec2& lowerVal = lower->value.get<glm::vec2>();
+    const glm::vec2& upperVal = upper->value.get<glm::vec2>();
+
+    return glm::vec2(lowerVal.x * (1 - lerp) + upperVal.x * lerp,
+                     lowerVal.y * (1 - lerp) + upperVal.y * lerp);
+
+}
+
+auto Stops::evalVec2(float _key) const -> glm::vec2 {
+    if (frames.empty()) { return glm::vec2{0.f}; }
+
+    auto upper = nearestHigherFrame(_key);
+    auto lower = upper - 1;
+
+    if (upper == frames.end()) {
+        return lower->value.get<glm::vec2>();
+    }
+    if (lower < frames.begin()) {
+        return upper->value.get<glm::vec2>();
+    }
+
+    float lerp = (_key - lower->key) / (upper->key - lower->key);
+
+    const glm::vec2& lowerVal = lower->value.get<glm::vec2>();
+    const glm::vec2& upperVal = upper->value.get<glm::vec2>();
+
+    return glm::vec2(lowerVal.x * (1 - lerp) + upperVal.x * lerp,
+                     lowerVal.y * (1 - lerp) + upperVal.y * lerp);
+
+}
+
+auto Stops::evalSize(float _key) const -> StyleParam::Value {
+    if (frames.empty()) { return 0.f; }
+
+    if (frames[0].value.is<float>()) {
+        return evalExpFloat(_key);
+    } else if (frames[0].value.is<glm::vec2>()) {
+        return evalExpVec2(_key);
+    }
+    return 0.f;
+}
+
+auto Stops::nearestHigherFrame(float _key) const -> std::vector<Frame>::const_iterator {
+
+    return std::lower_bound(frames.begin(), frames.end(), _key,
+                            [](const Frame& f, float z) { return f.key < z; });
+}
+
+void Stops::eval(const Stops& _stops, StyleParamKey _key, float _zoom, StyleParam::Value& _result) {
+    if (StyleParam::isColor(_key)) {
+        _result = _stops.evalColor(_zoom);
+    } else if (StyleParam::isWidth(_key)) {
+        _result = _stops.evalExpFloat(_zoom);
+    } else if (StyleParam::isOffsets(_key)) {
+        _result = _stops.evalVec2(_zoom);
+    } else if (StyleParam::isSize(_key)) {
+        _result = _stops.evalSize(_zoom);
+    } else {
+        _result = _stops.evalFloat(_zoom);
+    }
+}
+
+}
diff --git a/core/src/scene/stops.h b/core/src/scene/stops.h
new file mode 100644 (file)
index 0000000..798e667
--- /dev/null
@@ -0,0 +1,52 @@
+#pragma once
+
+#include "scene/styleParam.h"
+#include "util/color.h"
+#include "variant.hpp"
+
+#include <vector>
+
+namespace YAML {
+    class Node;
+}
+
+namespace Tangram {
+
+class MapProjection;
+
+using StopValue = variant<none_type, float, Color, glm::vec2>;
+
+struct Stops {
+
+    struct Frame {
+        float key = 0;
+        StopValue value;
+        Frame(float _k, float _v) : key(_k), value(_v) {}
+        Frame(float _k, Color _c) : key(_k), value(_c) {}
+        Frame(float _k, glm::vec2 _v) : key(_k), value(_v) {}
+    };
+
+    std::vector<Frame> frames;
+    static Stops Colors(const YAML::Node& _node);
+    static Stops Widths(const YAML::Node& _node, const MapProjection& _projection, const std::vector<Unit>& _units);
+    static Stops FontSize(const YAML::Node& _node);
+    static Stops Sizes(const YAML::Node& _node, const std::vector<Unit>& _units);
+    static Stops Offsets(const YAML::Node& _node, const std::vector<Unit>& _units);
+    static Stops Numbers(const YAML::Node& node);
+
+    Stops(const std::vector<Frame>& _frames) : frames(_frames) {}
+    Stops(const Stops& rhs) = default;
+    Stops() {}
+
+    auto evalFloat(float _key) const -> float;
+    auto evalExpFloat(float _key) const -> float;
+    auto evalColor(float _key) const -> uint32_t;
+    auto evalVec2(float _key) const -> glm::vec2;
+    auto evalExpVec2(float _key) const -> glm::vec2;
+    auto evalSize(float _key) const -> StyleParam::Value;
+    auto nearestHigherFrame(float _key) const -> std::vector<Frame>::const_iterator;
+
+    static void eval(const Stops& _stops, StyleParamKey _key, float _zoom, StyleParam::Value& _result);
+};
+
+}
diff --git a/core/src/scene/styleContext.cpp b/core/src/scene/styleContext.cpp
new file mode 100644 (file)
index 0000000..b627736
--- /dev/null
@@ -0,0 +1,538 @@
+#include "scene/styleContext.h"
+
+#include "data/propertyItem.h"
+#include "data/tileData.h"
+#include "log.h"
+#include "platform.h"
+#include "scene/filters.h"
+#include "scene/scene.h"
+#include "util/mapProjection.h"
+#include "util/builders.h"
+
+#include "duktape.h"
+
+#define DUMP(...) // do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)
+#define DBG(...) do { logMsg(__VA_ARGS__); duk_dump_context_stderr(m_ctx); } while(0)
+
+
+namespace Tangram {
+
+const static char INSTANCE_ID[] = "\xff""\xff""obj";
+const static char FUNC_ID[] = "\xff""\xff""fns";
+
+static const std::string key_geom("$geometry");
+static const std::string key_zoom("$zoom");
+
+static const std::vector<std::string> s_geometryStrings = {
+    "", // unknown
+    "point",
+    "line",
+    "polygon",
+};
+
+StyleContext::StyleContext() {
+    m_ctx = duk_create_heap_default();
+
+    //// Create global geometry constants
+    // TODO make immutable
+    duk_push_number(m_ctx, GeometryType::points);
+    duk_put_global_string(m_ctx, "point");
+
+    duk_push_number(m_ctx, GeometryType::lines);
+    duk_put_global_string(m_ctx, "line");
+
+    duk_push_number(m_ctx, GeometryType::polygons);
+    duk_put_global_string(m_ctx, "polygon");
+
+    //// Create global 'feature' object
+    // Get Proxy constructor
+    // -> [cons]
+    duk_eval_string(m_ctx, "Proxy");
+
+    // Add feature object
+    // -> [cons, { __obj: this }]
+    duk_idx_t featureObj = duk_push_object(m_ctx);
+    duk_push_pointer(m_ctx, this);
+    duk_put_prop_string(m_ctx, featureObj, INSTANCE_ID);
+
+    // Add handler object
+    // -> [cons, {...}, { get: func, has: func }]
+    duk_idx_t handlerObj = duk_push_object(m_ctx);
+    // Add 'get' property to handler
+    duk_push_c_function(m_ctx, jsGetProperty, 3 /*nargs*/);
+    duk_put_prop_string(m_ctx, handlerObj, "get");
+    // Add 'has' property to handler
+    duk_push_c_function(m_ctx, jsHasProperty, 2 /*nargs*/);
+    duk_put_prop_string(m_ctx, handlerObj, "has");
+
+    // Call proxy constructor
+    // [cons, feature, handler ] -> [obj|error]
+    if (duk_pnew(m_ctx, 2) == 0) {
+        // put feature proxy object in global scope
+        if (!duk_put_global_string(m_ctx, "feature")) {
+            LOGE("Initialization failed");
+        }
+    } else {
+        LOGE("Failure: %s", duk_safe_to_string(m_ctx, -1));
+        duk_pop(m_ctx);
+    }
+
+    DUMP("init\n");
+}
+
+StyleContext::~StyleContext() {
+    duk_destroy_heap(m_ctx);
+}
+
+// Convert a scalar node to a boolean, double, or string (in that order)
+// and for the first conversion that works, push it to the top of the JS stack.
+void pushYamlScalarAsJsPrimitive(duk_context* ctx, const YAML::Node& node) {
+    bool booleanValue = false;
+    double numberValue = 0.;
+    if (YAML::convert<bool>::decode(node, booleanValue)) {
+        duk_push_boolean(ctx, booleanValue);
+    } else if (YAML::convert<double>::decode(node, numberValue)) {
+        duk_push_number(ctx, numberValue);
+    } else {
+        duk_push_string(ctx, node.Scalar().c_str());
+    }
+}
+
+void pushYamlScalarAsJsFunctionOrString(duk_context* ctx, const YAML::Node& node) {
+    auto scalar = node.Scalar().c_str();
+    duk_push_string(ctx, scalar); // Push function source.
+    duk_push_string(ctx, ""); // Push a "filename".
+    if (duk_pcompile(ctx, DUK_COMPILE_FUNCTION) != 0) { // Compile function.
+        auto error = duk_safe_to_string(ctx, -1);
+        LOGW("Compile failed in global function: %s\n%s\n---", error, scalar);
+        duk_pop(ctx); // Pop error.
+        duk_push_string(ctx, scalar); // Push property as a string.
+    }
+}
+
+void StyleContext::parseSceneGlobals(const YAML::Node& node) {
+    switch(node.Type()) {
+    case YAML::NodeType::Scalar:
+        {
+            auto& scalar = node.Scalar();
+            if (scalar.compare(0, 8, "function") == 0) {
+                pushYamlScalarAsJsFunctionOrString(m_ctx, node);
+            } else {
+                pushYamlScalarAsJsPrimitive(m_ctx, node);
+            }
+            break;
+        }
+    case YAML::NodeType::Sequence:
+        {
+            auto seqObj = duk_push_array(m_ctx);
+            for (size_t i = 0; i < node.size(); i++) {
+                parseSceneGlobals(node[i]);
+                duk_put_prop_index(m_ctx, seqObj, i);
+            }
+            break;
+        }
+    case YAML::NodeType::Map:
+        {
+            auto mapObj = duk_push_object(m_ctx);
+            for (const auto& entry : node) {
+                if (!entry.first.IsScalar()) {
+                    continue; // Can't put non-scalar keys in JS objects.
+                }
+                parseSceneGlobals(entry.second);
+                duk_put_prop_string(m_ctx, mapObj, entry.first.Scalar().c_str());
+            }
+            break;
+        }
+    default:
+        duk_push_null(m_ctx);
+        break;
+    }
+}
+
+void StyleContext::setSceneGlobals(const YAML::Node& sceneGlobals) {
+
+    if (!sceneGlobals) { return; }
+
+    //[ "ctx" ]
+    // globalObject
+    duk_push_object(m_ctx);
+
+    parseSceneGlobals(sceneGlobals);
+
+    duk_put_global_string(m_ctx, "global");
+}
+
+void StyleContext::initFunctions(const Scene& _scene) {
+
+    if (_scene.id == m_sceneId) {
+        return;
+    }
+    m_sceneId = _scene.id;
+
+    setSceneGlobals(_scene.config()["global"]);
+    setFunctions(_scene.functions());
+}
+
+bool StyleContext::setFunctions(const std::vector<std::string>& _functions) {
+
+    auto arr_idx = duk_push_array(m_ctx);
+    int id = 0;
+
+    bool ok = true;
+
+    for (auto& function : _functions) {
+        duk_push_string(m_ctx, function.c_str());
+        duk_push_string(m_ctx, "");
+
+        if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) == 0) {
+            duk_put_prop_index(m_ctx, arr_idx, id);
+        } else {
+            LOGW("Compile failed: %s\n%s\n---",
+                 duk_safe_to_string(m_ctx, -1),
+                 function.c_str());
+            duk_pop(m_ctx);
+            ok = false;
+        }
+        id++;
+    }
+
+    if (!duk_put_global_string(m_ctx, FUNC_ID)) {
+        LOGE("'fns' object not set");
+    }
+
+    m_functionCount = id;
+
+    DUMP("setFunctions\n");
+    return ok;
+}
+
+bool StyleContext::addFunction(const std::string& _function) {
+    // Get all functions (array) in context
+    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
+        LOGE("AddFunction - functions array not initialized");
+        duk_pop(m_ctx); // pop [undefined] sitting at stack top
+        return false;
+    }
+
+    int id = m_functionCount++;
+    bool ok = true;
+
+    duk_push_string(m_ctx, _function.c_str());
+    duk_push_string(m_ctx, "");
+
+    if (duk_pcompile(m_ctx, DUK_COMPILE_FUNCTION) == 0) {
+        duk_put_prop_index(m_ctx, -2, id);
+    } else {
+        LOGW("Compile failed: %s\n%s\n---",
+             duk_safe_to_string(m_ctx, -1),
+             _function.c_str());
+        duk_pop(m_ctx);
+        ok = false;
+    }
+
+    // Pop the functions array off the stack
+    duk_pop(m_ctx);
+
+    return ok;
+}
+
+void StyleContext::setFeature(const Feature& _feature) {
+
+    m_feature = &_feature;
+
+    if (m_keywordGeom != m_feature->geometryType) {
+        setKeyword(key_geom, s_geometryStrings[m_feature->geometryType]);
+        m_keywordGeom = m_feature->geometryType;
+    }
+}
+
+void StyleContext::setKeywordZoom(int _zoom) {
+    if (m_keywordZoom != _zoom) {
+        setKeyword(key_zoom, _zoom);
+        m_keywordZoom = _zoom;
+    }
+}
+
+void StyleContext::setKeyword(const std::string& _key, Value _val) {
+    auto keywordKey = Filter::keywordType(_key);
+    if (keywordKey == FilterKeyword::undefined) {
+        LOG("Undefined Keyword: %s", _key.c_str());
+        return;
+    }
+
+    // Unset shortcuts in case setKeyword was not called by
+    // the helper functions above.
+    if (_key == key_zoom) { m_keywordZoom = -1; }
+    if (_key == key_geom) { m_keywordGeom = -1; }
+
+    Value& entry = m_keywords[static_cast<uint8_t>(keywordKey)];
+    if (entry == _val) { return; }
+
+    if (_val.is<std::string>()) {
+        duk_push_string(m_ctx, _val.get<std::string>().c_str());
+        duk_put_global_string(m_ctx, _key.c_str());
+    } else if (_val.is<double>()) {
+        duk_push_number(m_ctx, _val.get<double>());
+        duk_put_global_string(m_ctx, _key.c_str());
+    }
+
+    entry = std::move(_val);
+}
+
+float StyleContext::getPixelAreaScale() {
+    // scale the filter value with pixelsPerMeter
+    // used with `px2` area filtering
+    double metersPerPixel = 2.f * MapProjection::HALF_CIRCUMFERENCE * exp2(-m_keywordZoom) / View::s_pixelsPerTile;
+    return metersPerPixel * metersPerPixel;
+}
+
+const Value& StyleContext::getKeyword(const std::string& _key) const {
+    return getKeyword(Filter::keywordType(_key));
+}
+
+void StyleContext::clear() {
+    m_feature = nullptr;
+}
+
+bool StyleContext::evalFunction(FunctionID id) {
+    // Get all functions (array) in context
+    if (!duk_get_global_string(m_ctx, FUNC_ID)) {
+        LOGE("EvalFilterFn - functions array not initialized");
+        duk_pop(m_ctx); // pop [undefined] sitting at stack top
+        return false;
+    }
+
+    // Get function at index `id` from functions array, put it at stack top
+    if (!duk_get_prop_index(m_ctx, -1, id)) {
+        LOGE("EvalFilterFn - function %d not set", id);
+        duk_pop(m_ctx); // pop "undefined" sitting at stack top
+        duk_pop(m_ctx); // pop functions (array) now sitting at stack top
+        return false;
+    }
+
+    // pop fns array
+    duk_remove(m_ctx, -2);
+
+    // call popped function (sitting at stack top), evaluated value is put on stack top
+    if (duk_pcall(m_ctx, 0) != 0) {
+        LOGE("EvalFilterFn: %s", duk_safe_to_string(m_ctx, -1));
+        duk_pop(m_ctx);
+        return false;
+    }
+
+    return true;
+}
+
+bool StyleContext::evalFilter(FunctionID _id) {
+
+    if (!evalFunction(_id)) { return false; };
+
+    // Evaluate the "truthiness" of the function result at the top of the stack.
+    bool result = duk_to_boolean(m_ctx, -1);
+
+    // pop result
+    duk_pop(m_ctx);
+
+    return result;
+}
+
+bool StyleContext::evalStyle(FunctionID _id, StyleParamKey _key, StyleParam::Value& _val) {
+
+    if (!evalFunction(_id)) { return false; }
+
+    // parse evaluated result at stack top
+    parseStyleResult(_key, _val);
+
+    // pop result, empty stack
+    duk_pop(m_ctx);
+
+    return !_val.is<none_type>();
+}
+
+void StyleContext::parseStyleResult(StyleParamKey _key, StyleParam::Value& _val) const {
+    _val = none_type{};
+
+    if (duk_is_string(m_ctx, -1)) {
+        std::string value(duk_get_string(m_ctx, -1));
+
+        switch (_key) {
+            case StyleParamKey::text_source:
+                _val = value;
+                break;
+            default:
+                _val = StyleParam::parseString(_key, value);
+                break;
+        }
+
+    } else if (duk_is_boolean(m_ctx, -1)) {
+        bool value = duk_get_boolean(m_ctx, -1);
+
+        switch (_key) {
+            case StyleParamKey::interactive:
+            case StyleParamKey::text_interactive:
+            case StyleParamKey::visible:
+                _val = value;
+                break;
+            case StyleParamKey::extrude:
+                _val = value ? glm::vec2(NAN, NAN) : glm::vec2(0.0f, 0.0f);
+                break;
+            default:
+                break;
+        }
+
+    } else if (duk_is_array(m_ctx, -1)) {
+        duk_get_prop_string(m_ctx, -1, "length");
+        int len = duk_get_int(m_ctx, -1);
+        duk_pop(m_ctx);
+
+        switch (_key) {
+            case StyleParamKey::extrude: {
+                if (len != 2) {
+                    LOGW("Wrong array size for extrusion: '%d'.", len);
+                    break;
+                }
+
+                duk_get_prop_index(m_ctx, -1, 0);
+                double v1 = duk_get_number(m_ctx, -1);
+                duk_pop(m_ctx);
+
+                duk_get_prop_index(m_ctx, -1, 1);
+                double v2 = duk_get_number(m_ctx, -1);
+                duk_pop(m_ctx);
+
+                _val = glm::vec2(v1, v2);
+                break;
+            }
+            case StyleParamKey::color:
+            case StyleParamKey::outline_color:
+            case StyleParamKey::text_font_fill:
+            case StyleParamKey::text_font_stroke_color: {
+                if (len < 3 || len > 4) {
+                    LOGW("Wrong array size for color: '%d'.", len);
+                    break;
+                }
+                duk_get_prop_index(m_ctx, -1, 0);
+                double r = duk_get_number(m_ctx, -1);
+                duk_pop(m_ctx);
+
+                duk_get_prop_index(m_ctx, -1, 1);
+                double g = duk_get_number(m_ctx, -1);
+                duk_pop(m_ctx);
+
+                duk_get_prop_index(m_ctx, -1, 2);
+                double b = duk_get_number(m_ctx, -1);
+                duk_pop(m_ctx);
+
+                double a = 1.0;
+                if (len == 4) {
+                    duk_get_prop_index(m_ctx, -1, 3);
+                    a = duk_get_number(m_ctx, -1);
+                    duk_pop(m_ctx);
+                }
+
+                _val = (((uint32_t)(255.0 * a) & 0xff) << 24) |
+                       (((uint32_t)(255.0 * r) & 0xff)<< 16) |
+                       (((uint32_t)(255.0 * g) & 0xff)<< 8) |
+                       (((uint32_t)(255.0 * b) & 0xff));
+                break;
+            }
+            default:
+                break;
+        }
+
+    } else if (duk_is_nan(m_ctx, -1)) {
+        // Ignore setting value
+        LOGD("duk evaluates JS method to NAN.\n");
+    } else if (duk_is_number(m_ctx, -1)) {
+
+        switch (_key) {
+            case StyleParamKey::extrude:
+                _val = glm::vec2(0.f, static_cast<float>(duk_get_number(m_ctx, -1)));
+                break;
+            case StyleParamKey::placement_spacing: {
+                double v = duk_get_number(m_ctx, -1);
+                _val = StyleParam::Width{static_cast<float>(v), Unit::pixel};
+                break;
+            }
+            case StyleParamKey::width:
+            case StyleParamKey::outline_width: {
+                // TODO more efficient way to return pixels.
+                // atm this only works by return value as string
+                double v = duk_get_number(m_ctx, -1);
+                _val = StyleParam::Width{static_cast<float>(v)};
+                break;
+            }
+            case StyleParamKey::text_font_stroke_width:
+            case StyleParamKey::placement_min_length_ratio: {
+                _val = static_cast<float>(duk_get_number(m_ctx, -1));
+                break;
+            }
+            case StyleParamKey::order:
+            case StyleParamKey::outline_order:
+            case StyleParamKey::priority:
+            case StyleParamKey::color:
+            case StyleParamKey::outline_color:
+            case StyleParamKey::text_font_fill:
+            case StyleParamKey::text_font_stroke_color: {
+                _val = static_cast<uint32_t>(duk_get_uint(m_ctx, -1));
+                break;
+            }
+            default:
+                break;
+        }
+    } else if (duk_is_null_or_undefined(m_ctx, -1)) {
+        // Explicitly set value as 'undefined'. This is important for some styling rules.
+        _val = Undefined();
+    } else {
+        LOGW("Unhandled return type from Javascript style function for %d.", _key);
+    }
+
+    DUMP("parseStyleResult\n");
+}
+
+// Implements Proxy handler.has(target_object, key)
+duk_ret_t StyleContext::jsHasProperty(duk_context *_ctx) {
+
+    duk_get_prop_string(_ctx, 0, INSTANCE_ID);
+    auto* attr = static_cast<const StyleContext*> (duk_to_pointer(_ctx, -1));
+    if (!attr || !attr->m_feature) {
+        LOGE("Error: no context set %p %p", attr, attr ? attr->m_feature : nullptr);
+        duk_pop(_ctx);
+        return 0;
+    }
+
+    const char* key = duk_require_string(_ctx, 1);
+    duk_push_boolean(_ctx, attr->m_feature->props.contains(key));
+
+    return 1;
+}
+
+// Implements Proxy handler.get(target_object, key)
+duk_ret_t StyleContext::jsGetProperty(duk_context *_ctx) {
+
+    // Get the StyleContext instance from JS Feature object (first parameter).
+    duk_get_prop_string(_ctx, 0, INSTANCE_ID);
+    auto* attr = static_cast<const StyleContext*> (duk_to_pointer(_ctx, -1));
+    if (!attr || !attr->m_feature) {
+        LOGE("Error: no context set %p %p",  attr, attr ? attr->m_feature : nullptr);
+        duk_pop(_ctx);
+        return 0;
+    }
+
+    // Get the property name (second parameter)
+    const char* key = duk_require_string(_ctx, 1);
+
+    auto it = attr->m_feature->props.get(key);
+    if (it.is<std::string>()) {
+        duk_push_string(_ctx, it.get<std::string>().c_str());
+    } else if (it.is<double>()) {
+        duk_push_number(_ctx, it.get<double>());
+    } else {
+        duk_push_undefined(_ctx);
+    }
+    // FIXME: Distinguish Booleans here as well
+
+    return 1;
+}
+
+}
diff --git a/core/src/scene/styleContext.h b/core/src/scene/styleContext.h
new file mode 100644 (file)
index 0000000..065f0b8
--- /dev/null
@@ -0,0 +1,102 @@
+#pragma once
+
+#include "scene/styleParam.h"
+#include "util/fastmap.h"
+
+#include <array>
+#include <functional>
+#include <memory>
+#include <string>
+#include <unordered_map>
+
+struct duk_hthread;
+typedef struct duk_hthread duk_context;
+
+namespace YAML {
+    class Node;
+}
+
+namespace Tangram {
+
+class Scene;
+struct Feature;
+struct StyleParam;
+
+enum class StyleParamKey : uint8_t;
+enum class FilterKeyword : uint8_t;
+
+
+class StyleContext {
+
+public:
+
+    using FunctionID = uint32_t;
+
+    StyleContext();
+    ~StyleContext();
+
+    /*
+     * Set currently processed Feature
+     */
+    void setFeature(const Feature& _feature);
+
+    /*
+     * Set keyword for currently processed Tile
+     */
+    void setKeywordZoom(int _zoom);
+
+    /* Called from Filter::eval */
+    float getKeywordZoom() const { return m_keywordZoom; }
+
+    /* returns meters per pixels at current style zoom */
+    float getPixelAreaScale();
+
+    const Value& getKeyword(FilterKeyword _key) const {
+        return m_keywords[static_cast<uint8_t>(_key)];
+    }
+
+    /* Called from Filter::eval */
+    bool evalFilter(FunctionID id);
+
+    /* Called from DrawRule::eval */
+    bool evalStyle(FunctionID id, StyleParamKey _key, StyleParam::Value& _val);
+
+    /*
+     * Setup filter and style functions from @_scene
+     */
+    void initFunctions(const Scene& _scene);
+
+    /*
+     * Unset Feature handle
+     */
+    void clear();
+
+    bool setFunctions(const std::vector<std::string>& _functions);
+    bool addFunction(const std::string& _function);
+    void setSceneGlobals(const YAML::Node& sceneGlobals);
+
+    void setKeyword(const std::string& _key, Value _value);
+    const Value& getKeyword(const std::string& _key) const;
+
+private:
+    static int jsGetProperty(duk_context *_ctx);
+    static int jsHasProperty(duk_context *_ctx);
+
+    bool evalFunction(FunctionID id);
+    void parseStyleResult(StyleParamKey _key, StyleParam::Value& _val) const;
+    void parseSceneGlobals(const YAML::Node& node);
+
+    std::array<Value, 4> m_keywords;
+    int m_keywordGeom= -1;
+    int m_keywordZoom = -1;
+
+    int m_functionCount = 0;
+
+    int32_t m_sceneId = -1;
+
+    const Feature* m_feature = nullptr;
+
+    mutable duk_context *m_ctx;
+};
+
+}
diff --git a/core/src/scene/styleMixer.cpp b/core/src/scene/styleMixer.cpp
new file mode 100644 (file)
index 0000000..4ce483a
--- /dev/null
@@ -0,0 +1,225 @@
+#include "scene/styleMixer.h"
+
+#include "style/style.h"
+#include "util/topologicalSort.h"
+
+#include <algorithm>
+#include <set>
+#include "yaml-cpp/yaml.h"
+
+namespace Tangram {
+
+std::vector<std::string> StyleMixer::getStylesToMix(const Node& _style) {
+
+    std::vector<std::string> names;
+
+    // 'base' style is the first item to mix.
+    if (const Node& base = _style["base"]) {
+        if (base.IsScalar()) { names.push_back(base.Scalar()); }
+    }
+
+    // 'mix' styles are mixed next, in order of declaration.
+    if (const Node& mix = _style["mix"]) {
+        if (mix.IsScalar()) {
+            names.push_back(mix.Scalar());
+        } else if (mix.IsSequence()) {
+            for (const auto& m : mix) {
+                if (m.IsScalar()) { names.push_back(m.Scalar()); }
+            }
+        }
+    }
+
+    return names;
+}
+
+std::vector<std::string> StyleMixer::getMixingOrder(const Node& _styles) {
+
+    // Input must be a map of names to style configuration nodes.
+    if (!_styles.IsMap()) {
+        return {};
+    }
+
+    // Dependencies are pairs of strings that form a DAG.
+    // If style 'a' mixes style 'b', the dependency would be {'b', 'a'}.
+    std::vector<std::pair<std::string, std::string>> dependencies;
+
+    for (const auto& entry : _styles) {
+        const auto& name = entry.first;
+        const auto& config = entry.second;
+        for (const auto& mix : getStylesToMix(config)) {
+            dependencies.push_back({ mix, name.Scalar() });
+        }
+    }
+
+    return topologicalSort(dependencies);
+}
+
+void StyleMixer::mixStyleNodes(Node _styles) {
+
+    // First determine the order of nodes to evaluate.
+    auto styleNamesSorted = getMixingOrder(_styles);
+
+    for (const auto& name : styleNamesSorted) {
+
+        const auto& style = _styles[name];
+
+        if (!style || !style.IsMap()) {
+            // Something's wrong here, try the next one!
+            continue;
+        }
+
+        // For each style to evaluate, get the list of styles that need to be mixed with this one.
+        auto stylesToMix = getStylesToMix(style);
+
+        std::vector<Node> mixins;
+        for (const auto& styleNameToMix : stylesToMix) {
+
+            // Skip mixing built-in styles.
+            const auto& builtIn = Style::builtInStyleNames();
+            if (std::find(builtIn.begin(), builtIn.end(), styleNameToMix) != builtIn.end()) {
+                continue;
+            }
+
+            mixins.push_back(_styles[styleNameToMix]);
+        }
+
+        applyStyleMixins(style, mixins);
+    }
+}
+
+void StyleMixer::applyStyleMixins(Node _style, const std::vector<Node>& _mixins) {
+
+    // Merge boolean flags as a disjunction.
+    mergeBooleanFieldAsDisjunction("animated", _style, _mixins);
+    mergeBooleanFieldAsDisjunction("texcoords", _style, _mixins);
+
+    // Merge scalar fields with newer values taking precedence.
+    mergeFieldTakingLast("base", _style, _mixins);
+    mergeFieldTakingLast("lighting", _style, _mixins);
+    mergeFieldTakingLast("texture", _style, _mixins);
+    mergeFieldTakingLast("blend", _style, _mixins);
+    mergeFieldTakingLast("blend_order", _style, _mixins);
+    mergeFieldTakingLast("raster", _style, _mixins);
+
+    // Merge map fields with newer values taking precedence.
+    mergeMapFieldTakingLast("material", _style, _mixins);
+    mergeMapFieldTakingLast("draw", _style, _mixins);
+
+    // Produce a list of all 'mixins' with shader nodes and merge those separately.
+    std::vector<Node> shaderMixins;
+    for (const auto& mixin : _mixins) {
+        if (const auto& shaders = mixin["shaders"]) {
+            shaderMixins.push_back(shaders);
+        }
+    }
+    applyShaderMixins(_style["shaders"], shaderMixins);
+}
+
+void StyleMixer::applyShaderMixins(Node _shaders, const std::vector<Node>& _mixins) {
+
+    // Merge maps fields with newer values taking precedence.
+    mergeMapFieldTakingLast("defines", _shaders, _mixins);
+    mergeMapFieldTakingLast("uniforms", _shaders, _mixins);
+
+    // Merge "extensions" as a non-repeating set.
+    {
+        std::set<std::string> set;
+        Node output = _shaders["extensions_mixed"];
+        output = Node(); // Clear this node in case something was already there.
+        for (const auto& mixin : _mixins) {
+            Node extensions = mixin["extensions_mixed"];
+            for (const auto& e : extensions) {
+                set.insert(e.Scalar());
+            }
+        }
+        Node extensions = _shaders["extensions"];
+        if (extensions.IsScalar()) {
+            set.insert(extensions.Scalar());
+        } else if (extensions.IsSequence()) {
+            for (const auto& e : extensions) {
+                set.insert(e.Scalar());
+            }
+        }
+        for (const auto& extension : set) {
+            output.push_back(extension);
+        }
+    }
+
+    // Merge "blocks" into a list of strings for each key.
+    {
+        Node output = _shaders["blocks_mixed"];
+        output = Node(); // Clear this node in case something was already there.
+        for (const auto& mixin : _mixins) {
+            Node blocks = mixin["blocks_mixed"];
+            for (const auto& entry : blocks) {
+                Node list = output[entry.first.Scalar()];
+                for (const auto& block : entry.second) {
+                    // If the list already contains an exact reference to the same node,
+                    // don't add it again.
+                    if (std::find(list.begin(), list.end(), block) == list.end()) {
+                        list.push_back(block);
+                    }
+                }
+            }
+        }
+        for (const auto& entry : _shaders["blocks"]) {
+            output[entry.first.Scalar()].push_back(entry.second.Scalar());
+        }
+    }
+}
+
+void StyleMixer::mergeBooleanFieldAsDisjunction(const std::string& key, Node target, const std::vector<Node>& sources) {
+
+    auto current = target[key];
+    if (current && current.as<bool>(false)) {
+        // Target field is already true, we can stop here.
+        return;
+    }
+
+    for (const auto& source : sources) {
+        const auto& value = source[key];
+        if (value && value.as<bool>(false)) {
+            target[key] = true;
+            return;
+        }
+    }
+}
+
+void StyleMixer::mergeFieldTakingLast(const std::string& key, Node target, const std::vector<Node>& sources) {
+
+    if (target[key]) {
+        // Target already has a value, we can stop here.
+        return;
+    }
+
+    for (auto it = sources.rbegin(); it != sources.rend(); ++it) {
+        const auto& value = (*it)[key];
+        if (value) {
+            target[key] = value;
+            return;
+        }
+    }
+}
+
+void StyleMixer::mergeMapFieldTakingLast(const std::string& key, Node target, const std::vector<Node>& sources) {
+
+    Node map = target[key];
+    if (map && !map.IsMap()) { return; }
+
+    for (auto it = sources.rbegin(); it != sources.rend(); ++it) {
+        const auto& source = (*it)[key];
+        if (!source || !source.IsMap()) {
+            continue;
+        }
+
+        for (const auto& entry : source) {
+            const auto& subkey = entry.first.Scalar();
+            if (!map[subkey]) {
+                map[subkey] = entry.second;
+            }
+        }
+    }
+
+}
+
+}
diff --git a/core/src/scene/styleMixer.h b/core/src/scene/styleMixer.h
new file mode 100644 (file)
index 0000000..b2cb5ac
--- /dev/null
@@ -0,0 +1,49 @@
+#pragma once
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace YAML {
+    class Node;
+}
+
+namespace Tangram {
+
+class StyleMixer {
+
+public:
+
+    using Node = YAML::Node;
+
+    // Get the sequence of style names that are designated to be mixed into the
+    // input style node by its 'base' and 'mix' fields.
+    std::vector<std::string> getStylesToMix(const Node& _style);
+
+    // Get a sequence of style names ordered such that if style 'a' mixes style
+    // 'b', 'b' will always precede 'a' in the sequence.
+    std::vector<std::string> getMixingOrder(const Node& _styles);
+
+    // Apply mixing to all styles in the input map with modifications in-place
+    // unless otherwise noted.
+    void mixStyleNodes(Node _styles);
+
+    // Apply the given list of 'mixin' styles to the first style.
+    void applyStyleMixins(Node _style, const std::vector<Node>& _mixins);
+
+    // Apply the given list of 'mixin' style shader nodes to the first style
+    // shader node. Note that 'blocks' and 'extensions' are merged into new
+    // output fields called 'blocks_merged' and 'extensions_merged'.
+    void applyShaderMixins(Node _shaders, const std::vector<Node>& _mixins);
+
+private:
+
+    void mergeBooleanFieldAsDisjunction(const std::string& _key, Node _target, const std::vector<Node>& _sources);
+
+    void mergeFieldTakingLast(const std::string& _key, Node _target, const std::vector<Node>& _sources);
+
+    void mergeMapFieldTakingLast(const std::string& _key, Node _target, const std::vector<Node>& _sources);
+
+};
+
+}
diff --git a/core/src/scene/styleParam.cpp b/core/src/scene/styleParam.cpp
new file mode 100644 (file)
index 0000000..24eb8d3
--- /dev/null
@@ -0,0 +1,758 @@
+#include "scene/styleParam.h"
+
+#include "log.h"
+#include "platform.h"
+#include "style/textStyle.h"
+#include "util/builders.h" // for cap, join
+#include "util/extrude.h"
+#include "util/floatFormatter.h"
+#include "util/geom.h" // for CLAMP
+
+#include "csscolorparser.hpp"
+#include <algorithm>
+#include <cstring>
+#include <map>
+
+namespace Tangram {
+
+using Color = CSSColorParser::Color;
+
+const std::map<std::string, StyleParamKey> s_StyleParamMap = {
+    {"align", StyleParamKey::text_align},
+    {"anchor", StyleParamKey::anchor},
+    {"angle", StyleParamKey::angle},
+    {"buffer", StyleParamKey::buffer},
+    {"cap", StyleParamKey::cap},
+    {"collide", StyleParamKey::collide},
+    {"color", StyleParamKey::color},
+    {"extrude", StyleParamKey::extrude},
+    {"flat", StyleParamKey::flat},
+    {"font:family", StyleParamKey::text_font_family},
+    {"font:fill", StyleParamKey::text_font_fill},
+    {"font:size", StyleParamKey::text_font_size},
+    {"font:stroke:color", StyleParamKey::text_font_stroke_color},
+    {"font:stroke:width", StyleParamKey::text_font_stroke_width},
+    {"font:style", StyleParamKey::text_font_style},
+    {"font:transform", StyleParamKey::text_transform},
+    {"font:weight", StyleParamKey::text_font_weight},
+    {"interactive", StyleParamKey::interactive},
+    {"join", StyleParamKey::join},
+    {"miter_limit", StyleParamKey::miter_limit},
+    {"none", StyleParamKey::none},
+    {"offset", StyleParamKey::offset},
+    {"order", StyleParamKey::order},
+    {"outline:cap", StyleParamKey::outline_cap},
+    {"outline:color", StyleParamKey::outline_color},
+    {"outline:join", StyleParamKey::outline_join},
+    {"outline:miter_limit", StyleParamKey::outline_miter_limit},
+    {"outline:order", StyleParamKey::outline_order},
+    {"outline:style", StyleParamKey::outline_style},
+    {"outline:visible", StyleParamKey::outline_visible},
+    {"outline:width", StyleParamKey::outline_width},
+    {"placement", StyleParamKey::placement},
+    {"placement_spacing", StyleParamKey::placement_spacing},
+    {"placement_min_length_ratio", StyleParamKey::placement_min_length_ratio},
+    {"priority", StyleParamKey::priority},
+    {"repeat_distance", StyleParamKey::repeat_distance},
+    {"repeat_group", StyleParamKey::repeat_group},
+    {"size", StyleParamKey::size},
+    {"sprite", StyleParamKey::sprite},
+    {"sprite_default", StyleParamKey::sprite_default},
+    {"style", StyleParamKey::style},
+    {"text:align", StyleParamKey::text_align},
+    {"text:anchor", StyleParamKey::text_anchor},
+    {"text:buffer", StyleParamKey::text_buffer},
+    {"text:collide", StyleParamKey::text_collide},
+    {"text:font:family", StyleParamKey::text_font_family},
+    {"text:font:fill", StyleParamKey::text_font_fill},
+    {"text:font:size", StyleParamKey::text_font_size},
+    {"text:font:stroke:color", StyleParamKey::text_font_stroke_color},
+    {"text:font:stroke:width", StyleParamKey::text_font_stroke_width},
+    {"text:font:style", StyleParamKey::text_font_style},
+    {"text:font:transform", StyleParamKey::text_transform},
+    {"text:font:weight", StyleParamKey::text_font_weight},
+    {"text:interactive", StyleParamKey::text_interactive},
+    {"text:offset", StyleParamKey::text_offset},
+    {"text:order", StyleParamKey::text_order},
+    {"text:priority", StyleParamKey::text_priority},
+    {"text:repeat_distance", StyleParamKey::text_repeat_distance},
+    {"text:repeat_group", StyleParamKey::text_repeat_group},
+    {"text:optional", StyleParamKey::text_optional},
+    {"text:text_source", StyleParamKey::text_source},
+    {"text:text_source:left", StyleParamKey::text_source_left},
+    {"text:text_source:right", StyleParamKey::text_source_right},
+    {"text:text_wrap", StyleParamKey::text_wrap},
+    {"text:transition:hide:time", StyleParamKey::text_transition_hide_time},
+    {"text:transition:selected:time", StyleParamKey::text_transition_selected_time},
+    {"text:transition:show:time", StyleParamKey::text_transition_show_time},
+    {"text:visible", StyleParamKey::text_visible},
+    {"text_source", StyleParamKey::text_source},
+    {"text_source:left", StyleParamKey::text_source_left},
+    {"text_source:right", StyleParamKey::text_source_right},
+    {"text_wrap", StyleParamKey::text_wrap},
+    {"tile_edges", StyleParamKey::tile_edges},
+    {"transition:hide:time", StyleParamKey::transition_hide_time},
+    {"transition:selected:time", StyleParamKey::transition_selected_time},
+    {"transition:show:time", StyleParamKey::transition_show_time},
+    {"visible", StyleParamKey::visible},
+    {"width", StyleParamKey::width},
+};
+
+const std::map<StyleParamKey, std::vector<Unit>> s_StyleParamUnits = {
+    {StyleParamKey::offset, {Unit::pixel}},
+    {StyleParamKey::text_offset, {Unit::pixel}},
+    {StyleParamKey::buffer, {Unit::pixel}},
+    {StyleParamKey::text_buffer, {Unit::pixel}},
+    {StyleParamKey::size, {Unit::pixel}},
+    {StyleParamKey::placement_spacing, {Unit::pixel}},
+    {StyleParamKey::text_font_stroke_width, {Unit::pixel}},
+    {StyleParamKey::width, {Unit::meter, Unit::pixel}},
+    {StyleParamKey::outline_width, {Unit::meter, Unit::pixel}}
+};
+
+static int parseInt(const std::string& _str, int& _value) {
+    try {
+        size_t index;
+        _value = std::stoi(_str, &index);
+        return index;
+    } catch (std::invalid_argument) {
+    } catch (std::out_of_range) {}
+    LOGW("Not an Integer '%s'", _str.c_str());
+
+    return -1;
+}
+
+static int parseFloat(const std::string& _str, double& _value) {
+    int index = 0;
+    _value = ff::stod(_str.data(), _str.size(), &index);
+    if (index == 0) {
+        LOGW("Not a Float '%s'", _str.c_str());
+        return -1;
+    }
+
+    return index;
+}
+
+const std::string& StyleParam::keyName(StyleParamKey _key) {
+    static std::string fallback = "bug";
+    for (const auto& entry : s_StyleParamMap) {
+        if (entry.second == _key) { return entry.first; }
+    }
+    return fallback;
+}
+
+StyleParamKey StyleParam::getKey(const std::string& _key) {
+    auto it = s_StyleParamMap.find(_key);
+    if (it == s_StyleParamMap.end()) {
+        return StyleParamKey::none;
+    }
+    return it->second;
+}
+
+StyleParam::StyleParam(const std::string& _key, const std::string& _value) {
+    key = getKey(_key);
+    value = none_type{};
+
+    if (key == StyleParamKey::none) {
+        LOGW("Unknown StyleParam %s:%s", _key.c_str(), _value.c_str());
+        return;
+    }
+    if (!_value.empty()) {
+        value = parseString(key, _value);
+    }
+}
+
+StyleParam::Value StyleParam::parseString(StyleParamKey key, const std::string& _value) {
+    switch (key) {
+    case StyleParamKey::extrude: {
+        return parseExtrudeString(_value);
+    }
+    case StyleParamKey::text_wrap: {
+        int textWrap;
+        if (_value == "false") {
+            return std::numeric_limits<uint32_t>::max();
+        }
+        if (_value == "true") {
+            return uint32_t(15); // DEFAULT
+        }
+        if (parseInt(_value, textWrap) > 0 && textWrap > 0) {
+             return static_cast<uint32_t>(textWrap);
+        }
+        return std::numeric_limits<uint32_t>::max();
+    }
+    case StyleParamKey::text_offset:
+    case StyleParamKey::offset: {
+        UnitVec<glm::vec2> vec;
+        if (!parseVec2(_value, { Unit::pixel }, vec) || std::isnan(vec.value.y)) {
+            LOGW("Invalid offset parameter '%s'.", _value.c_str());
+        }
+        return vec.value;
+    }
+    case StyleParamKey::text_buffer:
+    case StyleParamKey::buffer: {
+        UnitVec<glm::vec2> vec;
+        if (!parseVec2(_value, { Unit::pixel }, vec)) {
+            LOGW("Invalid buffer parameter '%s'.", _value.c_str());
+        }
+        if (std::isnan(vec.value.y)) {
+            vec.value.y = vec.value.x;
+        }
+        return vec.value;
+    }
+    case StyleParamKey::size: {
+        UnitVec<glm::vec2> vec;
+        if (!parseVec2(_value, { Unit::pixel }, vec)) {
+            LOGW("Invalid size parameter '%s'.", _value.c_str());
+        }
+        return vec.value;
+    }
+    case StyleParamKey::transition_hide_time:
+    case StyleParamKey::transition_show_time:
+    case StyleParamKey::transition_selected_time:
+    case StyleParamKey::text_transition_hide_time:
+    case StyleParamKey::text_transition_show_time:
+    case StyleParamKey::text_transition_selected_time: {
+        float time = 0.0f;
+        if (!parseTime(_value, time)) {
+            LOGW("Invalid time param '%s'", _value.c_str());
+        }
+        return time;
+    }
+    case StyleParamKey::text_font_family:
+    case StyleParamKey::text_font_weight:
+    case StyleParamKey::text_font_style: {
+        std::string normalized = _value;
+        std::transform(normalized.begin(), normalized.end(), normalized.begin(), ::tolower);
+        return normalized;
+    }
+    case StyleParamKey::anchor:
+    case StyleParamKey::text_anchor: {
+        LabelProperty::Anchors anchors;
+        for (auto& anchor : splitString(_value, ',')) {
+            if (anchors.count == LabelProperty::max_anchors) { break; }
+
+            LabelProperty::Anchor labelAnchor;
+            if (LabelProperty::anchor(anchor, labelAnchor)) {
+                anchors.anchor[anchors.count++] = labelAnchor;
+            } else {
+                LOG("Invalid anchor %s", anchor.c_str());
+            }
+        }
+        return anchors;
+    }
+    case StyleParamKey::placement: {
+        LabelProperty::Placement placement = LabelProperty::Placement::vertex;
+        if (!LabelProperty::placement(_value, placement)) {
+            LOG("Invalid placement parameter, Setting vertex as default.");
+        }
+        return placement;
+    }
+    case StyleParamKey::text_source:
+    case StyleParamKey::text_source_left:
+    case StyleParamKey::text_source_right: {
+        TextSource textSource;
+        // FIXME remove white space
+        std::string tmp;
+        if (_value.find(',') != std::string::npos) {
+            std::stringstream ss(_value);
+            while (std::getline(ss, tmp, ',')) {
+                textSource.keys.push_back(tmp);
+            }
+        } else {
+            textSource.keys.push_back(_value);
+        }
+        return std::move(textSource);
+    }
+    case StyleParamKey::text_align:
+    case StyleParamKey::text_transform:
+    case StyleParamKey::sprite:
+    case StyleParamKey::sprite_default:
+    case StyleParamKey::style:
+    case StyleParamKey::outline_style:
+    case StyleParamKey::repeat_group:
+    case StyleParamKey::text_repeat_group:
+        return _value;
+    case StyleParamKey::text_font_size: {
+        float fontSize = 0.f;
+        if (!parseFontSize(_value, fontSize)) {
+            LOGW("Invalid font-size '%s'.", _value.c_str());
+        }
+        return fontSize;
+    }
+    case StyleParamKey::flat:
+    case StyleParamKey::interactive:
+    case StyleParamKey::text_interactive:
+    case StyleParamKey::tile_edges:
+    case StyleParamKey::visible:
+    case StyleParamKey::text_visible:
+    case StyleParamKey::outline_visible:
+    case StyleParamKey::collide:
+    case StyleParamKey::text_optional:
+    case StyleParamKey::text_collide:
+        if (_value == "true") { return true; }
+        if (_value == "false") { return false; }
+        LOGW("Invalid boolean value %s for key %s", _value.c_str(), StyleParam::keyName(key).c_str());
+        break;
+    case StyleParamKey::text_order:
+        LOGW("text:order parameter is ignored.");
+        break;
+    case StyleParamKey::order:
+    case StyleParamKey::outline_order:
+    case StyleParamKey::priority:
+    case StyleParamKey::text_priority: {
+        int num;
+        if (parseInt(_value, num) > 0) {
+            if (num >= 0) {
+                return static_cast<uint32_t>(num);
+            }
+        }
+        LOGW("Invalid '%s' value '%s'", keyName(key).c_str(), _value.c_str());
+        break;
+    }
+    case StyleParamKey::placement_spacing: {
+        ValueUnitPair placementSpacing;
+        placementSpacing.unit = Unit::pixel;
+
+        int pos = parseValueUnitPair(_value, 0, placementSpacing);
+        if (pos < 0) {
+            LOGW("Invalid placement spacing value '%s'", _value.c_str());
+            placementSpacing.value =  80.0f;
+            placementSpacing.unit = Unit::pixel;
+        } else {
+            if (placementSpacing.unit != Unit::pixel) {
+                LOGW("Invalid unit provided for placement spacing");
+            }
+        }
+
+        return Width(placementSpacing);
+    }
+    case StyleParamKey::repeat_distance:
+    case StyleParamKey::text_repeat_distance: {
+        ValueUnitPair repeatDistance;
+        repeatDistance.unit = Unit::pixel;
+
+        int pos = parseValueUnitPair(_value, 0, repeatDistance);
+        if (pos < 0) {
+            LOGW("Invalid repeat distance value '%s'", _value.c_str());
+            repeatDistance.value =  256.0f;
+            repeatDistance.unit = Unit::pixel;
+        } else {
+            if (repeatDistance.unit != Unit::pixel) {
+                LOGW("Invalid unit provided for repeat distance");
+            }
+        }
+
+        return Width(repeatDistance);
+    }
+    case StyleParamKey::width:
+    case StyleParamKey::outline_width: {
+        ValueUnitPair width;
+        width.unit = Unit::meter;
+
+        int pos = parseValueUnitPair(_value, 0, width);
+        if (pos < 0) {
+            LOGW("Invalid width value '%s'", _value.c_str());
+            width.value =  2.0f;
+            width.unit = Unit::pixel;
+        }
+
+        return Width(width);
+    }
+    case StyleParamKey::angle: {
+        double num;
+        if (_value == "auto") {
+            return std::nanf("1");
+        } else if (parseFloat(_value, num) > 0) {
+            return static_cast<float>(num);
+        }
+        break;
+    }
+    case StyleParamKey::miter_limit:
+    case StyleParamKey::outline_miter_limit:
+    case StyleParamKey::placement_min_length_ratio:
+    case StyleParamKey::text_font_stroke_width: {
+        double num;
+        if (parseFloat(_value, num) > 0) {
+             return static_cast<float>(num);
+        }
+        break;
+    }
+
+    case StyleParamKey::color:
+    case StyleParamKey::outline_color:
+    case StyleParamKey::text_font_fill:
+    case StyleParamKey::text_font_stroke_color:
+        return parseColor(_value);
+
+    case StyleParamKey::cap:
+    case StyleParamKey::outline_cap:
+        return static_cast<uint32_t>(CapTypeFromString(_value));
+
+    case StyleParamKey::join:
+    case StyleParamKey::outline_join:
+        return static_cast<uint32_t>(JoinTypeFromString(_value));
+
+    default:
+        break;
+    }
+
+    return none_type{};
+}
+
+std::string StyleParam::toString() const {
+
+    std::string k(keyName(key));
+    k += " : ";
+
+    // TODO: cap, join and color toString()
+    if (value.is<none_type>()) {
+        return k + "none";
+    }
+
+    switch (key) {
+    case StyleParamKey::extrude: {
+        if (!value.is<glm::vec2>()) break;
+        auto p = value.get<glm::vec2>();
+        return k + "(" + std::to_string(p[0]) + ", " + std::to_string(p[1]) + ")";
+    }
+    case StyleParamKey::size:
+    case StyleParamKey::offset:
+    case StyleParamKey::text_offset: {
+        if (!value.is<glm::vec2>()) break;
+        auto p = value.get<glm::vec2>();
+        return k + "(" + std::to_string(p.x) + "px, " + std::to_string(p.y) + "px)";
+    }
+    case StyleParamKey::text_source:
+    case StyleParamKey::text_source_left:
+    case StyleParamKey::text_source_right:
+        if (value.is<std::string>()) {
+            return k + value.get<std::string>();
+        } else if (value.is<TextSource>()) {
+            // TODO add more..
+            return k + value.get<TextSource>().keys[0];
+        }
+    case StyleParamKey::transition_hide_time:
+    case StyleParamKey::text_transition_hide_time:
+    case StyleParamKey::transition_show_time:
+    case StyleParamKey::text_transition_show_time:
+    case StyleParamKey::transition_selected_time:
+    case StyleParamKey::text_transition_selected_time:
+    case StyleParamKey::text_font_family:
+    case StyleParamKey::text_font_weight:
+    case StyleParamKey::text_font_style:
+    case StyleParamKey::text_transform:
+    case StyleParamKey::text_wrap:
+    case StyleParamKey::repeat_group:
+    case StyleParamKey::text_repeat_group:
+    case StyleParamKey::sprite:
+    case StyleParamKey::sprite_default:
+    case StyleParamKey::style:
+    case StyleParamKey::text_align:
+        if (!value.is<std::string>()) break;
+        return k + value.get<std::string>();
+    case StyleParamKey::anchor:
+    case StyleParamKey::text_anchor:
+        return "[anchor]"; // TODO
+    case StyleParamKey::interactive:
+    case StyleParamKey::flat:
+    case StyleParamKey::text_interactive:
+    case StyleParamKey::tile_edges:
+    case StyleParamKey::visible:
+    case StyleParamKey::text_visible:
+    case StyleParamKey::outline_visible:
+    case StyleParamKey::collide:
+    case StyleParamKey::text_optional:
+    case StyleParamKey::text_collide:
+        if (!value.is<bool>()) break;
+        return k + std::to_string(value.get<bool>());
+    case StyleParamKey::width:
+    case StyleParamKey::outline_width:
+    case StyleParamKey::text_font_stroke_width:
+    case StyleParamKey::text_font_size:
+        if (!value.is<Width>()) break;
+        return k + std::to_string(value.get<Width>().value);
+    case StyleParamKey::order:
+    case StyleParamKey::text_order:
+    case StyleParamKey::outline_order:
+    case StyleParamKey::priority:
+    case StyleParamKey::text_priority:
+    case StyleParamKey::color:
+    case StyleParamKey::outline_color:
+    case StyleParamKey::outline_style:
+    case StyleParamKey::repeat_distance:
+    case StyleParamKey::text_font_fill:
+    case StyleParamKey::text_font_stroke_color:
+    case StyleParamKey::text_repeat_distance:
+    case StyleParamKey::cap:
+    case StyleParamKey::outline_cap:
+    case StyleParamKey::join:
+    case StyleParamKey::outline_join:
+        if (!value.is<uint32_t>()) break;
+        return k + std::to_string(value.get<uint32_t>());
+    case StyleParamKey::miter_limit:
+    case StyleParamKey::angle:
+    case StyleParamKey::outline_miter_limit:
+        if (!value.is<float>()) break;
+        return k + std::to_string(value.get<float>());
+    default:
+        break;
+    }
+
+    if (value.is<std::string>()) {
+        return k + "wrong type: " + value.get<std::string>();
+
+    }
+
+    return k + "undefined " + std::to_string(static_cast<uint8_t>(key));
+
+}
+
+static const std::vector<std::string> s_units = { "px", "ms", "m", "s" };
+
+int StyleParam::parseValueUnitPair(const std::string& _value, size_t offset,
+                                   StyleParam::ValueUnitPair& _result) {
+
+    if (offset >= _value.length()) { return -1; }
+
+    const char* str = _value.c_str();
+    int count;
+    _result.value = ff::stof(str + offset,
+                             _value.length() - offset, &count);
+
+    if (count == 0) { return -1; }
+    offset += count;
+
+    if (offset >= _value.length()) { return offset; }
+
+    for (size_t i = 0; i < s_units.size(); ++i) {
+        const auto& unit = s_units[i];
+        std::string valueUnit;
+        if (unit == _value.substr(offset, std::min<int>(_value.length(), unit.length()))) {
+            _result.unit = static_cast<Unit>(i);
+            offset += unit.length();
+            break;
+        }
+    }
+
+    // Skip next comma
+    while (str[offset] == ' ') { offset++; }
+    if (str[offset] == ',') { offset++; }
+
+    return offset;
+}
+
+bool StyleParam::parseTime(const std::string &_value, float &_time) {
+    ValueUnitPair p;
+
+    if (!parseValueUnitPair(_value, 0, p)) {
+        return false;
+    }
+
+    switch (p.unit) {
+        case Unit::milliseconds:
+            _time = p.value / 1000.f;
+            break;
+        case Unit::seconds:
+            _time = p.value;
+            break;
+        default:
+            LOGW("Invalid unit provided for time %s", _value.c_str());
+            return false;
+            break;
+    }
+
+    return true;
+}
+
+template<typename T>
+int parseVec(const std::string& _value, T& _vec) {
+
+    const size_t elements = _vec.length();
+    const char* str = _value.data();
+
+    const int length = _value.length();
+    int count = 0;
+    int offset = 0;
+
+    for (size_t i = 0; i < elements; i++) {
+
+        float v = ff::stof(str + offset, length - offset, &count);
+        if (count == 0) { return i; }
+
+        _vec[i] = v;
+        offset += count;
+
+        if (length - offset <= 0) { return i; }
+
+        // Skip next comma
+        while (str[offset] == ' ') { offset++; }
+        if (str[offset++] != ',') { return i; }
+    }
+
+    return elements;
+}
+
+template<typename T>
+int parseVec(const std::string& _value, const std::vector<Unit>& units, UnitVec<T>& _vec) {
+     // initialize with defaults
+    const size_t elements = _vec.size;
+    for (size_t i = 0; i < elements; i++) {
+        _vec.units[i] = units[0];
+        _vec.value[i] = NAN;
+    }
+
+    int offset = 0;
+    for (size_t i = 0; i < elements; i++) {
+        StyleParam::ValueUnitPair v;
+        offset = StyleParam::parseValueUnitPair(_value, offset, v);
+        if (offset < 0) { return i; }
+
+        if (std::find(units.begin(), units.end(), v.unit) == units.end()) {
+            return 0;
+        }
+        _vec.units[i] = v.unit;
+        _vec.value[i] = v.value;
+    }
+
+    return elements;
+}
+
+bool StyleParam::parseVec2(const std::string& _value, const std::vector<Unit>& units, UnitVec<glm::vec2>& _vec) {
+    return parseVec(_value, units, _vec);
+}
+
+bool StyleParam::parseVec3(const std::string& _value, const std::vector<Unit>& units, UnitVec<glm::vec3> & _vec) {
+    return parseVec(_value, units, _vec);
+}
+
+uint32_t StyleParam::parseColor(const std::string& _color) {
+    Color color;
+
+    // First, try to parse as comma-separated rgba components.
+    glm::vec4 rgba(1.0f);
+    int elements = parseVec(_color, rgba);
+
+    if (elements >= 3) {
+        color = Color {
+            static_cast<uint8_t>(CLAMP((rgba[0] * 255.), 0, 255)),
+            static_cast<uint8_t>(CLAMP((rgba[1] * 255.), 0, 255)),
+            static_cast<uint8_t>(CLAMP((rgba[2] * 255.), 0, 255)),
+            CLAMP(rgba[3], 0, 1)
+        };
+    } else {
+        // parse as css color or #hex-num
+        color = CSSColorParser::parse(_color);
+    }
+    return color.getInt();
+}
+
+bool StyleParam::parseFontSize(const std::string& _str, float& _pxSize) {
+    if (_str.empty()) {
+        return false;
+    }
+
+    double num;
+    int index = parseFloat(_str, num);
+    if (index < 0) { return false; }
+
+    _pxSize = static_cast<float>(num);
+
+    if (size_t(index) == _str.length() && (_str.find('.') == std::string::npos)) {
+        return true;
+    }
+
+    size_t end = _str.length() - 1;
+
+    if (_str.compare(index, end, "px") == 0) {
+        return true;
+    } else if (_str.compare(index, end, "em") == 0) {
+        _pxSize *= 16.f;
+    } else if (_str.compare(index, end, "pt") == 0) {
+        _pxSize /= 0.75f;
+    } else if (_str.compare(index, end, "%") == 0) {
+        _pxSize /= 6.25f;
+    } else {
+        return false;
+    }
+
+    return true;
+}
+
+bool StyleParam::isColor(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::color:
+        case StyleParamKey::outline_color:
+        case StyleParamKey::text_font_fill:
+        case StyleParamKey::text_font_stroke_color:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isSize(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::size:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isWidth(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::width:
+        case StyleParamKey::outline_width:
+        case StyleParamKey::text_font_stroke_width:
+        case StyleParamKey::placement_spacing:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isOffsets(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::offset:
+        case StyleParamKey::text_offset:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isFontSize(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::text_font_size:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isNumberType(StyleParamKey _key) {
+    switch (_key) {
+        case StyleParamKey::placement_min_length_ratio:
+            return true;
+        default:
+            return false;
+    }
+}
+
+bool StyleParam::isRequired(StyleParamKey _key) {
+    static const std::vector<StyleParamKey> requiredKeys =
+        { StyleParamKey::color, StyleParamKey::order, StyleParamKey::width };
+
+    return std::find(requiredKeys.begin(), requiredKeys.end(), _key) != requiredKeys.end();
+}
+
+const std::vector<Unit>& StyleParam::unitsForStyleParam(StyleParamKey _key) {
+    auto it = s_StyleParamUnits.find(_key);
+    if (it != s_StyleParamUnits.end()) {
+        return it->second;
+    }
+    static const std::vector<Unit> empty;
+    return empty;
+}
+
+}
diff --git a/core/src/scene/styleParam.h b/core/src/scene/styleParam.h
new file mode 100644 (file)
index 0000000..940e00a
--- /dev/null
@@ -0,0 +1,240 @@
+#pragma once
+
+#include "labels/labelProperty.h"
+#include "util/variant.h"
+
+#include "glm/vec2.hpp"
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+struct Stops;
+
+enum class StyleParamKey : uint8_t {
+    text_align,
+    anchor,
+    angle,
+    buffer,
+    text_anchor,
+    cap,
+    collide,
+    text_collide,
+    color,
+    extrude,
+    flat,
+    text_buffer,
+    text_font_family,
+    text_font_fill,
+    text_font_size,
+    text_font_stroke_color,
+    text_font_stroke_width,
+    text_font_style,
+    text_font_weight,
+    interactive,
+    text_interactive,
+    join,
+    miter_limit,
+    none,
+    offset,
+    text_offset,
+    order,
+    outline_cap,
+    outline_color,
+    outline_join,
+    outline_miter_limit,
+    outline_order,
+    outline_width,
+    outline_style,
+    outline_visible,
+    placement,
+    placement_spacing,
+    placement_min_length_ratio,
+    priority,
+    repeat_distance,
+    repeat_group,
+    text_order,
+    text_priority,
+    text_repeat_distance,
+    text_repeat_group,
+    size,
+    sprite,
+    sprite_default,
+    style,
+    text_source,
+    text_source_left,
+    text_source_right,
+    text_wrap,
+    tile_edges,
+    text_transform,
+    transition_hide_time,
+    transition_selected_time,
+    transition_show_time,
+    text_optional,
+    text_transition_hide_time,
+    text_transition_selected_time,
+    text_transition_show_time,
+    text_visible,
+    visible,
+    width,
+    point_text,
+    NUM_ELEMENTS
+};
+
+constexpr size_t StyleParamKeySize = static_cast<size_t>(StyleParamKey::NUM_ELEMENTS);
+
+enum class Unit { pixel, milliseconds, meter, seconds };
+
+static inline std::string unitString(Unit unit) {
+    switch(unit) {
+        case Unit::pixel: return "pixel";
+        case Unit::milliseconds: return "milliseconds";
+        case Unit::meter: return "meter";
+        case Unit::seconds: return "seconds";
+        default: return "undefined";
+    }
+}
+
+template <typename T>
+struct UnitVec {
+    T value = T(0.0);
+    static constexpr int size = sizeof(value)/sizeof(value[0]);
+    Unit units[size];
+
+    UnitVec() {
+        for (int i = 0; i < size; ++i) {
+            units[i] = Unit::meter;
+        }
+    }
+};
+
+struct StyleParam {
+
+    struct ValueUnitPair {
+        ValueUnitPair() = default;
+        ValueUnitPair(float _value, Unit _unit)
+            : value(_value), unit(_unit) {}
+
+        float value = 0.f;
+        Unit unit = Unit::meter;
+
+        bool isMeter() const { return unit == Unit::meter; }
+        bool isPixel() const { return unit == Unit::pixel; }
+        bool isSeconds() const { return unit == Unit::seconds; }
+        bool isMilliseconds() const { return unit == Unit::milliseconds; }
+
+    };
+    struct Width : ValueUnitPair {
+
+        Width() = default;
+        Width(float _value) :
+            ValueUnitPair(_value, Unit::meter) {}
+        Width(float _value, Unit _unit)
+            : ValueUnitPair(_value, _unit) {}
+
+        Width(ValueUnitPair& _other) :
+            ValueUnitPair(_other) {}
+
+        bool operator==(const Width& _other) const {
+            return value == _other.value && unit == _other.unit;
+        }
+        bool operator!=(const Width& _other) const {
+            return value != _other.value || unit != _other.unit;
+        }
+    };
+
+
+    struct TextSource {
+        std::vector<std::string> keys;
+        bool operator==(const TextSource& _other) const {
+            return keys == _other.keys;
+        }
+    };
+
+    using Value = variant<none_type, Undefined, bool, float, uint32_t, std::string, glm::vec2, Width,
+                          LabelProperty::Placement, LabelProperty::Anchors, TextSource>;
+
+    StyleParam() :
+        key(StyleParamKey::none),
+        value(none_type{}) {};
+
+    StyleParam(const std::string& _key, const std::string& _value);
+
+    StyleParam(StyleParamKey _key, std::string _value) :
+        key(_key),
+        value(std::move(_value)) {}
+
+    StyleParam(StyleParamKey _key, Stops* _stops) :
+        key(_key),
+        value(none_type{}),
+        stops(_stops) {
+    }
+
+    StyleParamKey key;
+    Value value;
+    Stops* stops = nullptr;
+    int32_t function = -1;
+
+    bool operator<(const StyleParam& _rhs) const { return key < _rhs.key; }
+    bool valid() const { return !value.is<none_type>() || stops != nullptr || function >= 0; }
+    operator bool() const { return valid(); }
+
+    std::string toString() const;
+
+    /* parse a font size (in em, pt, %) and give the appropriate size in pixel */
+    static bool parseFontSize(const std::string& _size, float& _pxSize);
+
+    static uint32_t parseColor(const std::string& _color);
+
+    static bool parseTime(const std::string& _value, float& _time);
+
+    // values within _value string parameter must be delimited by ','
+    static bool parseVec2(const std::string& _value, const std::vector<Unit>& _allowedUnits, UnitVec<glm::vec2>& _vec2);
+    static bool parseVec3(const std::string& _value, const std::vector<Unit>& _allowedUnits, UnitVec<glm::vec3>& _vec3);
+
+    static int parseValueUnitPair(const std::string& _value, size_t start,
+                                  StyleParam::ValueUnitPair& _result);
+
+    static Value parseString(StyleParamKey key, const std::string& _value);
+
+    static bool isColor(StyleParamKey _key);
+    static bool isSize(StyleParamKey _key);
+    static bool isWidth(StyleParamKey _key);
+    static bool isOffsets(StyleParamKey _key);
+    static bool isNumberType(StyleParamKey _key);
+    static bool isFontSize(StyleParamKey _key);
+    static bool isRequired(StyleParamKey _key);
+
+    static const std::vector<Unit>& unitsForStyleParam(StyleParamKey _key);
+
+    static StyleParamKey getKey(const std::string& _key);
+
+    static const std::string& keyName(StyleParamKey _key);
+
+    template<typename T>
+    struct visitor {
+        using result_type = bool;
+        T& out;
+        bool operator()(const T& v) const {
+            out = v;
+            return true;
+        }
+        template<typename O>
+        bool operator()(const O v) const {
+            return false;
+        }
+    };
+    template<typename T>
+    struct visitor_ptr {
+        using result_type = const T*;
+        const T* operator()(const T& v) const {
+            return &v;
+        }
+        template<typename O>
+        const T* operator()(const O v) const {
+            return nullptr;
+        }
+    };
+};
+
+}
diff --git a/core/src/selection/featureSelection.cpp b/core/src/selection/featureSelection.cpp
new file mode 100644 (file)
index 0000000..1887e4c
--- /dev/null
@@ -0,0 +1,21 @@
+#include "selection/featureSelection.h"
+
+namespace Tangram {
+
+FeatureSelection::FeatureSelection() :
+    m_entry(0) {
+}
+
+uint32_t FeatureSelection::nextColorIdentifier() {
+
+    uint32_t entry = m_entry++;
+
+    // skip zero every 2^32 features
+    while (entry == 0) {
+        entry = m_entry++;
+    }
+
+    return entry;
+}
+
+}
diff --git a/core/src/selection/featureSelection.h b/core/src/selection/featureSelection.h
new file mode 100644 (file)
index 0000000..94079ad
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include <atomic>
+
+namespace Tangram {
+
+class FeatureSelection {
+
+public:
+
+    FeatureSelection();
+
+    uint32_t nextColorIdentifier();
+
+private:
+
+    std::atomic<uint32_t> m_entry;
+
+};
+
+}
diff --git a/core/src/selection/selectionQuery.cpp b/core/src/selection/selectionQuery.cpp
new file mode 100644 (file)
index 0000000..32ed35b
--- /dev/null
@@ -0,0 +1,129 @@
+#include "selection/selectionQuery.h"
+
+#include "gl/framebuffer.h"
+#include "labels/label.h"
+#include "labels/labels.h"
+#include "marker/marker.h"
+#include "marker/markerManager.h"
+#include "tile/tileManager.h"
+#include "view/view.h"
+
+#include <cmath>
+
+namespace Tangram {
+
+SelectionQuery::SelectionQuery(glm::vec2 _position, float _radius, QueryCallback _queryCallback)
+    : m_position(_position), m_radius(_radius), m_queryCallback(_queryCallback) {}
+
+QueryType SelectionQuery::type() const {
+    return m_queryCallback.is<FeaturePickCallback>() ? QueryType::feature :
+          (m_queryCallback.is<LabelPickCallback>() ? QueryType::label : QueryType::marker);
+}
+
+void SelectionQuery::process(const View& _view, const FrameBuffer& _framebuffer, const MarkerManager& _markerManager,
+                             const TileManager& _tileManager, const Labels& _labels, std::vector<SelectionColorRead>& _colorCache) const {
+
+    float radius = m_radius * _view.pixelScale();
+    glm::vec2 windowCoordinates = _view.normalizedWindowCoordinates(m_position.x - radius, m_position.y + radius);
+    glm::vec2 windowSize = _view.normalizedWindowCoordinates(m_position.x + radius, m_position.y - radius) - windowCoordinates;
+
+    GLuint color = 0;
+
+    auto it = std::find_if(_colorCache.begin(), _colorCache.end(), [=](const auto& _colorRead) {
+        return (m_position == _colorRead.position) && (m_radius == _colorRead.radius);
+    });
+
+    if (it == _colorCache.end()) {
+        // Find the first non-zero color nearest to the position and within the selection radius.
+        auto rect = _framebuffer.readRect(windowCoordinates.x, windowCoordinates.y, windowSize.x, windowSize.y);
+        float minDistance = std::fmin(rect.width, rect.height);
+        float hw = static_cast<float>(rect.width) / 2.f, hh = static_cast<float>(rect.height) / 2.f;
+        for (int32_t row = 0; row < rect.height; row++) {
+            for (int32_t col = 0; col < rect.width; col++) {
+                uint32_t sample = rect.pixels[row * rect.width + col];
+                float distance = std::hypot(row - hw, col - hh);
+                if (sample != 0 && distance < minDistance) {
+                    color = sample;
+                    minDistance = distance;
+                }
+            }
+        }
+        // Cache the resulting color for other queries.
+        _colorCache.push_back({color, m_radius, m_position});
+    } else {
+        color = it->color;
+    }
+
+    switch (type()) {
+    case QueryType::feature: {
+        auto& cb = m_queryCallback.get<FeaturePickCallback>();
+
+        if (color == 0) {
+            cb(nullptr);
+            return;
+        }
+
+        for (const auto& tile : _tileManager.getVisibleTiles()) {
+            if (auto props = tile->getSelectionFeature(color)) {
+                FeaturePickResult queryResult(props, {{m_position.x, m_position.y}});
+                cb(&queryResult);
+                return;
+            }
+        }
+
+        cb(nullptr);
+    } break;
+    case QueryType::marker: {
+        auto& cb = m_queryCallback.get<MarkerPickCallback>();
+
+        if (color == 0) {
+            cb(nullptr);
+            return;
+        }
+
+        auto marker = _markerManager.getMarkerOrNullBySelectionColor(color);
+
+        if (!marker) {
+            cb(nullptr);
+            return;
+        }
+
+        glm::dvec2 bbCenter = marker->bounds().center();
+        glm::dvec2 lonLat = _view.getMapProjection().MetersToLonLat(bbCenter);
+        MarkerPickResult markerResult(marker->id(), {lonLat.x, lonLat.y}, {{m_position.x, m_position.y}});
+
+        cb(&markerResult);
+    } break;
+    case QueryType::label: {
+        auto& cb = m_queryCallback.get<LabelPickCallback>();
+
+        if (color == 0) {
+            cb(nullptr);
+            return;
+        }
+
+        auto label = _labels.getLabel(color);
+
+        if (!label.first || !label.second) {
+            cb(nullptr);
+            return;
+        }
+
+        auto props = label.second->getSelectionFeature(label.first->options().featureId);
+
+        if (!props) {
+            cb(nullptr);
+            return;
+        }
+
+        auto coordinate = label.second->coordToLngLat(label.first->modelCenter());
+
+        LabelPickResult queryResult(label.first->renderType(), LngLat{coordinate.x, coordinate.y},
+                                    FeaturePickResult(props, {{m_position.x, m_position.y}}));
+
+        cb(&queryResult);
+    } break;
+    default: break;
+    }
+}
+}
diff --git a/core/src/selection/selectionQuery.h b/core/src/selection/selectionQuery.h
new file mode 100644 (file)
index 0000000..eb42e0b
--- /dev/null
@@ -0,0 +1,45 @@
+#pragma once
+
+#include "glm/vec2.hpp"
+#include "tangram.h"
+#include "util/variant.h"
+
+namespace Tangram {
+
+class MarkerManager;
+class FrameBuffer;
+class TileManager;
+class Labels;
+class View;
+
+enum class QueryType {
+    feature,
+    marker,
+    label,
+};
+
+using QueryCallback = variant<FeaturePickCallback, LabelPickCallback, MarkerPickCallback>;
+
+struct SelectionColorRead {
+    uint32_t color;
+    float radius;
+    glm::vec2 position;
+};
+
+class SelectionQuery {
+
+public:
+    SelectionQuery(glm::vec2 _position, float _radius, QueryCallback _queryCallback);
+
+    void process(const View& _view, const FrameBuffer& _framebuffer, const MarkerManager& _markerManager,
+                 const TileManager& _tileManager, const Labels& _labels, std::vector<SelectionColorRead>& _cache) const;
+
+    QueryType type() const;
+
+private:
+    glm::vec2 m_position;
+    float m_radius;
+    QueryCallback m_queryCallback;
+
+};
+}
diff --git a/core/src/style/debugStyle.cpp b/core/src/style/debugStyle.cpp
new file mode 100644 (file)
index 0000000..1338a3e
--- /dev/null
@@ -0,0 +1,83 @@
+#include "style/debugStyle.h"
+
+#include "gl/mesh.h"
+#include "gl/shaderProgram.h"
+#include "platform.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "style/material.h"
+
+#include <memory>
+#include <vector>
+#include <string>
+
+#include "debug_vs.h"
+#include "debug_fs.h"
+
+namespace Tangram {
+
+struct PosColVertex {
+    // Position Data
+    glm::vec3 pos;
+    // Color Data
+    GLuint abgr;
+};
+
+
+DebugStyle::DebugStyle(std::string _name, Blending _blendMode, GLenum _drawMode)
+    : Style(_name, _blendMode, _drawMode, false) {}
+
+void DebugStyle::constructVertexLayout() {
+
+    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+        {"a_position", 3, GL_FLOAT, false, 0},
+        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0}
+    }));
+
+}
+
+void DebugStyle::constructShaderProgram() {
+
+    m_shaderSource->setSourceStrings(SHADER_SOURCE(debug_fs),
+                                     SHADER_SOURCE(debug_vs));
+
+}
+
+struct DebugStyleBuilder : public StyleBuilder {
+
+    const DebugStyle& m_style;
+
+    void setup(const Tile& _tile) override {}
+    void setup(const Marker& _marker, int zoom) override {}
+
+    std::unique_ptr<StyledMesh> build() override {
+        if (!Tangram::getDebugFlag(Tangram::DebugFlags::tile_bounds)) {
+            return nullptr;
+        }
+
+        auto mesh = std::make_unique<Mesh<PosColVertex>>(m_style.vertexLayout(),
+                                                         m_style.drawMode());
+
+        GLuint abgr = 0xff0000ff;
+
+        // Add four vertices to draw the outline of the tile in red
+        mesh->compile({{ 0, 1, 2, 3, 0 },
+                       {{{ 0.f, 0.f, 0.f }, abgr },
+                        {{ 1.f, 0.f, 0.f }, abgr },
+                        {{ 1.f, 1.f, 0.f }, abgr },
+                        {{ 0.f, 1.f, 0.f }, abgr }}});
+
+        return std::move(mesh);
+    }
+
+    const Style& style() const override { return m_style; }
+
+    DebugStyleBuilder(const DebugStyle& _style) : m_style(_style) {}
+
+};
+
+std::unique_ptr<StyleBuilder> DebugStyle::createBuilder() const {
+    return std::make_unique<DebugStyleBuilder>(*this);
+}
+
+}
diff --git a/core/src/style/debugStyle.h b/core/src/style/debugStyle.h
new file mode 100644 (file)
index 0000000..a40aad8
--- /dev/null
@@ -0,0 +1,25 @@
+#pragma once
+
+#include "style/style.h"
+
+namespace Tangram {
+
+class DebugStyle : public Style {
+
+protected:
+
+    virtual void constructVertexLayout() override;
+    virtual void constructShaderProgram() override;
+
+    virtual std::unique_ptr<StyleBuilder> createBuilder() const override;
+
+public:
+
+    DebugStyle(std::string _name, Blending _blendMode = Blending::overlay, GLenum _drawMode = GL_LINE_LOOP);
+
+    virtual ~DebugStyle() {
+    }
+
+};
+
+}
diff --git a/core/src/style/debugTextStyle.cpp b/core/src/style/debugTextStyle.cpp
new file mode 100644 (file)
index 0000000..d868267
--- /dev/null
@@ -0,0 +1,84 @@
+#include "style/debugTextStyle.h"
+
+#include "labels/textLabels.h"
+#include "scene/drawRule.h"
+#include "style/textStyleBuilder.h"
+#include "tangram.h"
+#include "tile/tile.h"
+
+namespace Tangram {
+
+class DebugTextStyleBuilder : public TextStyleBuilder {
+
+public:
+
+    DebugTextStyleBuilder(const TextStyle& _style)
+        : TextStyleBuilder(_style) {}
+
+    void setup(const Tile& _tile) override;
+    void setup(const Marker& _marker, int zoom) override;
+
+    std::unique_ptr<StyledMesh> build() override;
+
+private:
+    std::string m_tileID;
+
+};
+
+void DebugTextStyleBuilder::setup(const Tile& _tile) {
+    if (!Tangram::getDebugFlag(Tangram::DebugFlags::tile_infos)) {
+        return;
+    }
+
+    m_tileID = _tile.getID().toString();
+
+    TextStyleBuilder::setup(_tile);
+}
+
+void DebugTextStyleBuilder::setup(const Marker& _marker, int zoom) {
+    if (!Tangram::getDebugFlag(Tangram::DebugFlags::tile_infos)) {
+        return;
+    }
+
+    m_tileID = "I AM A MARKER";
+
+    TextStyleBuilder::setup(_marker, zoom);
+}
+
+std::unique_ptr<StyledMesh> DebugTextStyleBuilder::build() {
+    if (!Tangram::getDebugFlag(Tangram::DebugFlags::tile_infos)) {
+        return nullptr;
+    }
+
+    TextStyle::Parameters params;
+
+    params.text = m_tileID;
+    params.fontSize = 30.f;
+
+    params.font = m_style.context()->getFont("sans-serif", "normal", "400", 32 * m_style.pixelScale());
+
+    TextStyleBuilder::LabelAttributes attrib;
+    if (!prepareLabel(params, Label::Type::debug, attrib)) {
+        return nullptr;
+    }
+
+    DrawRule rule({"", 0, {}}, "", 0);
+    addLabel(Label::Type::debug, {{ glm::vec3(0.5f, 0.5f, 0.f) }}, params, attrib, rule);
+
+    m_textLabels->setLabels(m_labels);
+
+    std::vector<GlyphQuad> quads(m_quads);
+    m_textLabels->setQuads(std::move(quads), m_atlasRefs);
+
+    m_quads.clear();
+    m_atlasRefs.reset();
+    m_labels.clear();
+
+    return std::move(m_textLabels);
+}
+
+std::unique_ptr<StyleBuilder> DebugTextStyle::createBuilder() const {
+    return std::make_unique<DebugTextStyleBuilder>(*this);
+}
+
+}
diff --git a/core/src/style/debugTextStyle.h b/core/src/style/debugTextStyle.h
new file mode 100644 (file)
index 0000000..4d5af86
--- /dev/null
@@ -0,0 +1,16 @@
+#pragma once
+
+#include "style/textStyle.h"
+
+namespace Tangram {
+
+class DebugTextStyle : public TextStyle {
+
+public:
+    DebugTextStyle(std::string _name, std::shared_ptr<FontContext> _fontContext, bool _sdf = false) : TextStyle(_name, _fontContext, _sdf) {}
+
+    std::unique_ptr<StyleBuilder> createBuilder() const override;
+
+};
+
+}
diff --git a/core/src/style/material.cpp b/core/src/style/material.cpp
new file mode 100644 (file)
index 0000000..be918a3
--- /dev/null
@@ -0,0 +1,225 @@
+#include "style/material.h"
+
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "gl/shaderSource.h"
+#include "gl/texture.h"
+#include "platform.h"
+
+#include "material_glsl.h"
+
+namespace Tangram {
+
+Material::Material() {
+}
+
+void Material::setEmission(glm::vec4 _emission){
+    m_emission = _emission;
+    m_emission_texture.tex.reset();
+    setEmissionEnabled(true);
+}
+
+void Material::setEmission(MaterialTexture _emissionTexture){
+    m_emission_texture = _emissionTexture;
+    m_emission = glm::vec4(m_emission_texture.amount, 1.f);
+    setEmissionEnabled((bool)m_emission_texture.tex);
+}
+
+void Material::setAmbient(glm::vec4 _ambient){
+    m_ambient = _ambient;
+    m_ambient_texture.tex.reset();
+    setAmbientEnabled(true);
+}
+
+void Material::setAmbient(MaterialTexture _ambientTexture){
+    m_ambient_texture = _ambientTexture;
+    m_ambient = glm::vec4(m_ambient_texture.amount, 1.f);
+    setAmbientEnabled((bool)m_ambient_texture.tex);
+}
+
+void Material::setDiffuse(glm::vec4 _diffuse){
+    m_diffuse = _diffuse;
+    m_diffuse_texture.tex.reset();
+    setDiffuseEnabled(true);
+}
+
+void Material::setDiffuse(MaterialTexture _diffuseTexture){
+    m_diffuse_texture = _diffuseTexture;
+    m_diffuse = glm::vec4(m_diffuse_texture.amount, 1.f);
+    setDiffuseEnabled((bool)m_diffuse_texture.tex);
+}
+
+void Material::setSpecular(glm::vec4 _specular){
+    m_specular = _specular;
+    m_specular_texture.tex.reset();
+    setSpecularEnabled(true);
+}
+
+void Material::setSpecular(MaterialTexture _specularTexture){
+    m_specular_texture = _specularTexture;
+    m_specular = glm::vec4(m_specular_texture.amount, 1.f);
+    setSpecularEnabled((bool)m_specular_texture.tex);
+}
+
+void Material::setShininess(float _shiny) {
+    m_shininess = _shiny;
+    setSpecularEnabled(true);
+}
+
+void Material::setEmissionEnabled(bool _enable) { m_bEmission = _enable; }
+void Material::setAmbientEnabled(bool _enable) { m_bAmbient = _enable; }
+void Material::setDiffuseEnabled(bool _enable) { m_bDiffuse = _enable; }
+void Material::setSpecularEnabled(bool _enable) { m_bSpecular = _enable; }
+
+void Material::setNormal(MaterialTexture _normalTexture){
+    m_normal_texture = _normalTexture;
+    if (m_normal_texture.mapping == MappingType::spheremap){
+        m_normal_texture.mapping = MappingType::planar;
+    }
+}
+
+std::string mappingTypeToString(MappingType type) {
+    switch(type) {
+        case MappingType::uv:        return "UV";
+        case MappingType::planar:    return "PLANAR";
+        case MappingType::triplanar: return "TRIPLANAR";
+        case MappingType::spheremap: return "SPHEREMAP";
+        default:                     return "";
+    }
+}
+
+std::string Material::getDefinesBlock(){
+    std::string defines = "";
+
+    bool mappings[4] = { false };
+
+    if (m_bEmission) {
+        defines += "#define TANGRAM_MATERIAL_EMISSION\n";
+        if (m_emission_texture.tex) {
+            defines += "#define TANGRAM_MATERIAL_EMISSION_TEXTURE\n";
+            defines += "#define TANGRAM_MATERIAL_EMISSION_TEXTURE_" +
+                mappingTypeToString(m_emission_texture.mapping) + "\n";
+            mappings[(int)m_emission_texture.mapping] = true;
+        }
+    }
+
+    if (m_bAmbient) {
+        defines += "#define TANGRAM_MATERIAL_AMBIENT\n";
+        if (m_ambient_texture.tex) {
+            defines += "#define TANGRAM_MATERIAL_AMBIENT_TEXTURE\n";
+            defines += "#define TANGRAM_MATERIAL_AMBIENT_TEXTURE_" +
+                mappingTypeToString(m_ambient_texture.mapping) + "\n";
+            mappings[(int)m_ambient_texture.mapping] = true;
+        }
+    }
+
+    if (m_bDiffuse) {
+        defines += "#define TANGRAM_MATERIAL_DIFFUSE\n";
+        if (m_diffuse_texture.tex) {
+            defines += "#define TANGRAM_MATERIAL_DIFFUSE_TEXTURE\n";
+            defines += "#define TANGRAM_MATERIAL_DIFFUSE_TEXTURE_" +
+                mappingTypeToString(m_diffuse_texture.mapping) + "\n";
+            mappings[(int)m_diffuse_texture.mapping] = true;
+        }
+    }
+
+    if (m_bSpecular) {
+        defines += "#define TANGRAM_MATERIAL_SPECULAR\n";
+        if (m_specular_texture.tex) {
+            defines += "#define TANGRAM_MATERIAL_SPECULAR_TEXTURE\n";
+            defines += "#define TANGRAM_MATERIAL_SPECULAR_TEXTURE_" +
+                mappingTypeToString(m_specular_texture.mapping) + "\n";
+            mappings[(int)m_specular_texture.mapping] = true;
+        }
+    }
+
+    if (m_normal_texture.tex){
+        defines += "#define TANGRAM_MATERIAL_NORMAL_TEXTURE\n";
+        defines += "#define TANGRAM_MATERIAL_NORMAL_TEXTURE_" +
+            mappingTypeToString(m_normal_texture.mapping) + "\n";
+        mappings[(int)m_specular_texture.mapping] = true;
+    }
+
+    for (int i = 0; i < 4; i++) {
+        if (mappings[i]) {
+            defines += "#define TANGRAM_MATERIAL_TEXTURE_" + mappingTypeToString((MappingType)i) + "\n";
+        }
+    }
+
+    return defines;
+}
+
+std::string Material::getClassBlock() {
+    return SHADER_SOURCE(material_glsl);
+}
+
+std::unique_ptr<MaterialUniforms> Material::injectOnProgram(ShaderSource& _source ) {
+    _source.addSourceBlock("defines", getDefinesBlock(), false);
+    _source.addSourceBlock("material", getClassBlock(), false);
+    _source.addSourceBlock("setup", "material = u_material;", false);
+
+    if (m_bEmission || m_bAmbient || m_bDiffuse || m_bSpecular || m_normal_texture.tex) {
+        return std::make_unique<MaterialUniforms>();
+    }
+    return nullptr;
+}
+
+void Material::setupProgram(RenderState& rs, ShaderProgram& _shader, MaterialUniforms& _uniforms) {
+
+    auto& u = _uniforms;
+
+    if (m_bEmission) {
+        _shader.setUniformf(rs, u.emission, m_emission);
+
+        if (m_emission_texture.tex) {
+            m_emission_texture.tex->update(rs, rs.nextAvailableTextureUnit());
+            m_emission_texture.tex->bind(rs, rs.currentTextureUnit());
+            _shader.setUniformi(rs, u.emissionTexture, rs.currentTextureUnit());
+            _shader.setUniformf(rs, u.emissionScale, m_emission_texture.scale);
+        }
+    }
+
+    if (m_bAmbient) {
+        _shader.setUniformf(rs, u.ambient, m_ambient);
+
+        if (m_ambient_texture.tex) {
+            m_ambient_texture.tex->update(rs, rs.nextAvailableTextureUnit());
+            m_ambient_texture.tex->bind(rs, rs.currentTextureUnit());
+            _shader.setUniformi(rs, u.ambientTexture, rs.currentTextureUnit());
+            _shader.setUniformf(rs, u.ambientScale, m_ambient_texture.scale);
+        }
+    }
+
+    if (m_bDiffuse) {
+        _shader.setUniformf(rs, u.diffuse, m_diffuse);
+
+        if (m_diffuse_texture.tex) {
+            m_diffuse_texture.tex->update(rs, rs.nextAvailableTextureUnit());
+            m_diffuse_texture.tex->bind(rs, rs.currentTextureUnit());
+            _shader.setUniformi(rs, u.diffuseTexture, rs.currentTextureUnit());
+            _shader.setUniformf(rs, u.diffuseScale, m_diffuse_texture.scale);
+        }
+    }
+
+    if (m_bSpecular) {
+        _shader.setUniformf(rs, u.specular, m_specular);
+        _shader.setUniformf(rs, u.shininess, m_shininess);
+
+        if (m_specular_texture.tex) {
+            m_specular_texture.tex->update(rs, rs.nextAvailableTextureUnit());
+            m_specular_texture.tex->bind(rs, rs.currentTextureUnit());
+            _shader.setUniformi(rs, u.specularTexture, rs.currentTextureUnit());
+            _shader.setUniformf(rs, u.specularScale, m_specular_texture.scale);
+        }
+    }
+
+    if (m_normal_texture.tex) {
+        m_normal_texture.tex->update(rs, rs.nextAvailableTextureUnit());
+        m_normal_texture.tex->bind(rs, rs.currentTextureUnit());
+        _shader.setUniformi(rs, u.normalTexture, rs.currentTextureUnit());
+        _shader.setUniformf(rs, u.normalScale, m_normal_texture.scale);
+        _shader.setUniformf(rs, u.normalAmount, m_normal_texture.amount);
+    }
+}
+
+}
diff --git a/core/src/style/material.h b/core/src/style/material.h
new file mode 100644 (file)
index 0000000..76c301f
--- /dev/null
@@ -0,0 +1,146 @@
+/* MATERIAL
+-------------------------------
+This openGL Material implementation follows from the WebGL version of Tangram
+( https://github.com/tangrams/tangram/wiki/Materials-Overview )
+*/
+
+#pragma once
+
+#include "gl/uniform.h"
+
+#include "glm/vec3.hpp"
+#include "glm/vec4.hpp"
+#include <memory>
+#include <string>
+
+namespace Tangram {
+
+class RenderState;
+class Texture;
+class ShaderProgram;
+class ShaderSource;
+
+enum class MappingType {
+    uv,
+    planar,
+    triplanar,
+    spheremap
+};
+
+struct MaterialTexture {
+    std::shared_ptr<Texture> tex = nullptr;
+    MappingType mapping = MappingType::uv;
+    glm::vec3 scale = glm::vec3(1.f);
+    glm::vec3 amount = glm::vec3(1.f);
+};
+
+struct MaterialUniforms {
+
+    UniformLocation emission{"u_material.emission"};
+    UniformLocation emissionTexture{"material_emission_texture"};
+    UniformLocation emissionScale{"u_material.emissionScale"};
+
+    UniformLocation ambient{"u_material.ambient"};
+    UniformLocation ambientTexture{"u_material_ambient_texture"};
+    UniformLocation ambientScale{"u_material.ambientScale"};
+
+    UniformLocation diffuse{"u_material.diffuse"};
+    UniformLocation diffuseTexture{"u_material_diffuse_texture"};
+    UniformLocation diffuseScale{"u_material.diffuseScale"};
+
+    UniformLocation specular{"u_material.specular"};
+    UniformLocation shininess{"u_material.shininess"};
+
+    UniformLocation specularTexture{"u_material_specular_texture"};
+    UniformLocation specularScale{"u_material.specularScale"};
+
+    UniformLocation normalTexture{"u_material_normal_texture"};
+    UniformLocation normalScale{"u_material.normalScale"};
+    UniformLocation normalAmount{"u_material.normalAmount"};
+};
+
+class Material {
+public:
+
+    Material();
+
+    virtual ~Material(){};
+
+    /*  Emission color is by default disabled and vec4(0.0).
+     *  Setting this property enables it and changes require reloading the shader. */
+    void setEmission(glm::vec4 _emission);
+    void setEmission(MaterialTexture _emissionTexture);
+
+    /*  Ambient color is by default disabled and vec4(1.0).
+     *  Setting this property enables it and changes require reloading the shader. */
+    void setAmbient(glm::vec4 _ambient);
+    void setAmbient(MaterialTexture _ambientTexture);
+
+    /*  Diffuse color is by default enabled and vec4(1.0).
+     *  Changes require reloading the shader. */
+    void setDiffuse(glm::vec4 _diffuse);
+    void setDiffuse(MaterialTexture _diffuseTexture);
+
+    /*  Specular color is by default disabled and vec4(0.2) with a shininess factor of 0.2.
+     *  Setting this property enables it and changes require reloading the shader. */
+    void setSpecular(glm::vec4 _specular);
+    void setSpecular(MaterialTexture _specularTexture);
+
+    void setShininess(float _shiny);
+
+    /* Enable or disable emission colors */
+    void setEmissionEnabled(bool _enable);
+
+    /* Enable or disable ambient colors */
+    void setAmbientEnabled(bool _enable);
+
+    /* Enable or disable diffuse colors */
+    void setDiffuseEnabled(bool _enable);
+
+    /* Enable or disable specular colors */
+    void setSpecularEnabled(bool _enable);
+
+    void setNormal(MaterialTexture _normalTexture);
+
+    /*  Inject the needed lines of GLSL code on the shader to make this material work */
+    virtual std::unique_ptr<MaterialUniforms> injectOnProgram(ShaderSource& _shader);
+
+    /*  Method to pass it self as a uniform to the shader program */
+    virtual void setupProgram(RenderState& rs, ShaderProgram& _shader,
+                              MaterialUniforms& _uniforms);
+
+    bool hasEmission() const { return m_bEmission; }
+    bool hasAmbient() const { return m_bAmbient; }
+    bool hasDiffuse() const { return m_bDiffuse; }
+    bool hasSpecular() const { return m_bSpecular; }
+
+private:
+
+    /* Get defines that need to be injected on top of the shader */
+    std::string getDefinesBlock();
+
+    /* Get the GLSL struct and classes need to be injected */
+    std::string getClassBlock();
+
+    bool m_bEmission = false;
+    glm::vec4 m_emission = glm::vec4(1.f);
+    MaterialTexture m_emission_texture;
+
+    bool m_bAmbient = false;
+    glm::vec4 m_ambient = glm::vec4(1.f);
+    MaterialTexture m_ambient_texture;
+
+    bool m_bDiffuse = true;
+    glm::vec4 m_diffuse = glm::vec4(1.f);
+    MaterialTexture m_diffuse_texture;
+
+    bool m_bSpecular = false;
+    glm::vec4 m_specular = glm::vec4(.2f);
+    MaterialTexture m_specular_texture;
+
+    MaterialTexture m_normal_texture;
+
+    float m_shininess = .2f;
+};
+
+}
diff --git a/core/src/style/pointStyle.cpp b/core/src/style/pointStyle.cpp
new file mode 100644 (file)
index 0000000..e4e5617
--- /dev/null
@@ -0,0 +1,100 @@
+#include "style/pointStyle.h"
+
+#include "gl/dynamicQuadMesh.h"
+#include "gl/shaderProgram.h"
+#include "gl/texture.h"
+#include "gl/vertexLayout.h"
+#include "platform.h"
+#include "scene/spriteAtlas.h"
+#include "style/pointStyleBuilder.h"
+#include "view/view.h"
+
+#include "point_vs.h"
+#include "point_fs.h"
+
+namespace Tangram {
+
+PointStyle::PointStyle(std::string _name, std::shared_ptr<FontContext> _fontContext,
+                       Blending _blendMode, GLenum _drawMode, bool _selection)
+    : Style(_name, _blendMode, _drawMode, _selection) {
+
+    m_textStyle = std::make_unique<TextStyle>(_name, _fontContext, true, _blendMode, _drawMode);
+}
+
+PointStyle::~PointStyle() {}
+
+void PointStyle::build(const Scene& _scene) {
+    Style::build(_scene);
+
+    m_textStyle->build(_scene);
+
+    m_mesh = std::make_unique<DynamicQuadMesh<SpriteVertex>>(m_vertexLayout, m_drawMode);
+}
+
+void PointStyle::constructVertexLayout() {
+
+    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+        {"a_position", 3, GL_FLOAT, false, 0},
+        {"a_uv", 2, GL_UNSIGNED_SHORT, true, 0},
+        {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        {"a_alpha", 1, GL_UNSIGNED_SHORT, true, 0},
+        {"a_scale", 1, GL_UNSIGNED_SHORT, false, 0},
+    }));
+}
+
+void PointStyle::constructShaderProgram() {
+    m_shaderSource->setSourceStrings(SHADER_SOURCE(point_fs),
+                                     SHADER_SOURCE(point_vs));
+}
+
+void PointStyle::onBeginUpdate() {
+    m_mesh->clear();
+    m_textStyle->onBeginUpdate();
+}
+
+void PointStyle::onBeginFrame(RenderState& rs) {
+    // Upload meshes for next frame
+    m_mesh->upload(rs);
+    m_textStyle->onBeginFrame(rs);
+}
+
+void PointStyle::onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) {
+    Style::onBeginDrawFrame(rs, _view, _scene);
+
+    auto texUnit = rs.nextAvailableTextureUnit();
+
+    m_shaderProgram->setUniformi(rs, m_mainUniforms.uTex, texUnit);
+    m_shaderProgram->setUniformMatrix4f(rs, m_mainUniforms.uOrtho,
+                                        _view.getOrthoViewportMatrix());
+
+    m_mesh->draw(rs, *m_shaderProgram, texUnit);
+
+    m_textStyle->onBeginDrawFrame(rs, _view, _scene);
+}
+
+void PointStyle::onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene) {
+    if (!m_selection) { return; }
+
+    m_mesh->upload(rs);
+
+    Style::onBeginDrawSelectionFrame(rs, _view, _scene);
+
+    m_selectionProgram->setUniformMatrix4f(rs, m_selectionUniforms.uOrtho,
+                                           _view.getOrthoViewportMatrix());
+
+    m_mesh->draw(rs, *m_selectionProgram, false);
+
+    m_textStyle->onBeginDrawSelectionFrame(rs, _view, _scene);
+}
+
+std::unique_ptr<StyleBuilder> PointStyle::createBuilder() const {
+    return std::make_unique<PointStyleBuilder>(*this);
+}
+
+void PointStyle::setPixelScale(float _pixelScale) {
+    Style::setPixelScale(_pixelScale);
+    m_textStyle->setPixelScale(_pixelScale);
+}
+
+}
diff --git a/core/src/style/pointStyle.h b/core/src/style/pointStyle.h
new file mode 100644 (file)
index 0000000..0043d63
--- /dev/null
@@ -0,0 +1,100 @@
+#pragma once
+
+#include "gl/dynamicQuadMesh.h"
+#include "labels/spriteLabel.h"
+#include "labels/labelProperty.h"
+#include "labels/textLabels.h"
+#include "style/style.h"
+#include "style/textStyle.h"
+
+#include "glm/vec3.hpp"
+#include "glm/vec2.hpp"
+
+namespace Tangram {
+
+class Texture;
+class SpriteAtlas;
+
+class PointStyle : public Style {
+
+public:
+
+    struct Parameters {
+        bool interactive = false;
+        bool keepTileEdges = false;
+        bool autoAngle = false;
+        std::string sprite;
+        std::string spriteDefault;
+        glm::vec2 size;
+        uint32_t color = 0xffffffff;
+        Label::Options labelOptions;
+        LabelProperty::Placement placement = LabelProperty::Placement::vertex;
+        float extrudeScale = 1.f;
+        float placementMinLengthRatio = 1.0f;
+        float placementSpacing = 80.f;
+    };
+
+    PointStyle(std::string _name, std::shared_ptr<FontContext> _fontContext,
+               Blending _blendMode = Blending::overlay, GLenum _drawMode = GL_TRIANGLES, bool _selection = true);
+
+    virtual void onBeginUpdate() override;
+    virtual void onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) override;
+    virtual void onBeginFrame(RenderState& rs) override;
+    virtual void onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene) override;
+    virtual void draw(RenderState& rs, const Tile& _tile) override {}
+    virtual void draw(RenderState& rs, const Marker& _marker) override {}
+
+    void setSpriteAtlas(std::shared_ptr<SpriteAtlas> _spriteAtlas) { m_spriteAtlas = _spriteAtlas; }
+    void setTexture(std::shared_ptr<Texture> _texture) { m_texture = _texture; }
+
+    const auto& texture() const { return m_texture; }
+    const auto& spriteAtlas() const { return m_spriteAtlas; }
+
+    virtual ~PointStyle();
+
+    auto& getMesh() const { return m_mesh; }
+    virtual size_t dynamicMeshSize() const override { return m_mesh->bufferSize(); }
+
+    virtual std::unique_ptr<StyleBuilder> createBuilder() const override;
+
+    virtual void build(const Scene& _scene) override;
+
+    virtual void constructVertexLayout() override;
+    virtual void constructShaderProgram() override;
+
+    TextStyle& textStyle() const { return *m_textStyle; }
+    virtual void setPixelScale(float _pixelScale) override;
+
+protected:
+
+    std::shared_ptr<SpriteAtlas> m_spriteAtlas;
+    std::shared_ptr<Texture> m_texture;
+
+    struct UniformBlock {
+        UniformLocation uTex{"u_tex"};
+        UniformLocation uOrtho{"u_ortho"};
+    } m_mainUniforms, m_selectionUniforms;
+
+    mutable std::unique_ptr<DynamicQuadMesh<SpriteVertex>> m_mesh;
+
+    std::unique_ptr<TextStyle> m_textStyle;
+};
+
+}
+
+namespace std {
+    template <>
+    struct hash<Tangram::PointStyle::Parameters> {
+        size_t operator() (const Tangram::PointStyle::Parameters& p) const {
+            std::hash<Tangram::Label::Options> optionsHash;
+            std::size_t seed = 0;
+            hash_combine(seed, p.sprite);
+            hash_combine(seed, p.color);
+            hash_combine(seed, p.size.x);
+            hash_combine(seed, p.size.y);
+            hash_combine(seed, (int)p.placement);
+            hash_combine(seed, optionsHash(p.labelOptions));
+            return seed;
+        }
+    };
+}
diff --git a/core/src/style/pointStyleBuilder.cpp b/core/src/style/pointStyleBuilder.cpp
new file mode 100644 (file)
index 0000000..d6fd233
--- /dev/null
@@ -0,0 +1,495 @@
+#include "style/pointStyleBuilder.h"
+
+#include "data/propertyItem.h"
+#include "marker/marker.h"
+#include "labels/labelCollider.h"
+#include "labels/spriteLabel.h"
+#include "log.h"
+#include "scene/drawRule.h"
+#include "scene/spriteAtlas.h"
+#include "scene/stops.h"
+#include "selection/featureSelection.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "util/geom.h"
+#include "util/lineSampler.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+
+void IconMesh::setTextLabels(std::unique_ptr<StyledMesh> _textLabels) {
+
+    auto* mesh = static_cast<TextLabels*>(_textLabels.get());
+    auto& labels = mesh->getLabels();
+
+    typedef std::vector<std::unique_ptr<Label>>::iterator iter_t;
+    m_labels.insert(m_labels.end(),
+                    std::move_iterator<iter_t>(labels.begin()),
+                    std::move_iterator<iter_t>(labels.end()));
+
+    labels.clear();
+
+    textLabels = std::move(_textLabels);
+}
+
+void PointStyleBuilder::addLayoutItems(LabelCollider& _layout) {
+    _layout.addLabels(m_labels);
+    m_textStyleBuilder->addLayoutItems(_layout);
+}
+
+std::unique_ptr<StyledMesh> PointStyleBuilder::build() {
+    if (m_quads.empty()) { return nullptr; }
+
+
+    if (Tangram::getDebugFlag(DebugFlags::draw_all_labels)) {
+
+        m_iconMesh->setLabels(m_labels);
+
+    } else {
+        size_t sumLabels = 0;
+
+        // Determine number of labels
+       for (auto& label : m_labels) {
+           if (label->state() != Label::State::dead) { sumLabels +=1; }
+        }
+
+       std::vector<std::unique_ptr<Label>> labels;
+       labels.reserve(sumLabels);
+
+       for (auto& label : m_labels) {
+           if (label->state() != Label::State::dead) {
+               labels.push_back(std::move(label));
+           }
+       }
+       m_iconMesh->setLabels(labels);
+    }
+
+    std::vector<SpriteQuad> quads(m_quads);
+    m_spriteLabels->setQuads(std::move(quads));
+
+    m_quads.clear();
+    m_labels.clear();
+
+    m_iconMesh->spriteLabels = std::move(m_spriteLabels);
+
+    if (auto textLabels = m_textStyleBuilder->build()) {
+        m_iconMesh->setTextLabels(std::move(textLabels));
+    }
+
+    return std::move(m_iconMesh);
+}
+
+void PointStyleBuilder::setup(const Tile& _tile) {
+    m_zoom = _tile.getID().z;
+    m_styleZoom = _tile.getID().s;
+
+    // < 1.0 when overzooming a tile
+    m_tileScale = pow(2, _tile.getID().s - _tile.getID().z);
+
+    m_spriteLabels = std::make_unique<SpriteLabels>(m_style);
+
+    m_textStyleBuilder->setup(_tile);
+    m_iconMesh = std::make_unique<IconMesh>();
+}
+
+void PointStyleBuilder::setup(const Marker& _marker, int zoom) {
+    m_zoom = zoom;
+    m_styleZoom = zoom;
+    m_spriteLabels = std::make_unique<SpriteLabels>(m_style);
+
+    m_textStyleBuilder->setup(_marker, zoom);
+    m_iconMesh = std::make_unique<IconMesh>();
+
+    m_texture = _marker.texture();
+}
+
+bool PointStyleBuilder::checkRule(const DrawRule& _rule) const {
+    uint32_t checkColor;
+    // require a color or texture atlas/texture to be valid
+    if (!_rule.get(StyleParamKey::color, checkColor) &&
+        !m_style.texture() &&
+        !m_style.spriteAtlas()) {
+        return false;
+    }
+    return true;
+}
+
+auto PointStyleBuilder::applyRule(const DrawRule& _rule, const Properties& _props) const -> PointStyle::Parameters {
+
+    PointStyle::Parameters p;
+    glm::vec2 size;
+
+    _rule.get(StyleParamKey::color, p.color);
+    _rule.get(StyleParamKey::sprite, p.sprite);
+    _rule.get(StyleParamKey::offset, p.labelOptions.offset);
+    _rule.get(StyleParamKey::buffer, p.labelOptions.buffer);
+
+    uint32_t priority = 0;
+    size_t repeatGroupHash = 0;
+    std::string repeatGroup;
+    StyleParam::Width repeatDistance;
+
+    if (_rule.get(StyleParamKey::priority, priority)) {
+        p.labelOptions.priority = (float)priority;
+    }
+
+    _rule.get(StyleParamKey::sprite_default, p.spriteDefault);
+    _rule.get(StyleParamKey::placement, p.placement);
+    StyleParam::Width placementSpacing;
+    auto placementSpacingParam = _rule.findParameter(StyleParamKey::placement_spacing);
+    if (placementSpacingParam.stops) {
+        p.placementSpacing = placementSpacingParam.stops->evalFloat(m_styleZoom);
+    } else if (_rule.get(StyleParamKey::placement_spacing, placementSpacing)) {
+        p.placementSpacing = placementSpacing.value;
+    }
+    auto placementMinLengthParam = _rule.findParameter(StyleParamKey::placement_min_length_ratio);
+    if (placementMinLengthParam.stops) {
+        p.placementMinLengthRatio = placementMinLengthParam.stops->evalFloat(m_styleZoom);
+    } else {
+        _rule.get(StyleParamKey::placement_min_length_ratio, p.placementMinLengthRatio);
+    }
+    _rule.get(StyleParamKey::tile_edges, p.keepTileEdges);
+    _rule.get(StyleParamKey::interactive, p.interactive);
+    _rule.get(StyleParamKey::collide, p.labelOptions.collide);
+    _rule.get(StyleParamKey::transition_hide_time, p.labelOptions.hideTransition.time);
+    _rule.get(StyleParamKey::transition_selected_time, p.labelOptions.selectTransition.time);
+    _rule.get(StyleParamKey::transition_show_time, p.labelOptions.showTransition.time);
+    _rule.get(StyleParamKey::flat, p.labelOptions.flat);
+    _rule.get(StyleParamKey::anchor, p.labelOptions.anchors);
+
+    if (_rule.get(StyleParamKey::repeat_distance, repeatDistance)) {
+        p.labelOptions.repeatDistance = repeatDistance.value;
+    }
+
+    if (p.labelOptions.repeatDistance > 0.f) {
+        if (_rule.get(StyleParamKey::repeat_group, repeatGroup)) {
+            hash_combine(repeatGroupHash, repeatGroup);
+        } else {
+            repeatGroupHash = _rule.getParamSetHash();
+        }
+
+        p.labelOptions.repeatGroup = repeatGroupHash;
+        p.labelOptions.repeatDistance *= m_style.pixelScale();
+    }
+
+    if (p.labelOptions.anchors.count == 0) {
+        p.labelOptions.anchors.anchor = { {LabelProperty::Anchor::center} };
+        p.labelOptions.anchors.count = 1;
+    }
+
+    _rule.get(StyleParamKey::angle, p.labelOptions.angle);
+    if (std::isnan(p.labelOptions.angle)) {
+        p.autoAngle = true;
+    }
+
+    auto sizeParam = _rule.findParameter(StyleParamKey::size);
+    if (sizeParam.stops) {
+        if (sizeParam.value.is<float>()) {
+            // Assume size here is 1D (TODO: 2D, in another PR)
+            // size to build this label from
+            float lowerSize = sizeParam.stops->evalSize(m_styleZoom).get<float>();
+            // size for next style zoom for interpolation
+            float higherSize = sizeParam.stops->evalSize(m_styleZoom + 1).get<float>();
+            p.extrudeScale = (higherSize - lowerSize);
+            p.size = glm::vec2(lowerSize);
+        } else if (sizeParam.value.is<glm::vec2>()) {
+            p.size = sizeParam.stops->evalExpVec2(m_styleZoom);
+            // NB: this assumes that the width/height ratio is
+            // constant for all stops
+            glm::vec2 higherSize = sizeParam.stops->evalExpVec2(m_styleZoom + 1);
+            p.extrudeScale = (higherSize.x - p.size.x);
+        }
+    } else if (_rule.get(StyleParamKey::size, size)) {
+        if (size.x == 0.f || std::isnan(size.y)) {
+            p.size = glm::vec2(size.x);
+        } else {
+            p.size = size;
+        }
+    } else {
+        p.size = glm::vec2(NAN, NAN);
+    }
+
+    std::hash<PointStyle::Parameters> hash;
+    p.labelOptions.paramHash = hash(p);
+
+    if (p.interactive) {
+        p.labelOptions.featureId = _rule.selectionColor;
+    }
+
+    return p;
+}
+
+void PointStyleBuilder::addLabel(const Point& _point, const glm::vec4& _quad,
+                                 const PointStyle::Parameters& _params, const DrawRule& _rule) {
+
+    uint32_t selectionColor = 0;
+
+    if (_params.interactive) {
+        if (_rule.featureSelection) {
+            selectionColor = _rule.featureSelection->nextColorIdentifier();
+        } else {
+            selectionColor = _rule.selectionColor;
+        }
+    }
+
+    m_labels.push_back(std::make_unique<SpriteLabel>(glm::vec3(glm::vec2(_point), m_zoom),
+                                                     _params.size,
+                                                     _params.labelOptions,
+                                                     SpriteLabel::VertexAttributes{_params.color,
+                                                             selectionColor, _params.extrudeScale },
+                                                     m_texture,
+                                                     *m_spriteLabels,
+                                                     m_quads.size()));
+
+    glm::i16vec2 size = _params.size;
+
+    // Attribute will be normalized - scale to max short;
+    glm::vec2 uvTR = glm::vec2{_quad.z, _quad.w} * SpriteVertex::texture_scale;
+    glm::vec2 uvBL = glm::vec2{_quad.x, _quad.y} * SpriteVertex::texture_scale;
+
+    float sx = size.x * 0.5f;
+    float sy = size.y * 0.5f;
+
+    glm::vec2 v0(-sx, sy);
+    glm::vec2 v1(sx, sy);
+    glm::vec2 v2(-sx, -sy);
+    glm::vec2 v3(sx, -sy);
+
+    if (_params.labelOptions.angle != 0.f) {
+        // Rotate the sprite icon quad vertices in clockwise order
+        glm::vec2 rotation(cos(-DEG_TO_RAD * _params.labelOptions.angle),
+                           sin(-DEG_TO_RAD * _params.labelOptions.angle));
+
+        v0 = rotateBy(v0, rotation);
+        v1 = rotateBy(v1, rotation);
+        v2 = rotateBy(v2, rotation);
+        v3 = rotateBy(v3, rotation);
+    }
+
+    m_quads.push_back({{
+        {v0, {uvBL.x, uvTR.y}},
+        {v1, {uvTR.x, uvTR.y}},
+        {v2, {uvBL.x, uvBL.y}},
+        {v3, {uvTR.x, uvBL.y}}}
+        });
+}
+
+bool PointStyleBuilder::getUVQuad(PointStyle::Parameters& _params, glm::vec4& _quad) const {
+    _quad = glm::vec4(0.0, 1.0, 1.0, 0.0);
+
+    if (m_style.spriteAtlas()) {
+        SpriteNode spriteNode;
+
+        if (!m_style.spriteAtlas()->getSpriteNode(_params.sprite, spriteNode) &&
+            !m_style.spriteAtlas()->getSpriteNode(_params.spriteDefault, spriteNode)) {
+            return false;
+        }
+
+        if (std::isnan(_params.size.x)) {
+            _params.size = spriteNode.m_size;
+        }
+
+        _quad.x = spriteNode.m_uvBL.x;
+        _quad.y = spriteNode.m_uvBL.y;
+        _quad.z = spriteNode.m_uvTR.x;
+        _quad.w = spriteNode.m_uvTR.y;
+    } else {
+        // default point size
+        if (std::isnan(_params.size.x)) {
+            _params.size = glm::vec2(8.0);
+        }
+    }
+
+    _params.size *= m_style.pixelScale();
+
+    return true;
+}
+
+void PointStyleBuilder::labelPointsPlacing(const Line& _line, const glm::vec4& uvsQuad,
+                                           PointStyle::Parameters& params, const DrawRule& _rule) {
+
+    if (_line.size() < 2) { return; }
+
+    auto isOutsideTile = [](const Point& p) {
+        float tolerance = 0.0005;
+        float tile_min = 0.0 + tolerance;
+        float tile_max = 1.0 - tolerance;
+        return ((p.x < tile_min) || (p.x > tile_max) ||
+                (p.y < tile_min) || (p.y > tile_max));
+    };
+
+    auto angleBetween = [](const Point& p, const Point& q) {
+        return RAD_TO_DEG * atan2(q[0] - p[0], q[1] - p[1]);
+    };
+
+    float minLineLength = std::max(params.size.x, params.size.y) *
+        params.placementMinLengthRatio * m_style.pixelScale() /
+        (View::s_pixelsPerTile * m_tileScale);
+
+    switch(params.placement) {
+        case LabelProperty::Placement::vertex: {
+            for (size_t i = 0; i < _line.size() - 1; i++) {
+                auto& p = _line[i];
+                auto& q = _line[i+1];
+                if (params.keepTileEdges || !isOutsideTile(p)) {
+                    if (params.autoAngle) {
+                        params.labelOptions.angle = angleBetween(p, q);
+                    }
+                    addLabel(p, uvsQuad, params, _rule);
+                    if (i == _line.size() - 2) {
+                        // Place label on endpoint
+                        addLabel(q, uvsQuad, params, _rule);
+                    }
+                }
+            }
+            break;
+        }
+        case LabelProperty::Placement::midpoint:
+            for (size_t i = 0; i < _line.size() - 1; i++) {
+                auto& p = _line[i];
+                auto& q = _line[i+1];
+                if ( (params.keepTileEdges || !isOutsideTile(p)) &&
+                     (minLineLength == 0.0f || glm::distance(p, q) > minLineLength) ) {
+                    if (params.autoAngle) {
+                        params.labelOptions.angle = angleBetween(p, q);
+                    }
+                    glm::vec3 midpoint(0.5f * (p.x + q.x), 0.5f * (p.y + q.y), 0.0f);
+                    addLabel(midpoint, uvsQuad, params, _rule);
+                }
+            }
+            break;
+        case LabelProperty::Placement::spaced: {
+            LineSampler<std::vector<Point>> sampler;
+
+            sampler.set(_line);
+
+            float lineLength = sampler.sumLength();
+            if (lineLength <= minLineLength) { break; }
+
+            float spacing = params.placementSpacing * m_style.pixelScale() /
+                (View::s_pixelsPerTile * m_tileScale);
+
+            int numLabels = std::max(std::floor(lineLength / spacing), 1.0f);
+            float remainderLength = lineLength - (numLabels - 1) * spacing;
+            float distance = 0.5 * remainderLength;
+            glm::vec2 p, r;
+            sampler.advance(distance, p, r);
+            do {
+
+                if (sampler.lengthToPrevSegment() < minLineLength*0.5 ||
+                    sampler.lengthToNextSegment() < minLineLength*0.5) {
+                    continue;
+                }
+                if (params.autoAngle) {
+                    params.labelOptions.angle = RAD_TO_DEG * atan2(r.x, r.y);
+                }
+
+                addLabel({p.x, p.y, 0.f}, uvsQuad, params, _rule);
+
+            } while (sampler.advance(spacing, p, r));
+        }
+        break;
+        case LabelProperty::Placement::centroid:
+            // nothing to be done here.
+            break;
+    }
+}
+
+bool PointStyleBuilder::addPoint(const Point& _point, const Properties& _props,
+                                 const DrawRule& _rule) {
+
+    PointStyle::Parameters p = applyRule(_rule, _props);
+    glm::vec4 uvsQuad;
+
+    if (!getUVQuad(p, uvsQuad)) {
+        return false;
+    }
+
+    addLabel(_point, uvsQuad, p, _rule);
+
+    return true;
+}
+
+bool PointStyleBuilder::addLine(const Line& _line, const Properties& _props,
+                                const DrawRule& _rule) {
+
+    PointStyle::Parameters p = applyRule(_rule, _props);
+    glm::vec4 uvsQuad;
+
+    if (!getUVQuad(p, uvsQuad)) {
+        return false;
+    }
+
+    labelPointsPlacing(_line, uvsQuad, p, _rule);
+
+    return true;
+}
+
+bool PointStyleBuilder::addPolygon(const Polygon& _polygon, const Properties& _props,
+                                   const DrawRule& _rule) {
+
+    PointStyle::Parameters p = applyRule(_rule, _props);
+    glm::vec4 uvsQuad;
+
+    if (!getUVQuad(p, uvsQuad)) {
+        return false;
+    }
+
+    if (p.placement != LabelProperty::centroid) {
+        for (auto line : _polygon) {
+            labelPointsPlacing(line, uvsQuad, p, _rule);
+        }
+    } else {
+        if (!_polygon.empty()) {
+            glm::vec3 c;
+            c = centroid(_polygon.front().begin(), _polygon.front().end());
+            addLabel(c, uvsQuad, p, _rule);
+        }
+    }
+
+    return true;
+}
+
+bool PointStyleBuilder::addFeature(const Feature& _feat, const DrawRule& _rule) {
+
+    size_t iconsStart = m_labels.size();
+
+    if (!StyleBuilder::addFeature(_feat, _rule)) {
+        return false;
+    }
+
+    size_t iconsCount = m_labels.size() - iconsStart;
+
+    bool textVisible = true;
+    _rule.get(StyleParamKey::text_visible, textVisible);
+
+    if (textVisible && _rule.contains(StyleParamKey::point_text)) {
+        if (iconsCount == 0) { return true; }
+
+        auto& textStyleBuilder = static_cast<TextStyleBuilder&>(*m_textStyleBuilder);
+        auto& textLabels = *textStyleBuilder.labels();
+
+        TextStyle::Parameters params = textStyleBuilder.applyRule(_rule, _feat.props, true);
+
+        TextStyleBuilder::LabelAttributes attrib;
+        if (textStyleBuilder.prepareLabel(params, Label::Type::point, attrib)) {
+
+            for (size_t i = 0; i < iconsCount; i++) {
+                auto pLabel = static_cast<SpriteLabel*>(m_labels[iconsStart + i].get());
+                auto p = pLabel->modelCenter();
+                textStyleBuilder.addLabel(Label::Type::point, {{p, p}}, params, attrib, _rule);
+
+                bool definePriority = !_rule.contains(StyleParamKey::text_priority);
+                bool defineCollide = _rule.contains(StyleParamKey::collide);
+
+                // Link labels together
+                textLabels.back()->setRelative(*pLabel, definePriority, defineCollide);
+            }
+        }
+    }
+
+    return true;
+}
+
+}
diff --git a/core/src/style/pointStyleBuilder.h b/core/src/style/pointStyleBuilder.h
new file mode 100644 (file)
index 0000000..5bd6433
--- /dev/null
@@ -0,0 +1,76 @@
+#pragma once
+
+#include "style/style.h"
+#include "style/pointStyle.h"
+#include "style/textStyleBuilder.h"
+#include <map>
+#include <memory>
+#include <vector>
+
+namespace Tangram {
+
+struct IconMesh : LabelSet {
+
+    std::unique_ptr<StyledMesh> textLabels;
+    std::unique_ptr<StyledMesh> spriteLabels;
+
+    void setTextLabels(std::unique_ptr<StyledMesh> _textLabels);
+};
+
+struct PointStyleBuilder : public StyleBuilder {
+
+    const PointStyle& m_style;
+
+
+    void setup(const Tile& _tile) override;
+    void setup(const Marker& _marker, int zoom) override;
+
+    bool checkRule(const DrawRule& _rule) const override;
+
+    bool addPolygon(const Polygon& _polygon, const Properties& _props, const DrawRule& _rule) override;
+    bool addLine(const Line& _line, const Properties& _props, const DrawRule& _rule) override;
+    bool addPoint(const Point& _line, const Properties& _props, const DrawRule& _rule) override;
+
+    std::unique_ptr<StyledMesh> build() override;
+
+    const Style& style() const override { return m_style; }
+
+    PointStyleBuilder(const PointStyle& _style) : m_style(_style) {
+        m_textStyleBuilder = m_style.textStyle().createBuilder();
+    }
+
+    bool getUVQuad(PointStyle::Parameters& _params, glm::vec4& _quad) const;
+
+    PointStyle::Parameters applyRule(const DrawRule& _rule, const Properties& _props) const;
+
+    // Gets points for label placement and appropriate angle for each label (if `auto` angle is set)
+    void labelPointsPlacing(const Line& _line, const glm::vec4& _quad,
+                            PointStyle::Parameters& _params, const DrawRule& _rule);
+
+    void addLabel(const Point& _point, const glm::vec4& _quad,
+                  const PointStyle::Parameters& _params, const DrawRule& _rule);
+
+    void addLayoutItems(LabelCollider& _layout) override;
+
+    bool addFeature(const Feature& _feat, const DrawRule& _rule) override;
+
+private:
+
+
+    std::vector<std::unique_ptr<Label>> m_labels;
+    std::vector<SpriteQuad> m_quads;
+
+    std::unique_ptr<IconMesh> m_iconMesh;
+
+    float m_zoom = 0;
+    float m_styleZoom = 0;
+    float m_tileScale = 1;
+    std::unique_ptr<SpriteLabels> m_spriteLabels;
+    std::unique_ptr<StyleBuilder> m_textStyleBuilder;
+
+    // Non-owning reference to a texture to use for the current feature.
+    Texture* m_texture = nullptr;
+
+};
+
+}
diff --git a/core/src/style/polygonStyle.cpp b/core/src/style/polygonStyle.cpp
new file mode 100644 (file)
index 0000000..21ae690
--- /dev/null
@@ -0,0 +1,208 @@
+#include "style/polygonStyle.h"
+
+#include "gl/mesh.h"
+#include "gl/shaderProgram.h"
+#include "marker/marker.h"
+#include "material.h"
+#include "platform.h"
+#include "scene/drawRule.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "util/builders.h"
+#include "util/extrude.h"
+
+#include "glm/vec2.hpp"
+#include "glm/vec3.hpp"
+#include "glm/gtc/type_precision.hpp"
+#include <cmath>
+
+#include "polygon_fs.h"
+#include "polygon_vs.h"
+
+constexpr float position_scale = 8192.0f;
+constexpr float texture_scale = 65535.0f;
+constexpr float normal_scale = 127.0f;
+
+namespace Tangram {
+
+
+struct PolygonVertexNoUVs {
+
+    PolygonVertexNoUVs(glm::vec3 position, uint32_t order, glm::vec3 normal, glm::vec2 uv, GLuint abgr, GLuint selection)
+        : pos(glm::i16vec4{ glm::round(position * position_scale), order }),
+          norm(normal * normal_scale),
+          abgr(abgr),
+          selection(selection) {}
+
+    glm::i16vec4 pos; // pos.w contains layer (params.order)
+    glm::i8vec3 norm;
+    uint8_t padding = 0;
+    GLuint abgr;
+    GLuint selection;
+};
+
+struct PolygonVertex : PolygonVertexNoUVs {
+
+    PolygonVertex(glm::vec3 position, uint32_t order, glm::vec3 normal, glm::vec2 uv, GLuint abgr, GLuint selection)
+        : PolygonVertexNoUVs(position, order, normal, uv, abgr, selection), texcoord(uv * texture_scale) {}
+
+    glm::u16vec2 texcoord;
+};
+
+PolygonStyle::PolygonStyle(std::string _name, Blending _blendMode, GLenum _drawMode, bool _selection)
+    : Style(_name, _blendMode, _drawMode, _selection)
+{}
+
+void PolygonStyle::constructVertexLayout() {
+
+    if (m_texCoordsGeneration) {
+        m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 4, GL_SHORT, false, 0},
+            {"a_normal", 4, GL_BYTE, true, 0}, // The 4th byte is for padding
+            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_texcoord", 2, GL_UNSIGNED_SHORT, true, 0},
+        }));
+    } else {
+        m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 4, GL_SHORT, false, 0},
+            {"a_normal", 4, GL_BYTE, true, 0},
+            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        }));
+    }
+
+}
+
+void PolygonStyle::constructShaderProgram() {
+
+    m_shaderSource->setSourceStrings(SHADER_SOURCE(polygon_fs),
+                                      SHADER_SOURCE(polygon_vs));
+
+    if (m_texCoordsGeneration) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_USE_TEX_COORDS\n");
+    }
+}
+
+template <class V>
+struct PolygonStyleBuilder : public StyleBuilder {
+
+public:
+
+    struct {
+        uint32_t order = 0;
+        uint32_t color = 0xffffffff;
+        glm::vec2 extrude;
+        float height;
+        float minHeight;
+        uint32_t selectionColor = 0;
+    } m_params;
+
+    void setup(const Tile& _tile) override {
+        m_tileUnitsPerMeter = _tile.getInverseScale();
+        m_zoom = _tile.getID().z;
+        m_meshData.clear();
+    }
+
+    void setup(const Marker& _marker, int zoom) override {
+        m_zoom = zoom;
+        m_tileUnitsPerMeter = 1.f / _marker.extent();
+        m_meshData.clear();
+    }
+
+    bool addPolygon(const Polygon& _polygon, const Properties& _props, const DrawRule& _rule) override;
+
+    const Style& style() const override { return m_style; }
+
+    std::unique_ptr<StyledMesh> build() override;
+
+    PolygonStyleBuilder(const PolygonStyle& _style) : m_style(_style) {}
+
+    void parseRule(const DrawRule& _rule, const Properties& _props);
+
+    PolygonBuilder& polygonBuilder() { return m_builder; }
+
+private:
+
+    const PolygonStyle& m_style;
+
+    PolygonBuilder m_builder;
+
+    MeshData<V> m_meshData;
+
+    float m_tileUnitsPerMeter = 0;
+    int m_zoom = 0;
+
+};
+
+template <class V>
+std::unique_ptr<StyledMesh> PolygonStyleBuilder<V>::build() {
+    if (m_meshData.vertices.empty()) { return nullptr; }
+
+    auto mesh = std::make_unique<Mesh<V>>(m_style.vertexLayout(),
+                                                      m_style.drawMode());
+    mesh->compile(m_meshData);
+    m_meshData.clear();
+
+    return std::move(mesh);
+}
+
+template <class V>
+void PolygonStyleBuilder<V>::parseRule(const DrawRule& _rule, const Properties& _props) {
+    _rule.get(StyleParamKey::color, m_params.color);
+    _rule.get(StyleParamKey::extrude, m_params.extrude);
+    _rule.get(StyleParamKey::order, m_params.order);
+
+    if (Tangram::getDebugFlag(Tangram::DebugFlags::proxy_colors)) {
+        m_params.color <<= (m_zoom % 6);
+    }
+
+    auto& extrude = m_params.extrude;
+    m_params.minHeight = getLowerExtrudeMeters(extrude, _props) * m_tileUnitsPerMeter;
+    m_params.height = getUpperExtrudeMeters(extrude, _props) * m_tileUnitsPerMeter;
+
+    m_params.selectionColor = _rule.selectionColor;
+}
+
+template <class V>
+bool PolygonStyleBuilder<V>::addPolygon(const Polygon& _polygon, const Properties& _props, const DrawRule& _rule) {
+
+    parseRule(_rule, _props);
+
+    m_builder.addVertex = [this](const glm::vec3& coord,
+                                 const glm::vec3& normal,
+                                 const glm::vec2& uv) {
+        m_meshData.vertices.push_back({ coord, m_params.order, normal, uv, m_params.color, m_params.selectionColor });
+    };
+
+    if (m_params.minHeight != m_params.height) {
+        Builders::buildPolygonExtrusion(_polygon, m_params.minHeight,
+                                        m_params.height, m_builder);
+    }
+
+    Builders::buildPolygon(_polygon, m_params.height, m_builder);
+
+    m_meshData.indices.insert(m_meshData.indices.end(),
+                              m_builder.indices.begin(),
+                              m_builder.indices.end());
+
+    m_meshData.offsets.emplace_back(m_builder.indices.size(),
+                                    m_builder.numVertices);
+    m_builder.clear();
+
+    return true;
+}
+
+std::unique_ptr<StyleBuilder> PolygonStyle::createBuilder() const {
+    if (m_texCoordsGeneration) {
+        auto builder = std::make_unique<PolygonStyleBuilder<PolygonVertex>>(*this);
+        builder->polygonBuilder().useTexCoords = true;
+        return std::move(builder);
+    } else {
+        auto builder = std::make_unique<PolygonStyleBuilder<PolygonVertexNoUVs>>(*this);
+        builder->polygonBuilder().useTexCoords = false;
+        return std::move(builder);
+    }
+}
+
+}
diff --git a/core/src/style/polygonStyle.h b/core/src/style/polygonStyle.h
new file mode 100644 (file)
index 0000000..13014a9
--- /dev/null
@@ -0,0 +1,23 @@
+#pragma once
+
+#include "style/style.h"
+
+#include <mutex>
+#include <tuple>
+
+namespace Tangram {
+
+class PolygonStyle : public Style {
+
+public:
+
+    PolygonStyle(std::string _name, Blending _blendMode = Blending::opaque, GLenum _drawMode = GL_TRIANGLES, bool _selection = true);
+
+    virtual void constructVertexLayout() override;
+    virtual void constructShaderProgram() override;
+    virtual std::unique_ptr<StyleBuilder> createBuilder() const override;
+    virtual ~PolygonStyle() {}
+
+};
+
+}
diff --git a/core/src/style/polylineStyle.cpp b/core/src/style/polylineStyle.cpp
new file mode 100644 (file)
index 0000000..115e824
--- /dev/null
@@ -0,0 +1,511 @@
+#include "style/polylineStyle.h"
+
+#include "gl/shaderProgram.h"
+#include "gl/mesh.h"
+#include "gl/texture.h"
+#include "gl/renderState.h"
+#include "log.h"
+#include "marker/marker.h"
+#include "material.h"
+#include "platform.h"
+#include "scene/stops.h"
+#include "scene/drawRule.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "util/builders.h"
+#include "util/dashArray.h"
+#include "util/extrude.h"
+#include "util/floatFormatter.h"
+#include "util/mapProjection.h"
+
+#include "glm/vec3.hpp"
+#include "glm/gtc/type_precision.hpp"
+
+#include "polyline_vs.h"
+#include "polyline_fs.h"
+
+constexpr float extrusion_scale = 4096.0f;
+constexpr float position_scale = 8192.0f;
+constexpr float texture_scale = 8192.0f;
+constexpr float order_scale = 2.0f;
+constexpr float dash_scale = 20.f;
+
+namespace Tangram {
+
+struct PolylineVertexNoUVs {
+    PolylineVertexNoUVs(glm::vec2 position, glm::vec2 extrude, glm::vec2 uv,
+                        glm::i16vec2 width, glm::i16vec2 height, GLuint abgr, GLuint selection)
+        : pos(glm::i16vec2{ glm::round(position * position_scale)}, height),
+          extrude(glm::i16vec2{extrude * extrusion_scale}, width),
+          abgr(abgr),
+          selection(selection) {}
+
+    PolylineVertexNoUVs(PolylineVertexNoUVs v, short order, glm::i16vec2 width, GLuint abgr, GLuint selection)
+        : pos(glm::i16vec4{glm::i16vec3{v.pos}, order}),
+          extrude(glm::i16vec4{ v.extrude.x, v.extrude.y, width }),
+          abgr(abgr),
+          selection(selection) {}
+
+    glm::i16vec4 pos;
+    glm::i16vec4 extrude;
+    GLuint abgr;
+    GLuint selection;
+};
+
+struct PolylineVertex : PolylineVertexNoUVs {
+    PolylineVertex(glm::vec2 position, glm::vec2 extrude, glm::vec2 uv,
+                   glm::i16vec2 width, glm::i16vec2 height, GLuint abgr, GLuint selection)
+        : PolylineVertexNoUVs(position, extrude, uv, width, height, abgr, selection),
+          texcoord(uv * texture_scale) {}
+
+    PolylineVertex(PolylineVertex v, short order, glm::i16vec2 width, GLuint abgr, GLuint selection)
+        : PolylineVertexNoUVs(v, order, width, abgr, selection),
+          texcoord(v.texcoord) {}
+
+    glm::u16vec2 texcoord;
+};
+
+PolylineStyle::PolylineStyle(std::string _name, Blending _blendMode, GLenum _drawMode, bool _selection)
+    : Style(_name, _blendMode, _drawMode, _selection)
+{}
+
+void PolylineStyle::constructVertexLayout() {
+
+    // TODO: Ideally this would be in the same location as the struct that it basically describes
+    if (m_texCoordsGeneration) {
+        m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 4, GL_SHORT, false, 0},
+            {"a_extrude", 4, GL_SHORT, false, 0},
+            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_texcoord", 2, GL_UNSIGNED_SHORT, false, 0},
+        }));
+    } else {
+        m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+            {"a_position", 4, GL_SHORT, false, 0},
+            {"a_extrude", 4, GL_SHORT, false, 0},
+            {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+            {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        }));
+    }
+
+}
+
+void PolylineStyle::onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) {
+    Style::onBeginDrawFrame(rs, _view, _scene);
+
+    if (m_texture) {
+        GLuint textureUnit = rs.nextAvailableTextureUnit();
+
+        m_texture->update(rs, textureUnit);
+        m_texture->bind(rs, textureUnit);
+
+        m_shaderProgram->setUniformi(rs, m_uTexture, textureUnit);
+        m_shaderProgram->setUniformf(rs, m_uTextureRatio, m_texture->getHeight() / m_texture->getWidth());
+    }
+}
+
+void PolylineStyle::setDashBackgroundColor(const glm::vec4 _dashBackgroundColor) {
+    m_dashBackgroundColor = _dashBackgroundColor;
+    m_dashBackground = true;
+}
+
+void PolylineStyle::constructShaderProgram() {
+
+    m_shaderSource->setSourceStrings(SHADER_SOURCE(polyline_fs),
+                                     SHADER_SOURCE(polyline_vs));
+
+    if (m_dashArray.size() > 0) {
+        TextureOptions options {GL_RGBA, GL_RGBA, {GL_NEAREST, GL_NEAREST}, {GL_CLAMP_TO_EDGE, GL_CLAMP_TO_EDGE}};
+        // provides precision for dash patterns that are a fraction of line width
+        auto pixels = DashArray::render(m_dashArray, dash_scale);
+
+        m_texture = std::make_shared<Texture>(1, pixels.size(), options);
+        m_texture->setData(pixels.data(), pixels.size());
+
+        if (m_dashBackground) {
+            m_shaderSource->addSourceBlock("defines", "#define TANGRAM_LINE_BACKGROUND_COLOR vec3(" +
+                ff::to_string(m_dashBackgroundColor.r) + ", " +
+                ff::to_string(m_dashBackgroundColor.g) + ", " +
+                ff::to_string(m_dashBackgroundColor.b) + ")\n");
+        }
+    }
+
+    if (m_dashArray.size() > 0 || m_texture) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_LINE_TEXTURE\n", false);
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_ALPHA_TEST 0.25\n", false);
+        if (m_dashArray.size() > 0) {
+            m_shaderSource->addSourceBlock("defines", "#define TANGRAM_DASHLINE_TEX_SCALE " +
+                                            ff::to_string(dash_scale) + "\n", false);
+        } else {
+            m_shaderSource->addSourceBlock("defines", "#define TANGRAM_DASHLINE_TEX_SCALE 1.0\n", false);
+        }
+    }
+
+    if (m_texCoordsGeneration) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_USE_TEX_COORDS\n");
+    }
+}
+
+template <class V>
+struct PolylineStyleBuilder : public StyleBuilder {
+
+public:
+
+    struct Parameters {
+
+        struct Attributes {
+            // Values prepared for the currently build mesh
+            glm::i16vec2 height;
+            glm::i16vec2 width;
+            uint32_t color;
+            float miterLimit = 3.0;
+            CapTypes cap = CapTypes::butt;
+            JoinTypes join = JoinTypes::miter;
+
+            void set(float _width, float _dWdZ, float _height, float _order) {
+                height = { glm::round(_height * position_scale), _order * order_scale};
+                width = { glm::round(_width * extrusion_scale), glm::round(_dWdZ * extrusion_scale) };
+            }
+        } fill, stroke;
+
+        bool keepTileEdges = false;
+        bool closedPolygon = false;
+        bool outlineOn = false;
+        bool lineOn = true;
+        uint32_t selectionColor = 0;
+    };
+
+    void setup(const Tile& _tile) override;
+    void setup(const Marker& _marker, int zoom) override;
+
+    const Style& style() const override { return m_style; }
+
+    bool addFeature(const Feature& _feat, const DrawRule& _rule) override;
+
+    std::unique_ptr<StyledMesh> build() override;
+
+    PolylineStyleBuilder(const PolylineStyle& _style)
+        : m_style(_style),
+          m_meshData(2) {}
+
+    void addMesh(const Line& _line, const Parameters& _params);
+
+    void buildLine(const Line& _line, const typename Parameters::Attributes& _att,
+                   MeshData<V>& _mesh, GLuint _selection);
+
+    Parameters parseRule(const DrawRule& _rule, const Properties& _props);
+
+    bool evalWidth(const StyleParam& _styleParam, float& width, float& slope);
+
+    PolyLineBuilder& polylineBuilder() { return m_builder; }
+
+private:
+
+    const PolylineStyle& m_style;
+    PolyLineBuilder m_builder;
+
+    std::vector<MeshData<V>> m_meshData;
+
+    float m_tileUnitsPerMeter = 0;
+    float m_tileUnitsPerPixel = 0;
+    int m_zoom = 0;
+    float m_overzoom2 = 1;
+};
+
+template <class V>
+void PolylineStyleBuilder<V>::setup(const Tile& tile) {
+
+    const auto& id = tile.getID();
+
+    // Use the 'style zoom' to evaluate style parameters.
+    m_zoom = id.s;
+    m_overzoom2 = exp2(id.s - id.z);
+    m_tileUnitsPerMeter = tile.getInverseScale();
+    m_tileUnitsPerPixel = 1.f / tile.getProjection()->TileSize();
+
+    // When a tile is overzoomed, we are actually styling the area of its
+    // 'source' tile, which will have a larger effective pixel size at the
+    // 'style' zoom level. This scaling is performed in the vertex shader to
+    // prevent loss of precision for small dimensions in packed attributes.
+}
+
+template <class V>
+void PolylineStyleBuilder<V>::setup(const Marker& marker, int zoom) {
+
+    m_zoom = zoom;
+    m_overzoom2 = 1.f;
+    m_tileUnitsPerMeter = 1.f / marker.extent();
+    float metersPerTile = 2.f * MapProjection::HALF_CIRCUMFERENCE * exp2(-zoom);
+
+    // In general, a Marker won't cover the same area as a tile, so the effective
+    // "tile size" for building a Marker is the size of a tile in pixels multiplied
+    // by the ratio of the Marker's extent to the length of a tile side at this zoom.
+    m_tileUnitsPerPixel = metersPerTile / (marker.extent() * 256.f);
+
+}
+
+template <class V>
+std::unique_ptr<StyledMesh> PolylineStyleBuilder<V>::build() {
+    if (m_meshData[0].vertices.empty() &&
+        m_meshData[1].vertices.empty()) {
+        return nullptr;
+    }
+
+    auto mesh = std::make_unique<Mesh<V>>(m_style.vertexLayout(), m_style.drawMode());
+
+    bool painterMode = (m_style.blendMode() == Blending::overlay ||
+                        m_style.blendMode() == Blending::inlay);
+
+    // Swap draw order to draw outline first when not using depth testing
+    if (painterMode) { std::swap(m_meshData[0], m_meshData[1]); }
+
+    mesh->compile(m_meshData);
+
+    // Swapping back since fill mesh may have more vertices than outline
+    if (painterMode) { std::swap(m_meshData[0], m_meshData[1]); }
+
+    m_meshData[0].clear();
+    m_meshData[1].clear();
+    return std::move(mesh);
+}
+
+template <class V>
+auto PolylineStyleBuilder<V>::parseRule(const DrawRule& _rule, const Properties& _props) -> Parameters {
+    Parameters p;
+
+    uint32_t cap = 0, join = 0;
+
+    struct {
+        uint32_t order = 0;
+        uint32_t color = 0xff00ffff;
+        float width = 0.f;
+        float slope = 0.f;
+    } fill, stroke;
+
+    auto& width = _rule.findParameter(StyleParamKey::width);
+    if (!evalWidth(width, fill.width, fill.slope)) {
+        fill.width = 0;
+        return p;
+    }
+    fill.slope -= fill.width;
+    _rule.get(StyleParamKey::color, p.fill.color);
+    _rule.get(StyleParamKey::cap, cap);
+    _rule.get(StyleParamKey::join, join);
+    _rule.get(StyleParamKey::order, fill.order);
+    _rule.get(StyleParamKey::tile_edges, p.keepTileEdges);
+    _rule.get(StyleParamKey::miter_limit, p.fill.miterLimit);
+
+    p.fill.cap = static_cast<CapTypes>(cap);
+    p.fill.join = static_cast<JoinTypes>(join);
+
+    glm::vec2 extrude = glm::vec2(0);
+    _rule.get(StyleParamKey::extrude, extrude);
+
+    float height = getUpperExtrudeMeters(extrude, _props);
+    height *= m_tileUnitsPerMeter;
+
+    p.fill.set(fill.width, fill.slope, height, fill.order);
+    p.lineOn = !_rule.isOutlineOnly;
+
+    stroke.order = fill.order;
+    p.stroke.cap = p.fill.cap;
+    p.stroke.join = p.fill.join;
+    p.stroke.miterLimit = p.fill.miterLimit;
+
+    auto& strokeWidth = _rule.findParameter(StyleParamKey::outline_width);
+    bool outlineVisible = true;
+    _rule.get(StyleParamKey::outline_visible, outlineVisible);
+    if ( outlineVisible && (!p.lineOn || !_rule.findParameter(StyleParamKey::outline_style)) ) {
+        if (strokeWidth |
+            _rule.get(StyleParamKey::outline_order, stroke.order) |
+            _rule.get(StyleParamKey::outline_cap, cap) |
+            _rule.get(StyleParamKey::outline_join, join) |
+            _rule.get(StyleParamKey::outline_miter_limit, p.stroke.miterLimit)) {
+
+            p.stroke.cap = static_cast<CapTypes>(cap);
+            p.stroke.join = static_cast<JoinTypes>(join);
+
+            if (!_rule.get(StyleParamKey::outline_color, p.stroke.color)) { return p; }
+            if (!evalWidth(strokeWidth, stroke.width, stroke.slope)) {
+                return p;
+            }
+
+            // NB: Multiply by 2 for the stroke to get the expected stroke pixel width.
+            stroke.width *= 2.0f;
+            stroke.slope *= 2.0f;
+            stroke.slope -= stroke.width;
+
+            stroke.width += fill.width;
+            stroke.slope += fill.slope;
+
+            stroke.order = std::min(stroke.order, fill.order);
+
+            p.stroke.set(stroke.width, stroke.slope,
+                    height, stroke.order - 0.5f);
+
+            p.outlineOn = true;
+        }
+    }
+
+    if (Tangram::getDebugFlag(Tangram::DebugFlags::proxy_colors)) {
+        fill.color <<= (m_zoom % 6);
+        stroke.color <<= (m_zoom % 6);
+    }
+
+    p.selectionColor = _rule.selectionColor;
+
+    return p;
+}
+
+template <class V>
+bool PolylineStyleBuilder<V>::evalWidth(const StyleParam& _styleParam, float& width, float& slope) {
+
+    // NB: 0.5 because 'width' will be extruded in both directions
+    float pixelWidthScale = .5f * m_tileUnitsPerPixel;
+    float meterWidthScale = .5f * m_tileUnitsPerMeter * m_overzoom2;
+
+    if (_styleParam.stops) {
+
+        width = _styleParam.value.get<float>();
+        width *= pixelWidthScale;
+
+        slope = _styleParam.stops->evalExpFloat(m_zoom + 1);
+        slope *= pixelWidthScale;
+        return true;
+    }
+
+    if (_styleParam.value.is<StyleParam::Width>()) {
+        auto& widthParam = _styleParam.value.get<StyleParam::Width>();
+
+        width = widthParam.value;
+
+        if (widthParam.isMeter()) {
+            width *= meterWidthScale;
+            slope = width * 2;
+        } else {
+            width *= pixelWidthScale;
+            slope = width;
+        }
+        return true;
+    }
+
+    LOGD("Invalid type for Width '%d'", _styleParam.value.which());
+    return false;
+}
+
+template <class V>
+bool PolylineStyleBuilder<V>::addFeature(const Feature& _feat, const DrawRule& _rule) {
+
+    if (_feat.geometryType == GeometryType::points) { return false; }
+    if (!checkRule(_rule)) { return false; }
+
+    Parameters params = parseRule(_rule, _feat.props);
+
+    if (params.fill.width[0] <= 0.0f && params.fill.width[1] <= 0.0f ) { return false; }
+
+    if (_feat.geometryType == GeometryType::lines) {
+        // Line geometries are never clipped to tiles, so keep all segments
+        params.keepTileEdges = true;
+
+        for (auto& line : _feat.lines) {
+            addMesh(line, params);
+        }
+    } else {
+        params.closedPolygon = true;
+
+        for (auto& polygon : _feat.polygons) {
+            for (const auto& line : polygon) {
+                addMesh(line, params);
+            }
+        }
+    }
+
+    return true;
+}
+
+template <class V>
+void PolylineStyleBuilder<V>::buildLine(const Line& _line, const typename Parameters::Attributes& _att,
+                                        MeshData<V>& _mesh, GLuint selection) {
+
+    float zoom = m_overzoom2;
+    m_builder.addVertex = [&](const glm::vec3& coord, const glm::vec2& normal, const glm::vec2& uv) {
+        _mesh.vertices.push_back({{ coord.x,coord.y }, normal, { uv.x, uv.y * zoom },
+                                  _att.width, _att.height, _att.color, selection});
+    };
+
+    Builders::buildPolyLine(_line, m_builder);
+
+    _mesh.indices.insert(_mesh.indices.end(),
+                         m_builder.indices.begin(),
+                         m_builder.indices.end());
+
+    _mesh.offsets.emplace_back(m_builder.indices.size(),
+                               m_builder.numVertices);
+
+    m_builder.clear();
+}
+
+template <class V>
+void PolylineStyleBuilder<V>::addMesh(const Line& _line, const Parameters& _params) {
+
+    m_builder.cap = _params.fill.cap;
+    m_builder.join = _params.fill.join;
+    m_builder.miterLimit = _params.fill.miterLimit;
+    m_builder.keepTileEdges = _params.keepTileEdges;
+    m_builder.closedPolygon = _params.closedPolygon;
+
+    if (_params.lineOn) { buildLine(_line, _params.fill, m_meshData[0], _params.selectionColor); }
+
+    if (!_params.outlineOn) { return; }
+
+    if (!_params.lineOn ||
+        _params.stroke.cap != _params.fill.cap ||
+        _params.stroke.join != _params.fill.join ||
+        _params.stroke.miterLimit != _params.fill.miterLimit) {
+        // need to re-triangulate with different cap and/or join
+        m_builder.cap = _params.stroke.cap;
+        m_builder.join = _params.stroke.join;
+        m_builder.miterLimit = _params.stroke.miterLimit;
+
+        buildLine(_line, _params.stroke, m_meshData[1], _params.selectionColor);
+
+    } else {
+        auto& fill = m_meshData[0];
+        auto& stroke = m_meshData[1];
+
+        // reuse indices from original line, overriding color and width
+        size_t nIndices = fill.offsets.back().first;
+        size_t nVertices = fill.offsets.back().second;
+        stroke.offsets.emplace_back(nIndices, nVertices);
+
+        auto indicesIt = fill.indices.end() - nIndices;
+        stroke.indices.insert(stroke.indices.end(),
+                                 indicesIt,
+                                 fill.indices.end());
+
+        auto vertexIt = fill.vertices.end() - nVertices;
+
+        glm::vec2 width = _params.stroke.width;
+        GLuint abgr = _params.stroke.color;
+        short order = _params.stroke.height[1];
+
+        for (; vertexIt != fill.vertices.end(); ++vertexIt) {
+            stroke.vertices.emplace_back(*vertexIt, order, width, abgr, _params.selectionColor);
+        }
+    }
+}
+
+std::unique_ptr<StyleBuilder> PolylineStyle::createBuilder() const {
+    if (m_texCoordsGeneration) {
+        auto builder = std::make_unique<PolylineStyleBuilder<PolylineVertex>>(*this);
+        builder->polylineBuilder().useTexCoords = true;
+        return std::move(builder);
+    } else {
+        auto builder = std::make_unique<PolylineStyleBuilder<PolylineVertexNoUVs>>(*this);
+        builder->polylineBuilder().useTexCoords = false;
+        return std::move(builder);
+    }
+}
+
+}
diff --git a/core/src/style/polylineStyle.h b/core/src/style/polylineStyle.h
new file mode 100644 (file)
index 0000000..c103da9
--- /dev/null
@@ -0,0 +1,37 @@
+#pragma once
+
+#include "style/style.h"
+
+namespace Tangram {
+
+class Texture;
+
+class PolylineStyle : public Style {
+
+public:
+
+    PolylineStyle(std::string _name, Blending _blendMode = Blending::opaque, GLenum _drawMode = GL_TRIANGLES, bool _selection = true);
+
+    virtual void constructVertexLayout() override;
+    virtual void constructShaderProgram() override;
+    virtual std::unique_ptr<StyleBuilder> createBuilder() const override;
+    virtual void onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) override;
+    virtual ~PolylineStyle() {}
+
+    void setDashArray(std::vector<float> _dashArray) { m_dashArray = _dashArray; }
+    void setTexture(std::shared_ptr<Texture>& _texture) { m_texture = _texture; }
+
+    void setDashBackgroundColor(const glm::vec4 _dashBackgroundColor);
+
+private:
+
+    std::vector<float> m_dashArray;
+    std::shared_ptr<Texture> m_texture;
+    bool m_dashBackground = false;
+    glm::vec4 m_dashBackgroundColor;
+
+    UniformLocation m_uTexture{"u_texture"};
+    UniformLocation m_uTextureRatio{"u_texture_ratio"};
+};
+
+}
diff --git a/core/src/style/rasterStyle.cpp b/core/src/style/rasterStyle.cpp
new file mode 100644 (file)
index 0000000..f7f46dd
--- /dev/null
@@ -0,0 +1,18 @@
+#include "style/rasterStyle.h"
+
+#include "gl/mesh.h"
+#include "gl/shaderProgram.h"
+
+namespace Tangram {
+
+RasterStyle::RasterStyle(std::string _name, Blending _blendMode, GLenum _drawMode)
+    : PolygonStyle(_name, _blendMode, _drawMode, false)
+{
+    m_rasterType = RasterType::color;
+}
+
+void RasterStyle::constructShaderProgram() {
+    PolygonStyle::constructShaderProgram();
+}
+
+}
diff --git a/core/src/style/rasterStyle.h b/core/src/style/rasterStyle.h
new file mode 100644 (file)
index 0000000..b7a0348
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "style/polygonStyle.h"
+
+namespace Tangram {
+
+class RasterStyle : public PolygonStyle {
+
+protected:
+
+    virtual void constructShaderProgram() override;
+
+    virtual bool hasRasters() const override { return true; }
+
+public:
+
+    RasterStyle(std::string _name, Blending _blendMode = Blending::opaque, GLenum _drawMode = GL_TRIANGLES);
+
+};
+
+}
diff --git a/core/src/style/style.cpp b/core/src/style/style.cpp
new file mode 100644 (file)
index 0000000..ce519b5
--- /dev/null
@@ -0,0 +1,538 @@
+#include "style/style.h"
+
+#include "data/tileSource.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "gl/mesh.h"
+#include "log.h"
+#include "marker/marker.h"
+#include "scene/light.h"
+#include "scene/scene.h"
+#include "scene/spriteAtlas.h"
+#include "scene/styleParam.h"
+#include "style/material.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "view/view.h"
+
+#include "rasters_glsl.h"
+
+namespace Tangram {
+
+Style::Style(std::string _name, Blending _blendMode, GLenum _drawMode, bool _selection) :
+    m_name(_name),
+    m_shaderSource(std::make_unique<ShaderSource>()),
+    m_blend(_blendMode),
+    m_drawMode(_drawMode),
+    m_selection(_selection) {
+    m_material.material = std::make_shared<Material>();
+}
+
+Style::~Style() {}
+
+Style::LightHandle::LightHandle(Light* _light, std::unique_ptr<LightUniforms> _uniforms)
+    : light(_light), uniforms(std::move(_uniforms)){}
+
+const std::vector<std::string>& Style::builtInStyleNames() {
+    static std::vector<std::string> builtInStyleNames{ "points", "lines", "polygons", "text", "debug", "debugtext" };
+    return builtInStyleNames;
+}
+
+void Style::build(const Scene& _scene) {
+
+    constructVertexLayout();
+    constructShaderProgram();
+
+    if (m_blend == Blending::inlay) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_BLEND_INLAY\n", false);
+    } else if (m_blend == Blending::overlay) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_BLEND_OVERLAY\n", false);
+    }
+
+    if (m_material.material) {
+        m_material.uniforms = m_material.material->injectOnProgram(*m_shaderSource);
+    }
+
+    if (m_lightingType != LightingType::none) {
+
+        switch (m_lightingType) {
+        case LightingType::vertex:
+            m_shaderSource->addSourceBlock("defines", "#define TANGRAM_LIGHTING_VERTEX\n", false);
+            break;
+        case LightingType::fragment:
+            m_shaderSource->addSourceBlock("defines", "#define TANGRAM_LIGHTING_FRAGMENT\n", false);
+            break;
+        default:
+            break;
+        }
+
+        for (auto& light : _scene.lights()) {
+            auto uniforms = light->getUniforms();
+            if (uniforms) {
+                m_lights.emplace_back(light.get(), std::move(uniforms));
+            }
+        }
+        for (auto& block : _scene.lightBlocks()) {
+            m_shaderSource->addSourceBlock(block.first, block.second);
+        }
+    }
+
+    setupRasters(_scene.tileSources());
+
+    const auto& blocks = m_shaderSource->getSourceBlocks();
+    if (blocks.find("color") != blocks.end() ||
+        blocks.find("filter") != blocks.end() ||
+        blocks.find("raster") != blocks.end()) {
+        m_hasColorShaderBlock = true;
+    }
+
+    std::string vertSrc = m_shaderSource->buildVertexSource();
+    std::string fragSrc = m_shaderSource->buildFragmentSource();
+
+    for (auto& s : _scene.styles()) {
+        auto& prg = s->m_shaderProgram;
+        if (!prg) { break; }
+        if (prg->vertexShaderSource() == vertSrc &&
+            prg->fragmentShaderSource() == fragSrc) {
+            m_shaderProgram = prg;
+            break;
+        }
+    }
+    if (!m_shaderProgram) {
+        m_shaderProgram = std::make_shared<ShaderProgram>();
+        m_shaderProgram->setDescription("{style:" + m_name + "}");
+        m_shaderProgram->setShaderSource(vertSrc, fragSrc);
+    }
+
+    if (m_selection) {
+        std::string vertSrc = m_shaderSource->buildSelectionVertexSource();
+        std::string fragSrc = m_shaderSource->buildSelectionFragmentSource();
+
+        for (auto& s : _scene.styles()) {
+            if (!s->m_selection) { continue; }
+
+            auto& prg = s->m_selectionProgram;
+            if (!prg) { break; }
+            if (prg->vertexShaderSource() == vertSrc &&
+                prg->fragmentShaderSource() == fragSrc) {
+                m_selectionProgram = prg;
+                break;
+            }
+        }
+        if (!m_selectionProgram) {
+            m_selectionProgram = std::make_shared<ShaderProgram>();
+            m_selectionProgram->setDescription("selection_program {style:" + m_name + "}");
+            m_selectionProgram->setShaderSource(vertSrc, fragSrc);
+        }
+    }
+
+    // Clear ShaderSource builder
+    m_shaderSource.reset();
+}
+
+void Style::setLightingType(LightingType _type) {
+    m_lightingType = _type;
+}
+
+void Style::setupSceneShaderUniforms(RenderState& rs, Scene& _scene, UniformBlock& _uniformBlock) {
+    for (auto& uniformPair : _uniformBlock.styleUniforms) {
+        const auto& name = uniformPair.first;
+        auto& value = uniformPair.second;
+
+        if (value.is<std::string>()) {
+            std::string textureName = value.get<std::string>();
+            std::shared_ptr<Texture> texture = _scene.getTexture(textureName);
+
+            if (!texture) {
+                LOGN("Texture with texture name %s is not available to be sent as uniform",
+                    textureName.c_str());
+                continue;
+            }
+
+            texture->update(rs, rs.nextAvailableTextureUnit());
+            texture->bind(rs, rs.currentTextureUnit());
+
+            m_shaderProgram->setUniformi(rs, name, rs.currentTextureUnit());
+        } else if (value.is<bool>()) {
+            m_shaderProgram->setUniformi(rs, name, value.get<bool>());
+        } else if(value.is<float>()) {
+            m_shaderProgram->setUniformf(rs, name, value.get<float>());
+        } else if(value.is<glm::vec2>()) {
+            m_shaderProgram->setUniformf(rs, name, value.get<glm::vec2>());
+        } else if(value.is<glm::vec3>()) {
+            m_shaderProgram->setUniformf(rs, name, value.get<glm::vec3>());
+        } else if(value.is<glm::vec4>()) {
+            m_shaderProgram->setUniformf(rs, name, value.get<glm::vec4>());
+        } else if (value.is<UniformArray1f>()) {
+            m_shaderProgram->setUniformf(rs, name, value.get<UniformArray1f>());
+        } else if (value.is<UniformTextureArray>()) {
+            UniformTextureArray& textureUniformArray = value.get<UniformTextureArray>();
+            textureUniformArray.slots.clear();
+
+            for (const auto& textureName : textureUniformArray.names) {
+                std::shared_ptr<Texture> texture = _scene.getTexture(textureName);
+
+                if (!texture) {
+                    LOGN("Texture with texture name %s is not available to be sent as uniform",
+                         textureName.c_str());
+                    continue;
+                }
+
+                texture->update(rs, rs.nextAvailableTextureUnit());
+                texture->bind(rs, rs.currentTextureUnit());
+
+                textureUniformArray.slots.push_back(rs.currentTextureUnit());
+            }
+
+            m_shaderProgram->setUniformi(rs, name, textureUniformArray);
+        }
+    }
+}
+
+void Style::setupRasters(const std::vector<std::shared_ptr<TileSource>>& _sources) {
+    if (!hasRasters()) {
+        return;
+    }
+
+    int numRasterSource = 0;
+    for (const auto& source : _sources) {
+        if (source->isRaster()) {
+            numRasterSource++;
+        }
+    }
+
+    if (numRasterSource == 0) {
+        return;
+    }
+
+    // Inject shader defines for raster sampling and uniforms
+    if (m_rasterType == RasterType::normal) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_RASTER_TEXTURE_NORMAL\n", false);
+    } else if (m_rasterType == RasterType::color) {
+        m_shaderSource->addSourceBlock("defines", "#define TANGRAM_RASTER_TEXTURE_COLOR\n", false);
+    }
+
+    m_shaderSource->addSourceBlock("defines", "#define TANGRAM_NUM_RASTER_SOURCES "
+            + std::to_string(numRasterSource) + "\n", false);
+    m_shaderSource->addSourceBlock("defines", "#define TANGRAM_MODEL_POSITION_BASE_ZOOM_VARYING\n", false);
+
+    m_shaderSource->addSourceBlock("raster", SHADER_SOURCE(rasters_glsl));
+}
+
+
+void Style::setupShaderUniforms(RenderState& rs, ShaderProgram& _program, const View& _view,
+                                Scene& _scene, UniformBlock& _uniforms) {
+
+    // Reset the currently used texture unit to 0
+    rs.resetTextureUnit();
+
+    // Set time uniforms style's shader programs
+    _program.setUniformf(rs, _uniforms.uTime, _scene.time());
+
+    _program.setUniformf(rs, _uniforms.uDevicePixelRatio, m_pixelScale);
+
+    if (m_material.uniforms) {
+        m_material.material->setupProgram(rs, *m_shaderProgram, *m_material.uniforms);
+    }
+
+    // Set up lights
+    for (const auto& light : m_lights) {
+        light.light->setupProgram(rs, _view, *m_shaderProgram, *light.uniforms);
+    }
+
+    // Set Map Position
+    _program.setUniformf(rs, _uniforms.uResolution, _view.getWidth(), _view.getHeight());
+
+    const auto& mapPos = _view.getPosition();
+    _program.setUniformf(rs, _uniforms.uMapPosition, mapPos.x, mapPos.y, _view.getZoom());
+    _program.setUniformMatrix3f(rs, _uniforms.uNormalMatrix, _view.getNormalMatrix());
+    _program.setUniformMatrix3f(rs, _uniforms.uInverseNormalMatrix, _view.getInverseNormalMatrix());
+    _program.setUniformf(rs, _uniforms.uMetersPerPixel, 1.0 / _view.pixelsPerMeter());
+    _program.setUniformMatrix4f(rs, _uniforms.uView, _view.getViewMatrix());
+    _program.setUniformMatrix4f(rs, _uniforms.uProj, _view.getProjectionMatrix());
+
+    setupSceneShaderUniforms(rs, _scene, _uniforms);
+
+}
+
+void Style::onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) {
+
+    setupShaderUniforms(rs, *m_shaderProgram, _view, _scene, m_mainUniforms);
+
+    // Configure render state
+    switch (m_blend) {
+        case Blending::opaque:
+            rs.blending(GL_FALSE);
+            rs.blendingFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_TRUE);
+            break;
+        case Blending::add:
+            rs.blending(GL_TRUE);
+            rs.blendingFunc(GL_ONE, GL_ONE);
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_TRUE);
+            break;
+        case Blending::multiply:
+            rs.blending(GL_TRUE);
+            rs.blendingFunc(GL_ZERO, GL_SRC_COLOR);
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_TRUE);
+            break;
+        case Blending::overlay:
+            rs.blending(GL_TRUE);
+            rs.blendingFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            rs.depthTest(GL_FALSE);
+            rs.depthMask(GL_FALSE);
+            break;
+        case Blending::inlay:
+            // TODO: inlay does not behave correctly for labels because they don't have a z position
+            rs.blending(GL_TRUE);
+            rs.blendingFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_FALSE);
+            break;
+        default:
+            break;
+    }
+}
+
+void Style::onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene) {
+
+    if (!m_selection) {
+        return;
+    }
+
+    setupShaderUniforms(rs, *m_selectionProgram, _view, _scene, m_selectionUniforms);
+
+    // Configure render state
+    rs.blending(GL_FALSE);
+
+    switch (m_blend) {
+        case Blending::opaque:
+        case Blending::add:
+        case Blending::multiply:
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_TRUE);
+            break;
+        case Blending::overlay:
+            rs.depthTest(GL_FALSE);
+            rs.depthMask(GL_FALSE);
+            break;
+        case Blending::inlay:
+            rs.depthTest(GL_TRUE);
+            rs.depthMask(GL_FALSE);
+            break;
+        default:
+            break;
+    }
+}
+
+void Style::drawSelectionFrame(RenderState& _rs, const Marker& _marker) {
+    if (!m_selection || _marker.styleId() != m_id || !_marker.isVisible()) {
+        return;
+    }
+
+    auto* mesh = _marker.mesh();
+
+    if (!mesh) { return; }
+
+    m_selectionProgram->setUniformMatrix4f(_rs, m_selectionUniforms.uModel, _marker.modelMatrix());
+    m_selectionProgram->setUniformf(_rs, m_selectionUniforms.uTileOrigin,
+                                    _marker.origin().x, _marker.origin().y,
+                                    _marker.builtZoomLevel(), _marker.builtZoomLevel());
+
+    if (!mesh->draw(_rs, *m_selectionProgram, false)) {
+        LOGN("Mesh built by style %s cannot be drawn", m_name.c_str());
+    }
+}
+
+void Style::drawSelectionFrame(Tangram::RenderState& rs, const Tangram::Tile &_tile) {
+
+    if (!m_selection) {
+        return;
+    }
+
+    auto& styleMesh = _tile.getMesh(*this);
+
+    if (!styleMesh) { return; }
+
+    TileID tileID = _tile.getID();
+
+    m_selectionProgram->setUniformMatrix4f(rs, m_selectionUniforms.uModel, _tile.getModelMatrix());
+    m_selectionProgram->setUniformf(rs, m_selectionUniforms.uProxyDepth, _tile.isProxy() ? 1.f : 0.f);
+    m_selectionProgram->setUniformf(rs, m_selectionUniforms.uTileOrigin,
+                                    _tile.getOrigin().x,
+                                    _tile.getOrigin().y,
+                                    tileID.s,
+                                    tileID.z);
+
+    if (!styleMesh->draw(rs, *m_selectionProgram, false)) {
+        LOGN("Mesh built by style %s cannot be drawn", m_name.c_str());
+    }
+
+}
+
+void Style::draw(RenderState& rs, const Tile& _tile) {
+
+    auto& styleMesh = _tile.getMesh(*this);
+
+    if (!styleMesh) { return; }
+
+    TileID tileID = _tile.getID();
+
+    if (hasRasters() && !_tile.rasters().empty()) {
+        UniformTextureArray textureIndexUniform;
+        UniformArray2f rasterSizeUniform;
+        UniformArray3f rasterOffsetsUniform;
+
+        for (auto& raster : _tile.rasters()) {
+            if (raster.isValid()) {
+                auto& texture = raster.texture;
+                auto texUnit = rs.nextAvailableTextureUnit();
+                texture->update(rs, texUnit);
+                texture->bind(rs, texUnit);
+
+                textureIndexUniform.slots.push_back(texUnit);
+                rasterSizeUniform.push_back({texture->getWidth(), texture->getHeight()});
+
+                if (tileID.z > raster.tileID.z) {
+                    float dz = tileID.z - raster.tileID.z;
+                    float dz2 = powf(2.f, dz);
+
+                    rasterOffsetsUniform.push_back({
+                            fmodf(tileID.x, dz2) / dz2,
+                                (dz2 - 1.f - fmodf(tileID.y, dz2)) / dz2,
+                                1.f / dz2
+                                });
+                } else {
+                    rasterOffsetsUniform.push_back({0, 0, 1});
+                }
+            }
+        }
+
+        m_shaderProgram->setUniformi(rs, m_mainUniforms.uRasters, textureIndexUniform);
+        m_shaderProgram->setUniformf(rs, m_mainUniforms.uRasterSizes, rasterSizeUniform);
+        m_shaderProgram->setUniformf(rs, m_mainUniforms.uRasterOffsets, rasterOffsetsUniform);
+    }
+
+    m_shaderProgram->setUniformMatrix4f(rs, m_mainUniforms.uModel, _tile.getModelMatrix());
+    m_shaderProgram->setUniformf(rs, m_mainUniforms.uProxyDepth, _tile.isProxy() ? 1.f : 0.f);
+    m_shaderProgram->setUniformf(rs, m_mainUniforms.uTileOrigin,
+                                 _tile.getOrigin().x,
+                                 _tile.getOrigin().y,
+                                 tileID.s,
+                                 tileID.z);
+
+    if (!styleMesh->draw(rs, *m_shaderProgram)) {
+        LOGN("Mesh built by style %s cannot be drawn", m_name.c_str());
+    }
+
+    if (hasRasters()) {
+        for (auto& raster : _tile.rasters()) {
+            if (raster.isValid()) {
+                rs.releaseTextureUnit();
+            }
+        }
+    }
+}
+
+void Style::draw(RenderState& rs, const Marker& marker) {
+
+    if (marker.styleId() != m_id || !marker.isVisible()) { return; }
+
+    auto* mesh = marker.mesh();
+
+    if (!mesh) { return; }
+
+    m_shaderProgram->setUniformMatrix4f(rs, m_mainUniforms.uModel, marker.modelMatrix());
+    m_shaderProgram->setUniformf(rs, m_mainUniforms.uTileOrigin,
+                                 marker.origin().x, marker.origin().y,
+                                 marker.builtZoomLevel(), marker.builtZoomLevel());
+
+    if (!mesh->draw(rs, *m_shaderProgram)) {
+        LOGN("Mesh built by style %s cannot be drawn", m_name.c_str());
+    }
+}
+
+void Style::setDefaultDrawRule(std::unique_ptr<DrawRuleData>&& _rule) {
+    m_defaultDrawRule = std::move(_rule);
+}
+
+void Style::applyDefaultDrawRules(DrawRule& _rule) const {
+    if (m_defaultDrawRule) {
+        for (auto& param : m_defaultDrawRule->parameters) {
+            auto key = static_cast<uint8_t>(param.key);
+            if (!_rule.active[key]) {
+                _rule.active[key] = true;
+                // NOTE: layername and layer depth are actually immaterial here, since these are
+                // only used during layer draw rules merging. Adding a default string for
+                // debugging purposes.
+                _rule.params[key] = { &param, "default_style_draw_rule", 0 };
+            }
+        }
+    }
+}
+
+bool StyleBuilder::checkRule(const DrawRule& _rule) const {
+
+    uint32_t checkColor;
+    uint32_t checkOrder;
+
+    if (!_rule.get(StyleParamKey::color, checkColor)) {
+        if (!style().hasColorShaderBlock()) {
+            return false;
+        }
+    }
+
+    if (!_rule.get(StyleParamKey::order, checkOrder)) {
+        return false;
+    }
+
+    return true;
+}
+
+bool StyleBuilder::addFeature(const Feature& _feat, const DrawRule& _rule) {
+
+    if (!checkRule(_rule)) { return false; }
+
+    bool added = false;
+    switch (_feat.geometryType) {
+        case GeometryType::points:
+            for (auto& point : _feat.points) {
+                added |= addPoint(point, _feat.props, _rule);
+            }
+            break;
+        case GeometryType::lines:
+            for (auto& line : _feat.lines) {
+                added |= addLine(line, _feat.props, _rule);
+            }
+            break;
+        case GeometryType::polygons:
+            for (auto& polygon : _feat.polygons) {
+                added |= addPolygon(polygon, _feat.props, _rule);
+            }
+            break;
+        default:
+            break;
+    }
+
+    return added;
+}
+
+bool StyleBuilder::addPoint(const Point& _point, const Properties& _props, const DrawRule& _rule) {
+    // No-op by default
+    return false;
+}
+
+bool StyleBuilder::addLine(const Line& _line, const Properties& _props, const DrawRule& _rule) {
+    // No-op by default
+    return false;
+}
+
+bool StyleBuilder::addPolygon(const Polygon& _polygon, const Properties& _props, const DrawRule& _rule) {
+    // No-op by default
+    return false;
+}
+
+}
diff --git a/core/src/style/style.h b/core/src/style/style.h
new file mode 100644 (file)
index 0000000..e2f47dc
--- /dev/null
@@ -0,0 +1,311 @@
+#pragma once
+
+#include "data/tileData.h"
+#include "gl.h"
+#include "gl/uniform.h"
+#include "scene/drawRule.h"
+#include "util/fastmap.h"
+
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class Label;
+class LabelCollider;
+class Light;
+class MapProjection;
+class Marker;
+class Material;
+class RenderState;
+class Scene;
+class ShaderProgram;
+class ShaderSource;
+class Style;
+class Tile;
+class TileSource;
+class VertexLayout;
+class View;
+struct DrawRule;
+struct LightUniforms;
+struct MaterialUniforms;
+
+enum class LightingType : uint8_t {
+    none,
+    vertex,
+    fragment
+};
+
+enum class Blending : uint8_t {
+    opaque,
+    add,
+    multiply,
+    inlay,
+    overlay,
+};
+
+enum class RasterType : uint8_t {
+    none,
+    color,
+    normal,
+    custom
+};
+
+struct StyledMesh {
+    virtual bool draw(RenderState& rs, ShaderProgram& _shader, bool _useVao = true) = 0;
+    virtual size_t bufferSize() const = 0;
+
+    virtual ~StyledMesh() {}
+};
+
+class StyleBuilder {
+public:
+
+    virtual ~StyleBuilder() = default;
+
+    virtual void setup(const Tile& _tile) = 0;
+
+    virtual void setup(const Marker& _marker, int zoom) = 0;
+
+    virtual bool addFeature(const Feature& _feat, const DrawRule& _rule);
+
+    /* Build styled vertex data for point geometry */
+    virtual bool addPoint(const Point& _point, const Properties& _props, const DrawRule& _rule);
+
+    /* Build styled vertex data for line geometry */
+    virtual bool addLine(const Line& _line, const Properties& _props, const DrawRule& _rule);
+
+    /* Build styled vertex data for polygon geometry */
+    virtual bool addPolygon(const Polygon& _polygon, const Properties& _props, const DrawRule& _rule);
+
+    /* Create a new mesh object using the vertex layout corresponding to this style */
+    virtual std::unique_ptr<StyledMesh> build() = 0;
+
+    virtual bool checkRule(const DrawRule& _rule) const;
+
+    virtual void addLayoutItems(LabelCollider& _layout) {}
+
+    virtual void addSelectionItems(LabelCollider& _layout) {}
+
+    virtual const Style& style() const = 0;
+};
+
+/* Means of constructing and rendering map geometry
+ *
+ * A Style defines a way to
+ *   1. Construct map geometry into a mesh for drawing and
+ *   2. Render the resulting mesh in a scene
+ * Style implementations must provide functions to construct
+ * a <VertexLayout> for their geometry, construct a <ShaderProgram>
+ * for rendering meshes, and build point, line, and polygon
+ * geometry into meshes. See <PolygonStyle> for a basic implementation.
+ */
+class Style {
+
+using StyleUniform = std::pair<UniformLocation, UniformValue >;
+
+protected:
+
+    /* The platform pixel scale */
+    float m_pixelScale = 1.0;
+
+    /* Unique name for a style instance */
+    std::string m_name;
+    uint32_t m_id = 0;
+
+    std::unique_ptr<ShaderSource> m_shaderSource;
+
+    /* <ShaderProgram> used to draw meshes using this style */
+    std::shared_ptr<ShaderProgram> m_shaderProgram;
+
+    std::shared_ptr<ShaderProgram> m_selectionProgram;
+
+    /* <VertexLayout> shared between meshes using this style */
+    std::shared_ptr<VertexLayout> m_vertexLayout;
+
+    /* Stores default style draw rules*/
+    std::unique_ptr<DrawRuleData> m_defaultDrawRule = nullptr;
+
+    /* <LightingType> to determine how lighting will be calculated for this style */
+    LightingType m_lightingType = LightingType::fragment;
+
+    Blending m_blend = Blending::opaque;
+    int m_blendOrder = -1;
+
+    /* Draw mode to pass into <Mesh>es created with this style */
+    GLenum m_drawMode;
+
+    /* animated property */
+    bool m_animated = false;
+
+    /* Whether the style should generate texture coordinates */
+    bool m_texCoordsGeneration = false;
+
+    bool m_hasColorShaderBlock = false;
+
+    RasterType m_rasterType = RasterType::none;
+
+    bool m_selection;
+
+private:
+
+    struct UniformBlock {
+        UniformLocation uTime{"u_time"};
+        // View uniforms
+        UniformLocation uDevicePixelRatio{"u_device_pixel_ratio"};
+        UniformLocation uResolution{"u_resolution"};
+        UniformLocation uMapPosition{"u_map_position"};
+        UniformLocation uNormalMatrix{"u_normal_matrix"};
+        UniformLocation uInverseNormalMatrix{"u_inverse_normal_matrix"};
+        UniformLocation uMetersPerPixel{"u_meters_per_pixel"};
+        UniformLocation uView{"u_view"};
+        UniformLocation uProj{"u_proj"};
+        // Tile uniforms
+        UniformLocation uModel{"u_model"};
+        UniformLocation uTileOrigin{"u_tile_origin"};
+        UniformLocation uProxyDepth{"u_proxy_depth"};
+        UniformLocation uRasters{"u_rasters"};
+        UniformLocation uRasterSizes{"u_raster_sizes"};
+        UniformLocation uRasterOffsets{"u_raster_offsets"};
+
+        std::vector<StyleUniform> styleUniforms;
+    } m_mainUniforms, m_selectionUniforms;
+
+    /* Set uniform values when @_updateUniforms is true,
+     */
+    void setupSceneShaderUniforms(RenderState& rs, Scene& _scene, UniformBlock& _uniformBlock);
+
+    void setupShaderUniforms(RenderState& rs, ShaderProgram& _program, const View& _view,
+                             Scene& _scene, UniformBlock& _uniformBlock);
+
+    struct LightHandle {
+        LightHandle(Light* _light, std::unique_ptr<LightUniforms> _uniforms);
+        Light *light;
+        std::unique_ptr<LightUniforms> uniforms;
+    };
+
+
+    struct MaterialHandle {
+        /* <Material> used for drawing meshes that use this style */
+        std::shared_ptr<Material> material;
+        std::unique_ptr<MaterialUniforms> uniforms;
+    };
+
+    std::vector<LightHandle> m_lights;
+    MaterialHandle m_material;
+
+public:
+
+    Style(std::string _name, Blending _blendMode, GLenum _drawMode, bool _selection);
+
+    virtual ~Style();
+
+    static bool compare(std::unique_ptr<Style>& a, std::unique_ptr<Style>& b) {
+
+        const auto& modeA = a->blendMode();
+        const auto& modeB = b->blendMode();
+        const auto& orderA = a->blendOrder();
+        const auto& orderB = b->blendOrder();
+
+        if (modeA != Blending::opaque && modeB != Blending::opaque) {
+            if (orderA != orderB) {
+                return orderA < orderB;
+            }
+        }
+        if (modeA != modeB) {
+            return static_cast<uint8_t>(modeA) < static_cast<uint8_t>(modeB);
+        }
+        return a->getName() < b->getName();
+    }
+
+    static const std::vector<std::string>& builtInStyleNames();
+
+    Blending blendMode() const { return m_blend; };
+    int blendOrder() const { return m_blendOrder; };
+
+    void setBlendMode(Blending _blendMode) { m_blend = _blendMode; }
+    void setBlendOrder(int _blendOrder) { m_blendOrder = _blendOrder; }
+
+    /* Whether or not the style is animated */
+    bool isAnimated() { return m_animated; }
+
+    /* Make this style ready to be used (call after all needed properties are set) */
+    virtual void build(const Scene& _scene);
+
+    virtual void onBeginUpdate() {}
+
+    virtual void onBeginFrame(RenderState& rs) {}
+
+    /* Create <VertexLayout> corresponding to this style; subclasses must
+     * implement this and call it on construction
+     */
+    virtual void constructVertexLayout() = 0;
+
+    /* Create <ShaderProgram> for this style; subclasses must implement
+     * this and call it on construction
+     */
+    virtual void constructShaderProgram() = 0;
+
+    /* Perform any setup needed before drawing each frame
+     * _textUnit is the next available texture unit
+     */
+    virtual void onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene);
+
+    virtual void onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene);
+
+    /* Perform any unsetup needed after drawing each frame */
+    virtual void onEndDrawFrame() {}
+
+    /* Draws the geometry associated with this <Style> */
+    virtual void draw(RenderState& rs, const Tile& _tile);
+
+    virtual void draw(RenderState& rs, const Marker& _marker);
+
+    void drawSelectionFrame(RenderState& rs, const Tile& _tile);
+
+    void drawSelectionFrame(RenderState& _rs, const Marker& _marker);
+
+    virtual void setLightingType(LightingType _lType);
+
+    void setAnimated(bool _animated) { m_animated = _animated; }
+
+    virtual void setPixelScale(float _pixelScale) { m_pixelScale = _pixelScale; }
+
+    void setRasterType(RasterType _rasterType) { m_rasterType = _rasterType; }
+
+    void setTexCoordsGeneration(bool _texCoordsGeneration) { m_texCoordsGeneration = _texCoordsGeneration; }
+
+    bool genTexCoords() const { return m_texCoordsGeneration; }
+
+    void setID(uint32_t _id) { m_id = _id; }
+
+    Material& getMaterial() { return *m_material.material; }
+
+    ShaderSource& getShaderSource() const { return *m_shaderSource; }
+
+    const std::string& getName() const { return m_name; }
+    const uint32_t& getID() const { return m_id; }
+
+    virtual size_t dynamicMeshSize() const { return 0; }
+
+    virtual bool hasRasters() const { return m_rasterType != RasterType::none; }
+
+    void setupRasters(const std::vector<std::shared_ptr<TileSource>>& _sources);
+
+    std::vector<StyleUniform>& styleUniforms() { return m_mainUniforms.styleUniforms; }
+
+    void setDefaultDrawRule(std::unique_ptr<DrawRuleData>&& _rule);
+    void applyDefaultDrawRules(DrawRule& _rule) const;
+
+    virtual std::unique_ptr<StyleBuilder> createBuilder() const = 0;
+
+    GLenum drawMode() const { return m_drawMode; }
+    float pixelScale() const { return m_pixelScale; }
+    const auto& vertexLayout() const { return m_vertexLayout; }
+
+    bool hasColorShaderBlock() const { return m_hasColorShaderBlock; }
+
+};
+
+}
diff --git a/core/src/style/textStyle.cpp b/core/src/style/textStyle.cpp
new file mode 100644 (file)
index 0000000..62ff861
--- /dev/null
@@ -0,0 +1,150 @@
+#include "style/textStyle.h"
+#include "style/textStyleBuilder.h"
+
+#include "gl/dynamicQuadMesh.h"
+#include "gl/mesh.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "labels/textLabels.h"
+#include "log.h"
+#include "text/fontContext.h"
+#include "view/view.h"
+
+#include "text_fs.h"
+#include "sdf_fs.h"
+#include "point_vs.h"
+
+namespace Tangram {
+
+TextStyle::TextStyle(std::string _name, std::shared_ptr<FontContext> _fontContext,
+                     bool _sdf, Blending _blendMode, GLenum _drawMode, bool _selection)
+    : Style(_name, _blendMode, _drawMode, _selection), m_sdf(_sdf),
+      m_context(_fontContext) {}
+
+TextStyle::~TextStyle() {}
+
+void TextStyle::constructVertexLayout() {
+    m_vertexLayout = std::shared_ptr<VertexLayout>(new VertexLayout({
+        {"a_position", 2, GL_SHORT, false, 0},
+        {"a_uv", 2, GL_UNSIGNED_SHORT, false, 0},
+        {"a_selection_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        {"a_color", 4, GL_UNSIGNED_BYTE, true, 0},
+        {"a_stroke", 4, GL_UNSIGNED_BYTE, true, 0},
+        {"a_alpha", 1, GL_UNSIGNED_SHORT, true, 0},
+        {"a_scale", 1, GL_UNSIGNED_SHORT, false, 0},
+    }));
+}
+
+void TextStyle::constructShaderProgram() {
+
+    if (m_sdf) {
+        m_shaderSource->setSourceStrings(SHADER_SOURCE(sdf_fs),
+                                         SHADER_SOURCE(point_vs));
+    } else {
+        m_shaderSource->setSourceStrings(SHADER_SOURCE(text_fs),
+                                         SHADER_SOURCE(point_vs));
+    }
+
+    m_shaderSource->addSourceBlock("defines", "#define TANGRAM_TEXT\n");
+}
+
+void TextStyle::onBeginUpdate() {
+
+    // Clear vertices from previous frame
+    for (auto& mesh : m_meshes) { mesh->clear(); }
+
+    // Ensure that meshes are available to push to on labels::update()
+    size_t s = m_context->glyphTextureCount();
+    while (m_meshes.size() < s) {
+        m_meshes.push_back(std::make_unique<DynamicQuadMesh<TextVertex>>(m_vertexLayout, GL_TRIANGLES));
+    }
+}
+
+void TextStyle::onBeginFrame(RenderState& rs) {
+
+    // Upload meshes and textures
+    m_context->updateTextures(rs);
+
+    for (auto& mesh : m_meshes) {
+        mesh->upload(rs);
+    }
+}
+
+void TextStyle::onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) {
+
+    Style::onBeginDrawFrame(rs, _view, _scene);
+
+    auto texUnit = rs.nextAvailableTextureUnit();
+
+    m_shaderProgram->setUniformf(rs, m_mainUniforms.uMaxStrokeWidth,
+                                 m_context->maxStrokeWidth());
+    m_shaderProgram->setUniformf(rs, m_mainUniforms.uTexScaleFactor,
+                                 glm::vec2(1.0f / GlyphTexture::size));
+    m_shaderProgram->setUniformi(rs, m_mainUniforms.uTex, texUnit);
+    m_shaderProgram->setUniformMatrix4f(rs, m_mainUniforms.uOrtho,
+                                        _view.getOrthoViewportMatrix());
+
+    if (m_sdf) {
+        m_shaderProgram->setUniformi(rs, m_mainUniforms.uPass, 1);
+
+        for (size_t i = 0; i < m_meshes.size(); i++) {
+            if (m_meshes[i]->isReady()) {
+                m_context->bindTexture(rs, i, texUnit);
+                m_meshes[i]->draw(rs, *m_shaderProgram);
+            }
+        }
+        m_shaderProgram->setUniformi(rs, m_mainUniforms.uPass, 0);
+    }
+
+    for (size_t i = 0; i < m_meshes.size(); i++) {
+        if (m_meshes[i]->isReady()) {
+            m_context->bindTexture(rs, i, texUnit);
+            m_meshes[i]->draw(rs, *m_shaderProgram);
+        }
+    }
+}
+
+void TextStyle::onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene) {
+    if (!m_selection) { return; }
+
+    for (auto& mesh : m_meshes) { mesh->upload(rs); }
+
+    Style::onBeginDrawSelectionFrame(rs, _view, _scene);
+
+    m_selectionProgram->setUniformMatrix4f(rs, m_selectionUniforms.uOrtho,
+                                           _view.getOrthoViewportMatrix());
+
+    for (const auto& mesh : m_meshes) {
+        if (mesh->isReady()) {
+            mesh->draw(rs, *m_selectionProgram, false);
+        }
+    }
+}
+
+std::unique_ptr<StyleBuilder> TextStyle::createBuilder() const {
+    return std::make_unique<TextStyleBuilder>(*this);
+}
+
+
+DynamicQuadMesh<TextVertex>& TextStyle::getMesh(size_t id) const {
+    if (id >= m_meshes.size()) {
+        LOGE("Accessing inconsistent quad mesh");
+        assert(false);
+        return *m_meshes[0];
+    }
+
+    return *m_meshes[id];
+}
+
+size_t TextStyle::dynamicMeshSize() const {
+    size_t size = 0;
+    for (const auto& mesh : m_meshes) {
+        size += mesh->bufferSize();
+    }
+
+    return size;
+}
+
+
+
+}
diff --git a/core/src/style/textStyle.h b/core/src/style/textStyle.h
new file mode 100644 (file)
index 0000000..346de19
--- /dev/null
@@ -0,0 +1,134 @@
+#pragma once
+
+#include "gl/dynamicQuadMesh.h"
+#include "style/style.h"
+#include "labels/labelProperty.h"
+#include "labels/textLabel.h"
+#include "util/hash.h"
+
+#include <memory>
+#include <vector>
+#include <string>
+
+namespace alfons { class Font; }
+
+namespace Tangram {
+
+class FontContext;
+struct Properties;
+
+class TextStyle : public Style {
+
+public:
+
+    struct Parameters {
+        std::shared_ptr<alfons::Font> font;
+        std::string text = "";
+        std::string textLeft = "";
+        std::string textRight = "";
+        bool interactive = false;
+        uint32_t fill = 0xff000000;
+        uint32_t strokeColor = 0xffffffff;
+        float strokeWidth = 0.0f;
+        float fontSize = 12.0f;
+        Label::Options labelOptions;
+        bool wordWrap = true;
+        uint32_t maxLineWidth = 15;
+
+        TextLabelProperty::Transform transform = TextLabelProperty::Transform::none;
+        TextLabelProperty::Align align = TextLabelProperty::Align::none;
+
+        float fontScale = 1;
+        float lineSpacing = 0;
+
+        bool hasComplexShaping = false;
+    };
+
+    auto& context() const { return m_context; }
+
+protected:
+
+    bool m_sdf;
+
+    std::shared_ptr<FontContext> m_context;
+
+    struct UniformBlock {
+        UniformLocation uTexScaleFactor{"u_uv_scale_factor"};
+        UniformLocation uTex{"u_tex"};
+        UniformLocation uOrtho{"u_ortho"};
+        UniformLocation uPass{"u_pass"};
+        UniformLocation uMaxStrokeWidth{"u_max_stroke_width"};
+    } m_mainUniforms, m_selectionUniforms;
+
+    mutable std::vector<std::unique_ptr<DynamicQuadMesh<TextVertex>>> m_meshes;
+
+public:
+
+    TextStyle(std::string _name, std::shared_ptr<FontContext> _fontContext, bool _sdf = false,
+              Blending _blendMode = Blending::overlay, GLenum _drawMode = GL_TRIANGLES, bool _selection = true);
+
+    void constructVertexLayout() override;
+    void constructShaderProgram() override;
+
+    /* Create the LabelMeshes associated with FontContext GlyphTexture<s>
+     * No GL involved, called from Tangram::update()
+     */
+    virtual void onBeginUpdate() override;
+
+    /* Upload the buffers of the text batches
+     * Upload the texture atlases
+     */
+    virtual void onBeginFrame(RenderState& rs) override;
+
+    /* Performs the actual drawing of the meshes in two passes
+     * - First pass if signed distance field is on, draw outlines
+     * - Second pass, draw the inner glyph pixels
+     */
+    virtual void onBeginDrawFrame(RenderState& rs, const View& _view, Scene& _scene) override;
+
+    virtual void onBeginDrawSelectionFrame(RenderState& rs, const View& _view, Scene& _scene) override;
+
+    virtual void draw(RenderState& rs, const Tile& _tile) override {}
+
+    virtual void draw(RenderState& rs, const Marker& _marker) override {}
+
+    std::unique_ptr<StyleBuilder> createBuilder() const override;
+
+    DynamicQuadMesh<TextVertex>& getMesh(size_t id) const;
+
+    auto& getMeshes() const { return m_meshes; }
+
+    virtual size_t dynamicMeshSize() const override;
+
+    virtual ~TextStyle() override;
+
+private:
+
+    const std::string& applyTextSource(const Parameters& _parameters, const Properties& _props) const;
+
+};
+
+}
+
+namespace std {
+    template <>
+    struct hash<Tangram::TextStyle::Parameters> {
+        size_t operator() (const Tangram::TextStyle::Parameters& p) const {
+            std::hash<Tangram::Label::Options> optionsHash;
+            std::size_t seed = 0;
+            // TODO
+            //hash_combine(seed, p.fontId);
+            hash_combine(seed, p.text);
+            hash_combine(seed, p.fill);
+            hash_combine(seed, p.strokeColor);
+            hash_combine(seed, p.strokeWidth);
+            hash_combine(seed, p.fontSize);
+            hash_combine(seed, p.wordWrap);
+            hash_combine(seed, p.maxLineWidth);
+            hash_combine(seed, int(p.transform));
+            hash_combine(seed, int(p.align));
+            hash_combine(seed, optionsHash(p.labelOptions));
+            return seed;
+        }
+    };
+}
diff --git a/core/src/style/textStyleBuilder.cpp b/core/src/style/textStyleBuilder.cpp
new file mode 100644 (file)
index 0000000..40026a1
--- /dev/null
@@ -0,0 +1,849 @@
+#include "style/textStyleBuilder.h"
+
+#include "labels/curvedLabel.h"
+#include "labels/labelCollider.h"
+#include "labels/labelSet.h"
+#include "labels/textLabel.h"
+#include "labels/textLabels.h"
+#include "log.h"
+#include "marker/marker.h"
+#include "selection/featureSelection.h"
+#include "scene/drawRule.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "util/geom.h"
+#include "util/mapProjection.h"
+#include "util/lineSampler.h"
+#include "view/view.h"
+
+#include "unicode/unistr.h"
+#include "unicode/schriter.h"
+#include "unicode/brkiter.h"
+#include "unicode/locid.h"
+
+#include <glm/gtx/norm.hpp>
+#include <algorithm>
+#include <cmath>
+#include <locale>
+#include <mutex>
+
+namespace Tangram {
+
+const static std::string key_name("name");
+
+TextStyleBuilder::TextStyleBuilder(const TextStyle& _style)
+    : m_style(_style) {
+    m_textLabels = std::make_unique<TextLabels>(m_style);
+}
+
+void TextStyleBuilder::setup(const Tile& _tile){
+    m_tileSize = _tile.getProjection()->TileSize();
+    m_tileSize *= m_style.pixelScale();
+
+    // < 1.0 when overzooming a tile
+    m_tileScale = pow(2, _tile.getID().s - _tile.getID().z);
+    m_tileSize *= m_tileScale;
+
+    m_atlasRefs.reset();
+
+    m_textLabels = std::make_unique<TextLabels>(m_style);
+}
+
+void TextStyleBuilder::setup(const Marker& marker, int zoom) {
+    float metersPerTile = 2.f * MapProjection::HALF_CIRCUMFERENCE * exp2(-zoom);
+
+    // In general, a Marker won't cover the same area as a tile, so the effective
+    // "tile size" for building a Marker is the size of a tile in pixels multiplied
+    // by the ratio of the Marker's extent to the length of a tile side at this zoom.
+    m_tileSize = 256 * (marker.extent() / metersPerTile);
+
+    // (Copied from Tile setup function above, purpose unclear)
+    m_tileSize *= m_style.pixelScale();
+
+    m_atlasRefs.reset();
+
+    m_textLabels = std::make_unique<TextLabels>(m_style);
+}
+
+void TextStyleBuilder::addLayoutItems(LabelCollider& _layout) {
+    _layout.addLabels(m_labels);
+}
+
+std::unique_ptr<StyledMesh> TextStyleBuilder::build() {
+
+    if (m_quads.empty()) { return nullptr; }
+
+    if (Tangram::getDebugFlag(DebugFlags::draw_all_labels)) {
+        m_textLabels->setLabels(m_labels);
+
+        std::vector<GlyphQuad> quads(m_quads);
+        m_textLabels->setQuads(std::move(quads), m_atlasRefs);
+
+    } else {
+
+        // TODO this could probably done more elegant
+
+        int quadPos = 0;
+        size_t sumQuads = 0;
+        size_t sumLabels = 0;
+        bool added = false;
+
+        // Determine number of labels and size of final quads vector
+        for (auto& label : m_labels) {
+            auto* textLabel = static_cast<TextLabel*>(label.get());
+
+            const auto& ranges = textLabel->textRanges();
+
+            bool active = textLabel->state() != Label::State::dead;
+
+            if (ranges.back().end() != quadPos) {
+                quadPos = ranges.back().end();
+                added = false;
+            }
+
+            if (!active) { continue; }
+
+            sumLabels +=1;
+            if (!added) {
+                added = true;
+
+                for (auto& textRange : ranges) {
+                    sumQuads += textRange.length;
+                }
+            }
+        }
+
+        size_t quadEnd = 0;
+        size_t quadStart = 0;
+        quadPos = 0;
+
+        std::vector<std::unique_ptr<Label>> labels;
+        labels.reserve(sumLabels);
+
+        std::vector<GlyphQuad> quads;
+        quads.reserve(sumQuads);
+
+        // Add only alive labels
+        for (auto& label : m_labels) {
+            auto* textLabel = static_cast<TextLabel*>(label.get());
+
+            bool active = textLabel->state() != Label::State::dead;
+            if (!active) { continue; }
+
+            auto& ranges = textLabel->textRanges();
+
+            // Add the quads of line-labels only once
+            if (ranges.back().end() != quadPos) {
+                quadStart = quadEnd;
+                quadPos = ranges.back().end();
+
+                for (auto& textRange : ranges) {
+                    if (textRange.length > 0) {
+                        quadEnd += textRange.length;
+
+                        auto it = m_quads.begin() + textRange.start;
+                        quads.insert(quads.end(), it, it + textRange.length);
+                    }
+                }
+            }
+
+            // Update TextRange
+            auto start = quadStart;
+
+            for (auto& textRange : ranges) {
+                textRange.start = start;
+                start += textRange.length;
+            }
+
+            labels.push_back(std::move(label));
+        }
+
+        m_textLabels->setLabels(labels);
+        m_textLabels->setQuads(std::move(quads), m_atlasRefs);
+    }
+
+    m_labels.clear();
+    m_quads.clear();
+
+    return std::move(m_textLabels);
+}
+
+bool getTextSource(const StyleParamKey _key, const DrawRule& _rule, const Properties& _props,
+                   std::string& _text) {
+
+    auto& textSource = _rule.findParameter(_key);
+    if (textSource.value.is<StyleParam::TextSource>()) {
+        for (auto& key : textSource.value.get<StyleParam::TextSource>().keys) {
+            _text = _props.getString(key);
+            if (!_text.empty()) { break; }
+        }
+    } else if (textSource.value.is<std::string>()) {
+        // From function evaluation
+        _text = textSource.value.get<std::string>();
+    } else {
+        return false;
+    }
+    return true;
+}
+
+bool TextStyleBuilder::handleBoundaryLabel(const Feature& _feat, const DrawRule& _rule,
+                                           const TextStyle::Parameters& _params) {
+    std::string leftText, rightText;
+
+    bool hasLeftSource = getTextSource(StyleParamKey::text_source_left, _rule, _feat.props, leftText);
+    bool hasRightSource = getTextSource(StyleParamKey::text_source_right, _rule, _feat.props, rightText);
+
+    if (!(hasLeftSource || hasRightSource)) { return false; }
+
+    if (_feat.geometryType != GeometryType::lines) { return true; }
+
+    LabelAttributes leftAttribs, rightAttribs;
+    TextStyle::Parameters rightParams = _params;
+    TextStyle::Parameters leftParams = _params;
+
+    // Deactivate offset horizontally for boundary labels
+    rightParams.labelOptions.offset.x = 0.0f;
+    leftParams.labelOptions.offset.x = 0.0f;
+
+    bool hasLeftLabel = false;
+    if (hasLeftSource && !leftText.empty()) {
+        leftParams.text = leftText;
+        leftParams.labelOptions.optional = true;
+        leftParams.labelOptions.anchors = {LabelProperty::Anchor::top};
+        leftParams.labelOptions.buffer = glm::vec2(0);
+
+        hash_combine(leftParams.labelOptions.repeatGroup, leftText);
+
+        hasLeftLabel = prepareLabel(leftParams, Label::Type::line, leftAttribs);
+    }
+
+    bool hasRightLabel = false;
+    if (hasRightSource && !rightText.empty()) {
+        rightParams.text = rightText;
+        rightParams.labelOptions.optional = true;
+        rightParams.labelOptions.anchors = {LabelProperty::Anchor::bottom};
+        rightParams.labelOptions.buffer = glm::vec2(0);
+
+        hash_combine(rightParams.labelOptions.repeatGroup, rightText);
+
+        hasRightLabel = prepareLabel(rightParams, Label::Type::line, rightAttribs);
+    }
+
+    float labelWidth = std::max(leftAttribs.width, rightAttribs.width);
+
+    auto onAddLabel = [&](glm::vec2 a, glm::vec2 b) {
+        Label* left = nullptr;
+        Label* right = nullptr;
+        if (hasLeftLabel) {
+            left = addLabel(Label::Type::line, {{ a, b }}, leftParams, leftAttribs, _rule);
+        }
+        if (hasRightLabel) {
+            right = addLabel(Label::Type::line, {{ a, b }}, rightParams, rightAttribs, _rule);
+        }
+        if (left && right) {
+            left->setRelative(*right, false, false);
+            right->setRelative(*left, false, false);
+        }
+    };
+
+    for (auto& line : _feat.lines) {
+        addStraightTextLabels(line, labelWidth, onAddLabel);
+    }
+
+    return true;
+}
+
+bool TextStyleBuilder::addFeature(const Feature& _feat, const DrawRule& _rule) {
+    TextStyle::Parameters params = applyRule(_rule, _feat.props, false);
+
+    Label::Type labelType;
+    if (_feat.geometryType == GeometryType::lines) {
+        labelType = Label::Type::line;
+        params.wordWrap = false;
+    } else {
+        labelType = Label::Type::point;
+    }
+
+    // Keep start position of new quads
+    size_t quadsStart = m_quads.size();
+    size_t numLabels = m_labels.size();
+
+    if (!handleBoundaryLabel(_feat, _rule, params)) {
+
+        LabelAttributes attrib;
+        if (!prepareLabel(params, labelType, attrib)) { return false; }
+
+        if (_feat.geometryType == GeometryType::points) {
+            for (auto& point : _feat.points) {
+                auto p = glm::vec2(point);
+                addLabel(Label::Type::point, {{ p }}, params, attrib, _rule);
+            }
+
+        } else if (_feat.geometryType == GeometryType::polygons) {
+            const auto& polygons = _feat.polygons;
+            for (const auto& polygon : polygons) {
+                if (!polygon.empty()) {
+                    glm::vec3 c;
+                    c = centroid(polygon.front().begin(), polygon.front().end());
+                    addLabel(Label::Type::point, {{ c }}, params, attrib, _rule);
+                }
+            }
+
+        } else if (_feat.geometryType == GeometryType::lines) {
+            addLineTextLabels(_feat, params, attrib, _rule);
+        }
+    }
+
+    if (numLabels == m_labels.size()) {
+        // Drop quads when no label was added
+        m_quads.resize(quadsStart);
+    }
+    return true;
+}
+
+bool TextStyleBuilder::addStraightTextLabels(const Line& _line, float _labelWidth,
+                                             const std::function<void(glm::vec2,glm::vec2)>& _onAddLabel) {
+
+    // Size of pixel in tile coordinates
+    float pixelSize = 1.0/m_tileSize;
+
+    // Minimal length of line needed for the label
+    float minLength = _labelWidth * pixelSize;
+
+    // Allow labels to appear later than tile's min-zoom
+    minLength *= 0.6;
+
+    //float tolerance = pow(pixelScale * 2, 2);
+    float tolerance = pow(pixelSize * 1.5, 2);
+    float sqDirLimit = powf(1.99f, 2);
+
+    for (size_t i = 0; i < _line.size() - 1; i++) {
+        glm::vec2 p0 = glm::vec2(_line[i]);
+        glm::vec2 p1 = glm::vec2(_line[i+1]);
+
+        float segmentLength = glm::length(p0 - p1);
+
+        glm::vec2 dir0 = (p0 - p1) / segmentLength;
+        glm::vec2 dir1 = dir0;
+        glm::vec2 dir2;
+
+        int merged = 0;
+
+        size_t j = i + 2;
+        for (; j < _line.size(); j++) {
+            glm::vec2 p2 = glm::vec2(_line[j]);
+
+            segmentLength = glm::length(p1 - p2);
+            dir2 = (p1 - p2) / segmentLength;
+
+            glm::vec2 pp = glm::vec2(_line[j-1]);
+            float d = sqPointSegmentDistance(pp, p0, p2);
+            if (d > tolerance) { break; }
+
+            if ((glm::length2(dir1 + dir2) < sqDirLimit) ||
+                (glm::length2(dir0 + dir2) < sqDirLimit)) {
+                break;
+            }
+
+            merged++;
+
+            p1 = p2;
+            dir1 = dir2;
+        }
+
+        // place labels at segment-subdivisions
+        int run = 1;
+        if (merged) { segmentLength = glm::length(p0 - p1); }
+
+        while (segmentLength > minLength && run <= 4) {
+            glm::vec2 a = p0;
+            glm::vec2 b = glm::vec2(p1 - p0) / float(run);
+
+            for (int r = 0; r < run; r++) {
+                _onAddLabel(a, a+b);
+
+                a += b;
+            }
+            run *= 2;
+            segmentLength /= 2.0f;
+        }
+
+        if (i == 0 && j == _line.size()) {
+            // Simple straight line
+            return true;
+        }
+
+        // Skip merged segments in outer loop
+        i += merged;
+
+    }
+    return false;
+}
+
+void TextStyleBuilder::addCurvedTextLabels(const Line& _line, const TextStyle::Parameters& _params,
+                                           const LabelAttributes& _attributes, const DrawRule& _rule) {
+
+    // Size of pixel in tile coordinates
+    const float pixelSize = 1.0/m_tileSize;
+    // length of line needed for the label
+    const float labelLength = _attributes.width * pixelSize;
+    // Allow labels to appear later than tile's min-zoom
+    const float minLength = labelLength * 0.6;
+
+    // Chord length for minimal ~120 degree inner angles (squared)
+    // sin(60)*2
+    const float sqDirLimit = powf(1.7f, 2);
+    // Range to check for angle changes
+    const float sampleWindow = pixelSize * 50;
+
+    // Minimal ~10 degree counts as change of direction
+    // cross(dir1,dir2) < sin(10)
+    const float flipTolerance = 0.17;
+
+    LineSampler<std::vector<glm::vec3>> sampler;
+
+    sampler.set(_line);
+
+    if (sampler.sumLength() < minLength) { return; }
+
+    struct LineRange {
+        size_t start, end;
+        int flips;
+        float sumAngle;
+    };
+
+    std::vector<LineRange> ranges;
+
+    for (size_t i = 0; i < _line.size()-1; i++) {
+
+        int flips = 0;
+        float lastAngle = 0;
+        float sumAngle = 0;
+        size_t lastBreak = 0;
+
+        glm::vec2 dir1 = sampler.segmentDirection(i);
+
+        for (size_t j = i + 1; j < _line.size()-1; j++) {
+            glm::vec2 dir2 = sampler.segmentDirection(j);
+            bool splitLine = false;
+
+            if (glm::length2(dir1 + dir2) < sqDirLimit) {
+                // Split if the angle between current and next segment is
+                // not whithin 120 < a < 240 degree
+                splitLine = true;
+            } else {
+                // Take cross product of direction (unit-) vectors of the current
+                // and next segment. The magnitude of the cross product is the sine
+                // angle between dir1 and dir2.
+                float angle = crossProduct(dir1, dir2);
+
+                if (std::abs(angle) > flipTolerance) {
+                    if (lastAngle > 0) {
+                        if (angle < 0) { flips++; }
+                    } else if (lastAngle < 0) {
+                        if (angle > 0) { flips++; }
+                    }
+                    lastAngle = angle;
+                }
+
+                // Limit number of direction changes (Avoid squiggly labels)
+                if (flips > 2) {
+                    splitLine = true;
+                } else {
+                    sumAngle += std::abs(angle);
+                }
+            }
+
+            if (!splitLine) {
+                // Go back within window to check for hard direction changes
+                for (int k = j - 1; k >= int(i); k--){
+                    if (glm::length2(sampler.segmentDirection(k) + dir2) < sqDirLimit) {
+                        splitLine = true;
+                    }
+                    if (sampler.point(k).z < sampler.point(j).z - sampleWindow) {
+                        break;
+                    }
+                }
+            }
+
+            if (splitLine) {
+                float length = sampler.point(j).z - sampler.point(i).z;
+                if (length > minLength) {
+                    ranges.push_back(LineRange{i, j+1, flips, sumAngle});
+                }
+
+                lastBreak = j;
+                break;
+
+            } else {
+                dir1 = dir2;
+            }
+        }
+
+        // Add segment from 'i' unless line got split.
+        if (lastBreak == 0) {
+            float length = sampler.sumLength() - sampler.point(i).z;
+            if (length > minLength) {
+                ranges.push_back(LineRange{i, _line.size(), flips, sumAngle});
+            }
+        }
+    }
+
+    for (auto& range : ranges) {
+        glm::vec2 center;
+        glm::vec2 rotation;
+        float startLen = sampler.point(range.start).z;
+        float length = (sampler.point(range.end-1).z - startLen);
+        float mid = startLen + length * 0.5;
+
+        sampler.sample(mid, center, rotation);
+        size_t offset = sampler.curSegment();
+
+        std::vector<glm::vec2> l;
+        l.reserve(range.end - range.start + 1);
+
+        for (size_t j = range.start; j < range.end; j++) {
+            auto& p = _line[j];
+            l.emplace_back(p.x, p.y);
+
+            if (j == offset) {
+                l.push_back(center);
+            }
+        }
+        size_t anchor = offset - range.start + 1;
+
+        // NB: Just some heuristic to prefer longer and less curvy parts..
+        float prio = (1.f + range.sumAngle) / length;
+
+        uint32_t selectionColor = 0;
+        if (_params.interactive) {
+            selectionColor = _rule.featureSelection->nextColorIdentifier();
+        }
+
+        m_labels.emplace_back(new CurvedLabel(l, _params.labelOptions, prio,
+                                               {_attributes.fill,
+                                                       _attributes.stroke,
+                                                       _attributes.fontScale,
+                                                       selectionColor},
+                                               {_attributes.width, _attributes.height},
+                                               *m_textLabels, _attributes.textRanges,
+                                               TextLabelProperty::Align::center,
+                                               anchor));
+
+    }
+}
+
+void TextStyleBuilder::addLineTextLabels(const Feature& _feat, const TextStyle::Parameters& _params,
+                                         const LabelAttributes& _attributes, const DrawRule& _rule) {
+
+    auto straightLabelCb = [&](glm::vec2 a, glm::vec2 b) {
+        addLabel(Label::Type::line, {{ a, b }}, _params, _attributes, _rule);
+    };
+
+    for (auto& line : _feat.lines) {
+
+        if (!addStraightTextLabels(line, _attributes.width, straightLabelCb) &&
+            line.size() > 2 && !_params.hasComplexShaping &&
+            // TODO: support line offset for curved labels
+            _params.labelOptions.offset == glm::vec2(0)) {
+            addCurvedTextLabels(line, _params, _attributes, _rule);
+        }
+    }
+}
+
+TextStyle::Parameters TextStyleBuilder::applyRule(const DrawRule& _rule,
+                                                  const Properties& _props,
+                                                  bool _iconText) const {
+
+    const static std::string defaultWeight("400");
+    const static std::string defaultStyle("normal");
+    const static std::string defaultFamily("default");
+
+    TextStyle::Parameters p;
+
+    if (!getTextSource(StyleParamKey::text_source, _rule, _props, p.text)) {
+        // Use default key
+        p.text = _props.getString(key_name);
+    }
+
+
+    if (p.text.empty()) { return p; }
+
+    auto fontFamily = _rule.get<std::string>(StyleParamKey::text_font_family);
+    fontFamily = (!fontFamily) ? &defaultFamily : fontFamily;
+
+    auto fontWeight = _rule.get<std::string>(StyleParamKey::text_font_weight);
+    fontWeight = (!fontWeight) ? &defaultWeight : fontWeight;
+
+    auto fontStyle = _rule.get<std::string>(StyleParamKey::text_font_style);
+    fontStyle = (!fontStyle) ? &defaultStyle : fontStyle;
+
+    _rule.get(StyleParamKey::text_font_size, p.fontSize);
+    p.fontSize *= m_style.pixelScale();
+
+    p.font = m_style.context()->getFont(*fontFamily, *fontStyle, *fontWeight, p.fontSize);
+
+    _rule.get(StyleParamKey::text_font_fill, p.fill);
+
+    _rule.get(StyleParamKey::text_font_stroke_color, p.strokeColor);
+    _rule.get(StyleParamKey::text_font_stroke_width, p.strokeWidth);
+    p.strokeWidth *= m_style.pixelScale();
+
+    _rule.get(StyleParamKey::transition_hide_time, p.labelOptions.hideTransition.time);
+    _rule.get(StyleParamKey::transition_selected_time, p.labelOptions.selectTransition.time);
+    _rule.get(StyleParamKey::transition_show_time, p.labelOptions.showTransition.time);
+
+    uint32_t priority = 0;
+    size_t repeatGroupHash = 0;
+    std::string repeatGroup;
+    StyleParam::Width repeatDistance;
+    glm::vec2 defaultBuffer = glm::vec2(p.fontSize * 0.25f);
+
+    if (_iconText) {
+        if (_rule.get(StyleParamKey::text_priority, priority)) {
+            p.labelOptions.priority = (float)priority;
+        }
+        _rule.get(StyleParamKey::text_collide, p.labelOptions.collide);
+        if (!_rule.get(StyleParamKey::text_interactive, p.interactive)) {
+            _rule.get(StyleParamKey::interactive, p.interactive);
+        }
+        _rule.get(StyleParamKey::text_offset, p.labelOptions.offset);
+        p.labelOptions.offset *= m_style.pixelScale();
+
+        _rule.get(StyleParamKey::text_anchor, p.labelOptions.anchors);
+        if (p.labelOptions.anchors.count == 0) {
+            p.labelOptions.anchors.anchor = { {LabelProperty::Anchor::bottom, LabelProperty::Anchor::top,
+                                               LabelProperty::Anchor::right, LabelProperty::Anchor::left} };
+            p.labelOptions.anchors.count = 4;
+        }
+
+        // child text's repeat group params
+        if (_rule.get(StyleParamKey::text_repeat_distance, repeatDistance)) {
+            p.labelOptions.repeatDistance = repeatDistance.value;
+        } else {
+            p.labelOptions.repeatDistance = View::s_pixelsPerTile;
+        }
+
+        if (p.labelOptions.repeatDistance > 0.f) {
+            if (_rule.get(StyleParamKey::text_repeat_group, repeatGroup)) {
+                hash_combine(repeatGroupHash, repeatGroup);
+            } else if (_rule.get(StyleParamKey::repeat_group, repeatGroup)) { //inherit from parent point
+                hash_combine(repeatGroupHash, repeatGroup);
+            } else {
+                repeatGroupHash = _rule.getParamSetHash();
+            }
+        }
+
+        _rule.get(StyleParamKey::text_transition_hide_time, p.labelOptions.hideTransition.time);
+        _rule.get(StyleParamKey::text_transition_selected_time, p.labelOptions.selectTransition.time);
+        _rule.get(StyleParamKey::text_transition_show_time, p.labelOptions.showTransition.time);
+
+        if (!_rule.get(StyleParamKey::text_buffer, p.labelOptions.buffer)) {
+            p.labelOptions.buffer = defaultBuffer;
+        }
+    } else {
+        if (_rule.get(StyleParamKey::priority, priority)) {
+            p.labelOptions.priority = (float)priority;
+        }
+        _rule.get(StyleParamKey::collide, p.labelOptions.collide);
+        _rule.get(StyleParamKey::interactive, p.interactive);
+        _rule.get(StyleParamKey::offset, p.labelOptions.offset);
+        p.labelOptions.offset *= m_style.pixelScale();
+
+        _rule.get(StyleParamKey::anchor, p.labelOptions.anchors);
+        if (p.labelOptions.anchors.count == 0) {
+            p.labelOptions.anchors = {LabelProperty::Anchor::center};
+        }
+
+        if (_rule.get(StyleParamKey::repeat_distance, repeatDistance)) {
+            p.labelOptions.repeatDistance = repeatDistance.value;
+        } else {
+            p.labelOptions.repeatDistance = View::s_pixelsPerTile;
+        }
+
+        if (p.labelOptions.repeatDistance > 0.f) {
+            if (_rule.get(StyleParamKey::repeat_group, repeatGroup)) {
+                hash_combine(repeatGroupHash, repeatGroup);
+            } else {
+                repeatGroupHash = _rule.getParamSetHash();
+            }
+        }
+
+        if (!_rule.get(StyleParamKey::buffer, p.labelOptions.buffer)) {
+            p.labelOptions.buffer = defaultBuffer;
+        }
+    }
+
+    if (p.labelOptions.repeatDistance > 0.f) {
+        hash_combine(repeatGroupHash, p.text);
+        p.labelOptions.repeatGroup = repeatGroupHash;
+        p.labelOptions.repeatDistance *= m_style.pixelScale();
+    }
+
+    _rule.get(StyleParamKey::text_wrap, p.maxLineWidth);
+
+    if (auto* transform = _rule.get<std::string>(StyleParamKey::text_transform)) {
+        TextLabelProperty::transform(*transform, p.transform);
+    }
+
+    if (auto* align = _rule.get<std::string>(StyleParamKey::text_align)) {
+        bool res = TextLabelProperty::align(*align, p.align);
+        if (!res && p.labelOptions.anchors.count > 0) {
+            p.align = TextLabelProperty::alignFromAnchor(p.labelOptions.anchors[0]);
+        }
+    }
+
+    _rule.get(StyleParamKey::text_optional, p.labelOptions.optional);
+
+    std::hash<TextStyle::Parameters> hash;
+    p.labelOptions.paramHash = hash(p);
+
+    p.lineSpacing = 2 * m_style.pixelScale();
+
+    if (p.interactive) {
+        p.labelOptions.featureId = _rule.selectionColor;
+    }
+
+    return p;
+}
+
+void applyTextTransform(const TextStyle::Parameters& _params,
+                        icu::UnicodeString& _string) {
+
+    icu::Locale loc("en");
+
+    switch (_params.transform) {
+    case TextLabelProperty::Transform::capitalize: {
+        UErrorCode status{U_ZERO_ERROR};
+        auto *wordIterator = BreakIterator::createWordInstance(loc, status);
+
+        if (U_SUCCESS(status)) { _string.toTitle(wordIterator); }
+
+        delete wordIterator;
+        break;
+    }
+    case TextLabelProperty::Transform::lowercase:
+        _string.toLower(loc);
+        break;
+    case TextLabelProperty::Transform::uppercase:
+        _string.toUpper(loc);
+        break;
+    default:
+        break;
+    }
+}
+
+bool isComplexShapingScript(const icu::UnicodeString& _text) {
+
+    // Taken from:
+    // https://github.com/tangrams/tangram/blob/labels-rebase/src/styles/text/canvas_text.js#L538-L553
+    // See also http://r12a.github.io/scripts/featurelist/
+
+    icu::StringCharacterIterator iterator(_text);
+    for (UChar c = iterator.first(); c != CharacterIterator::DONE; c = iterator.next()) {
+        if (c >= u'\u0600' && c <= u'\u18AF') {
+            if ((c <= u'\u06FF') ||                   // Arabic:     "\u0600-\u06FF"
+                (c >= u'\u0900' && c <= u'\u097F') || // Devanagari: "\u0900-\u097F"
+                (c >= u'\u0980' && c <= u'\u09FF') || // Bengali:    "\u0980-\u09FF"
+                (c >= u'\u0A00' && c <= u'\u0A7F') || // Gurmukhi:   "\u0A00-\u0A7F"
+                (c >= u'\u0A80' && c <= u'\u0AFF') || // Gujarati:   "\u0A80-\u0AFF"
+                (c >= u'\u0B00' && c <= u'\u0B7f') || // Oriya:      "\u0B00-\u0B7F"
+                (c >= u'\u0B80' && c <= u'\u0BFF') || // Tamil:      "\u0B80-\u0BFF"
+                (c >= u'\u0C00' && c <= u'\u0C7F') || // Telugu:     "\u0C00-\u0C7F"
+                (c >= u'\u0E80' && c <= u'\u0EFF') || // Lao:        "\u0E80-\u0EFF"
+                (c >= u'\u0F00' && c <= u'\u0FFF') || // Tibetan:    "\u0F00-\u0FFF"
+                (c >= u'\u1000' && c <= u'\u109F') || // Burmese:    "\u1000-\u109F"
+                (c >= u'\u1780' && c <= u'\u17FF') || // Khmer:      "\u1780-\u17FF"
+                (c >= u'\u1800' && c <= u'\u18AF')) { // Mongolian:  "\u1800-\u18AF"
+                return true;
+            }
+        }
+    }
+    return false;
+}
+
+bool TextStyleBuilder::prepareLabel(TextStyle::Parameters& _params, Label::Type _type,
+                                    LabelAttributes& _attributes) {
+
+    if (_params.text.empty() || _params.fontSize <= 0.f) {
+        // Nothing to render!
+        return false;
+    }
+
+    auto text = icu::UnicodeString::fromUTF8(_params.text);
+
+    applyTextTransform(_params, text);
+
+    if (_type == Label::Type::line) {
+        _params.hasComplexShaping = isComplexShapingScript(text);
+    }
+
+    // Scale factor by which the texture glyphs are scaled to match fontSize
+    _params.fontScale = _params.fontSize / _params.font->size();
+
+    // Stroke width is normalized by the distance of the SDF spread, then
+    // scaled to 255 and packed into the "alpha" channel of stroke.
+    // Maximal strokeWidth is 3px, attribute is normalized to 0-1 range.
+
+    auto ctx = m_style.context();
+
+    uint32_t strokeAttrib = std::max(_params.strokeWidth / ctx->maxStrokeWidth() * 255.f, 0.f);
+    if (strokeAttrib > 255) {
+        LOGN("stroke_width too large: %f / %f", _params.strokeWidth, strokeAttrib/255.f);
+        strokeAttrib = 255;
+    }
+    _attributes.stroke = (_params.strokeColor & 0x00ffffff) + (strokeAttrib << 24);
+    _attributes.fill = _params.fill;
+    _attributes.fontScale = std::min(int(_params.fontScale * 64.f), 255);
+    _attributes.quadsStart = m_quads.size();
+    _attributes.textRanges = TextRange{};
+
+    glm::vec2 bbox(0);
+    if (ctx->layoutText(_params, text, m_quads, m_atlasRefs, bbox, _attributes.textRanges)) {
+
+        int start = _attributes.quadsStart;
+        for (auto& range : _attributes.textRanges) {
+            assert(range.start == start);
+            assert(range.length >= 0);
+            start += range.length;
+        }
+        _attributes.width = bbox.x;
+        _attributes.height = bbox.y;
+        return true;
+    }
+
+    return false;
+}
+
+Label* TextStyleBuilder::addLabel(Label::Type _type, TextLabel::Coordinates _coordinates,
+                                const TextStyle::Parameters& _params, const LabelAttributes& _attributes,
+                                uint32_t _selectionColor) {
+
+
+    m_labels.emplace_back(new TextLabel(_coordinates, _type, _params.labelOptions,
+                                        {_attributes.fill,
+                                         _attributes.stroke,
+                                         _attributes.fontScale,
+                                         _selectionColor},
+                                        {_attributes.width, _attributes.height},
+                                        *m_textLabels, _attributes.textRanges,
+                                        _params.align));
+
+        return m_labels.back().get();
+
+}
+
+Label* TextStyleBuilder::addLabel(Label::Type _type, TextLabel::Coordinates _coordinates,
+                                  const TextStyle::Parameters& _params, const LabelAttributes& _attributes,
+                                  const DrawRule& _rule) {
+
+    uint32_t selectionColor = 0;
+
+    if (_params.interactive) {
+        selectionColor = _rule.featureSelection->nextColorIdentifier();
+    }
+
+    return addLabel(_type, _coordinates, _params, _attributes, selectionColor);
+}
+
+}
diff --git a/core/src/style/textStyleBuilder.h b/core/src/style/textStyleBuilder.h
new file mode 100644 (file)
index 0000000..00f44ba
--- /dev/null
@@ -0,0 +1,86 @@
+#pragma once
+
+#include "labels/textLabel.h"
+#include "labels/labelProperty.h"
+#include "style/textStyle.h"
+#include "text/fontContext.h"
+
+#include <memory>
+#include <vector>
+#include <string>
+
+namespace Tangram {
+
+class TextStyleBuilder : public StyleBuilder {
+
+public:
+
+    // Attributes of the prepared Label
+    struct LabelAttributes {
+        float width = 0;
+        float height = 0;
+        size_t quadsStart = 0;
+        uint32_t fill = 0;
+        uint32_t stroke = 0;
+        uint8_t fontScale = 0;
+        TextRange textRanges = {};
+    };
+
+    TextStyleBuilder(const TextStyle& _style);
+
+    const Style& style() const override { return m_style; }
+
+    bool addFeature(const Feature& _feature, const DrawRule& _rule) override;
+
+    void setup(const Tile& _tile) override;
+    void setup(const Marker& _marker, int zoom) override;
+
+    std::unique_ptr<StyledMesh> build() override;
+
+    TextStyle::Parameters applyRule(const DrawRule& _rule, const Properties& _props, bool _iconText) const;
+
+    bool prepareLabel(TextStyle::Parameters& _params, Label::Type _type, LabelAttributes& _attributes);
+
+    // Add label to the mesh using the prepared label data
+    Label* addLabel(Label::Type _type, TextLabel::Coordinates _coordinates, const TextStyle::Parameters& _params,
+                    const LabelAttributes& _attributes, const DrawRule& _rule);
+
+    Label*  addLabel(Label::Type _type, TextLabel::Coordinates _coordinates, const TextStyle::Parameters& _params,
+                     const LabelAttributes& _attributes, uint32_t _selectionColor);
+
+    void addLineTextLabels(const Feature& _feature, const TextStyle::Parameters& _params,
+                           const LabelAttributes& _attributes, const DrawRule& _rule);
+
+    bool addStraightTextLabels(const Line& _feature, float _labelWidth,
+                               const std::function<void(glm::vec2,glm::vec2)>& _onAddLabel);
+
+    void addCurvedTextLabels(const Line& _feature, const TextStyle::Parameters& _params,
+                             const LabelAttributes& _attributes, const DrawRule& _rule);
+
+    bool handleBoundaryLabel(const Feature& _feat, const DrawRule& _rule,
+                             const TextStyle::Parameters& _params);
+
+    bool checkRule(const DrawRule& _rule) const override { return true; }
+
+    std::vector<std::unique_ptr<Label>>* labels() { return &m_labels; }
+
+    void addLayoutItems(LabelCollider& _layout) override;
+
+protected:
+
+    const TextStyle& m_style;
+
+    // Result: TextLabel container
+    std::unique_ptr<TextLabels> m_textLabels;
+
+    // Buffers to hold data for TextLabels until build()
+    std::vector<GlyphQuad> m_quads;
+    std::bitset<FontContext::max_textures> m_atlasRefs;
+    std::vector<std::unique_ptr<Label>> m_labels;
+
+    float m_tileSize = 0;
+    float m_tileScale = 0;
+
+};
+
+}
diff --git a/core/src/tangram.cpp b/core/src/tangram.cpp
new file mode 100644 (file)
index 0000000..9b2c27e
--- /dev/null
@@ -0,0 +1,1022 @@
+#include "tangram.h"
+
+#include "data/clientGeoJsonSource.h"
+#include "debug/textDisplay.h"
+#include "debug/frameInfo.h"
+#include "gl.h"
+#include "gl/glError.h"
+#include "gl/framebuffer.h"
+#include "gl/hardware.h"
+#include "gl/primitives.h"
+#include "gl/renderState.h"
+#include "gl/shaderProgram.h"
+#include "labels/labels.h"
+#include "marker/marker.h"
+#include "marker/markerManager.h"
+#include "platform.h"
+#include "scene/scene.h"
+#include "scene/sceneLoader.h"
+#include "selection/selectionQuery.h"
+#include "style/material.h"
+#include "style/style.h"
+#include "style/textStyleBuilder.h"
+#include "text/fontContext.h"
+#include "tile/tile.h"
+#include "tile/tileCache.h"
+#include "tile/tileManager.h"
+#include "util/asyncWorker.h"
+#include "util/fastmap.h"
+#include "util/inputHandler.h"
+#include "util/ease.h"
+#include "util/jobQueue.h"
+#include "view/view.h"
+#include <bitset>
+#include <cmath>
+
+namespace Tangram {
+
+const static size_t MAX_WORKERS = 2;
+
+enum class EaseField { position, zoom, rotation, tilt };
+
+class Map::Impl {
+
+public:
+    Impl(std::shared_ptr<Platform> _platform) :
+        platform(_platform),
+        inputHandler(_platform, view),
+        scene(std::make_shared<Scene>(_platform)),
+        tileWorker(_platform, MAX_WORKERS),
+        tileManager(_platform, tileWorker) {}
+
+    void setScene(std::shared_ptr<Scene>& _scene);
+
+    void setEase(EaseField _f, Ease _e);
+    void clearEase(EaseField _f);
+
+    void setPositionNow(double _lon, double _lat);
+    void setZoomNow(float _z);
+    void setRotationNow(float _radians);
+    void setTiltNow(float _radians);
+
+    void setPixelScale(float _pixelsPerPoint);
+
+    std::mutex tilesMutex;
+    std::mutex sceneMutex;
+
+    RenderState renderState;
+    JobQueue jobQueue;
+    View view;
+    Labels labels;
+    std::unique_ptr<AsyncWorker> asyncWorker = std::make_unique<AsyncWorker>();
+    std::shared_ptr<Platform> platform;
+    InputHandler inputHandler;
+
+    std::vector<SceneUpdate> sceneUpdates;
+    std::array<Ease, 4> eases;
+
+    std::shared_ptr<Scene> scene;
+    std::shared_ptr<Scene> nextScene = nullptr;
+
+    // NB: Destruction of (managed and loading) tiles must happen
+    // before implicit destruction of 'scene' above!
+    // In particular any references of Labels and Markers to FontContext
+    TileWorker tileWorker;
+    TileManager tileManager;
+    MarkerManager markerManager;
+    std::unique_ptr<FrameBuffer> selectionBuffer = std::make_unique<FrameBuffer>(0, 0);
+
+    bool cacheGlState = false;
+    float pickRadius = .5f;
+
+    std::vector<SelectionQuery> selectionQueries;
+    struct {
+        std::unique_ptr<StyledMesh> mesh = nullptr;
+        std::unique_ptr<TextStyle> style = nullptr;
+        bool ready = false;;
+    } overlay;
+    void initOverlay(Scene& scene);
+    void renderOverlay();
+};
+
+void Map::Impl::setEase(EaseField _f, Ease _e) {
+    eases[static_cast<size_t>(_f)] = _e;
+    platform->requestRender();
+}
+
+void Map::Impl::clearEase(EaseField _f) {
+    static Ease none = {};
+    eases[static_cast<size_t>(_f)] = none;
+}
+
+static std::bitset<9> g_flags = 0;
+
+Map::Map(std::shared_ptr<Platform> _platform) : platform(_platform) {
+    impl.reset(new Impl(_platform));
+}
+
+Map::~Map() {
+    // The unique_ptr to Impl will be automatically destroyed when Map is destroyed.
+    impl->tileWorker.stop();
+    impl->asyncWorker.reset();
+
+    // Make sure other threads are stopped before calling stop()!
+    // All jobs will be executed immediately on add() afterwards.
+    impl->jobQueue.stop();
+
+    TextDisplay::Instance().deinit();
+    Primitives::deinit();
+}
+
+
+void Map::Impl::initOverlay(Scene& scene) {
+
+    overlay.mesh = nullptr;
+    overlay.style = nullptr;
+
+    if (scene.fontContext()) {
+        overlay.style = std::make_unique<TextStyle>("overlay", scene.fontContext(), true);
+        overlay.style->build(scene);
+        auto builder = overlay.style->createBuilder();
+
+        TextStyle::Parameters p;
+        p.font = scene.fontContext()->getFont("default", "normal", "400", 18);
+        p.text = "© Mapzen. © OpenStreetMap";
+        p.strokeWidth = 4;
+        p.fontSize = 18;
+        p.fill = 0xff444444;
+        p.strokeColor = 0xaaffffff;
+        p.wordWrap = false;
+        p.labelOptions.anchors.anchor = { {LabelProperty::Anchor::top_right} };
+        p.labelOptions.anchors.count = 1;
+
+        TextStyleBuilder* b = static_cast<TextStyleBuilder*>(builder.get());
+        TextStyleBuilder::LabelAttributes attrib;
+        b->prepareLabel(p, Label::Type::point, attrib);
+        b->addLabel(Label::Type::point, TextLabel::Coordinates{}, p, attrib, 0);
+        overlay.mesh = builder->build();
+
+        auto* mesh = dynamic_cast<const LabelSet*>(overlay.mesh.get());
+        if (!mesh || mesh->getLabels().empty()) {
+            LOGE("Failed to create overlay");
+            overlay.mesh = nullptr;
+            overlay.style = nullptr;
+        }
+
+        overlay.ready = false;
+    }
+}
+
+void Map::Impl::renderOverlay() {
+    if (overlay.mesh) {
+        if (!overlay.ready) {
+            overlay.ready = true;
+            overlay.style->onBeginUpdate();
+
+            auto* mesh = dynamic_cast<const LabelSet*>(overlay.mesh.get());
+            auto& l = mesh->getLabels()[0];
+            l->enterState(Label::State::visible);
+            l->evalState(0);
+            ScreenTransform::Buffer buf;
+            buf.points.push_back({10.f, view.getHeight(), 0.f});
+            buf.points.push_back({1.f, 0.f, 0.f});
+            Range range(0,2);
+            glm::vec2 screenSize(view.getWidth(), view.getHeight());
+            ScreenTransform transform(buf, range);
+            l->addVerticesToMesh(transform, screenSize);
+        }
+        overlay.style->onBeginFrame(renderState);
+        overlay.style->onBeginDrawFrame(renderState, view, *scene);
+        overlay.style->onEndDrawFrame();
+    }
+}
+
+void Map::Impl::setScene(std::shared_ptr<Scene>& _scene) {
+    {
+        std::lock_guard<std::mutex> lock(sceneMutex);
+        scene = _scene;
+    }
+
+    scene->setPixelScale(view.pixelScale());
+
+    auto& camera = scene->camera();
+    view.setCameraType(camera.type);
+
+    switch (camera.type) {
+    case CameraType::perspective:
+        view.setVanishingPoint(camera.vanishingPoint.x, camera.vanishingPoint.y);
+        if (camera.fovStops) {
+            view.setFieldOfViewStops(camera.fovStops);
+        } else {
+            view.setFieldOfView(camera.fieldOfView);
+        }
+        break;
+    case CameraType::isometric:
+        view.setObliqueAxis(camera.obliqueAxis.x, camera.obliqueAxis.y);
+        break;
+    case CameraType::flat:
+        break;
+    }
+
+    if (camera.maxTiltStops) {
+        view.setMaxPitchStops(camera.maxTiltStops);
+    } else {
+        view.setMaxPitch(camera.maxTilt);
+    }
+
+    if (scene->useScenePosition) {
+        glm::dvec2 projPos = view.getMapProjection().LonLatToMeters(scene->startPosition);
+        view.setPosition(projPos.x, projPos.y);
+        view.setZoom(scene->startZoom);
+    }
+
+    inputHandler.setView(view);
+    tileManager.setTileSources(_scene->tileSources());
+    tileWorker.setScene(_scene);
+    markerManager.setScene(_scene);
+
+    bool animated = scene->animated() == Scene::animate::yes;
+
+    if (scene->animated() == Scene::animate::none) {
+        for (const auto& style : scene->styles()) {
+            animated |= style->isAnimated();
+        }
+    }
+
+    if (animated != platform->isContinuousRendering()) {
+        platform->setContinuousRendering(animated);
+    }
+
+    initOverlay(*scene);
+}
+
+// NB: Not thread-safe. Must be called on the main/render thread!
+// (Or externally synchronized with main/render thread)
+void Map::loadScene(const char* _scenePath, bool _useScenePosition,
+                    const std::vector<SceneUpdate>& _sceneUpdates,
+                    SceneUpdateErrorCallback _onSceneUpdateError) {
+
+    LOG("Loading scene file: %s", _scenePath);
+
+    {
+        std::lock_guard<std::mutex> lock(impl->sceneMutex);
+        impl->sceneUpdates.clear();
+        impl->nextScene.reset();
+    }
+
+    auto scene = std::make_shared<Scene>(platform, _scenePath);
+    scene->useScenePosition = _useScenePosition;
+
+    if (SceneLoader::loadScene(platform, scene, _sceneUpdates, _onSceneUpdateError)) {
+        impl->setScene(scene);
+    }
+}
+
+void Map::loadSceneAsync(const char* _scenePath, bool _useScenePosition,
+                         MapReady _onMapReady, void *_onMapReadyUserData,
+                         const std::vector<SceneUpdate>& _sceneUpdates,
+                         SceneUpdateErrorCallback _onSceneUpdateError) {
+
+    LOG("Loading scene file (async): %s", _scenePath);
+
+    std::shared_ptr<Scene> nextScene;
+    {
+        std::lock_guard<std::mutex> lock(impl->sceneMutex);
+        impl->sceneUpdates.clear();
+        impl->nextScene = std::make_shared<Scene>(platform, _scenePath);
+        impl->nextScene->useScenePosition = _useScenePosition;
+        nextScene = impl->nextScene;
+    }
+
+    runAsyncTask([nextScene, _onMapReady, _onMapReadyUserData, _sceneUpdates, _onSceneUpdateError, this](){
+
+            bool newSceneLoaded = SceneLoader::loadScene(platform, nextScene, _sceneUpdates, _onSceneUpdateError);
+
+            impl->jobQueue.add([nextScene, newSceneLoaded, _onMapReady, _onMapReadyUserData, _onSceneUpdateError, this]() {
+                    {
+                        std::lock_guard<std::mutex> lock(impl->sceneMutex);
+                        if (nextScene == impl->nextScene) {
+                            impl->nextScene.reset();
+                        } else {
+                            // loadScene[Async] was called in the meantime.
+                            return;
+                        }
+                    }
+
+                    if (newSceneLoaded) {
+                        auto s = nextScene;
+                        impl->setScene(s);
+                        applySceneUpdates(_onSceneUpdateError);
+
+                        if (_onMapReady) {
+                            _onMapReady(_onMapReadyUserData);
+                        }
+                    }
+                });
+            platform->requestRender();
+        });
+}
+
+void Map::queueSceneUpdate(const char* _path, const char* _value) {
+    std::lock_guard<std::mutex> lock(impl->sceneMutex);
+    impl->sceneUpdates.push_back({_path, _value});
+}
+
+void Map::queueSceneUpdate(const std::vector<SceneUpdate>& sceneUpdates) {
+    std::lock_guard<std::mutex> lock(impl->sceneMutex);
+    impl->sceneUpdates.insert(impl->sceneUpdates.end(), sceneUpdates.begin(), sceneUpdates.end());
+}
+
+std::shared_ptr<Platform>& Map::getPlatform() {
+    return platform;
+}
+
+void Map::applySceneUpdates(SceneUpdateErrorCallback _onSceneUpdateError) {
+
+    std::shared_ptr<Scene> nextScene;
+    std::vector<SceneUpdate> updates;
+    {
+        std::lock_guard<std::mutex> lock(impl->sceneMutex);
+        if (impl->sceneUpdates.empty()) { return; }
+
+        if (impl->nextScene) {
+            // Changes are automatically applied once the scene is loaded
+            return;
+        }
+        LOG("Applying %d scene updates", impl->sceneUpdates.size());
+
+        impl->nextScene = std::make_shared<Scene>(*impl->scene);
+        impl->nextScene->useScenePosition = false;
+
+        updates = impl->sceneUpdates;
+        impl->sceneUpdates.clear();
+
+        nextScene = impl->nextScene;
+    }
+
+    runAsyncTask([nextScene, updates = std::move(updates), _onSceneUpdateError, this](){
+
+            if (!SceneLoader::applyUpdates(platform, *nextScene, updates, _onSceneUpdateError)) {
+                LOGW("Scene updates not applied to current scene");
+                return;
+            }
+
+            bool configApplied = SceneLoader::applyConfig(platform, nextScene);
+
+            impl->jobQueue.add([nextScene, configApplied, _onSceneUpdateError, this]() {
+                    {
+                        std::lock_guard<std::mutex> lock(impl->sceneMutex);
+                        if (nextScene == impl->nextScene) {
+                            impl->nextScene.reset();
+                        } else {
+                            // loadScene[Async] was called in the meantime.
+                            return;
+                        }
+                    }
+
+                    if (configApplied) {
+                        auto s = nextScene;
+                        impl->setScene(s);
+                        applySceneUpdates(_onSceneUpdateError);
+                    }
+                });
+            platform->requestRender();
+        });
+}
+
+void Map::setMBTiles(const char* _dataSourceName, const char* _mbtilesFilePath) {
+    std::string scenePath = std::string("sources.") + _dataSourceName + ".mbtiles";
+    queueSceneUpdate(scenePath.c_str(), _mbtilesFilePath);
+    applySceneUpdates();
+}
+
+void Map::resize(int _newWidth, int _newHeight) {
+
+    LOGS("resize: %d x %d", _newWidth, _newHeight);
+    LOG("resize: %d x %d", _newWidth, _newHeight);
+
+    impl->renderState.viewport(0, 0, _newWidth, _newHeight);
+
+    impl->view.setSize(_newWidth, _newHeight);
+
+    impl->selectionBuffer = std::make_unique<FrameBuffer>(_newWidth/2, _newHeight/2);
+
+    Primitives::setResolution(impl->renderState, _newWidth, _newHeight);
+
+    impl->overlay.ready = false;
+}
+
+bool Map::update(float _dt) {
+
+    // Wait until font resources are fully loaded
+    if (impl->scene->pendingFonts > 0) {
+        platform->requestRender();
+        return false;
+    }
+
+    FrameInfo::beginUpdate();
+
+    impl->jobQueue.runJobs();
+
+    impl->scene->updateTime(_dt);
+
+    bool viewComplete = true;
+    bool markersNeedUpdate = false;
+
+    for (auto& ease : impl->eases) {
+        if (!ease.finished()) {
+            ease.update(_dt);
+            viewComplete = false;
+        }
+    }
+
+    impl->inputHandler.update(_dt);
+
+    impl->view.update();
+
+    impl->markerManager.update(static_cast<int>(impl->view.getZoom()));
+
+    for (const auto& style : impl->scene->styles()) {
+        style->onBeginUpdate();
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(impl->tilesMutex);
+
+        impl->tileManager.updateTileSets(impl->view);
+
+        auto& tiles = impl->tileManager.getVisibleTiles();
+        auto& markers = impl->markerManager.markers();
+
+        for (const auto& marker : markers) {
+            marker->update(_dt, impl->view);
+            markersNeedUpdate |= marker->isEasing();
+        }
+
+        if (impl->view.changedOnLastUpdate() ||
+            impl->tileManager.hasTileSetChanged()) {
+
+            for (const auto& tile : tiles) {
+                tile->update(_dt, impl->view);
+            }
+            impl->labels.updateLabelSet(impl->view.state(), _dt, impl->scene, tiles, markers,
+                                        impl->tileManager);
+        } else {
+            impl->labels.updateLabels(impl->view.state(), _dt, impl->scene->styles(), tiles, markers);
+        }
+    }
+
+    FrameInfo::endUpdate();
+
+    bool viewChanged = impl->view.changedOnLastUpdate();
+    bool tilesChanged = impl->tileManager.hasTileSetChanged();
+    bool tilesLoading = impl->tileManager.hasLoadingTiles();
+    bool labelsNeedUpdate = impl->labels.needUpdate();
+    bool resourceLoading = (impl->scene->pendingTextures > 0);
+    bool nextScene = bool(impl->nextScene);
+
+    if (viewChanged || tilesChanged || tilesLoading || labelsNeedUpdate || resourceLoading || nextScene) {
+        viewComplete = false;
+    }
+
+    // Request render if labels are in fading states or markers are easing.
+    if (labelsNeedUpdate || markersNeedUpdate) { platform->requestRender(); }
+
+    return viewComplete;
+}
+
+void Map::setPickRadius(float _radius) {
+    impl->pickRadius = _radius;
+}
+
+void Map::pickFeatureAt(float _x, float _y, FeaturePickCallback _onFeaturePickCallback) {
+    impl->selectionQueries.push_back({{_x, _y}, impl->pickRadius, _onFeaturePickCallback});
+
+    platform->requestRender();
+}
+
+void Map::pickLabelAt(float _x, float _y, LabelPickCallback _onLabelPickCallback) {
+    impl->selectionQueries.push_back({{_x, _y}, impl->pickRadius, _onLabelPickCallback});
+
+    platform->requestRender();
+}
+
+void Map::pickMarkerAt(float _x, float _y, MarkerPickCallback _onMarkerPickCallback) {
+    impl->selectionQueries.push_back({{_x, _y}, impl->pickRadius, _onMarkerPickCallback});
+
+    platform->requestRender();
+}
+
+void Map::render() {
+
+    // Do not render if any texture resources are in process of being downloaded
+    if (impl->scene->pendingTextures > 0) {
+        return;
+    }
+
+    bool drawSelectionBuffer = getDebugFlag(DebugFlags::selection_buffer);
+
+    // Cache default framebuffer handle used for rendering
+    impl->renderState.cacheDefaultFramebuffer();
+
+    FrameInfo::beginFrame();
+
+    // Invalidate render states for new frame
+    if (!impl->cacheGlState) {
+        impl->renderState.invalidate();
+    }
+
+    // Run render-thread tasks
+    impl->renderState.jobQueue.runJobs();
+
+    // Render feature selection pass to offscreen framebuffer
+    if (impl->selectionQueries.size() > 0 || drawSelectionBuffer) {
+        impl->selectionBuffer->applyAsRenderTarget(impl->renderState);
+
+        std::lock_guard<std::mutex> lock(impl->tilesMutex);
+
+        for (const auto& style : impl->scene->styles()) {
+            style->onBeginDrawSelectionFrame(impl->renderState, impl->view, *(impl->scene));
+
+            for (const auto& tile : impl->tileManager.getVisibleTiles()) {
+                style->drawSelectionFrame(impl->renderState, *tile);
+            }
+
+            for (const auto& marker : impl->markerManager.markers()) {
+                style->drawSelectionFrame(impl->renderState, *marker);
+            }
+        }
+
+        std::vector<SelectionColorRead> colorCache;
+        // Resolve feature selection queries
+        for (const auto& selectionQuery : impl->selectionQueries) {
+            selectionQuery.process(impl->view, *impl->selectionBuffer, impl->markerManager,
+                                   impl->tileManager, impl->labels, colorCache);
+        }
+
+        impl->selectionQueries.clear();
+    }
+
+    // Setup default framebuffer for a new frame
+    glm::vec2 viewport(impl->view.getWidth(), impl->view.getHeight());
+    FrameBuffer::apply(impl->renderState, impl->renderState.defaultFrameBuffer(),
+                       viewport, impl->scene->background().asIVec4());
+
+    if (drawSelectionBuffer) {
+        impl->selectionBuffer->drawDebug(impl->renderState, viewport);
+        FrameInfo::draw(impl->renderState, impl->view, impl->tileManager);
+        return;
+    }
+
+    for (const auto& style : impl->scene->styles()) {
+        style->onBeginFrame(impl->renderState);
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(impl->tilesMutex);
+
+        // Loop over all styles
+        for (const auto& style : impl->scene->styles()) {
+
+            style->onBeginDrawFrame(impl->renderState, impl->view, *(impl->scene));
+
+            // Loop over all tiles in m_tileSet
+            for (const auto& tile : impl->tileManager.getVisibleTiles()) {
+                style->draw(impl->renderState, *tile);
+            }
+
+            for (const auto& marker : impl->markerManager.markers()) {
+                style->draw(impl->renderState, *marker);
+            }
+
+            style->onEndDrawFrame();
+        }
+    }
+
+    impl->renderOverlay();
+
+    impl->labels.drawDebug(impl->renderState, impl->view);
+
+    FrameInfo::draw(impl->renderState, impl->view, impl->tileManager);
+}
+
+int Map::getViewportHeight() {
+    return impl->view.getHeight();
+}
+
+int Map::getViewportWidth() {
+    return impl->view.getWidth();
+}
+
+float Map::getPixelScale() {
+    return impl->view.pixelScale();
+}
+
+void Map::captureSnapshot(unsigned int* _data) {
+    GL::readPixels(0, 0, impl->view.getWidth(), impl->view.getHeight(), GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)_data);
+}
+
+void Map::Impl::setPositionNow(double _lon, double _lat) {
+
+    glm::dvec2 meters = view.getMapProjection().LonLatToMeters({ _lon, _lat});
+    view.setPosition(meters.x, meters.y);
+    inputHandler.cancelFling();
+    platform->requestRender();
+
+}
+
+void Map::setPosition(double _lon, double _lat) {
+
+    impl->setPositionNow(_lon, _lat);
+    impl->clearEase(EaseField::position);
+
+}
+
+void Map::setPositionEased(double _lon, double _lat, float _duration, EaseType _e) {
+
+    double lon_start, lat_start;
+    getPosition(lon_start, lat_start);
+    auto cb = [=](float t) { impl->setPositionNow(ease(lon_start, _lon, t, _e), ease(lat_start, _lat, t, _e)); };
+    impl->setEase(EaseField::position, { _duration, cb });
+
+}
+
+void Map::getPosition(double& _lon, double& _lat) {
+
+    glm::dvec2 meters(impl->view.getPosition().x, impl->view.getPosition().y);
+    glm::dvec2 degrees = impl->view.getMapProjection().MetersToLonLat(meters);
+    _lon = degrees.x;
+    _lat = degrees.y;
+
+}
+
+void Map::Impl::setZoomNow(float _z) {
+
+    view.setZoom(_z);
+    inputHandler.cancelFling();
+    platform->requestRender();
+
+}
+
+void Map::setZoom(float _z) {
+
+    impl->setZoomNow(_z);
+    impl->clearEase(EaseField::zoom);
+
+}
+
+void Map::setZoomEased(float _z, float _duration, EaseType _e) {
+
+    float z_start = getZoom();
+    auto cb = [=](float t) { impl->setZoomNow(ease(z_start, _z, t, _e)); };
+    impl->setEase(EaseField::zoom, { _duration, cb });
+
+}
+
+float Map::getZoom() {
+
+    return impl->view.getZoom();
+
+}
+
+void Map::Impl::setRotationNow(float _radians) {
+
+    view.setRoll(_radians);
+    platform->requestRender();
+
+}
+
+void Map::setRotation(float _radians) {
+
+    impl->setRotationNow(_radians);
+    impl->clearEase(EaseField::rotation);
+
+}
+
+void Map::setRotationEased(float _radians, float _duration, EaseType _e) {
+
+    float radians_start = getRotation();
+
+    // Ease over the smallest angular distance needed
+    float radians_delta = glm::mod(_radians - radians_start, (float)TWO_PI);
+    if (radians_delta > PI) { radians_delta -= TWO_PI; }
+    _radians = radians_start + radians_delta;
+
+    auto cb = [=](float t) { impl->setRotationNow(ease(radians_start, _radians, t, _e)); };
+    impl->setEase(EaseField::rotation, { _duration, cb });
+
+}
+
+float Map::getRotation() {
+
+    return impl->view.getRoll();
+
+}
+
+
+void Map::Impl::setTiltNow(float _radians) {
+
+    view.setPitch(_radians);
+    platform->requestRender();
+
+}
+
+void Map::setTilt(float _radians) {
+
+    impl->setTiltNow(_radians);
+    impl->clearEase(EaseField::tilt);
+
+}
+
+void Map::setTiltEased(float _radians, float _duration, EaseType _e) {
+
+    float tilt_start = getTilt();
+    auto cb = [=](float t) { impl->setTiltNow(ease(tilt_start, _radians, t, _e)); };
+    impl->setEase(EaseField::tilt, { _duration, cb });
+
+}
+
+float Map::getTilt() {
+
+    return impl->view.getPitch();
+
+}
+
+bool Map::screenPositionToLngLat(double _x, double _y, double* _lng, double* _lat) {
+
+    double intersection = impl->view.screenToGroundPlane(_x, _y);
+    glm::dvec3 eye = impl->view.getPosition();
+    glm::dvec2 meters(_x + eye.x, _y + eye.y);
+    glm::dvec2 lngLat = impl->view.getMapProjection().MetersToLonLat(meters);
+    *_lng = lngLat.x;
+    *_lat = lngLat.y;
+
+    return (intersection >= 0);
+}
+
+bool Map::lngLatToScreenPosition(double _lng, double _lat, double* _x, double* _y) {
+    bool clipped = false;
+
+    glm::vec2 screenCoords = impl->view.lonLatToScreenPosition(_lng, _lat, clipped);
+
+    *_x = screenCoords.x;
+    *_y = screenCoords.y;
+
+    float width = impl->view.getWidth();
+    float height = impl->view.getHeight();
+    bool withinViewport = *_x >= 0. && *_x <= width && *_y >= 0. && *_y <= height;
+
+    return !clipped && withinViewport;
+}
+
+void Map::setPixelScale(float _pixelsPerPoint) {
+
+    impl->setPixelScale(_pixelsPerPoint);
+
+}
+
+void Map::Impl::setPixelScale(float _pixelsPerPoint) {
+
+    // If the pixel scale changes we need to re-build all the tiles.
+    // This is expensive, so first check whether the new value is different.
+    if (_pixelsPerPoint == view.pixelScale()) {
+        // Nothing to do!
+        return;
+    }
+    view.setPixelScale(_pixelsPerPoint);
+    scene->setPixelScale(_pixelsPerPoint);
+
+    // Tiles must be rebuilt to apply the new pixel scale to labels.
+    tileManager.clearTileSets();
+
+    // Markers must be rebuilt to apply the new pixel scale.
+    markerManager.rebuildAll();
+}
+
+void Map::setCameraType(int _type) {
+
+    impl->view.setCameraType(static_cast<CameraType>(_type));
+    platform->requestRender();
+
+}
+
+int Map::getCameraType() {
+
+    return static_cast<int>(impl->view.cameraType());
+
+}
+
+void Map::addTileSource(std::shared_ptr<TileSource> _source) {
+    std::lock_guard<std::mutex> lock(impl->tilesMutex);
+    impl->tileManager.addClientTileSource(_source);
+}
+
+bool Map::removeTileSource(TileSource& source) {
+    std::lock_guard<std::mutex> lock(impl->tilesMutex);
+    return impl->tileManager.removeClientTileSource(source);
+}
+
+void Map::clearTileSource(TileSource& _source, bool _data, bool _tiles) {
+    std::lock_guard<std::mutex> lock(impl->tilesMutex);
+
+    if (_tiles) { impl->tileManager.clearTileSet(_source.id()); }
+    if (_data) { _source.clearData(); }
+
+    platform->requestRender();
+}
+
+MarkerID Map::markerAdd() {
+    return impl->markerManager.add();
+}
+
+bool Map::markerRemove(MarkerID _marker) {
+    bool success = impl->markerManager.remove(_marker);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetPoint(MarkerID _marker, LngLat _lngLat) {
+    bool success = impl->markerManager.setPoint(_marker, _lngLat);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetPointEased(MarkerID _marker, LngLat _lngLat, float _duration, EaseType ease) {
+    bool success = impl->markerManager.setPointEased(_marker, _lngLat, _duration, ease);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetPolyline(MarkerID _marker, LngLat* _coordinates, int _count) {
+    bool success = impl->markerManager.setPolyline(_marker, _coordinates, _count);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetPolygon(MarkerID _marker, LngLat* _coordinates, int* _counts, int _rings) {
+    bool success = impl->markerManager.setPolygon(_marker, _coordinates, _counts, _rings);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetStylingFromString(MarkerID _marker, const char* _styling) {
+    bool success = impl->markerManager.setStylingFromString(_marker, _styling);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetStylingFromPath(MarkerID _marker, const char* _path) {
+    bool success = impl->markerManager.setStylingFromPath(_marker, _path);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetBitmap(MarkerID _marker, int _width, int _height, const unsigned int* _data) {
+    bool success = impl->markerManager.setBitmap(_marker, _width, _height, _data);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetVisible(MarkerID _marker, bool _visible) {
+    bool success = impl->markerManager.setVisible(_marker, _visible);
+    platform->requestRender();
+    return success;
+}
+
+bool Map::markerSetDrawOrder(MarkerID _marker, int _drawOrder) {
+    bool success = impl->markerManager.setDrawOrder(_marker, _drawOrder);
+    platform->requestRender();
+    return success;
+}
+
+void Map::markerRemoveAll() {
+    impl->markerManager.removeAll();
+    platform->requestRender();
+}
+
+void Map::handleTapGesture(float _posX, float _posY) {
+
+    impl->inputHandler.handleTapGesture(_posX, _posY);
+
+}
+
+void Map::handleDoubleTapGesture(float _posX, float _posY) {
+
+    impl->inputHandler.handleDoubleTapGesture(_posX, _posY);
+
+}
+
+void Map::handlePanGesture(float _startX, float _startY, float _endX, float _endY) {
+
+    impl->inputHandler.handlePanGesture(_startX, _startY, _endX, _endY);
+
+}
+
+void Map::handleFlingGesture(float _posX, float _posY, float _velocityX, float _velocityY) {
+
+    impl->inputHandler.handleFlingGesture(_posX, _posY, _velocityX, _velocityY);
+
+}
+
+void Map::handlePinchGesture(float _posX, float _posY, float _scale, float _velocity) {
+
+    impl->inputHandler.handlePinchGesture(_posX, _posY, _scale, _velocity);
+
+}
+
+void Map::handleRotateGesture(float _posX, float _posY, float _radians) {
+
+    impl->inputHandler.handleRotateGesture(_posX, _posY, _radians);
+
+}
+
+void Map::handleShoveGesture(float _distance) {
+
+    impl->inputHandler.handleShoveGesture(_distance);
+
+}
+
+void Map::setupGL() {
+
+    LOG("setup GL");
+
+    impl->renderState.invalidate();
+
+    impl->tileManager.clearTileSets();
+
+    impl->markerManager.rebuildAll();
+
+    if (impl->selectionBuffer->valid()) {
+        impl->selectionBuffer = std::make_unique<FrameBuffer>(impl->selectionBuffer->getWidth(),
+                                                              impl->selectionBuffer->getHeight());
+    }
+
+    impl->overlay.ready = false;
+
+    // Set default primitive render color
+    Primitives::setColor(impl->renderState, 0xffffff);
+
+    // Load GL extensions and capabilities
+    Hardware::loadExtensions();
+    Hardware::loadCapabilities();
+
+    // Hardware::printAvailableExtensions();
+}
+
+void Map::useCachedGlState(bool _useCache) {
+    impl->cacheGlState = _useCache;
+}
+
+void Map::runAsyncTask(std::function<void()> _task) {
+    if (impl->asyncWorker) {
+        impl->asyncWorker->enqueue(std::move(_task));
+    }
+}
+
+void Map::onMemoryWarning() {
+    auto& tileCache = impl->tileManager.getTileCache();
+
+    if (tileCache) {
+        tileCache->clear();
+    }
+
+    for (auto& tileSet : impl->tileManager.getTileSets()) {
+        tileSet.source->clearData();
+    }
+
+    if (impl->scene && impl->scene->fontContext()) {
+        impl->scene->fontContext()->releaseFonts();
+    }
+}
+
+void setDebugFlag(DebugFlags _flag, bool _on) {
+
+    g_flags.set(_flag, _on);
+    // m_view->setZoom(m_view->getZoom()); // Force the view to refresh
+
+}
+
+bool getDebugFlag(DebugFlags _flag) {
+
+    return g_flags.test(_flag);
+
+}
+
+void toggleDebugFlag(DebugFlags _flag) {
+
+    g_flags.flip(_flag);
+    // m_view->setZoom(m_view->getZoom()); // Force the view to refresh
+
+    // Rebuild tiles for debug modes that needs it
+    // if (_flag == DebugFlags::proxy_colors
+    //  || _flag == DebugFlags::draw_all_labels
+    //  || _flag == DebugFlags::tile_bounds
+    //  || _flag == DebugFlags::tile_infos) {
+    //     if (m_tileManager) {
+    //         std::lock_guard<std::mutex> lock(m_tilesMutex);
+    //         m_tileManager->clearTileSets();
+    //     }
+    // }
+}
+
+}
diff --git a/core/src/text/fontContext.cpp b/core/src/text/fontContext.cpp
new file mode 100644 (file)
index 0000000..2b09674
--- /dev/null
@@ -0,0 +1,340 @@
+#include "text/fontContext.h"
+
+#include "log.h"
+#include "platform.h"
+
+#define SDF_IMPLEMENTATION
+#include "sdf.h"
+
+#include <memory>
+#include <regex>
+
+#define BASE_SIZE 16
+#define STEP_SIZE 12
+#define MAX_STEPS 3
+#define SDF_WIDTH 6
+
+#define MIN_LINE_WIDTH 4
+
+namespace Tangram {
+
+FontContext::FontContext(std::shared_ptr<const Platform> _platform) :
+    m_sdfRadius(SDF_WIDTH),
+    m_atlas(*this, GlyphTexture::size, m_sdfRadius),
+    m_batch(m_atlas, m_scratch),
+    m_platform(_platform) {}
+
+void FontContext::setPixelScale(float _scale) {
+    m_sdfRadius = SDF_WIDTH * _scale;
+}
+
+void FontContext::loadFonts() {
+    auto fallbacks = m_platform->systemFontFallbacksHandle();
+
+    for (int i = 0, size = BASE_SIZE; i < MAX_STEPS; i++, size += STEP_SIZE) {
+        m_font[i] = m_alfons.addFont("default", size);
+    }
+
+    for (auto fallback : fallbacks) {
+        alfons::InputSource source;
+
+        if (fallback.path.empty()) {
+            source = alfons::InputSource(fallback.load);
+        } else {
+            source = alfons::InputSource(fallback.path);
+        }
+
+        for (int i = 0, size = BASE_SIZE; i < MAX_STEPS; i++, size += STEP_SIZE) {
+            m_font[i]->addFace(m_alfons.addFontFace(source, size));
+        }
+    }
+}
+
+// Synchronized on m_mutex in layoutText(), called on tile-worker threads
+void FontContext::addTexture(alfons::AtlasID id, uint16_t width, uint16_t height) {
+
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+
+    if (m_textures.size() == max_textures) {
+        LOGE("Way too many glyph textures!");
+        return;
+    }
+    m_textures.emplace_back();
+}
+
+// Synchronized on m_mutex in layoutText(), called on tile-worker threads
+void FontContext::addGlyph(alfons::AtlasID id, uint16_t gx, uint16_t gy, uint16_t gw, uint16_t gh,
+                           const unsigned char* src, uint16_t pad) {
+
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+
+    if (id >= max_textures) { return; }
+
+    auto& texData = m_textures[id].texData;
+    auto& texture = m_textures[id].texture;
+
+    size_t stride = GlyphTexture::size;
+    size_t width =  GlyphTexture::size;
+
+    unsigned char* dst = &texData[(gx + pad) + (gy + pad) * stride];
+
+    for (size_t y = 0, pos = 0; y < gh; y++, pos += gw) {
+        std::memcpy(dst + (y * stride), src + pos, gw);
+    }
+
+    dst = &texData[size_t(gx) + (size_t(gy) * width)];
+    gw += pad * 2;
+    gh += pad * 2;
+
+    size_t bytes = size_t(gw) * size_t(gh) * sizeof(float) * 3;
+    if (m_sdfBuffer.size() < bytes) {
+        m_sdfBuffer.resize(bytes);
+    }
+
+    sdfBuildDistanceFieldNoAlloc(dst, width, m_sdfRadius,
+                                 dst, gw, gh, width,
+                                 &m_sdfBuffer[0]);
+
+    texture.setDirty(gy, gh);
+    m_textures[id].dirty = true;
+}
+
+void FontContext::releaseAtlas(std::bitset<max_textures> _refs) {
+    if (!_refs.any()) { return; }
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+    for (size_t i = 0; i < m_textures.size(); i++) {
+        if (_refs[i]) { m_atlasRefCount[i] -= 1; }
+    }
+}
+
+void FontContext::updateTextures(RenderState& rs) {
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+
+    for (auto& gt : m_textures) {
+        if (gt.dirty) {
+            gt.dirty = false;
+            auto td = reinterpret_cast<const GLuint*>(gt.texData.data());
+            gt.texture.update(rs, 0, td);
+        }
+    }
+}
+
+void FontContext::bindTexture(RenderState& rs, alfons::AtlasID _id, GLuint _unit) {
+    std::lock_guard<std::mutex> lock(m_textureMutex);
+    m_textures[_id].texture.bind(rs, _unit);
+
+}
+
+bool FontContext::layoutText(TextStyle::Parameters& _params, const icu::UnicodeString& _text,
+                             std::vector<GlyphQuad>& _quads, std::bitset<max_textures>& _refs,
+                             glm::vec2& _size, TextRange& _textRanges) {
+
+    std::lock_guard<std::mutex> lock(m_fontMutex);
+
+    alfons::LineLayout line = m_shaper.shapeICU(_params.font, _text);
+
+    if (line.missingGlyphs() || line.shapes().size() == 0) {
+        // Nothing to do!
+        return false;
+    }
+
+    line.setScale(_params.fontScale);
+
+    // m_batch.drawShapeRange() calls FontContext's TextureCallback for new glyphs
+    // and MeshCallback (drawGlyph) for vertex quads of each glyph in LineLayout.
+
+    m_scratch.quads = &_quads;
+
+    size_t quadsStart = _quads.size();
+    alfons::LineMetrics metrics;
+
+    std::array<bool, 3> alignments = {};
+    if (_params.align != TextLabelProperty::Align::none) {
+        alignments[int(_params.align)] = true;
+    }
+
+    // Collect possible alignment from anchor fallbacks
+    for (int i = 0; i < _params.labelOptions.anchors.count; i++) {
+        auto anchor = _params.labelOptions.anchors[i];
+        TextLabelProperty::Align alignment = TextLabelProperty::alignFromAnchor(anchor);
+        if (alignment != TextLabelProperty::Align::none) {
+            alignments[int(alignment)] = true;
+        }
+    }
+
+    if (_params.wordWrap) {
+        m_textWrapper.clearWraps();
+
+        float width = m_textWrapper.getShapeRangeWidth(line, MIN_LINE_WIDTH,
+                                                       _params.maxLineWidth);
+
+        for (size_t i = 0; i < 3; i++) {
+
+            int rangeStart = m_scratch.quads->size();
+            if (!alignments[i]) {
+                _textRanges[i] = Range(rangeStart, 0);
+                continue;
+            }
+            int numLines = m_textWrapper.draw(m_batch, width, line, TextLabelProperty::Align(i),
+                                              _params.lineSpacing, metrics);
+            int rangeEnd = m_scratch.quads->size();
+
+            _textRanges[i] = Range(rangeStart, rangeEnd - rangeStart);
+
+            // For single line text alignments are the same
+            if (i == 0 && numLines == 1) {
+                _textRanges[1] = Range(rangeEnd, 0);
+                _textRanges[2] = Range(rangeEnd, 0);
+                break;
+            }
+        }
+    } else {
+        glm::vec2 position(0);
+        int rangeStart = m_scratch.quads->size();
+        m_batch.drawShapeRange(line, 0, line.shapes().size(), position, metrics);
+        int rangeEnd = m_scratch.quads->size();
+
+        _textRanges[0] = Range(rangeStart, rangeEnd - rangeStart);
+
+        _textRanges[1] = Range(rangeEnd, 0);
+        _textRanges[2] = Range(rangeEnd, 0);
+    }
+
+    auto it = _quads.begin() + quadsStart;
+    if (it == _quads.end()) {
+        // No glyphs added
+        return false;
+    }
+
+    // TextLabel parameter: Dimension
+    float width = metrics.aabb.z - metrics.aabb.x;
+    float height = metrics.aabb.w - metrics.aabb.y;
+    _size = glm::vec2(width, height);
+
+    // Offset to center all glyphs around 0/0
+    glm::vec2 offset((metrics.aabb.x + width * 0.5) * TextVertex::position_scale,
+                     (metrics.aabb.y + height * 0.5) * TextVertex::position_scale);
+
+    {
+        std::lock_guard<std::mutex> lock(m_textureMutex);
+        for (; it != _quads.end(); ++it) {
+
+            if (!_refs[it->atlas]) {
+                _refs[it->atlas] = true;
+                m_atlasRefCount[it->atlas]++;
+            }
+
+            it->quad[0].pos -= offset;
+            it->quad[1].pos -= offset;
+            it->quad[2].pos -= offset;
+            it->quad[3].pos -= offset;
+        }
+
+        // Clear unused textures
+        for (size_t i = 0; i < m_textures.size(); i++) {
+            if (m_atlasRefCount[i] == 0) {
+                m_atlas.clear(i);
+                m_textures[i].texData.assign(GlyphTexture::size *
+                                             GlyphTexture::size, 0);
+            }
+        }
+    }
+
+    return true;
+}
+
+void FontContext::addFont(const FontDescription& _ft, alfons::InputSource _source) {
+
+    // NB: Synchronize for calls from download thread
+    std::lock_guard<std::mutex> lock(m_fontMutex);
+
+    for (int i = 0, size = BASE_SIZE; i < MAX_STEPS; i++, size += STEP_SIZE) {
+        auto font = m_alfons.getFont(_ft.alias, size);
+        font->addFace(m_alfons.addFontFace(_source, size));
+
+        // add fallbacks from default font
+        font->addFaces(*m_font[i]);
+    }
+}
+
+void FontContext::releaseFonts() {
+    // Unload Freetype and Harfbuzz resources for all font faces
+    m_alfons.unload();
+
+    // Release system font fallbacks input source data from default fonts, since
+    // those are 'weak' resources (would be automatically reloaded by alfons from
+    // its URI or source callback.
+    for (auto& font : m_font) {
+        for (auto& face : font->faces()) {
+            alfons::InputSource& fontSource = face->descriptor().source;
+
+            if (fontSource.isUri() || fontSource.hasSourceCallback()) {
+                fontSource.clearData();
+            }
+        }
+    }
+}
+
+void FontContext::ScratchBuffer::drawGlyph(const alfons::Rect& q, const alfons::AtlasGlyph& atlasGlyph) {
+    if (atlasGlyph.atlas >= max_textures) { return; }
+
+    auto& g = *atlasGlyph.glyph;
+
+    quads->push_back({
+            atlasGlyph.atlas,
+            {{glm::vec2{q.x1, q.y1} * TextVertex::position_scale, {g.u1, g.v1}},
+             {glm::vec2{q.x1, q.y2} * TextVertex::position_scale, {g.u1, g.v2}},
+             {glm::vec2{q.x2, q.y1} * TextVertex::position_scale, {g.u2, g.v1}},
+             {glm::vec2{q.x2, q.y2} * TextVertex::position_scale, {g.u2, g.v2}}}});
+}
+
+std::shared_ptr<alfons::Font> FontContext::getFont(const std::string& _family, const std::string& _style,
+                                                   const std::string& _weight, float _size) {
+
+    int sizeIndex = 0;
+
+    // Pick the smallest font that does not scale down too much
+    float fontSize = BASE_SIZE;
+    for (int i = 0; i < MAX_STEPS; i++) {
+        sizeIndex = i;
+
+        if (_size <= fontSize) { break; }
+        fontSize += STEP_SIZE;
+    }
+
+    std::lock_guard<std::mutex> lock(m_fontMutex);
+
+    auto font = m_alfons.getFont(FontDescription::Alias(_family, _style, _weight), fontSize);
+    if (font->hasFaces()) { return font; }
+
+    // 1. Bundle
+    // Assuming bundled ttf file follows this convention
+    std::string bundleFontPath = m_sceneResourceRoot + "fonts/" +
+        FontDescription::BundleAlias(_family, _style, _weight);
+
+    std::vector<char> fontData = m_platform->bytesFromFile(bundleFontPath.c_str());
+
+    // 2. System font
+    if (fontData.size() == 0) {
+        fontData = m_platform->systemFont(_family, _weight, _style);
+    }
+
+    if (fontData.size() == 0) {
+        LOGN("Could not load font file %s", FontDescription::BundleAlias(_family, _style, _weight).c_str());
+
+        // 3. Add fallbacks from default font
+        if (m_font[sizeIndex]) {
+            font->addFaces(*m_font[sizeIndex]);
+        }
+    } else {
+        font->addFace(m_alfons.addFontFace(alfons::InputSource(std::move(fontData)), fontSize));
+
+        if (m_font[sizeIndex]) {
+            font->addFaces(*m_font[sizeIndex]);
+        }
+    }
+
+    return font;
+}
+
+}
diff --git a/core/src/text/fontContext.h b/core/src/text/fontContext.h
new file mode 100644 (file)
index 0000000..83ef3c5
--- /dev/null
@@ -0,0 +1,151 @@
+#pragma once
+
+#include "gl/texture.h"
+#include "labels/textLabel.h"
+#include "style/textStyle.h"
+#include "text/textUtil.h"
+
+#include "alfons/alfons.h"
+#include "alfons/atlas.h"
+#include "alfons/font.h"
+#include "alfons/fontManager.h"
+#include "alfons/inputSource.h"
+#include "alfons/textBatch.h"
+#include "alfons/textShaper.h"
+#include <bitset>
+#include <mutex>
+
+namespace Tangram {
+
+struct FontMetrics {
+    float ascender, descender, lineHeight;
+};
+
+// TODO could be a shared_ptr<Texture>
+struct GlyphTexture {
+
+    static constexpr int size = 256;
+
+    GlyphTexture() : texture(size, size) {
+        texData.resize(size * size);
+    }
+
+    std::vector<unsigned char> texData;
+    Texture texture;
+
+    bool dirty = false;
+    size_t refCount = 0;
+};
+
+struct FontDescription {
+    std::string uri;
+    std::string alias;
+    std::string bundleAlias;
+
+    FontDescription(std::string family, std::string style, std::string weight, std::string uri)
+        : uri(uri) {
+        alias = Alias(family, style, weight);
+        bundleAlias = BundleAlias(family, style, weight);
+    }
+
+    static std::string Alias(const std::string& family, const std::string& style, const std::string& weight) {
+        return family + "_" + weight + "_" + style;
+    }
+
+    static std::string BundleAlias(const std::string& family, const std::string& style, const std::string& weight) {
+        // TODO: support .woff on bundle fonts
+        std::string alias = family + "-" + weight + style + ".ttf";
+        return alias;
+    }
+};
+
+class FontContext : public alfons::TextureCallback {
+
+public:
+
+    static constexpr int max_textures = 64;
+
+    FontContext(std::shared_ptr<const Platform> _platform);
+
+    void loadFonts();
+
+    /* Synchronized on m_mutex on tile-worker threads
+     * Called from alfons when a texture atlas needs to be created
+     * Triggered from TextStyleBuilder::prepareLabel
+     */
+    void addTexture(alfons::AtlasID id, uint16_t width, uint16_t height) override;
+
+    /* Synchronized on m_mutex, called tile-worker threads
+     * Called from alfons when a glyph needs to be added the the atlas identified by id
+     * Triggered from TextStyleBuilder::prepareLabel
+     */
+    void addGlyph(alfons::AtlasID id, uint16_t gx, uint16_t gy, uint16_t gw, uint16_t gh,
+                  const unsigned char* src, uint16_t pad) override;
+
+    void releaseAtlas(std::bitset<max_textures> _refs);
+
+    /* Update all textures batches, uploads the data to the GPU */
+    void updateTextures(RenderState& rs);
+
+    std::shared_ptr<alfons::Font> getFont(const std::string& _family, const std::string& _style,
+                                          const std::string& _weight, float _size);
+
+    size_t glyphTextureCount() {
+        std::lock_guard<std::mutex> lock(m_textureMutex);
+        return m_textures.size();
+    }
+
+    void bindTexture(RenderState& rs, alfons::AtlasID _id, GLuint _unit);
+
+    float maxStrokeWidth() { return m_sdfRadius; }
+
+    bool layoutText(TextStyle::Parameters& _params, const icu::UnicodeString& _text,
+                    std::vector<GlyphQuad>& _quads, std::bitset<max_textures>& _refs,
+                    glm::vec2& _bbox, TextRange& _textRanges);
+
+    struct ScratchBuffer : public alfons::MeshCallback {
+        void drawGlyph(const alfons::Quad& q, const alfons::AtlasGlyph& altasGlyph) override {}
+        void drawGlyph(const alfons::Rect& q, const alfons::AtlasGlyph& atlasGlyph) override;
+        std::vector<GlyphQuad>* quads;
+    };
+
+    void setSceneResourceRoot(const std::string& sceneResourceRoot) { m_sceneResourceRoot = sceneResourceRoot; }
+
+    void addFont(const FontDescription& _ft, alfons::InputSource _source);
+
+    void setPixelScale(float _scale);
+
+    void releaseFonts();
+
+private:
+
+    float m_sdfRadius;
+    ScratchBuffer m_scratch;
+    std::vector<unsigned char> m_sdfBuffer;
+
+    std::mutex m_fontMutex;
+    std::mutex m_textureMutex;
+
+    std::array<int, max_textures> m_atlasRefCount = {{0}};
+    alfons::GlyphAtlas m_atlas;
+
+    alfons::FontManager m_alfons;
+    std::array<std::shared_ptr<alfons::Font>, 3> m_font;
+
+    std::vector<GlyphTexture> m_textures;
+
+    // TextShaper to create <LineLayout> for a given text and Font
+    alfons::TextShaper m_shaper;
+
+    // TextBatch to 'draw' <LineLayout>s, i.e. creating glyph textures and glyph quads.
+    // It is intialized with a TextureCallback implemented by FontContext for adding glyph
+    // textures and a MeshCallback implemented by TextStyleBuilder for adding glyph quads.
+    alfons::TextBatch m_batch;
+    TextWrapper m_textWrapper;
+    std::string m_sceneResourceRoot = "";
+
+    std::shared_ptr<const Platform> m_platform;
+
+};
+
+}
diff --git a/core/src/text/textUtil.cpp b/core/src/text/textUtil.cpp
new file mode 100644 (file)
index 0000000..cda6a1f
--- /dev/null
@@ -0,0 +1,112 @@
+#include "text/textUtil.h"
+
+#include "platform.h"
+
+namespace Tangram {
+
+float TextWrapper::getShapeRangeWidth(const alfons::LineLayout& _line,
+                                      size_t _minLineChars, size_t _maxLineChars) {
+    float maxWidth = 0;
+
+    float lineWidth = 0;
+    size_t charCount = 0;
+    size_t shapeCount = 0;
+
+    float lastWidth = 0;
+    size_t lastShape = 0;
+    size_t lastChar = 0;
+
+    for (auto& shape : _line.shapes()) {
+
+        if (!shape.cluster) {
+            shapeCount++;
+            lineWidth += _line.advance(shape);
+            continue;
+        }
+
+        charCount++;
+        shapeCount++;
+        lineWidth += _line.advance(shape);
+
+        if (shape.canBreak || shape.mustBreak) {
+            lastShape = shapeCount;
+            lastChar = charCount;
+            lastWidth = lineWidth;
+        }
+
+        if (lastShape != 0 && (shape.mustBreak || charCount >= _maxLineChars)) {
+            // only go to next line if chars have been added on the current line
+            if (shape.mustBreak || lastChar > _minLineChars) {
+
+                auto& endShape = _line.shapes()[lastShape-1];
+
+                if (endShape.isSpace) {
+                    lineWidth -= _line.advance(endShape);
+                    lastWidth -= _line.advance(endShape);
+                }
+
+                m_lineWraps.emplace_back(lastShape, lastWidth);
+                maxWidth = std::max(maxWidth, lastWidth);
+
+                lineWidth -= lastWidth;
+                charCount -= lastChar;
+                lastShape = 0;
+            }
+        }
+    }
+
+    if (charCount > 0) {
+        m_lineWraps.emplace_back(shapeCount, lineWidth);
+        maxWidth = std::max(maxWidth, lineWidth);
+    }
+
+    return maxWidth;
+}
+
+void TextWrapper::clearWraps() {
+    m_lineWraps.clear();
+}
+
+int TextWrapper::draw(alfons::TextBatch& _batch, float _maxWidth, const alfons::LineLayout& _line,
+                      TextLabelProperty::Align _alignment, float _lineSpacing,
+                      alfons::LineMetrics& _layoutMetrics) {
+    size_t shapeStart = 0;
+    glm::vec2 position;
+
+    for (auto wrap : m_lineWraps) {
+        alfons::LineMetrics lineMetrics;
+
+        switch(_alignment) {
+            case TextLabelProperty::Align::center:
+            case TextLabelProperty::Align::none:
+                position.x = (_maxWidth - wrap.second) * 0.5;
+                break;
+            case TextLabelProperty::Align::right:
+                position.x = (_maxWidth - wrap.second);
+                break;
+            default:
+                position.x = 0;
+        }
+
+        size_t shapeEnd = wrap.first;
+
+        // Draw line quads
+        _batch.drawShapeRange(_line, shapeStart, shapeEnd, position, lineMetrics);
+
+        shapeStart = shapeEnd;
+
+        // FIXME hardcoded value for SDF radius 6
+        float height = lineMetrics.height();
+        height -= (2 * 6) * _line.scale(); // substract glyph padding
+        height += _lineSpacing; // add some custom line offset
+
+        position.y += height;
+
+        _layoutMetrics.addExtents(lineMetrics.aabb);
+    }
+
+    return int(m_lineWraps.size());
+}
+
+
+}
diff --git a/core/src/text/textUtil.h b/core/src/text/textUtil.h
new file mode 100644 (file)
index 0000000..5fe3a9a
--- /dev/null
@@ -0,0 +1,41 @@
+#pragma once
+
+#include "labels/labelProperty.h"
+
+#include "alfons/alfons.h"
+#include "alfons/lineLayout.h"
+#include "alfons/textBatch.h"
+#include <vector>
+
+namespace Tangram {
+
+class TextWrapper {
+
+public:
+
+    float getShapeRangeWidth(const alfons::LineLayout& _line,
+        size_t _minLineChars, size_t _maxLineChars);
+
+    void clearWraps();
+
+    /* Wrap an Alfons line layout, and draw the glyph quads to the TextBatch.
+     *
+     * This method is not threadsafe!
+     *
+     * _batch the text batch on which the mesh callback and atlas callback would be triggered
+     * _line the alfons LineLayout containing the glyph shapes and their related codepoints
+     * _maxChar the maximum line length
+     * _minWordLength a parameter to control the minimum word length
+     * _alignment align text (center, left, right)
+     * _lineSpacing
+     * _metrics out: text extents
+     */
+    int draw(alfons::TextBatch& _batch, float _maxWidth, const alfons::LineLayout& _line,
+             TextLabelProperty::Align _alignment, float _lineSpacing,
+             alfons::LineMetrics& _metrics);
+
+private:
+    std::vector<std::pair<int,float>> m_lineWraps;
+};
+
+}
diff --git a/core/src/tile/tile.cpp b/core/src/tile/tile.cpp
new file mode 100644 (file)
index 0000000..e772f9e
--- /dev/null
@@ -0,0 +1,120 @@
+#include "tile/tile.h"
+
+#include "data/tileSource.h"
+#include "labels/labelSet.h"
+#include "style/style.h"
+#include "tile/tileID.h"
+#include "view/view.h"
+
+#include "glm/gtc/matrix_transform.hpp"
+
+namespace Tangram {
+
+Tile::Tile(TileID _id, const MapProjection& _projection, const TileSource* _source) :
+    m_id(_id),
+    m_projection(&_projection),
+    m_sourceId(_source ? _source->id() : 0),
+    m_sourceGeneration(_source ? _source->generation() : 0) {
+
+    BoundingBox bounds(_projection.TileBounds(_id));
+
+    m_scale = bounds.width();
+    m_inverseScale = 1.0/m_scale;
+
+    updateTileOrigin(_id.wrap);
+
+    // Init model matrix to size of tile
+    m_modelMatrix = glm::scale(glm::mat4(1.0), glm::vec3(m_scale));
+}
+
+
+glm::dvec2 Tile::coordToLngLat(const glm::vec2& _tileCoord) const {
+    double scale = 1.0 / m_inverseScale;
+
+    glm::dvec2 meters = glm::dvec2(_tileCoord) * scale + m_tileOrigin;
+    glm::dvec2 degrees = m_projection->MetersToLonLat(meters);
+
+    return {degrees.x, degrees.y};
+}
+
+Tile::~Tile() {}
+
+//Note: This could set tile origin to be something different than the one if TileID's wrap is used.
+// But, this is required for wrapped tiles which are picked up from the cache
+void Tile::updateTileOrigin(const int _wrap) {
+    BoundingBox bounds(m_projection->TileBounds(m_id));
+
+    m_tileOrigin = { bounds.min.x, bounds.max.y }; // South-West corner
+    // negative y coordinate: to change from y down to y up
+    // (tile system has y down and gl context we use has y up).
+    m_tileOrigin.y *= -1.0;
+
+    auto mapBound = m_projection->MapBounds();
+    auto mapSpan = mapBound.max.x - mapBound.min.x;
+
+    m_tileOrigin.x += (mapSpan * _wrap);
+}
+
+void Tile::initGeometry(uint32_t _size) {
+    m_geometry.resize(_size);
+}
+
+void Tile::update(float _dt, const View& _view) {
+
+    // Apply tile-view translation to the model matrix
+    const auto& viewOrigin = _view.getPosition();
+    m_modelMatrix[3][0] = m_tileOrigin.x - viewOrigin.x;
+    m_modelMatrix[3][1] = m_tileOrigin.y - viewOrigin.y;
+
+    m_mvp = _view.getViewProjectionMatrix() * m_modelMatrix;
+}
+
+void Tile::resetState() {
+    for (auto& entry : m_geometry) {
+        if (!entry) { continue; }
+        auto labelSet = dynamic_cast<LabelSet*>(entry.get());
+        if (!labelSet) { continue; }
+        labelSet->reset();
+    }
+}
+
+void Tile::setMesh(const Style& _style, std::unique_ptr<StyledMesh> _mesh) {
+    size_t id = _style.getID();
+    if (id >= m_geometry.size()) {
+        m_geometry.resize(id+1);
+    }
+    m_geometry[_style.getID()] = std::move(_mesh);
+}
+
+const std::unique_ptr<StyledMesh>& Tile::getMesh(const Style& _style) const {
+    static std::unique_ptr<StyledMesh> NONE = nullptr;
+    if (_style.getID() >= m_geometry.size()) { return NONE; }
+
+    return m_geometry[_style.getID()];
+}
+
+void Tile::setSelectionFeatures(const fastmap<uint32_t, std::shared_ptr<Properties>> _selectionFeatures) {
+    m_selectionFeatures = _selectionFeatures;
+}
+
+std::shared_ptr<Properties> Tile::getSelectionFeature(uint32_t _id) {
+    auto it = m_selectionFeatures.find(_id);
+    if (it != m_selectionFeatures.end()) {
+        return it->second;
+    }
+    return nullptr;
+}
+
+size_t Tile::getMemoryUsage() const {
+    if (m_memoryUsage == 0) {
+        for (auto& entry : m_geometry) {
+            if (entry) {
+                m_memoryUsage += entry->bufferSize();
+            }
+        }
+    }
+
+    return m_memoryUsage;
+}
+
+}
diff --git a/core/src/tile/tile.h b/core/src/tile/tile.h
new file mode 100644 (file)
index 0000000..282d859
--- /dev/null
@@ -0,0 +1,140 @@
+#pragma once
+
+#include "gl/texture.h"
+#include "tile/tileID.h"
+#include "util/fastmap.h"
+
+#include "glm/mat4x4.hpp"
+#include "glm/vec2.hpp"
+#include <map>
+#include <memory>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+class TileSource;
+class MapProjection;
+struct Properties;
+class Style;
+class View;
+struct StyledMesh;
+
+struct Raster {
+    TileID tileID;
+    std::shared_ptr<Texture> texture;
+
+    Raster(TileID tileID, std::shared_ptr<Texture> texture) : tileID(tileID), texture(texture) {}
+    Raster(Raster&& other) : tileID(other.tileID), texture(std::move(other.texture)) {}
+
+    bool isValid() const { return texture != nullptr; }
+};
+
+/* Tile of vector map data
+ *
+ * Tile represents a fixed area of a map at a fixed zoom level; It contains its
+ * position within a quadtree of tiles and its location in projected global
+ * space; It stores drawable geometry of the map features in its area
+ */
+class Tile {
+
+public:
+
+    Tile(TileID _id, const MapProjection& _projection, const TileSource* _source = nullptr);
+
+
+    virtual ~Tile();
+
+    /* Returns the immutable <TileID> of this tile */
+    const TileID& getID() const { return m_id; }
+
+    /* Returns the center of the tile area in projection units */
+    const glm::dvec2& getOrigin() const { return m_tileOrigin; }
+
+    /* Returns the map projection with which this tile interprets coordinates */
+    const MapProjection* getProjection() const { return m_projection; }
+
+    /* Returns the length of a side of this tile in projection units */
+    float getScale() const { return m_scale; }
+
+    /* Returns the reciprocal of <getScale()> */
+    float getInverseScale() const { return m_inverseScale; }
+
+    const glm::mat4& getModelMatrix() const { return m_modelMatrix; }
+
+    const glm::mat4& mvp() const { return m_mvp; }
+
+    glm::dvec2 coordToLngLat(const glm::vec2& _tileCoord) const;
+
+    void initGeometry(uint32_t _size);
+
+    const std::unique_ptr<StyledMesh>& getMesh(const Style& _style) const;
+
+    void setMesh(const Style& _style, std::unique_ptr<StyledMesh> _mesh);
+
+    void setSelectionFeatures(const fastmap<uint32_t, std::shared_ptr<Properties>> _selectionFeatures);
+
+    std::shared_ptr<Properties> getSelectionFeature(uint32_t _id);
+
+    const auto& getSelectionFeatures() const { return m_selectionFeatures; }
+
+    auto& rasters() { return m_rasters; }
+    const auto& rasters() const { return m_rasters; }
+
+    /* Update the Tile considering the current view */
+    void update(float _dt, const View& _view);
+
+    /* Update tile origin based on wraping for this tile */
+    void updateTileOrigin(const int _wrap);
+
+    void resetState();
+
+    /* Get the sum in bytes of static <Mesh>es */
+    size_t getMemoryUsage() const;
+
+    int64_t sourceGeneration() const { return m_sourceGeneration; }
+
+    int32_t sourceID() const { return m_sourceId; }
+
+    bool isProxy() const { return m_proxyState; }
+
+    void setProxyState(bool isProxy) { m_proxyState = isProxy; }
+
+private:
+
+    const TileID m_id;
+
+    const MapProjection* m_projection = nullptr;
+
+    float m_scale = 1;
+
+    float m_inverseScale = 1;
+
+    /* ID of the TileSource */
+    const int32_t m_sourceId;
+
+    /* State of the TileSource for which this tile was created */
+    const int64_t m_sourceGeneration;
+
+    bool m_proxyState = false;
+
+    glm::dvec2 m_tileOrigin; // South-West corner of the tile in 2D projection space in meters (e.g. mercator meters)
+
+    glm::mat4 m_modelMatrix; // Matrix relating tile-local coordinates to global projection space coordinates;
+    // Note that this matrix does not contain the relative translation from the global origin to the tile origin.
+    // Distances from the global origin are too large to represent precisely in 32-bit floats, so we only apply the
+    // relative translation from the view origin to the model origin immediately before drawing the tile.
+
+    glm::mat4 m_mvp;
+
+    // Map of <Style>s and their associated <Mesh>es
+    std::vector<std::unique_ptr<StyledMesh>> m_geometry;
+    std::vector<Raster> m_rasters;
+
+    mutable size_t m_memoryUsage = 0;
+
+    fastmap<uint32_t, std::shared_ptr<Properties>> m_selectionFeatures;
+
+};
+
+}
diff --git a/core/src/tile/tileBuilder.cpp b/core/src/tile/tileBuilder.cpp
new file mode 100644 (file)
index 0000000..dd4d1f2
--- /dev/null
@@ -0,0 +1,151 @@
+#include "tile/tileBuilder.h"
+
+#include "data/properties.h"
+#include "data/propertyItem.h"
+#include "data/tileSource.h"
+#include "gl/mesh.h"
+#include "log.h"
+#include "scene/dataLayer.h"
+#include "scene/scene.h"
+#include "selection/featureSelection.h"
+#include "style/style.h"
+#include "tile/tile.h"
+#include "util/mapProjection.h"
+#include "view/view.h"
+
+namespace Tangram {
+
+TileBuilder::TileBuilder(std::shared_ptr<Scene> _scene)
+    : m_scene(_scene) {
+
+    m_styleContext.initFunctions(*_scene);
+
+    // Initialize StyleBuilders
+    for (auto& style : _scene->styles()) {
+        m_styleBuilder[style->getName()] = style->createBuilder();
+    }
+}
+
+TileBuilder::~TileBuilder() {}
+
+StyleBuilder* TileBuilder::getStyleBuilder(const std::string& _name) {
+    auto it = m_styleBuilder.find(_name);
+    if (it == m_styleBuilder.end()) { return nullptr; }
+
+    return it->second.get();
+}
+
+void TileBuilder::applyStyling(const Feature& _feature, const SceneLayer& _layer) {
+
+    // If no rules matched the feature, return immediately
+    if (!m_ruleSet.match(_feature, _layer, m_styleContext)) { return; }
+
+    uint32_t selectionColor = 0;
+    bool added = false;
+
+    // For each matched rule, find the style to be used and
+    // build the feature with the rule's parameters
+    for (auto& rule : m_ruleSet.matchedRules()) {
+
+        StyleBuilder* style = getStyleBuilder(rule.getStyleName());
+
+        if (!style) {
+            LOGN("Invalid style %s", rule.getStyleName().c_str());
+            continue;
+        }
+
+        // Apply defaul draw rules defined for this style
+        style->style().applyDefaultDrawRules(rule);
+
+        if (!m_ruleSet.evaluateRuleForContext(rule, m_styleContext)) {
+            continue;
+        }
+
+        bool interactive = false;
+        if (rule.get(StyleParamKey::interactive, interactive) && interactive) {
+            if (selectionColor == 0) {
+                selectionColor = m_scene->featureSelection()->nextColorIdentifier();
+            }
+            rule.selectionColor = selectionColor;
+            rule.featureSelection = m_scene->featureSelection().get();
+        } else {
+            rule.selectionColor = 0;
+        }
+
+        // build outline explicitly with outline style
+        const auto& outlineStyleName = rule.findParameter(StyleParamKey::outline_style);
+        if (outlineStyleName) {
+            auto& styleName = outlineStyleName.value.get<std::string>();
+            auto* outlineStyle = getStyleBuilder(styleName);
+            if (!outlineStyle) {
+                LOGN("Invalid style %s", styleName.c_str());
+            } else {
+                rule.isOutlineOnly = true;
+                outlineStyle->addFeature(_feature, rule);
+                rule.isOutlineOnly = false;
+            }
+        }
+
+        // build feature with style
+        added |= style->addFeature(_feature, rule);
+    }
+
+    if (added && (selectionColor != 0)) {
+        m_selectionFeatures[selectionColor] = std::make_shared<Properties>(_feature.props);
+    }
+}
+
+std::shared_ptr<Tile> TileBuilder::build(TileID _tileID, const TileData& _tileData, const TileSource& _source) {
+
+    m_selectionFeatures.clear();
+
+    auto tile = std::make_shared<Tile>(_tileID, *m_scene->mapProjection(), &_source);
+
+    tile->initGeometry(m_scene->styles().size());
+
+    m_styleContext.setKeywordZoom(_tileID.s);
+
+    for (auto& builder : m_styleBuilder) {
+        if (builder.second)
+            builder.second->setup(*tile);
+    }
+
+    for (const auto& datalayer : m_scene->layers()) {
+
+        if (datalayer.source() != _source.name()) { continue; }
+
+        for (const auto& collection : _tileData.layers) {
+
+            if (!collection.name.empty()) {
+                const auto& dlc = datalayer.collections();
+                bool layerContainsCollection =
+                    std::find(dlc.begin(), dlc.end(), collection.name) != dlc.end();
+
+                if (!layerContainsCollection) { continue; }
+            }
+
+            for (const auto& feat : collection.features) {
+                applyStyling(feat, datalayer);
+            }
+        }
+    }
+
+    for (auto& builder : m_styleBuilder) {
+
+        builder.second->addLayoutItems(m_labelLayout);
+    }
+
+    float tileSize = m_scene->mapProjection()->TileSize() * m_scene->pixelScale();
+
+    m_labelLayout.process(_tileID, tile->getInverseScale(), tileSize);
+
+    for (auto& builder : m_styleBuilder) {
+        tile->setMesh(builder.second->style(), builder.second->build());
+    }
+
+    tile->setSelectionFeatures(m_selectionFeatures);
+
+    return tile;
+}
+
+}
diff --git a/core/src/tile/tileBuilder.h b/core/src/tile/tileBuilder.h
new file mode 100644 (file)
index 0000000..2733bb8
--- /dev/null
@@ -0,0 +1,49 @@
+#pragma once
+
+#include "data/tileSource.h"
+#include "labels/labelCollider.h"
+#include "scene/styleContext.h"
+#include "scene/drawRule.h"
+
+namespace Tangram {
+
+class DataLayer;
+class StyleBuilder;
+class Tile;
+class TileSource;
+struct Feature;
+struct Properties;
+struct TileData;
+
+class TileBuilder {
+
+public:
+
+    TileBuilder(std::shared_ptr<Scene> _scene);
+
+    ~TileBuilder();
+
+    StyleBuilder* getStyleBuilder(const std::string& _name);
+
+    std::shared_ptr<Tile> build(TileID _tileID, const TileData& _data, const TileSource& _source);
+
+    const Scene& scene() const { return *m_scene; }
+
+private:
+
+    // Determine and apply DrawRules for a @_feature
+    void applyStyling(const Feature& _feature, const SceneLayer& _layer);
+
+    std::shared_ptr<Scene> m_scene;
+
+    StyleContext m_styleContext;
+    DrawRuleMergeSet m_ruleSet;
+
+    LabelCollider m_labelLayout;
+
+    fastmap<std::string, std::unique_ptr<StyleBuilder>> m_styleBuilder;
+
+    fastmap<uint32_t, std::shared_ptr<Properties>> m_selectionFeatures;
+};
+
+}
diff --git a/core/src/tile/tileCache.h b/core/src/tile/tileCache.h
new file mode 100644 (file)
index 0000000..9a7bd0c
--- /dev/null
@@ -0,0 +1,122 @@
+#pragma once
+
+#include "log.h"
+#include "tile/tile.h"
+#include "tile/tileHash.h"
+#include "tile/tileID.h"
+
+#include <list>
+#include <memory>
+#include <unordered_map>
+
+namespace Tangram {
+// TileSet serial + TileID
+using TileCacheKey = std::pair<int32_t, TileID>;
+}
+
+namespace std {
+    template <>
+    struct hash<Tangram::TileCacheKey> {
+        size_t operator()(const Tangram::TileCacheKey& k) const {
+            std::size_t seed = 0;
+            hash_combine(seed, k.first);
+            hash_combine(seed, k.second);
+            return seed;
+        }
+    };
+}
+
+namespace Tangram {
+
+class TileCache {
+    struct CacheEntry {
+        TileCacheKey key;
+        std::shared_ptr<Tile> tile;
+    };
+
+    using CacheList = std::list<CacheEntry>;
+    using CacheMap = std::unordered_map<TileCacheKey, typename CacheList::iterator>;
+
+public:
+
+    TileCache(size_t _cacheSizeMB) :
+        m_cacheUsage(0),
+        m_cacheMaxUsage(_cacheSizeMB) {}
+
+    std::vector<TileID> put(int32_t _sourceId, std::shared_ptr<Tile> _tile) {
+        TileCacheKey k(_sourceId, _tile->getID());
+
+        m_cacheList.push_front({k, _tile});
+        m_cacheMap[k] = m_cacheList.begin();
+        m_cacheUsage += _tile->getMemoryUsage();
+
+        return limitCacheSize(m_cacheMaxUsage);
+    }
+
+    std::shared_ptr<Tile> get(int32_t _sourceId, TileID _tileId) {
+        std::shared_ptr<Tile> tile;
+        TileCacheKey k(_sourceId, _tileId);
+
+        auto it = m_cacheMap.find(k);
+        if (it != m_cacheMap.end()) {
+            std::swap(tile, (*(it->second)).tile);
+            m_cacheList.erase(it->second);
+            m_cacheMap.erase(it);
+            m_cacheUsage -= tile->getMemoryUsage();
+        }
+        return tile;
+    }
+
+    std::shared_ptr<Tile> contains(int32_t _source, TileID _tileID) {
+        std::shared_ptr<Tile> tile;
+        TileCacheKey k(_source, _tileID);
+
+        auto it = m_cacheMap.find(k);
+        if (it != m_cacheMap.end()) {
+            return it->second->tile;
+        }
+        return nullptr;
+    }
+
+    std::vector<TileID> limitCacheSize(size_t _cacheSizeBytes) {
+        std::vector<TileID> poppedTileIDs;
+        m_cacheMaxUsage = _cacheSizeBytes;
+
+        while (m_cacheUsage > m_cacheMaxUsage) {
+            if (m_cacheList.empty()) {
+                LOGE("Invalid cache state!");
+                m_cacheUsage = 0;
+                break;
+            }
+            auto& tile = m_cacheList.back().tile;
+            poppedTileIDs.push_back(tile->getID());
+            m_cacheUsage -= tile->getMemoryUsage();
+            m_cacheMap.erase(m_cacheList.back().key);
+            m_cacheList.pop_back();
+        }
+        return poppedTileIDs;
+    }
+
+    size_t getMemoryUsage() const {
+        size_t sum = 0;
+        for (auto& entry : m_cacheList) {
+            sum += entry.tile->getMemoryUsage();
+        }
+        return sum;
+    }
+
+    void clear() {
+        m_cacheMap.clear();
+        m_cacheList.clear();
+        m_cacheUsage = 0;
+    }
+
+private:
+    CacheMap m_cacheMap;
+    CacheList m_cacheList;
+
+    int m_cacheUsage;
+    int m_cacheMaxUsage;
+};
+
+}
diff --git a/core/src/tile/tileHash.h b/core/src/tile/tileHash.h
new file mode 100644 (file)
index 0000000..93f4671
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "tile/tileID.h"
+#include "util/hash.h"
+
+namespace std {
+    template <>
+    struct hash<Tangram::TileID> {
+        size_t operator()(const Tangram::TileID& k) const {
+            std::size_t seed = 0;
+            hash_combine(seed, k.x);
+            hash_combine(seed, k.y);
+            hash_combine(seed, k.z);
+            return seed;
+        }
+    };
+}
diff --git a/core/src/tile/tileManager.cpp b/core/src/tile/tileManager.cpp
new file mode 100644 (file)
index 0000000..93a06e0
--- /dev/null
@@ -0,0 +1,570 @@
+#include "tile/tileManager.h"
+
+#include "data/tileSource.h"
+#include "platform.h"
+#include "tangram.h"
+#include "tile/tile.h"
+#include "tile/tileCache.h"
+#include "util/mapProjection.h"
+#include "view/view.h"
+
+#include "glm/gtx/norm.hpp"
+
+#include <algorithm>
+
+#define DBG(...) // LOGD(__VA_ARGS__)
+
+namespace Tangram {
+
+TileManager::TileManager(std::shared_ptr<Platform> platform, TileTaskQueue& _tileWorker) :
+    m_workers(_tileWorker) {
+
+    m_tileCache = std::unique_ptr<TileCache>(new TileCache(DEFAULT_CACHE_SIZE));
+
+    // Callback to pass task from Download-Thread to Worker-Queue
+    m_dataCallback = TileTaskCb{[this, platform](std::shared_ptr<TileTask> task) {
+
+        if (task->isReady()) {
+             platform->requestRender();
+
+        } else if (task->hasData()) {
+            m_workers.enqueue(task);
+
+        } else {
+            task->cancel();
+        }
+    }};
+}
+
+TileManager::~TileManager() {
+    m_tileSets.clear();
+}
+
+void TileManager::setTileSources(const std::vector<std::shared_ptr<TileSource>>& _sources) {
+
+    m_tileCache->clear();
+
+    // Remove all (non-client datasources) sources and respective tileSets not present in the
+    // new scene
+    auto it = std::remove_if(
+        m_tileSets.begin(), m_tileSets.end(),
+        [&](auto& tileSet) {
+            if (!tileSet.clientTileSource) {
+                LOGN("Remove source %s", tileSet.source->name().c_str());
+                return true;
+            }
+            // Clear cache
+            tileSet.tiles.clear();
+            return false;
+        });
+
+    m_tileSets.erase(it, m_tileSets.end());
+
+    // add new sources
+    for (const auto& source : _sources) {
+
+        if (!source->generateGeometry()) { continue; }
+
+        if (std::find_if(m_tileSets.begin(), m_tileSets.end(),
+                         [&](const TileSet& a) {
+                             return a.source->name() == source->name();
+                         }) == m_tileSets.end()) {
+            LOGN("add source %s", source->name().c_str());
+            m_tileSets.push_back({ source, false });
+        } else {
+            LOGW("Duplicate named datasource (not added): %s", source->name().c_str());
+        }
+    }
+}
+
+std::shared_ptr<TileSource> TileManager::getClientTileSource(int32_t sourceID) {
+    for (const auto& tileSet : m_tileSets) {
+        if (tileSet.clientTileSource && tileSet.source->id() == sourceID) {
+            return tileSet.source;
+        }
+    }
+    return nullptr;
+}
+
+void TileManager::addClientTileSource(std::shared_ptr<TileSource> _tileSource) {
+    m_tileSets.push_back({ _tileSource, true });
+}
+
+bool TileManager::removeClientTileSource(TileSource& _tileSource) {
+    bool removed = false;
+    for (auto it = m_tileSets.begin(); it != m_tileSets.end();) {
+        if (it->source.get() == &_tileSource) {
+            // Remove the textures for this tile source
+            it->source->clearRasters();
+            // Remove the tile set associated with this tile source
+            it = m_tileSets.erase(it);
+            removed = true;
+        } else {
+            ++it;
+        }
+    }
+    return removed;
+}
+
+void TileManager::clearTileSets() {
+    for (auto& tileSet : m_tileSets) {
+        tileSet.tiles.clear();
+    }
+
+    m_tileCache->clear();
+}
+
+void TileManager::clearTileSet(int32_t _sourceId) {
+    for (auto& tileSet : m_tileSets) {
+        if (tileSet.source->id() != _sourceId) { continue; }
+        tileSet.tiles.clear();
+    }
+
+    m_tileCache->clear();
+    m_tileSetChanged = true;
+}
+
+void TileManager::updateTileSets(const View& _view) {
+
+    m_tiles.clear();
+    m_tilesInProgress = 0;
+    m_tileSetChanged = false;
+
+    if (_view.changedOnLastUpdate() && !getDebugFlag(DebugFlags::freeze_tiles)) {
+
+        for (auto& tileSet : m_tileSets) {
+            tileSet.visibleTiles.clear();
+        }
+
+        auto tileCb = [&, zoom = _view.getZoom()](TileID _tileID){
+            for (auto& tileSet : m_tileSets) {
+                auto zoomBias = tileSet.source->zoomBias();
+                auto maxZoom = tileSet.source->maxZoom();
+
+                // Insert scaled and maxZoom mapped tileID in the visible set
+                tileSet.visibleTiles.insert(_tileID.zoomBiasAdjusted(zoomBias).withMaxSourceZoom(maxZoom));
+            }
+        };
+
+        _view.getVisibleTiles(tileCb);
+    }
+
+    for (auto& tileSet : m_tileSets) {
+        // check if tile set is active for zoom (zoom might be below min_zoom)
+        if (tileSet.source->isActiveForZoom(_view.getZoom())) {
+            updateTileSet(tileSet, _view.state());
+        }
+    }
+
+    loadTiles();
+
+    // Make m_tiles an unique list of tiles for rendering sorted from
+    // high to low zoom-levels.
+    std::sort(m_tiles.begin(), m_tiles.end(), [](auto& a, auto& b) {
+            return a->sourceID() == b->sourceID() ?
+                a->getID() < b->getID() :
+                a->sourceID() < b->sourceID(); }
+        );
+
+    // Remove duplicates: Proxy tiles could have been added more than once
+    m_tiles.erase(std::unique(m_tiles.begin(), m_tiles.end()), m_tiles.end());
+}
+
+void TileManager::updateTileSet(TileSet& _tileSet, const ViewState& _view) {
+
+    bool newTiles = false;
+
+    if (_tileSet.sourceGeneration != _tileSet.source->generation()) {
+        _tileSet.sourceGeneration = _tileSet.source->generation();
+    }
+
+    // Tile load request above this zoom-level will be canceled in order to
+    // not wait for tiles that are too small to contribute significantly to
+    // the current view.
+    int maxZoom = _view.zoom + 2;
+
+    std::vector<TileID> removeTiles;
+    auto& tiles = _tileSet.tiles;
+
+    // Check for ready tasks, move Tile to active TileSet and unset Proxies.
+    for (auto& it : tiles) {
+        auto& entry = it.second;
+        if (entry.newData()) {
+            clearProxyTiles(_tileSet, it.first, entry, removeTiles);
+            entry.task->complete();
+
+            entry.tile = std::move(entry.task->tile());
+            entry.task.reset();
+            newTiles = true;
+
+            m_tileSetChanged = true;
+        }
+    }
+
+    const auto& visibleTiles = _tileSet.visibleTiles;
+
+    // Loop over visibleTiles and add any needed tiles to tileSet
+    auto curTilesIt = tiles.begin();
+    auto visTilesIt = visibleTiles.begin();
+
+    auto generation = _tileSet.source->generation();
+
+    while (visTilesIt != visibleTiles.end() || curTilesIt != tiles.end()) {
+
+        auto& visTileId = visTilesIt == visibleTiles.end()
+            ? NOT_A_TILE : *visTilesIt;
+
+        auto& curTileId = curTilesIt == tiles.end()
+            ? NOT_A_TILE : curTilesIt->first;
+
+        if (visTileId == curTileId) {
+            // tiles in both sets match
+            assert(visTilesIt != visibleTiles.end() &&
+                   curTilesIt != tiles.end());
+
+            auto& entry = curTilesIt->second;
+            entry.setVisible(true);
+
+            auto sourceGeneration = (entry.isReady()) ?
+                entry.tile->sourceGeneration() : entry.task->sourceGeneration();
+
+            if (entry.isReady()) {
+                m_tiles.push_back(entry.tile);
+
+                if (!entry.isInProgress() &&
+                    (sourceGeneration < generation)) {
+                    // Tile needs update - enqueue for loading
+                    entry.task = _tileSet.source->createTask(visTileId);
+                    enqueueTask(_tileSet, visTileId, _view);
+                }
+            } else if (entry.needsLoading()) {
+                // Not yet available - enqueue for loading
+                enqueueTask(_tileSet, visTileId, _view);
+
+            } else if (entry.isCanceled() &&
+                       (sourceGeneration < generation)) {
+                // Tile needs update - enqueue for loading
+                entry.task = _tileSet.source->createTask(visTileId);
+                enqueueTask(_tileSet, visTileId, _view);
+            }
+
+            if (entry.isInProgress()) {
+                m_tilesInProgress++;
+            }
+
+            if (newTiles && entry.isInProgress()) {
+                // check again for proxies
+                updateProxyTiles(_tileSet, visTileId, entry);
+            }
+
+            ++curTilesIt;
+            ++visTilesIt;
+
+        } else if (curTileId > visTileId) {
+            // tileSet is missing an element present in visibleTiles
+            // NB: if (curTileId == NOT_A_TILE) it is always > visTileId
+            //     and if curTileId > visTileId, then visTileId cannot be
+            //     NOT_A_TILE. (for the current implementation of > operator)
+            assert(visTilesIt != visibleTiles.end());
+
+            if (!addTile(_tileSet, visTileId)) {
+                // Not in cache - enqueue for loading
+                enqueueTask(_tileSet, visTileId, _view);
+                m_tilesInProgress++;
+            }
+
+            ++visTilesIt;
+
+        } else {
+            // tileSet has a tile not present in visibleTiles
+            assert(curTilesIt != tiles.end());
+
+            auto& entry = curTilesIt->second;
+
+            if (entry.getProxyCounter() > 0) {
+                if (entry.isReady()) {
+                    m_tiles.push_back(entry.tile);
+                } else if (curTileId.z < maxZoom) {
+                    // Cancel loading
+                    removeTiles.push_back(curTileId);
+                }
+            } else {
+                removeTiles.push_back(curTileId);
+            }
+            entry.setVisible(false);
+            ++curTilesIt;
+        }
+    }
+
+    while (!removeTiles.empty()) {
+        auto it = tiles.find(removeTiles.back());
+        removeTiles.pop_back();
+
+        if ((it != tiles.end()) &&
+            (!it->second.isVisible()) &&
+            (it->second.getProxyCounter() <= 0  ||
+             it->first.z >= maxZoom)) {
+
+            clearProxyTiles(_tileSet, it->first, it->second, removeTiles);
+
+            removeTile(_tileSet, it);
+        }
+    }
+
+    for (auto& it : tiles) {
+        auto& entry = it.second;
+
+#if LOG_LEVEL >= 3
+        size_t rasterLoading = 0;
+        size_t rasterDone = 0;
+        if (entry.task) {
+            for (auto &raster : entry.task->subTasks()) {
+                if (raster->isReady()) { rasterDone++; }
+                else { rasterLoading++; }
+            }
+        }
+        DBG("> %s - ready:%d proxy:%d/%d loading:%d rDone:%d rLoading:%d rPending:%d canceled:%d",
+             it.first.toString().c_str(),
+             entry.isReady(),
+             entry.getProxyCounter(),
+             entry.m_proxies,
+             entry.task && !entry.task->isReady(),
+             rasterDone,
+             rasterLoading,
+             entry.rastersPending(),
+             entry.task && entry.task->isCanceled());
+#endif
+
+        if (entry.isInProgress()) {
+            auto& id = it.first;
+            auto& task = entry.task;
+
+            // Update tile distance to map center for load priority.
+            auto tileCenter = _view.mapProjection->TileCenter(id);
+            double scaleDiv = exp2(id.z - _view.zoom);
+            if (scaleDiv < 1) { scaleDiv = 0.1/scaleDiv; } // prefer parent tiles
+            task->setPriority(glm::length2(tileCenter - _view.center) * scaleDiv);
+            task->setProxyState(entry.getProxyCounter() > 0);
+        }
+
+        if (entry.isReady()) {
+            // Mark as proxy
+            entry.tile->setProxyState(entry.getProxyCounter() > 0);
+        }
+    }
+}
+
+void TileManager::enqueueTask(TileSet& _tileSet, const TileID& _tileID,
+                              const ViewState& _view) {
+
+    // Keep the items sorted by distance
+    auto tileCenter = _view.mapProjection->TileCenter(_tileID);
+    double distance = glm::length2(tileCenter - _view.center);
+
+    auto it = std::upper_bound(m_loadTasks.begin(), m_loadTasks.end(), distance,
+                               [](auto& distance, auto& other){
+                                   return distance < std::get<0>(other);
+                               });
+
+    m_loadTasks.insert(it, std::make_tuple(distance, &_tileSet, _tileID));
+}
+
+void TileManager::loadTiles() {
+
+    if (m_loadTasks.empty()) { return; }
+
+    for (auto& loadTask : m_loadTasks) {
+
+        auto tileId = std::get<2>(loadTask);
+        auto& tileSet = *std::get<1>(loadTask);
+        auto tileIt = tileSet.tiles.find(tileId);
+        auto& entry = tileIt->second;
+
+        tileSet.source->loadTileData(entry.task, m_dataCallback);
+    }
+
+    DBG("loading:%d pending:%d cache: %fMB",
+        m_loadTasks.size(), m_loadPending,
+        (double(m_tileCache->getMemoryUsage()) / (1024 * 1024)));
+
+    m_loadTasks.clear();
+}
+
+bool TileManager::addTile(TileSet& _tileSet, const TileID& _tileID) {
+
+    auto tile = m_tileCache->get(_tileSet.source->id(), _tileID);
+
+    if (tile) {
+        if (tile->sourceGeneration() == _tileSet.source->generation()) {
+            m_tiles.push_back(tile);
+
+            // Update tile origin based on wrap (set in the new tileID)
+            tile->updateTileOrigin(_tileID.wrap);
+
+            // Reset tile on potential internal dynamic data set
+            // TODO rename to resetState() to avoid ambiguity
+            tile->resetState();
+        } else {
+            // Clear stale tile data
+            tile.reset();
+        }
+    }
+
+    // Add TileEntry to TileSet
+    auto entry = _tileSet.tiles.emplace(_tileID, tile);
+
+    if (!tile) {
+        // Add Proxy if corresponding proxy MapTile ready
+        updateProxyTiles(_tileSet, _tileID, entry.first->second);
+
+        entry.first->second.task = _tileSet.source->createTask(_tileID);
+    }
+    entry.first->second.setVisible(true);
+
+    return bool(tile);
+}
+
+void TileManager::removeTile(TileSet& _tileSet, std::map<TileID, TileEntry>::iterator& _tileIt) {
+
+    auto& id = _tileIt->first;
+    auto& entry = _tileIt->second;
+
+
+    if (entry.isInProgress()) {
+        entry.clearTask();
+
+        // 1. Remove from Datasource. Make sure to cancel
+        //  the network request associated with this tile.
+        _tileSet.source->cancelLoadingTile(id);
+
+    } else if (entry.isReady()) {
+        // Add to cache
+        auto poppedTiles = m_tileCache->put(_tileSet.source->id(), entry.tile);
+        for (auto& tileID : poppedTiles) {
+            _tileSet.source->clearRaster(tileID);
+        }
+    }
+
+    // Remove rasters from this TileSource
+    _tileSet.source->clearRaster(id);
+
+    // Remove tile from set
+    _tileIt = _tileSet.tiles.erase(_tileIt);
+}
+
+bool TileManager::updateProxyTile(TileSet& _tileSet, TileEntry& _tile,
+                                  const TileID& _proxyTileId,
+                                  const ProxyID _proxyId) {
+
+    if (!_proxyTileId.isValid()) { return false; }
+
+    auto& tiles = _tileSet.tiles;
+
+    // check if the proxy exists in the visible tile set
+    {
+        const auto& it = tiles.find(_proxyTileId);
+        if (it != tiles.end()) {
+            auto& entry = it->second;
+
+            if (!entry.isCanceled() && _tile.setProxy(_proxyId)) {
+                entry.incProxyCounter();
+
+                if (entry.isReady()) {
+                    m_tiles.push_back(entry.tile);
+                }
+
+                // Note: No need to check the cache: When the tile is in
+                // tileSet it would have already been fetched from cache
+                return true;
+            }
+        }
+    }
+
+    // check if the proxy exists in the cache
+    {
+        auto proxyTile = m_tileCache->get(_tileSet.source->id(), _proxyTileId);
+        if (proxyTile && _tile.setProxy(_proxyId)) {
+
+            auto result = tiles.emplace(_proxyTileId, proxyTile);
+            auto& entry = result.first->second;
+            entry.incProxyCounter();
+
+            m_tiles.push_back(proxyTile);
+            return true;
+        }
+    }
+
+    return false;
+}
+
+void TileManager::updateProxyTiles(TileSet& _tileSet, const TileID& _tileID, TileEntry& _tile) {
+    // TODO: this should be improved to use the nearest proxy tile available.
+    // Currently it would use parent or grand*parent  as proxies even if the
+    // child proxies would be more appropriate
+
+    // Try parent proxy
+    auto zoomBias = _tileSet.source->zoomBias();
+    auto maxZoom = _tileSet.source->maxZoom();
+    auto parentID = _tileID.getParent(zoomBias);
+    auto minZoom = _tileSet.source->minDisplayZoom();
+    if (minZoom <= parentID.z
+            && updateProxyTile(_tileSet, _tile, parentID, ProxyID::parent)) {
+        return;
+    }
+    // Try grandparent
+    auto grandparentID = parentID.getParent(zoomBias);
+    if (minZoom <= grandparentID.z
+            && updateProxyTile(_tileSet, _tile, grandparentID, ProxyID::parent2)) {
+        return;
+    }
+    // Try children
+    if (maxZoom > _tileID.z) {
+        for (int i = 0; i < 4; i++) {
+            auto childID = _tileID.getChild(i, maxZoom);
+            updateProxyTile(_tileSet, _tile, childID, static_cast<ProxyID>(1 << i));
+        }
+    }
+}
+
+void TileManager::clearProxyTiles(TileSet& _tileSet, const TileID& _tileID, TileEntry& _tile,
+                                  std::vector<TileID>& _removes) {
+    auto& tiles = _tileSet.tiles;
+    auto zoomBias = _tileSet.source->zoomBias();
+    auto maxZoom = _tileSet.source->maxZoom();
+
+    auto removeProxy = [&tiles,&_removes](TileID id) {
+        auto it = tiles.find(id);
+        if (it != tiles.end()) {
+            auto& entry = it->second;
+            entry.decProxyCounter();
+            if (entry.getProxyCounter() <= 0 && !entry.isVisible()) {
+                _removes.push_back(id);
+            }
+        }
+    };
+    // Check if grand parent proxy is present
+    if (_tile.unsetProxy(ProxyID::parent2)) {
+        TileID gparentID(_tileID.getParent(zoomBias).getParent(zoomBias));
+        removeProxy(gparentID);
+    }
+
+    // Check if parent proxy is present
+    if (_tile.unsetProxy(ProxyID::parent)) {
+        TileID parentID(_tileID.getParent(zoomBias));
+        removeProxy(parentID);
+    }
+
+    // Check if child proxies are present
+    for (int i = 0; i < 4; i++) {
+        if (_tile.unsetProxy(static_cast<ProxyID>(1 << i))) {
+            TileID childID(_tileID.getChild(i, maxZoom));
+            removeProxy(childID);
+        }
+    }
+}
+
+void TileManager::setCacheSize(size_t _cacheSize) {
+    m_tileCache->limitCacheSize(_cacheSize);
+}
+
+}
diff --git a/core/src/tile/tileManager.h b/core/src/tile/tileManager.h
new file mode 100644 (file)
index 0000000..b927605
--- /dev/null
@@ -0,0 +1,261 @@
+#pragma once
+
+#include "data/tileData.h"
+#include "data/tileSource.h"
+#include "tile/tile.h"
+#include "tile/tileID.h"
+#include "tile/tileTask.h"
+#include "tile/tileWorker.h"
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <tuple>
+#include <set>
+#include <vector>
+
+class Platform;
+
+namespace Tangram {
+
+class TileSource;
+class TileCache;
+class View;
+struct ViewState;
+
+/* Singleton container of <TileSet>s
+ *
+ * TileManager is a singleton that maintains a set of Tiles based on the current
+ * view into the map
+ */
+class TileManager {
+
+    const static size_t DEFAULT_CACHE_SIZE = 32*1024*1024; // 32 MB
+
+public:
+
+    TileManager(std::shared_ptr<Platform> platform, TileTaskQueue& _tileWorker);
+
+    virtual ~TileManager();
+
+    /* Sets the tile TileSources */
+    void setTileSources(const std::vector<std::shared_ptr<TileSource>>& _sources);
+
+    /* Updates visible tile set and load missing tiles */
+    void updateTileSets(const View& _view);
+
+    void clearTileSets();
+
+    void clearTileSet(int32_t _sourceId);
+
+    /* Returns the set of currently visible tiles */
+    const auto& getVisibleTiles() const { return m_tiles; }
+
+    bool hasTileSetChanged() { return m_tileSetChanged; }
+
+    bool hasLoadingTiles() {
+        return m_tilesInProgress > 0;
+    }
+
+    std::shared_ptr<TileSource> getClientTileSource(int32_t sourceID);
+
+    void addClientTileSource(std::shared_ptr<TileSource> _source);
+
+    bool removeClientTileSource(TileSource& _source);
+
+    std::unique_ptr<TileCache>& getTileCache() { return m_tileCache; }
+
+    const auto& getTileSets() { return m_tileSets; }
+
+    /* @_cacheSize: Set size of in-memory tile cache in bytes.
+     * This cache holds recently used <Tile>s that are ready for rendering.
+     */
+    void setCacheSize(size_t _cacheSize);
+
+protected:
+
+    enum class ProxyID : uint8_t {
+        no_proxies = 0,
+        child1 = 1 << 0,
+        child2 = 1 << 1,
+        child3 = 1 << 2,
+        child4 = 1 << 3,
+        parent = 1 << 4,
+        parent2 = 1 << 5,
+    };
+
+    struct TileEntry {
+
+        TileEntry(){}
+        TileEntry(std::shared_ptr<Tile>& _tile) : tile(_tile) {}
+
+        ~TileEntry() { clearTask(); }
+
+        std::shared_ptr<Tile> tile;
+        std::shared_ptr<TileTask> task;
+
+        /* A Counter for number of tiles this tile acts a proxy for */
+        int m_proxyCounter = 0;
+
+        /* The set of proxy tiles referenced by this tile */
+        uint8_t m_proxies = 0;
+
+        bool isReady() { return bool(tile); }
+        bool isInProgress() { return bool(task) && !task->isCanceled(); }
+
+        bool needsLoading() {
+            //return !bool(task) || (task->needsLoading() && !task->isCanceled());
+            if (isReady()) { return false; }
+            if (!task) { return true; }
+            if (task->isCanceled()) { return false; }
+            if (task->needsLoading()) { return true; }
+
+            for (auto& subtask : task->subTasks()) {
+                if (subtask->needsLoading()) { return true; }
+            }
+            return false;
+        }
+
+        // size_t rastersPending() {
+        //     if (task) {
+        //         return (task->source().rasterSources().size() - task->subTasks().size());
+        //     }
+        //     return 0;
+        // }
+        bool isCanceled() { return bool(task) && task->isCanceled(); }
+
+        // New Data only when
+        // - task still exists
+        // - task has a tile ready
+        // - tile has all rasters set
+        bool newData() {
+            if (bool(task) && task->isReady()) {
+
+                //if (rastersPending()) { return false; }
+
+                for (auto& rTask : task->subTasks()) {
+                    if (!rTask->isReady()) { return false; }
+                }
+                return true;
+            }
+            return false;
+        }
+
+        void clearTask() {
+            if (task) {
+                for (auto& raster : task->subTasks()) {
+                    raster->cancel();
+                }
+                task->subTasks().clear();
+                task->cancel();
+
+                task.reset();
+            }
+        }
+
+        /*
+         * Methods to set and get proxy counter
+         */
+        int getProxyCounter() { return m_proxyCounter; }
+        void incProxyCounter() { m_proxyCounter++; }
+        void decProxyCounter() { m_proxyCounter = m_proxyCounter > 0 ? m_proxyCounter - 1 : 0; }
+        void resetProxyCounter() { m_proxyCounter = 0; }
+
+        bool setProxy(ProxyID id) {
+            if ((m_proxies & static_cast<uint8_t>(id)) == 0) {
+                m_proxies |= static_cast<uint8_t>(id);
+                return true;
+            }
+            return false;
+        }
+
+        bool unsetProxy(ProxyID id) {
+            if ((m_proxies & static_cast<uint8_t>(id)) != 0) {
+                m_proxies &= ~static_cast<uint8_t>(id);
+                return true;
+            }
+            return false;
+        }
+
+        bool m_visible = false;
+
+        /* Method to check whther this tile is in the current set of visible tiles
+         * determined by view::updateTiles().
+         */
+        bool isVisible() const {
+            return m_visible;
+        }
+
+        void setVisible(bool _visible) {
+            m_visible = _visible;
+        }
+    };
+
+    struct TileSet {
+        TileSet(std::shared_ptr<TileSource> _source, bool _clientSource)
+            : source(_source), clientTileSource(_clientSource) {}
+
+        std::shared_ptr<TileSource> source;
+
+        std::set<TileID> visibleTiles;
+        std::map<TileID, TileEntry> tiles;
+
+        int64_t sourceGeneration = 0;
+        bool clientTileSource;
+    };
+
+    void updateTileSet(TileSet& tileSet, const ViewState& _view);
+
+    void enqueueTask(TileSet& _tileSet, const TileID& _tileID, const ViewState& _view);
+
+    void loadTiles();
+
+    /*
+     * Constructs a future (async) to load data of a new visible tile this is
+     *      also responsible for loading proxy tiles for the newly visible tiles
+     * @_tileID: TileID for which new Tile needs to be constructed
+     */
+    bool addTile(TileSet& _tileSet, const TileID& _tileID);
+
+    /*
+     * Removes a tile from m_tileSet
+     */
+    void removeTile(TileSet& _tileSet, std::map<TileID, TileEntry>::iterator& _tileIter);
+
+    /*
+     * Checks and updates m_tileSet with proxy tiles for every new visible tile
+     *  @_tile: Tile, the new visible tile for which proxies needs to be added
+     */
+    bool updateProxyTile(TileSet& _tileSet, TileEntry& _tile, const TileID& _proxy, const ProxyID _proxyID);
+    void updateProxyTiles(TileSet& _tileSet, const TileID& _tileID, TileEntry& _tile);
+
+    /*
+     * Once a visible tile finishes loading and is added to m_tileSet, all
+     * its proxy(ies) Tiles are removed
+     */
+    void clearProxyTiles(TileSet& _tileSet, const TileID& _tileID, TileEntry& _tile, std::vector<TileID>& _removes);
+
+    int32_t m_tilesInProgress = 0;
+
+    std::vector<TileSet> m_tileSets;
+
+    /* Current tiles ready for rendering */
+    std::vector<std::shared_ptr<Tile>> m_tiles;
+
+    std::unique_ptr<TileCache> m_tileCache;
+
+    TileTaskQueue& m_workers;
+
+    bool m_tileSetChanged = false;
+
+    /* Callback for TileSource:
+     * Passes TileTask back with data for further processing by <TileWorker>s
+     */
+    TileTaskCb m_dataCallback;
+
+    /* Temporary list of tiles that need to be loaded */
+    std::vector<std::tuple<double, TileSet*, TileID>> m_loadTasks;
+
+};
+
+}
diff --git a/core/src/tile/tileTask.cpp b/core/src/tile/tileTask.cpp
new file mode 100644 (file)
index 0000000..55cd12b
--- /dev/null
@@ -0,0 +1,38 @@
+#include "tile/tileTask.h"
+
+#include "data/tileSource.h"
+#include "scene/scene.h"
+#include "tile/tile.h"
+#include "tile/tileBuilder.h"
+#include "util/mapProjection.h"
+
+namespace Tangram {
+
+TileTask::TileTask(TileID& _tileId, std::shared_ptr<TileSource> _source, int _subTask) :
+    m_tileId(_tileId),
+    m_subTaskId(_subTask),
+    m_source(_source),
+    m_sourceGeneration(_source->generation()),
+    m_priority(0) {}
+
+void TileTask::process(TileBuilder& _tileBuilder) {
+
+    auto tileData = m_source->parse(*this, *_tileBuilder.scene().mapProjection());
+
+    if (tileData) {
+        m_tile = _tileBuilder.build(m_tileId, *tileData, *m_source);
+    } else {
+        cancel();
+    }
+}
+
+void TileTask::complete() {
+
+    for (auto& subTask : m_subTasks) {
+        assert(subTask->isReady());
+        subTask->complete(*this);
+    }
+
+}
+
+}
diff --git a/core/src/tile/tileWorker.cpp b/core/src/tile/tileWorker.cpp
new file mode 100644 (file)
index 0000000..a757c4e
--- /dev/null
@@ -0,0 +1,132 @@
+#include "tile/tileWorker.h"
+
+#include "data/tileSource.h"
+#include "log.h"
+#include "platform.h"
+#include "tangram.h"
+#include "tile/tileBuilder.h"
+#include "tile/tileID.h"
+#include "tile/tileTask.h"
+
+#include <algorithm>
+
+#define WORKER_NICENESS 10
+
+namespace Tangram {
+
+TileWorker::TileWorker(std::shared_ptr<Platform> _platform, int _numWorker) : m_platform(_platform) {
+    m_running = true;
+
+    for (int i = 0; i < _numWorker; i++) {
+        auto worker = std::make_unique<Worker>();
+        worker->thread = std::thread(&TileWorker::run, this, worker.get());
+        m_workers.push_back(std::move(worker));
+    }
+}
+
+TileWorker::~TileWorker(){
+    if (m_running) {
+        stop();
+    }
+}
+
+void TileWorker::run(Worker* instance) {
+
+    setCurrentThreadPriority(WORKER_NICENESS);
+
+    std::unique_ptr<TileBuilder> builder;
+
+    while (true) {
+
+        std::shared_ptr<TileTask> task;
+        {
+            std::unique_lock<std::mutex> lock(m_mutex);
+
+            m_condition.wait(lock, [&, this]{
+                    return !m_running || !m_queue.empty();
+                });
+
+            if (instance->tileBuilder) {
+                builder = std::move(instance->tileBuilder);
+                LOG("Passed new TileBuilder to TileWorker");
+            }
+
+            // Check if thread should stop
+            if (!m_running) {
+                break;
+            }
+
+            if (!builder) {
+                continue;
+            }
+
+            // Remove all canceled tasks
+            auto removes = std::remove_if(m_queue.begin(), m_queue.end(),
+                                          [](const auto& a) { return a->isCanceled(); });
+
+            m_queue.erase(removes, m_queue.end());
+
+            if (m_queue.empty()) {
+                continue;
+            }
+
+            // Pop highest priority tile from queue
+            auto it = std::min_element(m_queue.begin(), m_queue.end(),
+                [](const auto& a, const auto& b) {
+                    if (a->isProxy() != b->isProxy()) {
+                        return !a->isProxy();
+                    }
+                    if (a->source().id() == b->source().id() &&
+                        a->sourceGeneration() != b->sourceGeneration()) {
+                        return a->sourceGeneration() < b->sourceGeneration();
+                    }
+                    return a->getPriority() < b->getPriority();
+                });
+
+            task = std::move(*it);
+            m_queue.erase(it);
+        }
+
+        if (task->isCanceled()) {
+            continue;
+        }
+
+        task->process(*builder);
+
+        m_platform->requestRender();
+    }
+}
+
+void TileWorker::setScene(std::shared_ptr<Scene>& _scene) {
+    for (auto& worker : m_workers) {
+        worker->tileBuilder = std::make_unique<TileBuilder>(_scene);
+    }
+}
+
+void TileWorker::enqueue(std::shared_ptr<TileTask> task) {
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        if (!m_running) {
+            return;
+        }
+        m_queue.push_back(std::move(task));
+    }
+    m_condition.notify_one();
+}
+
+void TileWorker::stop() {
+    {
+        std::unique_lock<std::mutex> lock(m_mutex);
+        m_running = false;
+    }
+
+    m_condition.notify_all();
+
+    for (auto& worker : m_workers) {
+        worker->thread.join();
+    }
+
+    m_queue.clear();
+}
+
+}
diff --git a/core/src/tile/tileWorker.h b/core/src/tile/tileWorker.h
new file mode 100644 (file)
index 0000000..13fe762
--- /dev/null
@@ -0,0 +1,57 @@
+#pragma once
+
+#include "tile/tileTask.h"
+#include "util/jobQueue.h"
+
+#include <atomic>
+#include <condition_variable>
+#include <memory>
+#include <mutex>
+#include <thread>
+#include <vector>
+
+namespace Tangram {
+
+class JobQueue;
+class Platform;
+class Scene;
+class TileBuilder;
+
+class TileWorker : public TileTaskQueue {
+
+public:
+
+    TileWorker(std::shared_ptr<Platform> _platform, int _numWorker);
+
+    ~TileWorker();
+
+    virtual void enqueue(std::shared_ptr<TileTask> task) override;
+
+    void stop();
+
+    bool isRunning() const { return m_running; }
+
+    void setScene(std::shared_ptr<Scene>& _scene);
+
+private:
+
+    struct Worker {
+        std::thread thread;
+        std::unique_ptr<TileBuilder> tileBuilder;
+    };
+
+    void run(Worker* instance);
+
+    bool m_running;
+
+    std::vector<std::unique_ptr<Worker>> m_workers;
+
+    std::condition_variable m_condition;
+
+    std::mutex m_mutex;
+    std::vector<std::shared_ptr<TileTask>> m_queue;
+
+    std::shared_ptr<Platform> m_platform;
+};
+
+}
diff --git a/core/src/util/asyncWorker.h b/core/src/util/asyncWorker.h
new file mode 100644 (file)
index 0000000..1f076a2
--- /dev/null
@@ -0,0 +1,58 @@
+#include <condition_variable>
+#include <deque>
+#include <mutex>
+#include <thread>
+
+namespace Tangram {
+
+class AsyncWorker {
+public:
+
+    AsyncWorker() {
+        thread = std::thread(&AsyncWorker::run, this);
+    }
+
+    ~AsyncWorker() {
+        {
+            std::unique_lock<std::mutex> lock(m_mutex);
+            m_running = false;
+        }
+        m_condition.notify_all();
+        thread.join();
+    }
+
+    void enqueue(std::function<void()> _task) {
+        {
+            std::unique_lock<std::mutex> lock(m_mutex);
+            if (!m_running) { return; }
+
+            m_queue.push_back(std::move(_task));
+        }
+        m_condition.notify_one();
+    }
+
+private:
+
+    void run() {
+        while (true) {
+            std::function<void()> task;
+            {
+                std::unique_lock<std::mutex> lock(m_mutex);
+                m_condition.wait(lock, [&]{ return !m_running || !m_queue.empty(); });
+                if (!m_running) { break; }
+
+                task = std::move(m_queue.front());
+                m_queue.pop_front();
+            }
+            task();
+        }
+    }
+
+    std::thread thread;
+    bool m_running = true;
+    std::condition_variable m_condition;
+    std::mutex m_mutex;
+    std::deque<std::function<void()>> m_queue;
+};
+
+}
diff --git a/core/src/util/base64.h b/core/src/util/base64.h
new file mode 100644 (file)
index 0000000..e055179
--- /dev/null
@@ -0,0 +1,68 @@
+#pragma once
+
+// public domain from https://en.wikibooks.org/wiki/Algorithm_Implementation
+
+#include <string>
+#include <vector>
+
+struct Base64 {
+
+static bool checkPrefix(const std::string &path) {
+    return path.substr(0, 22) == "data:image/png;base64,";
+}
+
+static void stripPrefix(std::string &data) {
+    data.erase(0, 22);
+}
+
+const static char padCharacter = ('=');
+
+static std::vector<unsigned char> decode(const std::string& input) {
+    if (input.length() % 4) // Sanity check
+        throw std::runtime_error("Non-Valid base64!");
+    size_t padding = 0;
+    if (input.length()) {
+        if (input[input.length() - 1] == padCharacter) padding++;
+        if (input[input.length() - 2] == padCharacter) padding++;
+    }
+    // Setup a vector to hold the result
+    std::vector<unsigned char> decodedBytes;
+    decodedBytes.reserve(((input.length() / 4) * 3) - padding);
+    uint32_t temp = 0; // Holds decoded quanta
+    std::string::const_iterator cursor = input.begin();
+    while (cursor < input.end()) {
+        for (size_t quantumPosition = 0; quantumPosition < 4; quantumPosition++) {
+            temp <<= 6;
+            if (*cursor >= 0x41 && *cursor <= 0x5A) // This area will need tweaking if
+                temp |= *cursor - 0x41;             // you are using an alternate alphabet
+            else if (*cursor >= 0x61 && *cursor <= 0x7A)
+                temp |= *cursor - 0x47;
+            else if (*cursor >= 0x30 && *cursor <= 0x39)
+                temp |= *cursor + 0x04;
+            else if (*cursor == 0x2B)
+                temp |= 0x3E; // change to 0x2D for URL alphabet
+            else if (*cursor == 0x2F)
+                temp |= 0x3F;                 // change to 0x5F for URL alphabet
+            else if (*cursor == padCharacter) // pad
+            {
+                switch (input.end() - cursor) {
+                case 1: // One pad character
+                    decodedBytes.push_back((temp >> 16) & 0x000000FF);
+                    decodedBytes.push_back((temp >> 8) & 0x000000FF);
+                    return decodedBytes;
+                case 2: // Two pad characters
+                    decodedBytes.push_back((temp >> 10) & 0x000000FF);
+                    return decodedBytes;
+                default: throw std::runtime_error("Invalid Padding in Base 64!");
+                }
+            } else
+                throw std::runtime_error("Non-Valid Character in Base 64!");
+            cursor++;
+        }
+        decodedBytes.push_back((temp >> 16) & 0x000000FF);
+        decodedBytes.push_back((temp >> 8) & 0x000000FF);
+        decodedBytes.push_back((temp)&0x000000FF);
+    }
+    return decodedBytes;
+}
+};
diff --git a/core/src/util/builders.cpp b/core/src/util/builders.cpp
new file mode 100644 (file)
index 0000000..d746c37
--- /dev/null
@@ -0,0 +1,462 @@
+#include "util/builders.h"
+
+#include "util/geom.h"
+
+#include "glm/gtx/rotate_vector.hpp"
+#include "glm/gtx/norm.hpp"
+
+namespace mapbox { namespace util {
+template <>
+struct nth<0, Tangram::Point> {
+    inline static float get(const Tangram::Point &t) { return t.x; };
+};
+template <>
+struct nth<1, Tangram::Point> {
+    inline static float get(const Tangram::Point &t) { return t.y; };
+};
+}}
+
+namespace Tangram {
+
+CapTypes CapTypeFromString(const std::string& str) {
+    if (str == "square") { return CapTypes::square; }
+    if (str == "round") { return CapTypes::round; }
+    return CapTypes::butt;
+}
+
+JoinTypes JoinTypeFromString(const std::string& str) {
+    if (str == "bevel") { return JoinTypes::bevel; }
+    if (str == "round") { return JoinTypes::round; }
+    return JoinTypes::miter;
+}
+
+void Builders::buildPolygon(const Polygon& _polygon, float _height, PolygonBuilder& _ctx) {
+
+    glm::vec2 min, max;
+    if (_ctx.useTexCoords) {
+        min = glm::vec2(std::numeric_limits<float>::max());
+        max = glm::vec2(std::numeric_limits<float>::min());
+
+        for (auto& p : _polygon[0]) {
+            min.x = std::min(min.x, p.x);
+            min.y = std::min(min.y, p.y);
+            max.x = std::max(max.x, p.x);
+            max.y = std::max(max.y, p.y);
+        }
+    }
+
+    // Run earcut, triangles are stored in _ctx.earcut.indices
+    _ctx.earcut(_polygon);
+
+    size_t sumPoints = 0;
+    for (auto& line : _polygon) {
+        sumPoints += line.size();
+    }
+
+    // Mark the points that are referenced by indices as used.
+    size_t sumVertices = 0;
+    _ctx.used.assign(sumPoints, 0);
+    for (auto i : _ctx.earcut.indices) {
+        if (_ctx.used[i] == 0) {
+            _ctx.used[i] = 1;
+            sumVertices++;
+        }
+    }
+
+    uint16_t vertexDataOffset = _ctx.numVertices;
+    _ctx.numVertices += sumVertices;
+
+    size_t ring = 0;
+    size_t offset = 0;
+
+    // Go through all points of the polyon.
+    for (size_t src = 0, dst = 0; src < sumPoints; src++) {
+        // The points of the polygon rings are indexed linearly.
+        // This maps the indices back to the original ring and point.
+        if (src - offset >= _polygon[ring].size()) {
+            offset += _polygon[ring].size();
+            ring += 1;
+        }
+
+        // Add vertex only when the point is used.
+        if (_ctx.used[src] == 0) { continue; }
+
+        // Keep track of skipped points to update indices
+        _ctx.used[src] = dst++;
+
+        auto& p = _polygon[ring][src - offset];
+        glm::vec3 coord(p.x, p.y, _height);
+
+        if (_ctx.useTexCoords) {
+            glm::vec2 uv(mapValue(coord.x, min.x, max.x, 0., 1.),
+                         mapValue(coord.y, min.y, max.y, 1., 0.));
+
+            _ctx.addVertex(coord, glm::vec3(0.0, 0.0, 1.0), uv);
+        } else {
+            _ctx.addVertex(coord, glm::vec3(0.0, 0.0, 1.0), glm::vec2(0));
+        }
+    }
+
+    for (auto i : _ctx.earcut.indices) {
+        _ctx.indices.push_back(vertexDataOffset + _ctx.used[i]);
+    }
+}
+
+void Builders::buildPolygonExtrusion(const Polygon& _polygon, float _minHeight, float _maxHeight, PolygonBuilder& _ctx) {
+
+    auto vertexDataOffset = _ctx.numVertices;
+
+    static const glm::vec3 upVector(0.0f, 0.0f, 1.0f);
+    glm::vec3 normalVector;
+
+    for (auto& line : _polygon) {
+
+        size_t lineSize = line.size();
+
+        for (size_t i = 0; i < lineSize - 1; i++) {
+
+            glm::vec3 a(line[i]);
+            glm::vec3 b(line[i+1]);
+
+            normalVector = glm::cross(upVector, b - a);
+            normalVector = glm::normalize(normalVector);
+
+            if (std::isnan(normalVector.x)
+             || std::isnan(normalVector.y)
+             || std::isnan(normalVector.z)) {
+                continue;
+            }
+
+            // 1st vertex top
+            a.z = _maxHeight;
+            _ctx.addVertex(a, normalVector, glm::vec2(1.,1.));
+
+            // 2nd vertex top
+            b.z = _maxHeight;
+            _ctx.addVertex(b, normalVector, glm::vec2(0.,1.));
+
+            // 1st vertex bottom
+            a.z = _minHeight;
+            _ctx.addVertex(a, normalVector, glm::vec2(1.,0.));
+
+            // 2nd vertex bottom
+            b.z = _minHeight;
+            _ctx.addVertex(b, normalVector, glm::vec2(0.,0.));
+
+            // Start the index from the previous state of the vertex Data
+            _ctx.indices.push_back(vertexDataOffset);
+            _ctx.indices.push_back(vertexDataOffset + 1);
+            _ctx.indices.push_back(vertexDataOffset + 2);
+
+            _ctx.indices.push_back(vertexDataOffset + 1);
+            _ctx.indices.push_back(vertexDataOffset + 3);
+            _ctx.indices.push_back(vertexDataOffset + 2);
+
+            vertexDataOffset += 4;
+        }
+
+        _ctx.numVertices = vertexDataOffset;
+    }
+}
+
+// Get 2D perpendicular of two points
+glm::vec2 perp2d(const glm::vec3& _v1, const glm::vec3& _v2 ){
+    return glm::vec2(_v2.y - _v1.y, _v1.x - _v2.x);
+}
+
+// Helper function for polyline tesselation
+inline void addPolyLineVertex(const glm::vec3& _coord, const glm::vec2& _normal, const glm::vec2& _uv, PolyLineBuilder& _ctx) {
+    _ctx.numVertices++;
+    _ctx.addVertex(_coord, _normal, _uv);
+}
+
+// Helper function for polyline tesselation; adds indices for pairs of vertices arranged like a line strip
+void indexPairs( int _nPairs, int _nVertices, std::vector<uint16_t>& _indicesOut) {
+    for (int i = 0; i < _nPairs; i++) {
+        _indicesOut.push_back(_nVertices - 2*i - 4);
+        _indicesOut.push_back(_nVertices - 2*i - 2);
+        _indicesOut.push_back(_nVertices - 2*i - 3);
+
+        _indicesOut.push_back(_nVertices - 2*i - 3);
+        _indicesOut.push_back(_nVertices - 2*i - 2);
+        _indicesOut.push_back(_nVertices - 2*i - 1);
+    }
+}
+
+//  Tessalate a fan geometry between points A       B
+//  using their normals from a center        \ . . /
+//  and interpolating their UVs               \ p /
+//                                             \./
+//                                              C
+void addFan(const glm::vec3& _pC,
+            const glm::vec2& _nA, const glm::vec2& _nB, const glm::vec2& _nC,
+            const glm::vec2& _uA, const glm::vec2& _uB, const glm::vec2& _uC,
+            int _numTriangles, PolyLineBuilder& _ctx) {
+
+    // Find angle difference
+    float cross = _nA.x * _nB.y - _nA.y * _nB.x; // z component of cross(_CA, _CB)
+    float angle = atan2f(cross, glm::dot(_nA, _nB));
+
+    int startIndex = _ctx.numVertices;
+
+    // Add center vertex
+    addPolyLineVertex(_pC, _nC, _uC, _ctx);
+
+    // Add vertex for point A
+    addPolyLineVertex(_pC, _nA, _uA, _ctx);
+
+    // Add radial vertices
+    glm::vec2 radial = _nA;
+    for (int i = 0; i < _numTriangles; i++) {
+        float frac = (i + 1)/(float)_numTriangles;
+        radial = glm::rotate(_nA, angle * frac);
+
+        glm::vec2 uv(0.0);
+        if (_ctx.useTexCoords) {
+            uv = (1.f - frac) * _uA + frac * _uB;
+        }
+
+        addPolyLineVertex(_pC, radial, uv, _ctx);
+
+        // Add indices
+        _ctx.indices.push_back(startIndex); // center vertex
+        _ctx.indices.push_back(startIndex + i + (angle > 0 ? 1 : 2));
+        _ctx.indices.push_back(startIndex + i + (angle > 0 ? 2 : 1));
+    }
+
+}
+
+// Function to add the vertices for line caps
+void addCap(const glm::vec3& _coord, const glm::vec2& _normal, int _numCorners, bool _isBeginning, PolyLineBuilder& _ctx) {
+
+    float v = _isBeginning ? 0.f : 1.f; // length-wise tex coord
+
+    if (_numCorners < 1) {
+        // "Butt" cap needs no extra vertices
+        return;
+    } else if (_numCorners == 2) {
+        // "Square" cap needs two extra vertices
+        glm::vec2 tangent(-_normal.y, _normal.x);
+        addPolyLineVertex(_coord, _normal + tangent, {0.f, v}, _ctx);
+        addPolyLineVertex(_coord, -_normal + tangent, {0.f, v}, _ctx);
+        if (!_isBeginning) { // At the beginning of a line we can't form triangles with previous vertices
+            indexPairs(1, _ctx.numVertices, _ctx.indices);
+        }
+        return;
+    }
+
+    // "Round" cap type needs a fan of vertices
+    glm::vec2 nA(_normal), nB(-_normal), nC(0.f, 0.f), uA(1.f, v), uB(0.f, v), uC(0.5f, v);
+    if (_isBeginning) {
+        nA *= -1.f; // To flip the direction of the fan, we negate the normal vectors
+        nB *= -1.f;
+        uA.x = 0.f; // To keep tex coords consistent, we must reverse these too
+        uB.x = 1.f;
+    }
+    addFan(_coord, nA, nB, nC, uA, uB, uC, _numCorners, _ctx);
+}
+
+// Tests if a line segment (from point A to B) is outside the edge of a tile
+bool isOutsideTile(const glm::vec3& _a, const glm::vec3& _b) {
+
+    // tweak this adjust if catching too few/many line segments near tile edges
+    // TODO: make tolerance configurable by source if necessary
+    float tolerance = 0.0005;
+    float tile_min = 0.0 + tolerance;
+    float tile_max = 1.0 - tolerance;
+
+    if ( (_a.x < tile_min && _b.x < tile_min) ||
+         (_a.x > tile_max && _b.x > tile_max) ||
+         (_a.y < tile_min && _b.y < tile_min) ||
+         (_a.y > tile_max && _b.y > tile_max) ) {
+        return true;
+    }
+
+    return false;
+}
+
+void buildPolyLineSegment(const Line& _line, PolyLineBuilder& _ctx, size_t _startIndex,
+                          size_t _endIndex, bool endCap = true) {
+
+    float distance = 0; // Cumulative distance along the polyline.
+
+    size_t origLineSize = _line.size();
+
+    // endIndex/startIndex could be wrapped values, calculate lineSize accordingly
+    int lineSize = (int)((_endIndex > _startIndex) ?
+                   (_endIndex - _startIndex) :
+                   (origLineSize - _startIndex + _endIndex));
+    if (lineSize < 2) { return; }
+
+    glm::vec3 coordCurr(_line[_startIndex]);
+    // get the Point using wrapped index in the original line geometry
+    glm::vec3 coordNext(_line[(_startIndex + 1) % origLineSize]);
+    glm::vec2 normPrev, normNext, miterVec;
+
+    int cornersOnCap = (int)_ctx.cap;
+    int trianglesOnJoin = (int)_ctx.join;
+
+    // Process first point in line with an end cap
+    normNext = glm::normalize(perp2d(coordCurr, coordNext));
+
+    if (endCap) {
+        addCap(coordCurr, normNext, cornersOnCap, true, _ctx);
+    }
+    addPolyLineVertex(coordCurr, normNext, {1.0f, 0.0f}, _ctx); // right corner
+    addPolyLineVertex(coordCurr, -normNext, {0.0f, 0.0f}, _ctx); // left corner
+
+
+    // Process intermediate points
+    for (int i = 1; i < lineSize - 1; i++) {
+        // get the Point using wrapped index in the original line geometry
+        int nextIndex = (i + _startIndex + 1) % origLineSize;
+
+        distance += glm::distance(coordCurr, coordNext);
+
+        coordCurr = coordNext;
+        coordNext = _line[nextIndex];
+
+        if (coordCurr == coordNext) {
+            continue;
+        }
+
+        normPrev = normNext;
+        normNext = glm::normalize(perp2d(coordCurr, coordNext));
+
+        // Compute "normal" for miter joint
+        miterVec = normPrev + normNext;
+
+        float scale = 1.f;
+
+        // normPrev and normNext are in the opposite direction
+        // in order to prevent NaN values, we use the perp
+        // vector of those two vectors
+        if (miterVec == glm::zero<glm::vec2>()) {
+            miterVec = perp2d(glm::vec3(normNext, 0.f), glm::vec3(normPrev, 0.f));
+        } else {
+            scale = 2.f / glm::dot(miterVec, miterVec);
+        }
+
+        miterVec *= scale;
+
+        if (glm::length2(miterVec) > glm::length2(_ctx.miterLimit)) {
+            trianglesOnJoin = 1;
+            miterVec *= _ctx.miterLimit / glm::length(miterVec);
+        }
+
+        float v = distance;
+
+        if (trianglesOnJoin == 0) {
+            // Join type is a simple miter
+
+            addPolyLineVertex(coordCurr, miterVec, {1.0, v}, _ctx); // right corner
+            addPolyLineVertex(coordCurr, -miterVec, {0.0, v}, _ctx); // left corner
+            indexPairs(1, _ctx.numVertices, _ctx.indices);
+
+        } else {
+
+            // Join type is a fan of triangles
+
+            bool isRightTurn = (normNext.x * normPrev.y - normNext.y * normPrev.x) > 0; // z component of cross(normNext, normPrev)
+
+            if (isRightTurn) {
+
+                addPolyLineVertex(coordCurr, miterVec, {1.0f, v}, _ctx); // right (inner) corner
+                addPolyLineVertex(coordCurr, -normPrev, {0.0f, v}, _ctx); // left (outer) corner
+                indexPairs(1, _ctx.numVertices, _ctx.indices);
+
+                addFan(coordCurr, -normPrev, -normNext, miterVec, {0.f, v}, {0.f, v}, {1.f, v}, trianglesOnJoin, _ctx);
+
+                addPolyLineVertex(coordCurr, miterVec, {1.0f, v}, _ctx); // right (inner) corner
+                addPolyLineVertex(coordCurr, -normNext, {0.0f, v}, _ctx); // left (outer) corner
+
+            } else {
+
+                addPolyLineVertex(coordCurr, normPrev, {1.0f, v}, _ctx); // right (outer) corner
+                addPolyLineVertex(coordCurr, -miterVec, {0.0f, v}, _ctx); // left (inner) corner
+                indexPairs(1, _ctx.numVertices, _ctx.indices);
+
+                addFan(coordCurr, normPrev, normNext, -miterVec, {1.f, v}, {1.f, v}, {0.0f, v}, trianglesOnJoin, _ctx);
+
+                addPolyLineVertex(coordCurr, normNext, {1.0f, v}, _ctx); // right (outer) corner
+                addPolyLineVertex(coordCurr, -miterVec, {0.0f, v}, _ctx); // left (inner) corner
+            }
+        }
+    }
+
+    distance += glm::distance(coordCurr, coordNext);
+
+    // Process last point in line with a cap
+    addPolyLineVertex(coordNext, normNext, {1.f, distance}, _ctx); // right corner
+    addPolyLineVertex(coordNext, -normNext, {0.f, distance}, _ctx); // left corner
+    indexPairs(1, _ctx.numVertices, _ctx.indices);
+    if (endCap) {
+        addCap(coordNext, normNext, cornersOnCap, false, _ctx);
+    }
+
+}
+
+void Builders::buildPolyLine(const Line& _line, PolyLineBuilder& _ctx) {
+
+    size_t lineSize = _line.size();
+
+    if (_ctx.keepTileEdges) {
+
+        buildPolyLineSegment(_line, _ctx, 0, lineSize);
+
+    } else {
+
+        int cut = 0;
+        int firstCutEnd = 0;
+
+        // Determine cuts
+        for (size_t i = 0; i < lineSize - 1; i++) {
+            const glm::vec3& coordCurr = _line[i];
+            const glm::vec3& coordNext = _line[i+1];
+            if (isOutsideTile(coordCurr, coordNext)) {
+                if (cut == 0) {
+                    firstCutEnd = i + 1;
+                }
+                buildPolyLineSegment(_line, _ctx, cut, i + 1);
+                cut = i + 1;
+            }
+        }
+
+        if (_ctx.closedPolygon) {
+            if (cut == 0) {
+                // no tile edge cuts!
+                // loop and close the polygon with no endcaps
+                buildPolyLineSegment(_line, _ctx, 0, lineSize+2, false);
+            } else {
+                // merge first and last cut line-segments together
+                buildPolyLineSegment(_line, _ctx, cut, firstCutEnd);
+            }
+        } else {
+            buildPolyLineSegment(_line, _ctx, cut, lineSize);
+        }
+
+    }
+
+}
+
+void Builders::buildQuadAtPoint(const glm::vec2& _screenPosition, const glm::vec2& _size, const glm::vec2& _uvBL, const glm::vec2& _uvTR, SpriteBuilder& _ctx) {
+    float halfWidth = _size.x * .5f;
+    float halfHeight = _size.y * .5f;
+
+    _ctx.addVertex(glm::vec2(-halfWidth, -halfHeight), _screenPosition, {_uvBL.x, _uvBL.y});
+    _ctx.addVertex(glm::vec2(-halfWidth, halfHeight), _screenPosition, {_uvBL.x, _uvTR.y});
+    _ctx.addVertex(glm::vec2(halfWidth, -halfHeight), _screenPosition, {_uvTR.x, _uvBL.y});
+    _ctx.addVertex(glm::vec2(halfWidth, halfHeight), _screenPosition, {_uvTR.x, _uvTR.y});
+
+    _ctx.indices.push_back(_ctx.numVerts + 2);
+    _ctx.indices.push_back(_ctx.numVerts + 0);
+    _ctx.indices.push_back(_ctx.numVerts + 1);
+    _ctx.indices.push_back(_ctx.numVerts + 1);
+    _ctx.indices.push_back(_ctx.numVerts + 3);
+    _ctx.indices.push_back(_ctx.numVerts + 2);
+
+    _ctx.numVerts += 4;
+
+}
+
+}
diff --git a/core/src/util/builders.h b/core/src/util/builders.h
new file mode 100644 (file)
index 0000000..60089a1
--- /dev/null
@@ -0,0 +1,146 @@
+#pragma once
+
+#include "data/tileData.h"
+
+#include "earcut.hpp"
+#include <functional>
+#include <vector>
+
+
+namespace Tangram {
+
+enum class CapTypes {
+    butt = 0, // No points added to end of line
+    square = 2, // Two points added to make a square extension
+    round = 6 // Six points added in a fan to make a round cap
+};
+
+CapTypes CapTypeFromString(const std::string& str);
+
+enum class JoinTypes {
+    miter = 0, // No points added at line join
+    bevel = 1, // One point added to flatten the corner of a join
+    round = 5 // Five points added in a fan to make a round outer join
+};
+
+JoinTypes JoinTypeFromString(const std::string& str);
+
+/* Callback function for PolygonBuilder:
+ *
+ * @coord  tesselated output coordinate
+ * @normal triangle plane normal
+ * @uv     texture coordinate of the output coordinate
+ */
+typedef std::function<void(const glm::vec3& coord, const glm::vec3& normal, const glm::vec2& uv)> PolygonVertexFn;
+
+/* PolygonBuilder context,
+ * see Builders::buildPolygon() and Builders::buildPolygonExtrusion()
+ */
+struct PolygonBuilder {
+    std::vector<uint16_t> indices; // indices for drawing the polyon as triangles are added to this vector
+    std::vector<int> used;
+
+    PolygonVertexFn addVertex;
+    size_t numVertices = 0;
+    bool useTexCoords;
+
+    mapbox::detail::Earcut<uint16_t> earcut;
+
+    PolygonBuilder(PolygonVertexFn _addVertex = [](auto&,auto&,auto&){},
+                   bool _useTexCoords = true)
+        : addVertex(_addVertex), useTexCoords(_useTexCoords){}
+
+    void clear() {
+        numVertices = 0;
+        indices.clear();
+    }
+};
+
+
+/* Callback function for PolyLineBuilder:
+ *
+ * @coord   tesselated output coordinate
+ * @enormal extrusion vector of the output coordinate
+ * @uv      texture coordinate of the output coordinate
+ */
+typedef std::function<void(const glm::vec3& coord, const glm::vec2& enormal, const glm::vec2& uv)> PolyLineVertexFn;
+
+/* PolyLineBuilder context,
+ * see Builders::buildPolyLine()
+ */
+struct PolyLineBuilder {
+    std::vector<uint16_t> indices; // indices for drawing the polyline as triangles are added to this vector
+    PolyLineVertexFn addVertex;
+    size_t numVertices = 0;
+    float miterLimit = 3.f;
+    CapTypes cap;
+    JoinTypes join;
+    bool keepTileEdges;
+    bool closedPolygon;
+    bool useTexCoords = false;
+
+    PolyLineBuilder(PolyLineVertexFn _addVertex = [](auto&,auto&,auto&){},
+                    CapTypes _cap = CapTypes::butt,
+                    JoinTypes _join = JoinTypes::bevel,
+                    bool _kte = true, bool _closedPoly = false)
+        : addVertex(_addVertex), cap(_cap), join(_join), keepTileEdges(_kte), closedPolygon(_closedPoly) {}
+
+    void clear() {
+        numVertices = 0;
+        indices.clear();
+    }
+};
+
+/* Callback function for SpriteBuilder
+ * @coord tesselated coordinates of the sprite quad in screen space
+ * @screenPos the screen position
+ * @uv texture coordinate of the ouptput coordinate
+ */
+typedef std::function<void(const glm::vec2& coord, const glm::vec2& screenPos, const glm::vec2& uv)> SpriteBuilderFn;
+
+/* SpriteBuidler context
+ */
+struct SpriteBuilder {
+    std::vector<uint16_t> indices;
+    SpriteBuilderFn addVertex;
+    size_t numVerts = 0;
+
+    SpriteBuilder(SpriteBuilderFn _addVertex) : addVertex(_addVertex) {}
+};
+
+class Builders {
+
+public:
+
+    /* Build a tesselated polygon
+     * @_polygon input coordinates describing the polygon
+     * @_ctx output vectors, see <PolygonBuilder>
+     */
+    static void buildPolygon(const Polygon& _polygon, float _height, PolygonBuilder& _ctx);
+
+    /* Build extruded 'walls' from a polygon
+     * @_polygon input coordinates describing the polygon
+     * @_minHeight the extrusion will extend from this z coordinate to the z of the polygon points
+     * @_ctx output vectors, see <PolygonBuilder>
+     */
+    static void buildPolygonExtrusion(const Polygon& _polygon, float _minHeight, float _maxHeight, PolygonBuilder& _ctx);
+
+    /* Build a tesselated polygon line of fixed width from line coordinates
+     * @_line input coordinates describing the line
+     * @_options parameters for polyline construction
+     * @_ctx output vectors, see <PolyLineBuilder>
+     */
+    static void buildPolyLine(const Line& _line, PolyLineBuilder& _ctx);
+
+    /* Build a tesselated quad centered on _screenOrigin
+     * @_screenOrigin the sprite origin in screen space
+     * @_size the size of the sprite in pixels
+     * @_uvBL the bottom left UV coordinate of the quad
+     * @_uvTR the top right UV coordinate of the quad
+     * @_ctx output vectors, see <SpriteBuilder>
+     */
+    static void buildQuadAtPoint(const glm::vec2& _screenOrigin, const glm::vec2& _size, const glm::vec2& _uvBL, const glm::vec2& _uvTR, SpriteBuilder& _ctx);
+
+};
+
+}
diff --git a/core/src/util/color.h b/core/src/util/color.h
new file mode 100644 (file)
index 0000000..53ced03
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+#include <cstdint>
+#include "glm/vec4.hpp"
+
+namespace Tangram {
+
+struct Color {
+
+    union {
+        struct {
+            uint8_t r, g, b, a;
+        };
+        uint32_t abgr = 0;
+    };
+
+    Color() = default;
+    Color(uint32_t _abgr) : abgr(_abgr) {}
+    Color(uint8_t _r, uint8_t _g, uint8_t _b, uint8_t _a) : r(_r), g(_g), b(_b), a(_a) {}
+
+    glm::ivec4 asIVec4() {
+        return glm::ivec4(r, g, b, a);
+    }
+
+    static Color mix(const Color& _x, const Color& _y, float _a) {
+        return Color(
+            _x.r * (1 - _a) + _y.r * _a,
+            _x.g * (1 - _a) + _y.g * _a,
+            _x.b * (1 - _a) + _y.b * _a,
+            _x.a * (1 - _a) + _y.a * _a
+        );
+    }
+
+};
+
+}
diff --git a/core/src/util/dashArray.cpp b/core/src/util/dashArray.cpp
new file mode 100644 (file)
index 0000000..f234d8a
--- /dev/null
@@ -0,0 +1,27 @@
+#include "util/dashArray.h"
+
+#include <cmath>
+
+namespace Tangram {
+
+std::vector<unsigned int> DashArray::render(std::vector<float> _pattern, float _dashScale,
+    unsigned int _dashColor, unsigned int _backgroundColor)
+{
+    std::vector<unsigned int> dashArray;
+    if (_pattern.size() % 2 == 1) {
+        _pattern.insert(_pattern.end(), _pattern.begin(), _pattern.end());
+    }
+
+    bool dash = true;
+    for (auto& pat : _pattern) {
+        int segment = std::floor(pat * _dashScale);
+        for (int i = 0; i < segment; ++i) {
+            dashArray.push_back(dash ? _dashColor : _backgroundColor);
+        }
+        dash = !dash;
+    }
+
+    return dashArray;
+}
+
+}
diff --git a/core/src/util/dashArray.h b/core/src/util/dashArray.h
new file mode 100644 (file)
index 0000000..b65f754
--- /dev/null
@@ -0,0 +1,13 @@
+#pragma once
+
+#include <vector>
+
+namespace Tangram {
+
+struct DashArray {
+    static std::vector<unsigned int> render(std::vector<float> _pattern, float _dashScale,
+        unsigned int _dashColor = 0xffffffff,
+        unsigned int _backgroundColor = 0x00000000);
+};
+
+}
diff --git a/core/src/util/ease.h b/core/src/util/ease.h
new file mode 100644 (file)
index 0000000..cd847d7
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "tangram.h"
+
+#include <cmath>
+#include <functional>
+
+namespace Tangram {
+
+using EaseCb = std::function<void (float)>;
+
+template<typename T>
+T ease(T _start, T _end, float _t, EaseType _e) {
+    float f = _t;
+    switch (_e) {
+        case EaseType::cubic: f = (-2 * f + 3) * f * f; break;
+        case EaseType::quint: f = (6 * f * f - 15 * f + 10) * f * f * f; break;
+        case EaseType::sine: f = 0.5 - 0.5 * cos(M_PI * f); break;
+        default: break;
+    }
+    return _start + (_end - _start) * f;
+}
+
+struct Ease {
+
+    float t;
+    float d;
+    EaseCb cb;
+
+    Ease() : t(0), d(0), cb([](float) {}) {}
+    Ease(float _duration, EaseCb _cb) : t(-1), d(_duration), cb(_cb) {}
+
+    bool finished() const { return t >= d; }
+
+    void update(float _dt) {
+        t = t < 0 ? 0 : std::fmin(t + _dt, d);
+        cb(std::fmin(1, t / d));
+    }
+
+};
+
+}
diff --git a/core/src/util/extrude.cpp b/core/src/util/extrude.cpp
new file mode 100644 (file)
index 0000000..9e94bcb
--- /dev/null
@@ -0,0 +1,95 @@
+#include "util/extrude.h"
+
+#include "util/floatFormatter.h"
+
+#include <cmath>
+#include <cstdlib>
+
+namespace Tangram {
+
+Extrude parseExtrudeString(const std::string& _str) {
+
+    // Values specified from the stylesheet are assumed to be meters with no unit suffix
+    float first = 0, second = 0;
+
+    if (_str == "true") {
+        // "true" means use default properties for both heights, we indicate this with NANs
+        return Extrude(NAN, NAN);
+    }
+
+    if (_str == "false") {
+        // "false" means perform no extrusion
+        return Extrude(0, 0);
+    }
+
+    // Parse the first of two possible numbers
+    const char* str = _str.c_str();
+
+    // Get a float if possible & advance pos to the end of the number
+    const int length = _str.length();
+    int count = 0;
+    int offset = 0;
+
+    first = ff::stof(str, length, &count);
+    if (count == 0) {
+        // No numbers found, return zero extrusion
+        return Extrude(0, 0);
+    }
+
+    // Advance and skip the delimiter character
+    offset += count;
+    if (length - offset <= 0) {
+        return Extrude(0, first);
+    }
+    while (str[offset] == ' ') { offset++; }
+    if (str[offset++] != ',') {
+        return Extrude(0, first);
+    }
+
+    // Get a float if possible & advance pos to the end of the number
+    second = ff::stof(str + offset, length - offset, &count);
+    if (count == 0) {
+        // No second number, so return an extrusion from 0 to the first number
+        return Extrude(0, first);
+    }
+
+    // Got two numbers, so return an extrusion from first to second
+    return Extrude(first, second);
+
+}
+
+float getLowerExtrudeMeters(const Extrude& _extrude, const Properties& _props) {
+
+    const static std::string key_min_height("min_height");
+
+    double lower = 0;
+
+    if (std::isnan(_extrude[0])) {
+        // A NAN indicates that the default property should be used for this height
+        _props.getNumber(key_min_height, lower);
+    } else {
+        lower = _extrude[0];
+    }
+
+    return lower;
+
+}
+
+float getUpperExtrudeMeters(const Extrude& _extrude, const Properties& _props) {
+
+    const static std::string key_height("height");
+
+    double upper = 0;
+
+    if (std::isnan(_extrude[1])) {
+        // A NAN indicates that the default property should be used for this height
+        _props.getNumber(key_height, upper);
+    } else {
+        upper = _extrude[1];
+    }
+
+    return upper;
+
+}
+
+}
diff --git a/core/src/util/extrude.h b/core/src/util/extrude.h
new file mode 100644 (file)
index 0000000..a60d933
--- /dev/null
@@ -0,0 +1,21 @@
+#pragma once
+
+#include "data/properties.h"
+
+#include "glm/vec2.hpp"
+#include <string>
+
+namespace Tangram {
+
+// Extrude is a 2-element vector that follows specific conventions to encode extrusion options
+using Extrude = glm::vec2;
+
+// Returns an Extrude to represent the extrusion option specified in the string, one of:
+// "true", "false", a single number, or a comma-separated pair of numbers
+Extrude parseExtrudeString(const std::string& _str);
+
+// Returns the lower or upper extrusion values for a given Extrude and set of feature properties
+float getLowerExtrudeMeters(const Extrude& _extrude, const Properties& _props);
+float getUpperExtrudeMeters(const Extrude& _extrude, const Properties& _props);
+
+}
diff --git a/core/src/util/fastmap.h b/core/src/util/fastmap.h
new file mode 100644 (file)
index 0000000..c236660
--- /dev/null
@@ -0,0 +1,138 @@
+#pragma once
+
+#include <algorithm>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+// see also:
+// http://www.boost.org/doc/libs/1_59_0/doc/html/boost/container/flat_map.html
+// https://realm.io/assets/news/binary-search/blog.cpp
+
+template<typename K, typename T>
+struct fastmap {
+    std::vector<std::pair<K, T>> map;
+
+    using iterator = typename std::vector<std::pair<K, T>>::iterator;
+    using const_iterator = typename std::vector<std::pair<K, T>>::const_iterator;
+
+    T& operator[](const K& key) {
+        iterator it = std::lower_bound(
+            map.begin(), map.end(), key,
+            [&](const auto& item, const auto& key) {
+                return item.first < key;
+            });
+
+        if (it == map.end() || it->first != key) {
+            auto entry = map.emplace(it, key, T{});
+            return entry->second;
+        }
+
+        return it->second;
+    }
+
+    const_iterator find(const K& key) const {
+        const_iterator it = std::lower_bound(
+            map.begin(), map.end(), key,
+            [&](const auto& item, const auto& key) {
+                return item.first < key;
+            });
+
+        if (it == map.end() || it->first == key) {
+            return it;
+        }
+        return map.end();
+    }
+
+    iterator find(const K& key) {
+        iterator it = std::lower_bound(
+            map.begin(), map.end(), key,
+            [&](const auto& item, const auto& key) {
+                return item.first < key;
+            });
+
+        if (it == map.end() || it->first == key) {
+            return it;
+        }
+        return map.end();
+    }
+
+    iterator erase(const_iterator position) {
+        return map.erase(position);
+    }
+
+    iterator begin() { return map.begin(); }
+    iterator end() { return map.end(); }
+
+    const_iterator begin() const { return map.begin(); }
+    const_iterator end() const { return map.end(); }
+
+    size_t size() const { return map.size(); }
+
+    void clear() { map.clear(); }
+};
+
+template<typename T>
+struct fastmap<std::string, T> {
+
+    struct Key {
+        size_t hash;
+        std::string k;
+    };
+
+    using iterator = typename std::vector<std::pair<Key, T>>::iterator;
+    using const_iterator = typename std::vector<std::pair<Key, T>>::const_iterator;
+
+    std::vector<std::pair<Key, T>> map;
+    std::vector<size_t> lengths;
+
+    T& operator[](const std::string& key) {
+
+        size_t hash = std::hash<std::string>()(key);
+        iterator it = std::lower_bound(
+            map.begin(), map.end(), key,
+            [&](const auto& item, const auto& key) {
+                if (item.first.hash == hash) {
+                    return item.first.k < key;
+                }
+                return item.first.hash < hash;
+            });
+
+        if (it == map.end() || it->first.k != key) {
+            auto entry = map.emplace(it, Key{hash, key}, T{});
+            return entry->second;
+        }
+
+        return it->second;
+    }
+
+    const_iterator find(const std::string& key) const {
+        size_t hash = std::hash<std::string>()(key);
+
+        const_iterator it = std::lower_bound(
+            map.begin(), map.end(), key,
+            [&](const auto& item, const auto& key) {
+                if (item.first.hash == hash) {
+                    return item.first.k < key;
+                }
+                return item.first.hash < hash;
+            });
+
+        if (it == map.end() || it->first.k == key) {
+            return it;
+        }
+        return map.end();
+    }
+    void clear() { map.clear(); }
+
+    iterator begin() { return map.begin(); }
+    iterator end() { return map.end(); }
+
+    size_t size() const { return map.size(); }
+
+    const_iterator begin() const { return map.begin(); }
+    const_iterator end() const { return map.end(); }
+};
+
+}
diff --git a/core/src/util/floatFormatter.cpp b/core/src/util/floatFormatter.cpp
new file mode 100644 (file)
index 0000000..fcb8c59
--- /dev/null
@@ -0,0 +1,78 @@
+#include "util/floatFormatter.h"
+
+#include "double-conversion.h"
+#include <cmath>
+
+namespace Tangram {
+
+
+using namespace double_conversion;
+
+StringToDoubleConverter S2D = {
+    StringToDoubleConverter::ALLOW_TRAILING_JUNK |
+    StringToDoubleConverter::ALLOW_LEADING_SPACES,
+    0.0, NAN, "inf", "nan" };
+
+DoubleToStringConverter D2S = {
+    DoubleToStringConverter::EMIT_TRAILING_DECIMAL_POINT |
+    DoubleToStringConverter::EMIT_TRAILING_ZERO_AFTER_POINT |
+    DoubleToStringConverter::UNIQUE_ZERO,
+    "inf", "nan", 'e', -10, 10, 6, 6 };
+
+const size_t StringBuilderBufferSize = 256;
+
+double ff::stod(const char* _string, int _length, int* _end) {
+    return S2D.StringToDouble(_string, _length, _end);
+}
+
+float ff::stof(const char* _string, int _length, int* _end) {
+    return S2D.StringToFloat(_string, _length, _end);
+}
+
+std::string ff::to_string(glm::vec2 _vec) {
+    char buffer[StringBuilderBufferSize];
+    StringBuilder builder(buffer, StringBuilderBufferSize);
+    builder.AddString("vec2(");
+    D2S.ToShortest(_vec[0], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[1], &builder);
+    builder.AddCharacter(')');
+    return std::string(builder.Finalize());
+}
+
+std::string ff::to_string(glm::vec3 _vec) {
+    char buffer[StringBuilderBufferSize];
+    StringBuilder builder(buffer, StringBuilderBufferSize);
+    builder.AddString("vec3(");
+    D2S.ToShortest(_vec[0], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[1], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[2], &builder);
+    builder.AddCharacter(')');
+    return std::string(builder.Finalize());
+}
+
+std::string ff::to_string(glm::vec4 _vec) {
+    char buffer[StringBuilderBufferSize];
+    StringBuilder builder(buffer, StringBuilderBufferSize);
+    builder.AddString("vec4(");
+    D2S.ToShortest(_vec[0], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[1], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[2], &builder);
+    builder.AddCharacter(',');
+    D2S.ToShortest(_vec[3], &builder);
+    builder.AddCharacter(')');
+    return std::string(builder.Finalize());
+}
+
+std::string ff::to_string(float _value) {
+    char buffer[StringBuilderBufferSize];
+    StringBuilder builder(buffer, StringBuilderBufferSize);
+    D2S.ToShortest(_value, &builder);
+    return std::string(builder.Finalize());
+}
+
+}
diff --git a/core/src/util/floatFormatter.h b/core/src/util/floatFormatter.h
new file mode 100644 (file)
index 0000000..b6d3f01
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+#include <string>
+#include "glm/vec2.hpp"
+#include "glm/vec3.hpp"
+#include "glm/vec4.hpp"
+
+namespace Tangram {
+
+struct ff {
+
+    static std::string to_string(glm::vec2 _vec);
+
+    static std::string to_string(glm::vec3 _vec);
+
+    static std::string to_string(glm::vec4 _vec);
+
+    static std::string to_string(float _value);
+
+    static double stod(const char* _string, int _length, int* _end);
+
+    static double stod(const std::string& _string) {
+        int end = 0;
+        return stod(_string.data(), _string.size(), &end);
+    }
+
+    static float stof(const char* _string, int _length, int* _end);
+
+    static float stof(const std::string& _string) {
+        int end = 0;
+        return stof(_string.data(), _string.size(), &end);
+    }
+
+};
+
+}
diff --git a/core/src/util/geom.cpp b/core/src/util/geom.cpp
new file mode 100644 (file)
index 0000000..8d09efc
--- /dev/null
@@ -0,0 +1,128 @@
+#include "util/geom.h"
+
+#include "glm/gtx/norm.hpp"
+#include <cmath>
+#include <limits>
+
+namespace Tangram {
+
+float mapValue(const float& _value, const float& _inputMin, const float& _inputMax, const float& _outputMin,
+               const float& _outputMax, bool _clamp) {
+    if (fabs(_inputMin - _inputMax) < std::numeric_limits<float>::epsilon()) { return _outputMin; } else {
+        float outVal = ((_value - _inputMin) / (_inputMax - _inputMin) * (_outputMax - _outputMin) + _outputMin);
+
+        if (_clamp) {
+            if (_outputMax < _outputMin) {
+                if (outVal < _outputMax) {
+                    outVal = _outputMax;
+                } else if (outVal > _outputMin) {
+                    outVal = _outputMin;
+                }
+            } else {
+                if (outVal > _outputMax) {
+                    outVal = _outputMax;
+                } else if (outVal < _outputMin) {
+                    outVal = _outputMin;
+                }
+            }
+        }
+        return outVal;
+    }
+}
+
+float angleBetweenPoints(const glm::vec2& _p1, const glm::vec2& _p2) {
+    glm::vec2 p1p2 = _p2 - _p1;
+    p1p2 = glm::normalize(p1p2);
+    return (float)atan2(p1p2.x, -p1p2.y);
+}
+
+float sqPointSegmentDistance(const glm::vec2& _p, const glm::vec2& _a, const glm::vec2& _b) {
+
+    float dx = _b.x - _a.x;
+    float dy = _b.y - _a.y;
+
+    float x = _a.x;
+    float y = _a.y;
+
+    float d = dx * dx + dy * dy;
+
+    if (d != 0) {
+        // project point onto segment
+        float t = ((_p.x - _a.x) * dx + (_p.y - _a.y) * dy) / d;
+        if (t > 1) {
+            x = _b.x;
+            y = _b.y;
+        } else if (t > 0) {
+            x += dx * t;
+            y += dy * t;
+        }
+    }
+
+    dx = _p.x - x;
+    dy = _p.y - y;
+
+    return dx * dx + dy * dy;
+}
+
+float pointSegmentDistance(const glm::vec2& _p, const glm::vec2& _a, const glm::vec2& _b) {
+    return sqrt(sqPointSegmentDistance(_p, _a, _b));
+}
+
+glm::vec4 worldToClipSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition) {
+    return _mvp * _worldPosition;
+}
+
+glm::vec2 clipToScreenSpace(const glm::vec4& _clipCoords, const glm::vec2& _screenSize) {
+    glm::vec2 halfScreen = glm::vec2(_screenSize * 0.5f);
+
+    // from normalized device coordinates to screen space coordinate system
+    // top-left screen axis, y pointing down
+
+    glm::vec2 screenPos;
+    screenPos.x = (_clipCoords.x / _clipCoords.w) + 1;
+    screenPos.y = 1 - (_clipCoords.y / _clipCoords.w);
+
+    return screenPos * halfScreen;
+}
+
+glm::vec2 worldToScreenSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition, const glm::vec2& _screenSize) {
+    return clipToScreenSpace(worldToClipSpace(_mvp, _worldPosition), _screenSize);
+}
+
+glm::vec2 worldToScreenSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition, const glm::vec2& _screenSize, bool& _clipped) {
+
+    glm::vec4 clipCoords = worldToClipSpace(_mvp, _worldPosition);
+
+    if (clipCoords.w <= 0.0f) {
+        _clipped = true;
+        return {};
+    }
+
+    return clipToScreenSpace(clipCoords, _screenSize);
+}
+
+// square distance from a point <_p> to a segment <_p1,_p2>
+// http://stackoverflow.com/questions/849211/shortest-distance-between-a-point-and-a-line-segment
+//
+float sqSegmentDistance(const glm::vec2& _p, const glm::vec2& _p1, const glm::vec2& _p2) {
+    glm::vec2 d(_p2 - _p1);
+    float lengthSq = glm::length2(d);
+
+    if (lengthSq != 0) {
+
+        float t = glm::dot(_p - _p1, d) / lengthSq;
+
+        if (t > 1) {
+            return glm::length2(_p - _p2);
+        } else if (t > 0) {
+            return glm::length2(_p - (_p1 + d * t));
+        }
+    }
+    return glm::length2(_p - _p1);
+}
+
+bool isPowerOfTwo(int _value) {
+    return (_value & (_value - 1)) == 0;
+}
+
+}
diff --git a/core/src/util/geom.h b/core/src/util/geom.h
new file mode 100644 (file)
index 0000000..85fb70f
--- /dev/null
@@ -0,0 +1,151 @@
+#pragma once
+
+#include "glm/glm.hpp"
+#include <vector>
+
+#ifndef PI
+#define PI 3.14159265358979323846
+#endif
+
+#ifndef TWO_PI
+#define TWO_PI 6.28318530717958647693
+#endif
+
+#ifndef FOUR_PI
+#define FOUR_PI 12.56637061435917295385
+#endif
+
+#ifndef HALF_PI
+#define HALF_PI 1.57079632679489661923
+#endif
+
+#ifndef QUARTER_PI
+#define QUARTER_PI 0.785398163
+#endif
+
+/* Multiply degrees by DEG_TO_RAD to get radians */
+#ifndef DEG_TO_RAD
+#define DEG_TO_RAD 0.01745329251994329576
+#endif
+
+/* Multiply radians by RAD_TO_DEG to get degrees */
+#ifndef RAD_TO_DEG
+#define RAD_TO_DEG 57.2957795130823208767
+#endif
+
+/* Minimum value between two variables that support < comparison */
+#ifndef MIN
+#define MIN(x, y) (((x) < (y)) ? (x) : (y))
+#endif
+
+/* Maximum value between two values that support > comparison */
+#ifndef MAX
+#define MAX(x, y) (((x) > (y)) ? (x) : (y))
+#endif
+
+/* Clamp a value between a min and max value */
+#ifndef CLAMP
+#define CLAMP(val, min, max) ((val) < (min) ? (min) : ((val > max) ? (max) : (val)))
+#endif
+
+/* Absolute value of a numeric variable */
+#ifndef ABS
+#define ABS(x) (((x) < 0) ? -(x) : (x))
+#endif
+
+namespace Tangram {
+
+struct BoundingBox {
+
+    glm::dvec2 min;
+    glm::dvec2 max;
+
+    double width() const { return glm::abs(max.x - min.x); }
+    double height() const { return glm::abs(max.y - min.y); }
+    glm::dvec2 center() const { return 0.5 * (min + max); }
+    bool containsX(double x) const { return x >= min.x && x <= max.x; }
+    bool containsY(double y) const { return y >= min.y && y <= max.y; }
+    bool contains(double x, double y) const { return containsX(x) && containsY(y); }
+    void expand(double x, double y) {
+        min = { glm::min(min.x, x), glm::min(min.y, y) };
+        max = { glm::max(max.x, x), glm::max(max.y, y) };
+    }
+};
+
+template<class InputIt>
+float signedArea(InputIt _begin, InputIt _end) {
+    if (_begin == _end) { return 0; }
+    float area = 0;
+    auto prev = _end - 1;
+    for (auto curr = _begin; curr != _end; ++curr) {
+        area += curr->x * prev->y - curr->y * prev->x;
+        prev = curr;
+    }
+    return 0.5 * area;
+}
+
+/* Calculate the area centroid of a closed polygon given as a sequence of vectors.
+ * If the polygon has no area, the coordinates returned are NaN.
+ */
+template<class InputIt, class Vector = typename InputIt::value_type>
+Vector centroid(InputIt begin, InputIt end) {
+    Vector centroid;
+    float area = 0.f;
+    for (auto curr = begin, prev = end - 1; curr != end; prev = curr, ++curr) {
+        float a = (prev->x * curr->y - curr->x * prev->y);
+        centroid.x += (prev->x + curr->x) * a;
+        centroid.y += (prev->y + curr->y) * a;
+        area += a;
+    }
+    return centroid / (3.f * area);
+}
+
+template<class T>
+float signedArea(const T& _a, const T& _b, const T& _c) {
+    return 0.5 * ((_b.y - _a.y) * (_c.x - _b.x) - (_b.x - _a.x) * (_c.y - _b.y));
+}
+
+inline float crossProduct(const glm::vec2& _a, const glm::vec2& _b) {
+    return (_a.x * _b.y) - (_a.y * _b.x);
+}
+
+/* Map a value from the range [_inputMin, _inputMax] into the range [_outputMin, _outputMax];
+ * If _clamp is true, the output is strictly within the output range.
+ * Ex: mapValue(5, 0, 10, 0, 360) == 180
+ */
+float mapValue(const float& _value, const float& _inputMin, const float& _inputMax, const float& _outputMin,
+               const float& _outputMax, bool _clamp = true);
+
+/* Computes the angle in radians between two points with the axis y = 0 in 2d space */
+float angleBetweenPoints(const glm::vec2& _p1, const glm::vec2& _p2);
+
+/* Computes the clip coordinates from position in world space and a model view matrix */
+glm::vec4 worldToClipSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition);
+
+/* Computes the screen coordinates from a coordinate in clip space and a screen size */
+glm::vec2 clipToScreenSpace(const glm::vec4& _clipCoords, const glm::vec2& _screenSize);
+
+/* Computes the screen coordinates from a world position, a model view matrix and a screen size */
+glm::vec2 worldToScreenSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition, const glm::vec2& _screenSize);
+glm::vec2 worldToScreenSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition, const glm::vec2& _screenSize, bool& clipped);
+
+glm::vec2 worldToScreenSpace(const glm::mat4& _mvp, const glm::vec4& _worldPosition, const glm::vec2& _screenSize, bool& _clipped);
+
+/* Computes the geometric center of the two dimensional region defined by the polygon */
+glm::vec2 centroid(const std::vector<std::vector<glm::vec3>>& _polygon);
+
+inline glm::vec2 rotateBy(const glm::vec2& _in, const glm::vec2& _normal) {
+    return {
+        _in.x * _normal.x + _in.y * _normal.y,
+        -_in.x * _normal.y + _in.y * _normal.x
+    };
+}
+
+float sqSegmentDistance(const glm::vec2& _p, const glm::vec2& _p1, const glm::vec2& _p2);
+
+bool isPowerOfTwo(int _value);
+
+float sqPointSegmentDistance(const glm::vec2& _p, const glm::vec2& _a, const glm::vec2& _b);
+float pointSegmentDistance(const glm::vec2& _p, const glm::vec2& _a, const glm::vec2& _b);
+
+}
diff --git a/core/src/util/hash.h b/core/src/util/hash.h
new file mode 100644 (file)
index 0000000..ad17c21
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <functional> // for hash function
+
+// The generic hash_combine used in Boost
+// http://www.boost.org/doc/libs/1_35_0/doc/html/boost/hash_combine_id241013.html
+template <class T>
+inline void hash_combine(std::size_t & seed, const T & v) {
+    std::hash<T> hasher;
+    seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
+}
+
diff --git a/core/src/util/inputHandler.cpp b/core/src/util/inputHandler.cpp
new file mode 100644 (file)
index 0000000..748d7a8
--- /dev/null
@@ -0,0 +1,176 @@
+#include "util/inputHandler.h"
+
+#include "platform.h"
+
+#include "glm/gtx/rotate_vector.hpp"
+#include "glm/vec2.hpp"
+#include <cmath>
+
+// Damping factor for translation; reciprocal of the decay period in seconds
+#define DAMPING_PAN 4.0f
+
+// Damping factor for zoom; reciprocal of the decay period in seconds
+#define DAMPING_ZOOM 6.0f
+
+// Minimum translation at which momentum should start (pixels per second)
+#define THRESHOLD_START_PAN 350.f
+
+// Minimum translation at which momentum should stop (pixels per second)
+#define THRESHOLD_STOP_PAN 24.f
+
+// Minimum zoom at which momentum should start (zoom levels per second)
+#define THRESHOLD_START_ZOOM 1.f
+
+// Minimum zoom at which momentum should stop (zoom levels per second)
+#define THRESHOLD_STOP_ZOOM 0.3f
+
+namespace Tangram {
+
+InputHandler::InputHandler(std::shared_ptr<Platform> _platform, View& _view) : m_platform(_platform), m_view(_view) {}
+
+void InputHandler::update(float _dt) {
+
+    auto velocityPanPixels = m_view.pixelsPerMeter() / m_view.pixelScale() * m_velocityPan;
+
+    bool isFlinging = glm::length(velocityPanPixels) > THRESHOLD_STOP_PAN ||
+                      std::abs(m_velocityZoom) > THRESHOLD_STOP_ZOOM;
+
+    if (isFlinging) {
+
+        m_velocityPan -= _dt * DAMPING_PAN * m_velocityPan;
+        m_view.translate(_dt * m_velocityPan.x, _dt * m_velocityPan.y);
+
+        m_velocityZoom -= _dt * DAMPING_ZOOM * m_velocityZoom;
+        m_view.zoom(m_velocityZoom * _dt);
+
+        m_platform->requestRender();
+    }
+}
+
+void InputHandler::handleTapGesture(float _posX, float _posY) {
+
+    onGesture();
+
+    float viewCenterX = 0.5f * m_view.getWidth();
+    float viewCenterY = 0.5f * m_view.getHeight();
+
+    m_view.screenToGroundPlane(viewCenterX, viewCenterY);
+    m_view.screenToGroundPlane(_posX, _posY);
+
+    m_view.translate((_posX - viewCenterX), (_posY - viewCenterY));
+
+}
+
+void InputHandler::handleDoubleTapGesture(float _posX, float _posY) {
+
+    handlePinchGesture(_posX, _posY, 2.f, 0.f);
+
+}
+
+void InputHandler::handlePanGesture(float _startX, float _startY, float _endX, float _endY) {
+
+    onGesture();
+
+    m_view.screenToGroundPlane(_startX, _startY);
+    m_view.screenToGroundPlane(_endX, _endY);
+
+    float dx = _startX - _endX;
+    float dy = _startY - _endY;
+
+    m_view.translate(dx, dy);
+
+}
+
+void InputHandler::handleFlingGesture(float _posX, float _posY, float _velocityX, float _velocityY) {
+
+    if (glm::length(glm::vec2(_velocityX, _velocityY)) / m_view.pixelScale() <= THRESHOLD_START_PAN) {
+        return;
+    }
+
+    const static float epsilon = 0.0167f;
+
+    onGesture();
+
+    float startX = _posX;
+    float startY = _posY;
+    float endX = _posX + epsilon * _velocityX;
+    float endY = _posY + epsilon * _velocityY;
+
+    m_view.screenToGroundPlane(startX, startY);
+    m_view.screenToGroundPlane(endX, endY);
+
+    float dx = (startX - endX) / epsilon;
+    float dy = (startY - endY) / epsilon;
+
+    setVelocity(0.f, glm::vec2(dx, dy));
+
+}
+
+void InputHandler::handlePinchGesture(float _posX, float _posY, float _scale, float _velocity) {
+
+    onGesture();
+
+    float z = m_view.getZoom();
+    static float invLog2 = 1 / log(2);
+    m_view.zoom(log(_scale) * invLog2);
+
+    m_view.screenToGroundPlane(_posX, _posY);
+    float s = pow(2, m_view.getZoom() - z) - 1;
+    m_view.translate(s * _posX, s * _posY);
+
+    // Take the derivative of zoom as a function of scale:
+    // z(s) = log2(s) + C
+    // z'(s) = s' / s / log(2)
+    float vz = _velocity / _scale * invLog2;
+    if (std::abs(vz) >= THRESHOLD_START_ZOOM) {
+        setVelocity(vz, glm::vec2(0.f));
+    }
+
+}
+
+void InputHandler::handleRotateGesture(float _posX, float _posY, float _radians) {
+
+    onGesture();
+
+    // Get vector from center of rotation to view center
+    m_view.screenToGroundPlane(_posX, _posY);
+    glm::vec2 offset(_posX, _posY);
+
+    // Rotate vector by gesture rotation and apply difference as translation
+    glm::vec2 translation = offset - glm::rotate(offset, _radians);
+    m_view.translate(translation.x, translation.y);
+
+    m_view.roll(_radians);
+
+}
+
+void InputHandler::handleShoveGesture(float _distance) {
+
+    onGesture();
+
+    float angle = -M_PI * _distance / m_view.getHeight();
+    m_view.pitch(angle);
+
+}
+
+void InputHandler::cancelFling() {
+
+    setVelocity(0.f, { 0.f, 0.f});
+
+}
+
+void InputHandler::onGesture() {
+
+    setVelocity(0.f, { 0.f, 0.f });
+    m_platform->requestRender();
+
+}
+
+void InputHandler::setVelocity(float _zoom, glm::vec2 _translate) {
+
+    // setup deltas for momentum on gesture
+    m_velocityPan = _translate;
+    m_velocityZoom = _zoom;
+}
+
+}
diff --git a/core/src/util/inputHandler.h b/core/src/util/inputHandler.h
new file mode 100644 (file)
index 0000000..4007fea
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "view/view.h"
+
+#include <bitset>
+#include <memory>
+
+namespace Tangram {
+
+class Platform;
+
+class InputHandler {
+
+public:
+    InputHandler(std::shared_ptr<Platform> _platform, View& _view);
+
+    void handleTapGesture(float _posX, float _posY);
+    void handleDoubleTapGesture(float _posX, float _posY);
+    void handlePanGesture(float _startX, float _startY, float _endX, float _endY);
+    void handleFlingGesture(float _posX, float _posY, float _velocityX, float _velocityY);
+    void handlePinchGesture(float _posX, float _posY, float _scale, float _velocity);
+    void handleRotateGesture(float _posX, float _posY, float _radians);
+    void handleShoveGesture(float _distance);
+
+    void update(float _dt);
+
+    void cancelFling();
+
+    void setView(View& _view) { m_view = _view; }
+
+private:
+
+    void setVelocity(float _zoom, glm::vec2 _pan);
+
+    void onGesture();
+
+    std::shared_ptr<Platform> m_platform;
+
+    View& m_view;
+
+    // fling deltas on zoom and translation
+    glm::vec2 m_velocityPan;
+    float m_velocityZoom = 0.f;
+
+};
+
+}
diff --git a/core/src/util/jobQueue.cpp b/core/src/util/jobQueue.cpp
new file mode 100644 (file)
index 0000000..ab487f2
--- /dev/null
@@ -0,0 +1,36 @@
+#include "util/jobQueue.h"
+
+namespace Tangram {
+
+JobQueue::~JobQueue() {
+
+    if (!m_jobs.empty()) {
+        runJobs();
+    }
+}
+
+void JobQueue::add(Job job) {
+
+    if (!m_stopped) {
+        std::lock_guard<std::mutex> lock(m_mutex);
+        m_jobs.push_back(job);
+    } else {
+        job();
+    }
+}
+
+void JobQueue::runJobs() {
+
+    for (size_t i = 0; i < m_jobs.size(); i++) {
+        Job job;
+        {
+            std::lock_guard<std::mutex> lock(m_mutex);
+            job.swap(m_jobs[i]);
+        }
+        job();
+    }
+    m_jobs.clear();
+
+}
+
+} //namespace Tangram
diff --git a/core/src/util/jobQueue.h b/core/src/util/jobQueue.h
new file mode 100644 (file)
index 0000000..efd8a0b
--- /dev/null
@@ -0,0 +1,39 @@
+#pragma once
+
+#include <functional>
+#include <mutex>
+#include <vector>
+
+namespace Tangram {
+
+// JobQueue allows you to queue a sequence of jobs to run later.
+// This is useful for OpenGL resources that must be created and destroyed on the GL thread.
+
+class JobQueue {
+
+public:
+    using Job = std::function<void()>;
+
+    JobQueue() = default;
+
+    // Any jobs left in the queue will be run in the destructor. This is thread-safe.
+    ~JobQueue();
+
+    // Put a job on the queue. This is thread-safe.
+    void add(Job job);
+
+    // Run all jobs on the queue in the order they were added, then remove them. This is thread-safe.
+    void runJobs();
+
+    void stop() {
+        m_stopped = true;
+        runJobs();
+    }
+private:
+
+    std::vector<Job> m_jobs;
+    std::mutex m_mutex;
+    bool m_stopped = false;
+};
+
+}
diff --git a/core/src/util/json.cpp b/core/src/util/json.cpp
new file mode 100644 (file)
index 0000000..579d2fe
--- /dev/null
@@ -0,0 +1,27 @@
+#include "util/json.h"
+
+#include "rapidjson/encodedstream.h"
+#include "rapidjson/error/en.h"
+#include "rapidjson/memorystream.h"
+
+namespace Tangram {
+
+    JsonDocument JsonParseBytes(const char* _bytes, size_t _length, const char** _error, size_t* _errorOffset) {
+
+        JsonDocument document;
+        rapidjson::MemoryStream mstream(_bytes, _length);
+        rapidjson::EncodedInputStream<rapidjson::UTF8<char>, rapidjson::MemoryStream> istream(mstream);
+        document.ParseStream(istream);
+
+        *_error = nullptr;
+        *_errorOffset = 0;
+        if (document.HasParseError()) {
+            *_error = rapidjson::GetParseError_En(document.GetParseError());
+            *_errorOffset = document.GetErrorOffset();
+        }
+
+        return document;
+
+    }
+
+}
diff --git a/core/src/util/json.h b/core/src/util/json.h
new file mode 100644 (file)
index 0000000..ef5083f
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include "rapidjson/document.h"
+
+namespace Tangram {
+
+    using JsonDocument = rapidjson::Document;
+    using JsonValue = rapidjson::Value;
+
+    JsonDocument JsonParseBytes(const char* _bytes, size_t _length, const char** _error, size_t* _errorOffset);
+
+}
diff --git a/core/src/util/lineSampler.h b/core/src/util/lineSampler.h
new file mode 100644 (file)
index 0000000..df1d39c
--- /dev/null
@@ -0,0 +1,202 @@
+#pragma once
+
+#include "glm/glm.hpp"
+
+namespace Tangram {
+
+template<typename Points>
+struct LineSampler {
+
+    template<typename T>
+    void set(std::vector<T> _points) {
+        m_points.clear();
+
+        if (_points.empty()) { return; }
+
+        glm::vec2 p = { _points[0].x, _points[0].y };
+
+        m_points.reserve(_points.size());
+        m_points.emplace_back(p, 0.f);
+
+        float sum = 0.f;
+
+        for (size_t i = 0; i < _points.size()-1; i++) {
+            glm::vec2 n = { _points[i+1].x, _points[i+1].y };
+            float d = glm::distance(p, n);
+            if (d > 0.f) {
+                sum += d;
+                m_points.push_back({n.x, n.y, sum});
+            }
+            p = n;
+        }
+        reset();
+    }
+
+    template<typename T>
+    bool add(T _point) {
+
+        glm::vec2 p = { _point.x, _point.y };
+
+        if (m_points.empty()) {
+            m_points.push_back(glm::vec3{p, 0.f});
+            return true;
+        }
+
+        size_t i = m_points.size()-1;
+
+        glm::vec2 prev = { m_points[i].x, m_points[i].y };
+        float d = glm::distance(prev, p);
+
+        if (d > 0.f) {
+            m_points.push_back(glm::vec3{p, m_points[i].z + d});
+            return true;
+        }
+        return false;
+    }
+
+    void clearPoints() {
+        m_points.clear();
+        reset();
+    }
+
+    void reset() {
+        m_curAdvance = 0.f;
+        m_curPoint = 0;
+    }
+
+    void reversePoints() {
+        float sum = sumLength();
+
+        std::reverse(m_points.begin(), m_points.end());
+        for (auto& p : m_points) { p.z = sum - p.z; }
+
+        m_curAdvance = 0.f;
+        m_curPoint = 0;
+    }
+
+    float sumLength() {
+        if (m_points.empty()) { return 0.f; }
+
+        return m_points[m_points.size()-1].z;
+    }
+
+    size_t curSegment() {
+        return m_curPoint;
+    }
+
+    glm::vec3 point(size_t _pos) {
+        return m_points[_pos];
+    }
+
+    float segmentLength(size_t _pos) {
+        if (_pos >= m_points.size()-1) { return 0; }
+
+        return (m_points[_pos+1].z - m_points[_pos].z);
+    }
+
+    glm::vec2 segmentDirection(size_t _pos) {
+        if (_pos >= m_points.size()-1) {
+            _pos = m_points.size()-2;
+        }
+
+        return ((glm::vec2(m_points[_pos+1]) - glm::vec2(m_points[_pos])) /
+                (m_points[_pos+1].z - m_points[_pos].z));
+    }
+
+
+    bool sample(float _offset, glm::vec2& _point, glm::vec2& _rotation) {
+        return advance(_offset - m_curAdvance, _point, _rotation);
+    }
+
+    bool advance(float _amount, glm::vec2& _point, glm::vec2& _rotation) {
+
+        if (m_curPoint >= m_points.size()-1) { return false; }
+
+        float end = m_curAdvance + _amount;
+
+        if (_amount > 0) {
+
+            while (true) {
+                const auto& curr = m_points[m_curPoint];
+                const auto& next = m_points[m_curPoint+1];
+
+                // needed length from cur point
+                float length = end - curr.z;
+                // length from cur to next point
+                float segmentLength = next.z - curr.z;
+
+                if (length <= segmentLength) {
+                    float f = length / segmentLength;
+
+                    _point = glm::vec2(curr) + (glm::vec2(next) - glm::vec2(curr)) * f;
+                    _rotation = (glm::vec2(next) - glm::vec2(curr)) / segmentLength;
+
+                    m_curAdvance = end;
+                    return true;
+
+                } else {
+                    if (m_curPoint >= m_points.size()-2) {
+                        _point = glm::vec2(next);
+                        _rotation = (glm::vec2(next) - glm::vec2(curr)) / segmentLength;
+                        m_curAdvance = sumLength();
+                        return false;
+                    }
+                    m_curPoint += 1;
+                }
+            }
+        } else {
+
+            while (true) {
+                const auto& curr = m_points[m_curPoint];
+                const auto& next = m_points[m_curPoint+1];
+
+                // needed length from cur point
+                float length = end - curr.z;
+
+                // length from cur to next point
+                float segmentLength = next.z - curr.z;
+
+                if (curr.z <= end) {
+                    float f = length / segmentLength;
+
+                    _point = glm::vec2(curr) + (glm::vec2(next) - glm::vec2(curr)) * f;
+                    _rotation = (glm::vec2(next) - glm::vec2(curr)) / segmentLength;
+
+                    m_curAdvance = end;
+                    return true;
+
+                } else {
+                    if (m_curPoint == 0) {
+                        _point = glm::vec2(curr);
+                        _rotation = (glm::vec2(next) - glm::vec2(curr)) / segmentLength;
+                        m_curAdvance = 0;
+                        return false;
+                    }
+                    m_curPoint -= 1;
+                }
+            }
+        }
+
+        return false;
+    }
+
+    float lengthToNextSegment() {
+        if (m_curPoint >= m_points.size()-1) { return 0; }
+        return m_points[m_curPoint + 1].z - m_curAdvance;
+    }
+    float lengthToPrevSegment() {
+        if (m_curPoint >= m_points.size()) { return 0; }
+        return m_curAdvance - m_points[m_curPoint].z;
+    }
+
+    LineSampler(Points _points) : m_points(_points) { }
+    LineSampler() { }
+
+private:
+    Points m_points;
+
+    size_t m_curPoint = 0;
+    float m_curAdvance = 0.f;
+};
+
+}
diff --git a/core/src/util/mapProjection.cpp b/core/src/util/mapProjection.cpp
new file mode 100644 (file)
index 0000000..44bf4b6
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Reference used for implementation: http://www.maptiler.org/google-maps-coordinates-tile-bounds-projection/
+ */
+
+#include "util/mapProjection.h"
+
+#include <cmath>
+
+namespace Tangram {
+
+MercatorProjection::MercatorProjection(int _tileSize) :
+    MapProjection(ProjectionType::mercator),
+    m_TileSize(_tileSize) {
+
+    double invTileSize = 1.0 / m_TileSize;
+    m_Res = 2.0 * HALF_CIRCUMFERENCE * invTileSize;
+}
+
+glm::dvec2 MercatorProjection::LonLatToMeters(const glm::dvec2 _lonLat) const {
+    glm::dvec2 meters;
+    meters.x = _lonLat.x * HALF_CIRCUMFERENCE * INV_180;
+    meters.y = log( tan( PI*0.25 + _lonLat.y * PI * INV_360));
+    meters.y = meters.y * (double)R_EARTH;
+    return (meters);
+}
+
+glm::dvec2 MercatorProjection::MetersToLonLat(const glm::dvec2 _meters) const {
+    glm::dvec2 lonLat;
+    double invHalfCircum = 1.0/HALF_CIRCUMFERENCE;
+    double invPI = 1.0/PI;
+    lonLat.x = _meters.x * invHalfCircum * 180.0;
+    lonLat.y = (2.0 * atan(exp( (_meters.y / R_EARTH ) )) - PI*0.5) * 180 * invPI;
+    return lonLat;
+}
+
+glm::dvec2 MercatorProjection::PixelsToMeters(const glm::dvec2 _pix, const int _zoom) const {
+    glm::dvec2 meters;
+    double res = m_Res / (1 << _zoom);
+    meters.x = _pix.x * res - HALF_CIRCUMFERENCE;
+    meters.y = _pix.y * res - HALF_CIRCUMFERENCE;
+    return meters;
+}
+
+glm::dvec2 MercatorProjection::MetersToPixel(const glm::dvec2 _meters, const int _zoom) const {
+    glm::dvec2 pix;
+    double invRes = (1 << _zoom) / m_Res;
+    pix.x = ( _meters.x + HALF_CIRCUMFERENCE ) * invRes;
+    pix.y = ( _meters.y + HALF_CIRCUMFERENCE ) * invRes;
+    return pix;
+}
+
+glm::ivec2 MercatorProjection::PixelsToTileXY(const glm::dvec2 _pix) const {
+    //returns the tile covering a region of a pixel
+    glm::ivec2 tileXY;
+    double invTileSize = 1.0/m_TileSize;
+    tileXY.x = int(ceil( _pix.x * invTileSize) - 1);
+    tileXY.y = int(ceil( _pix.y * invTileSize) - 1);
+    return tileXY;
+}
+
+glm::ivec2 MercatorProjection::MetersToTileXY(const glm::dvec2 _meters, const int _zoom) const {
+    glm::dvec2 pix;
+    glm::ivec2 tileXY;
+    pix = MetersToPixel(_meters, _zoom);
+    tileXY = PixelsToTileXY(pix);
+    return tileXY;
+}
+
+glm::dvec2 MercatorProjection::PixelsToRaster(const glm::dvec2 _pix, const int _zoom) const {
+    glm::dvec2 transformedPix;
+    double mapSize;
+    mapSize = m_TileSize << _zoom;
+    transformedPix = glm::dvec2(_pix.x, (mapSize - _pix.y));
+    return transformedPix;
+}
+
+BoundingBox MercatorProjection::TileBounds(const TileID _tileCoord) const {
+    return {
+        PixelsToMeters({
+                _tileCoord.x * m_TileSize,
+                _tileCoord.y * m_TileSize },
+            _tileCoord.z),
+        PixelsToMeters({
+                (_tileCoord.x + 1) * m_TileSize,
+                (_tileCoord.y + 1) * m_TileSize },
+            _tileCoord.z)
+    };
+}
+
+
+BoundingBox MercatorProjection::TileLonLatBounds(const TileID _tileCoord) const {
+    BoundingBox tileBounds(TileBounds(_tileCoord));
+    return {
+        MetersToLonLat(tileBounds.min),
+        MetersToLonLat(tileBounds.max)
+    };
+}
+
+glm::dvec2 MercatorProjection::TileCenter(const TileID _tileCoord) const {
+    return PixelsToMeters(glm::dvec2(_tileCoord.x*m_TileSize +m_TileSize*0.5,
+                                     (_tileCoord.y*m_TileSize+m_TileSize*0.5)),
+                          _tileCoord.z);
+}
+
+// Reference: https://en.wikipedia.org/wiki/Mercator_projection#Truncation_and_aspect_ratio
+BoundingBox MercatorProjection::MapLonLatBounds() const {
+    return { glm::dvec2(-180, -85.05113), glm::dvec2(180, 85.05113) } ;
+}
+
+BoundingBox MercatorProjection::MapBounds() const {
+    BoundingBox bound = MapLonLatBounds();
+    return { LonLatToMeters(bound.min), LonLatToMeters(bound.max) };
+}
+
+double MercatorProjection::TileSize() const { return m_TileSize; }
+
+}
diff --git a/core/src/util/mapProjection.h b/core/src/util/mapProjection.h
new file mode 100644 (file)
index 0000000..a5e936a
--- /dev/null
@@ -0,0 +1,179 @@
+#pragma once
+
+//Define global constants
+#define R_EARTH 6378137.0
+
+#include "tile/tileID.h"
+#include "util/geom.h"
+
+namespace Tangram {
+
+enum class ProjectionType {
+    mercator
+};
+
+class MapProjection {
+protected:
+    /* m_type: type of map projection: example: mercator*/
+    ProjectionType m_type;
+public:
+    constexpr static double INV_360 = 1.0/360.0;
+    constexpr static double INV_180 = 1.0/180.0;
+    constexpr static double HALF_CIRCUMFERENCE = PI * R_EARTH;
+    /*
+     * 256 is default tile size
+     */
+    MapProjection(ProjectionType _type) : m_type(_type) {};
+
+    /*
+     * LonLat to ProjectionType-Meter
+     * Arguments:
+     *   _lonlat: glm::dvec2 having lon and lat info
+     * Return value:
+     *    meter (glm::dvec2).
+     */
+    virtual glm::dvec2 LonLatToMeters(const glm::dvec2 _lonLat) const = 0;
+
+    /*
+     * ProjectionType-Meters to Lon Lat
+     *  Arguments:
+     *    _meter: glm::dvec2 having the projection units in meters
+     *  Return value:
+     *    lonlat (glm::dvec2)
+     */
+    virtual glm::dvec2 MetersToLonLat(const glm::dvec2 _meters) const = 0;
+
+    /*
+     * Converts a pixel coordinate at a given zoom level of pyramid to projection meters
+     * Screen pixels to Meters
+     *  Arguments:
+     *    _pix: pixels defined as glm::dvec2
+     *    _zoom: zoom level to determine the projection-meters
+     *  Return value:
+     *    projection-meters (glm::dvec2)
+     */
+    virtual glm::dvec2 PixelsToMeters(const glm::dvec2 _pix, const int _zoom) const = 0;
+
+    /*
+     * Converts projection meters to pyramid pixel coordinates in given zoom level.
+     * Meters to Screen Pixels
+     * Arguments:
+     *   _meters: projection-meters (glm::dvec2)
+     *   _zoom: zoom level to determine pixels
+     * Return Value:
+     *   pixels (glm::dvec2)
+     */
+    virtual glm::dvec2 MetersToPixel(const glm::dvec2 _meters, const int _zoom) const = 0;
+
+    /*
+     * Returns a tile covering region in given pixel coordinates.
+     * Argument:
+     *   _pix: pixel
+     * Return Value:
+     *   Tile coordinates (x and y) glm::ivec2
+     */
+    virtual glm::ivec2 PixelsToTileXY(const glm::dvec2 _pix) const = 0;
+
+    /*
+     * Returns tile for given projection coordinates.
+     *  Arguments:
+     *    _meters: projection-meters (glm::dvec2)
+     *    _zoom: zoom level for which tile coordinates need to be determined
+     *  Return Value:
+     *    Tile coordinates (x and y) (glm::ivec2)
+     */
+    virtual glm::ivec2 MetersToTileXY(const glm::dvec2 _meters, const int _zoom) const = 0;
+
+    /*
+     * Move the origin of pixel coordinates to top-left corner
+     * Arguments:
+     *   _pix: pixels
+     *   _zoom: zoom level
+     * Return Value:
+     *   glm::dvec2 newPixels at top-left corner
+     */
+    virtual glm::dvec2 PixelsToRaster(const glm::dvec2 _pix, const int _zoom) const = 0;
+
+    /*
+     * Returns bounds of the given tile
+     *  Arguments:
+     *    _tileCoord: glm::ivec3 (x,y and zoom)
+     *  Return value:
+     *    bounds in projection-meters (BoundingBox)
+     */
+    virtual BoundingBox TileBounds(const TileID _tileCoord) const = 0;
+
+    /*
+     * bounds of space in lon lat
+     *  Arguments:
+     *    _tileCoord: glm::ivec3 (x,y and zoom)
+     *  Return value:
+     *    bounds in lon lat (BoundingBox)
+     */
+    virtual BoundingBox TileLonLatBounds(const TileID _tileCoord) const = 0;
+
+    /*
+     * Returns center of the given tile
+     *  Arguments:
+     *    _tileCoord: glm::ivec3 (x,y and zoom)
+     *  Return value:
+     *    center in projection-meters (glm::dvec2)
+     *       x,y : position in projection meters
+     */
+    virtual glm::dvec2 TileCenter(const TileID _tileCoord) const = 0;
+
+    /*
+     * Returns the bounds (projection units) of the map per the map projection
+     */
+    virtual BoundingBox MapBounds() const = 0;
+
+    /*
+     * Returns the bounds (lon, lat) of the map per the map projection
+     */
+    virtual BoundingBox MapLonLatBounds() const = 0;
+
+    /*
+     * Returns the projection type of a given projection instance
+     *   (example: ProjectionType::Mercator)
+     */
+    virtual ProjectionType GetMapProjectionType() const {return m_type;}
+
+    virtual double TileSize() const = 0;
+
+    virtual ~MapProjection() {}
+};
+
+class MercatorProjection : public MapProjection {
+    /*
+     * Following define the boundry covered by this mercator projection
+     */
+    int m_TileSize;
+    double m_Res;
+
+public:
+    /*
+     * Constructor for MercatorProjection
+     * _type: type of map projection, example ProjectionType::Mercator
+     * _tileSize: size of the map tile, default is 256
+     */
+    MercatorProjection(int  _tileSize=256);
+
+    virtual glm::dvec2 LonLatToMeters(const glm::dvec2 _lonLat) const override;
+    virtual glm::dvec2 MetersToLonLat(const glm::dvec2 _meters) const override;
+    virtual glm::dvec2 PixelsToMeters(const glm::dvec2 _pix, const int _zoom) const override;
+    virtual glm::dvec2 MetersToPixel(const glm::dvec2 _meters, const int _zoom) const override;
+    virtual glm::ivec2 PixelsToTileXY(const glm::dvec2 _pix) const override;
+    virtual glm::ivec2 MetersToTileXY(const glm::dvec2 _meters, const int _zoom) const override;
+    virtual glm::dvec2 PixelsToRaster(const glm::dvec2 _pix, const int _zoom) const override;
+    virtual BoundingBox TileBounds(const TileID _tileCoord) const override;
+    virtual BoundingBox TileLonLatBounds(const TileID _tileCoord) const override;
+    virtual glm::dvec2 TileCenter(const TileID _tileCoord) const override;
+    /* Map Bounds for mercator projection */
+    virtual BoundingBox MapBounds() const override;
+    virtual BoundingBox MapLonLatBounds() const override;
+    virtual double TileSize() const override;
+
+    virtual ~MercatorProjection() {}
+};
+
+}
diff --git a/core/src/util/rasterize.cpp b/core/src/util/rasterize.cpp
new file mode 100644 (file)
index 0000000..650fd6b
--- /dev/null
@@ -0,0 +1,67 @@
+#include "util/rasterize.h"
+
+namespace Tangram {
+namespace Rasterize {
+
+// Triangle rasterization adapted from Polymaps: https://github.com/simplegeo/polymaps/blob/master/src/Layer.js#L333-L383
+
+Edge::Edge(glm::dvec2 _a, glm::dvec2 _b) {
+    if (_a.y > _b.y) { std::swap(_a, _b); }
+    x0 = _a.x;
+    y0 = _a.y;
+    x1 = _b.x;
+    y1 = _b.y;
+    dx = x1 - x0;
+    dy = y1 - y0;
+}
+
+void scanLine(int _x0, int _x1, int _y, const ScanCallback& _s) {
+    for (int x = _x0; x < _x1; x++) {
+        _s(x, _y);
+    }
+}
+
+void scanSpan(Edge _e0, Edge _e1, int _min, int _max, const ScanCallback& _s) {
+
+    // _e1 has a shorter y-span, so we'll use it to limit our y coverage
+    int y0 = fmax(_min, floor(_e1.y0));
+    int y1 = fmin(_max, ceil(_e1.y1));
+
+    // sort edges by x-coordinate
+    if (_e0.x0 == _e1.x0 && _e0.y0 == _e1.y0) {
+        if (_e0.x0 + _e1.dy / _e0.dy * _e0.dx < _e1.x1) { std::swap(_e0, _e1); }
+    } else {
+        if (_e0.x1 - _e1.dy / _e0.dy * _e0.dx < _e1.x0) { std::swap(_e0, _e1); }
+    }
+
+    // scan lines!
+    double m0 = _e0.dx / _e0.dy;
+    double m1 = _e1.dx / _e1.dy;
+    double d0 = _e0.dx > 0 ? 1.0 : 0.0;
+    double d1 = _e1.dx < 0 ? 1.0 : 0.0;
+    for (int y = y0; y < y1; y++) {
+        double x0 = m0 * fmax(0.0, fmin(_e0.dy, y + d0 - _e0.y0)) + _e0.x0;
+        double x1 = m1 * fmax(0.0, fmin(_e1.dy, y + d1 - _e1.y0)) + _e1.x0;
+        scanLine(floor(x1), ceil(x0), y, _s);
+    }
+
+}
+
+void scanTriangle(glm::dvec2& _a, glm::dvec2& _b, glm::dvec2& _c, int _min, int _max, const ScanCallback& _s) {
+
+    Edge ab = Edge(_a, _b);
+    Edge bc = Edge(_b, _c);
+    Edge ca = Edge(_c, _a);
+
+    // place edge with greatest y distance in ca
+    if (ab.dy > ca.dy) { std::swap(ab, ca); }
+    if (bc.dy > ca.dy) { std::swap(bc, ca); }
+
+    // scan span! scan span!
+    if (ab.dy > 0) { scanSpan(ca, ab, _min, _max, _s); }
+    if (bc.dy > 0) { scanSpan(ca, bc, _min, _max, _s); }
+
+}
+
+}
+}
diff --git a/core/src/util/rasterize.h b/core/src/util/rasterize.h
new file mode 100644 (file)
index 0000000..4a3812a
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "glm/vec2.hpp"
+#include <cmath>
+#include <functional>
+
+namespace Tangram {
+namespace Rasterize {
+
+using ScanCallback = std::function<void (int, int)>;
+
+struct Edge { // An edge between two points; oriented such that y is non-decreasing
+    double x0 = 0, y0 = 0;
+    double x1 = 0, y1 = 0;
+    double dx = 0, dy = 0;
+    Edge(glm::dvec2 _a, glm::dvec2 _b);
+};
+
+void scanLine(int _x0, int _x1, int _y, const ScanCallback& _s);
+
+void scanSpan(Edge _e0, Edge _e1, int _min, int _max, const ScanCallback& _s);
+
+void scanTriangle(glm::dvec2& _a, glm::dvec2& _b, glm::dvec2& _c, int _min, int _max, const ScanCallback& _s);
+
+}
+}
diff --git a/core/src/util/topologicalSort.h b/core/src/util/topologicalSort.h
new file mode 100644 (file)
index 0000000..1e6e5ea
--- /dev/null
@@ -0,0 +1,72 @@
+#pragma once\r
+\r
+#include <algorithm>\r
+#include <unordered_map>\r
+#include <utility>\r
+#include <vector>\r
+\r
+namespace Tangram {\r
+\r
+/**\r
+ * Given a list of edges describing a directed acyclic graph, returns a\r
+ * list of nodes sorted in topological order; that is, if there is a path\r
+ * from node 'a' to node 'b' in the graph, then 'a' will always precede\r
+ * 'b' in the sorted result.\r
+ */\r
+template<typename T>\r
+std::vector<T> topologicalSort(std::vector<std::pair<T, T>> edges) {\r
+\r
+    // Produce a sorted list of nodes using Kahn's algorithm.\r
+    std::vector<T> sorted;\r
+\r
+    // Loop over input edges, counting the incoming edges for each node.\r
+    std::unordered_map<T, size_t> incoming_edges;\r
+    for (const auto& edge : edges) {\r
+        incoming_edges[edge.first];\r
+        ++incoming_edges[edge.second];\r
+    }\r
+\r
+    // Find the set of starting nodes that have no incoming edges.\r
+    std::vector<T> start_nodes;\r
+    for (const auto& node : incoming_edges) {\r
+        if (node.second == 0) {\r
+            start_nodes.push_back(node.first);\r
+        }\r
+    }\r
+\r
+    while (!start_nodes.empty()) {\r
+        // Choose a node 'n' from the set of starting nodes and remove it.\r
+        auto n = start_nodes.back();\r
+        start_nodes.pop_back();\r
+\r
+        // Add the value of 'n' to the sorted list.\r
+        sorted.push_back(n);\r
+\r
+        // For each node 'm' with an edge 'e' from 'n' to 'm' ...\r
+        for (auto it = edges.begin(); it != edges.end(); ) {\r
+            auto e = *it;\r
+            if (e.first == n) {\r
+                auto m = e.second;\r
+                // ... remove edge 'e' from the graph.\r
+                it = edges.erase(it);\r
+                // If 'm' has no more incoming edges,\r
+                // add it to the set of starting nodes.\r
+                if (--incoming_edges[m] == 0) {\r
+                    start_nodes.push_back(m);\r
+                }\r
+            } else {\r
+                ++it;\r
+            }\r
+        }\r
+    }\r
+\r
+    if (!edges.empty()) {\r
+        // Graph has cycles! This is an error.\r
+        return {};\r
+    }\r
+\r
+    return sorted;\r
+\r
+}\r
+\r
+}\r
diff --git a/core/src/util/url.cpp b/core/src/util/url.cpp
new file mode 100644 (file)
index 0000000..0b64293
--- /dev/null
@@ -0,0 +1,525 @@
+#include "util/url.h"
+
+#include <cstdlib>
+#include <cassert>
+
+namespace Tangram {
+
+Url::Url() {}
+
+Url::Url(const std::string& source) :
+    buffer(source) {
+    parse();
+}
+
+Url::Url(std::string&& source) :
+    buffer(source) {
+    parse();
+}
+
+Url::Url(const char* source) :
+    buffer(source) {
+    parse();
+}
+
+Url::Url(const Url& other) :
+    buffer(other.buffer),
+    parts(other.parts),
+    flags(other.flags) {
+}
+
+Url::Url(Url&& other) :
+    buffer(std::move(other.buffer)),
+    parts(other.parts),
+    flags(other.flags) {
+}
+
+Url& Url::operator=(const Url& other) {
+    buffer = other.buffer;
+    parts = other.parts;
+    flags = other.flags;
+    return *this;
+}
+
+Url& Url::operator=(Url&& other) {
+    buffer = std::move(other.buffer);
+    parts = other.parts;
+    flags = other.flags;
+    return *this;
+}
+
+bool Url::operator==(const Url& rhs) const {
+    return buffer == rhs.buffer;
+}
+
+bool Url::isEmpty() const {
+    return buffer.empty();
+}
+
+bool Url::isAbsolute() const {
+    return (flags & IS_ABSOLUTE);
+}
+
+bool Url::isStandardized() const {
+    return (flags & IS_STANDARDIZED);
+}
+
+bool Url::hasHttpScheme() const {
+    return (flags & HAS_HTTP_SCHEME);
+}
+
+bool Url::hasFileScheme() const {
+    return (flags & HAS_FILE_SCHEME);
+}
+
+bool Url::hasDataScheme() const {
+    return (flags & HAS_DATA_SCHEME);
+}
+
+bool Url::hasBase64Data() const {
+    return (flags & HAS_BASE64_DATA);
+}
+
+bool Url::hasScheme() const {
+    return parts.scheme.count != 0;
+}
+
+bool Url::hasNetLocation() const {
+    return parts.location.count != 0;
+}
+
+bool Url::hasPath() const {
+    return parts.path.count != 0;
+}
+
+bool Url::hasParameters() const {
+    return parts.parameters.count != 0;
+}
+
+bool Url::hasQuery() const {
+    return parts.query.count != 0;
+}
+
+bool Url::hasFragment() const {
+    return parts.fragment.count != 0;
+}
+
+bool Url::hasMediaType() const {
+    return parts.media.count != 0;
+}
+
+bool Url::hasData() const {
+    return parts.data.count != 0;
+}
+
+std::string Url::scheme() const {
+    return std::string(buffer, parts.scheme.start, parts.scheme.count);
+}
+
+std::string Url::netLocation() const {
+    return std::string(buffer, parts.location.start, parts.location.count);
+}
+
+std::string Url::path() const {
+    return std::string(buffer, parts.path.start, parts.path.count);
+}
+
+std::string Url::parameters() const {
+    return std::string(buffer, parts.parameters.start, parts.parameters.count);
+}
+
+std::string Url::query() const {
+    return std::string(buffer, parts.query.start, parts.query.count);
+}
+
+std::string Url::fragment() const {
+    return std::string(buffer, parts.fragment.start, parts.fragment.count);
+}
+
+std::string Url::mediaType() const {
+    return std::string(buffer, parts.media.start, parts.media.count);
+}
+
+std::string Url::data() const {
+    return std::string(buffer, parts.data.start, parts.data.count);
+}
+
+const std::string& Url::string() const {
+    return buffer;
+}
+
+Url Url::standardized() const {
+
+    // If this URL is already standardized, return a copy.
+    if (isStandardized()) {
+        return *this;
+    }
+
+    // If this is a data URI, return a copy.
+    if (hasDataScheme()) {
+        return *this;
+    }
+
+    // Create the target URL by copying this URL.
+    Url t(*this);
+
+    // Remove any dot segments from the path.
+    size_t count = removeDotSegmentsFromRange(t.buffer, t.parts.path.start, t.parts.path.count);
+
+    if (count != t.parts.path.count) {
+
+        // The new path should always be the same size or shorter.
+        assert(count < t.parts.path.count);
+        size_t offset = t.parts.path.count - count;
+
+        // Adjust the size of the 'path' part.
+        t.parts.path.count = count;
+
+        // Remove any extra parts of the old path from the string.
+        t.buffer.erase(t.parts.path.start + t.parts.path.count, offset);
+
+        // Adjust the locations of the URL parts after 'path'.
+        t.parts.parameters.start -= offset;
+        t.parts.query.start -= offset;
+        t.parts.fragment.start -= offset;
+    }
+
+    // Set the standardized flag.
+    t.flags |= IS_STANDARDIZED;
+
+    return t;
+}
+
+Url Url::resolved(const Url& base) const {
+    return resolve(base, *this);
+}
+
+Url Url::resolve(const Url& b, const Url& r) {
+    // https://tools.ietf.org/html/rfc1808#section-4
+    // https://tools.ietf.org/html/rfc3986#section-5.2
+
+    // If the base URL is empty or the relative URL is already absolute, return the relative URL.
+    // This includes the case where the relative URL is a data URI.
+    if (r.isAbsolute() || b.isEmpty()) {
+        return r.standardized();
+    }
+
+    // If the relative URL is empty, return the base URL.
+    if (r.isEmpty()) {
+        return b;
+    }
+
+    // Start composing the new target URL.
+    Url t;
+
+    // Take the scheme from the base URL.
+    if (b.hasScheme()) {
+        t.parts.scheme = b.parts.scheme;
+        t.buffer.append(b.buffer, b.parts.scheme.start, b.parts.scheme.count);
+        t.buffer.append("://");
+    }
+
+    // Resolve the netLocation.
+    t.parts.location.start = t.buffer.size();
+    if (r.hasNetLocation()) {
+        // If the relative URL has a netLocation, use it for the new URL.
+        t.buffer.append(r.buffer, r.parts.location.start, r.parts.location.count);
+    } else {
+        // Use the netLocation of the base in the new URL.
+        t.buffer.append(b.buffer, b.parts.location.start, b.parts.location.count);
+    }
+    t.parts.location.count = t.buffer.size() - t.parts.location.start;
+
+    // Resolve the path.
+    t.parts.path.start = t.buffer.size();
+    if (r.hasNetLocation()) {
+        // If the relative URL has a netLocation, use its path as well.
+        t.buffer.append(r.buffer, r.parts.path.start, r.parts.path.count);
+    } else if (r.hasPath()) {
+        // If the relative URL's path starts with '/', it is absolute.
+        if (r.buffer[r.parts.path.start] == '/') {
+            t.buffer.append(r.buffer, r.parts.path.start, r.parts.path.count);
+        } else {
+            // Merge the relative path with the base path.
+            if (b.hasNetLocation() && !b.hasPath()) {
+                t.buffer += '/';
+                t.buffer.append(r.buffer, r.parts.path.start, r.parts.path.count);
+            } else {
+                // Add the base URL's path.
+                t.buffer.append(b.buffer, b.parts.path.start, b.parts.path.count);
+                // Remove the last segment of the base URL's path, up to the last '/'.
+                while (!t.buffer.empty() && t.buffer.back() != '/') { t.buffer.pop_back(); }
+                // Add the relative URL's path.
+                t.buffer.append(r.buffer, r.parts.path.start, r.parts.path.count);
+            }
+        }
+    } else {
+        // If the relative URL has no netLocation or path, use the base URL's path.
+        t.buffer.append(b.buffer, b.parts.path.start, b.parts.path.count);
+    }
+    t.parts.path.count = t.buffer.size() - t.parts.path.start;
+
+    // Remove dot segments from the resolved path.
+    t.parts.path.count = removeDotSegmentsFromRange(t.buffer, t.parts.path.start, t.parts.path.count);
+    t.buffer.resize(t.parts.path.start + t.parts.path.count);
+
+    // Resolve the parameters.
+    t.parts.parameters.start = t.buffer.size();
+    if (r.hasParameters()) {
+        // If the relative URL has parameters, use it in the new URL.
+        t.buffer += ';';
+        t.parts.parameters.start += 1;
+        t.parts.parameters.count = r.parts.parameters.count;
+        t.buffer.append(r.buffer, r.parts.parameters.start, r.parts.parameters.count);
+    } else if (b.hasParameters() && !(r.hasNetLocation() || r.hasPath())) {
+        // Use the base URL parameters.
+        t.buffer += ';';
+        t.parts.parameters.start += 1;
+        t.parts.parameters.count = b.parts.parameters.count;
+        t.buffer.append(b.buffer, b.parts.parameters.start, b.parts.parameters.count);
+    }
+    t.parts.parameters.count = t.buffer.size() - t.parts.parameters.start;
+
+    // Resolve the query.
+    t.parts.query.start = t.buffer.size();
+    if (r.hasQuery()) {
+        // If this URL has a query, use it in the new URL.
+        t.buffer += '?';
+        t.parts.query.start += 1;
+        t.buffer.append(r.buffer, r.parts.query.start, r.parts.query.count);
+    } else if (b.hasQuery() && !(r.hasNetLocation() || r.hasPath() || r.hasParameters())) {
+        // Use the base URL query.
+        t.buffer += '?';
+        t.parts.query.start += 1;
+        t.buffer.append(b.buffer, b.parts.query.start, b.parts.query.count);
+    }
+    t.parts.query.count = t.buffer.size() - t.parts.query.start;
+
+    // Use the fragment from the relative URL.
+    t.parts.fragment.start = t.buffer.size();
+    if (r.hasFragment()) {
+        t.buffer += '#';
+        t.parts.fragment.start += 1;
+        t.buffer.append(r.buffer, r.parts.fragment.start, r.parts.fragment.count);
+    }
+    t.parts.fragment.count = t.buffer.size() - t.parts.fragment.start;
+
+    // Flags can be copied from the base URL.
+    t.flags = b.flags;
+
+    // The path had dot segments removed, so we can set the standardized flag.
+    t.flags |= IS_STANDARDIZED;
+
+    return t;
+}
+
+std::string Url::removeDotSegmentsFromString(std::string path) {
+    auto count = removeDotSegmentsFromRange(path, 0, path.size());
+    path.resize(count);
+    return path;
+}
+
+void Url::parse() {
+
+    // The parsing process roughly follows https://tools.ietf.org/html/rfc1808#section-2.4
+
+    size_t start = 0;
+    size_t end = buffer.size();
+
+    // Parse the fragment.
+    {
+        // If there's a '#' in the string, the substring after it to the end is the fragment.
+        auto pound = std::min(buffer.find('#', start), end);
+        parts.fragment.start = std::min(pound + 1, end);
+        parts.fragment.count = end - parts.fragment.start;
+
+        // Remove the '#' and fragment from parsing.
+        end = pound;
+    }
+
+    // Parse the scheme.
+    {
+        size_t i = start;
+        auto c = buffer[i];
+
+        // A scheme is permitted to contain only alphanumeric characters, '+', '.', and '-'.
+        while (i < end && (isalnum(c) || c == '+' || c == '.' || c == '-')) {
+            c = buffer[++i];
+        }
+
+        // If a scheme is present, it must be followed by a ':'.
+        if (c == ':') {
+            parts.scheme.start = start;
+            parts.scheme.count = i - start;
+
+            // Remove the scheme and ':' from parsing.
+            start = i + 1;
+
+            // Set the absolute URL flag.
+            flags |= IS_ABSOLUTE;
+        }
+    }
+
+    // If scheme is 'data', parse as data URI.
+    if (buffer.compare(parts.scheme.start, parts.scheme.count, "data") == 0) {
+
+        // Set the data scheme flag.
+        flags |= HAS_DATA_SCHEME;
+
+        // A data scheme will be followed by a media type, then either a comma or a base 64 indicator string.
+        auto base64Indicator = std::min(buffer.find(";base64", start), end);
+        auto comma = std::min(buffer.find(',', start), end);
+
+        // If the base 64 indicator string is found before the comma, set the matching flag.
+        if (base64Indicator < comma) {
+            flags |= HAS_BASE64_DATA;
+        }
+
+        // The media type goes from the colon after the scheme up to either the comma or the base 64 string.
+        parts.media.start = start;
+        parts.media.count = std::min(base64Indicator, comma) - start;
+
+        // The data section is separated by a comma and goes to the end of the URI.
+        start = std::min(comma + 1, end);
+        parts.data.start = start;
+        parts.data.count = end - start;
+
+        // We're done!
+        return;
+    }
+
+    // Check whether the scheme is 'http', 'https', or 'file' and set appropriate flags.
+    if (buffer.compare(parts.scheme.start, parts.scheme.count, "http") == 0 ||
+        buffer.compare(parts.scheme.start, parts.scheme.count, "https") == 0) {
+        flags |= HAS_HTTP_SCHEME;
+    } else if (buffer.compare(parts.scheme.start, parts.scheme.count, "file") == 0) {
+        flags |= HAS_FILE_SCHEME;
+    }
+
+    // If '//' is next in the string, then the substring up to the following '/' is the network location.
+    if (buffer.compare(start, 2, "//") == 0) {
+        start += 2;
+        auto slash = std::min(buffer.find('/', start), end);
+        parts.location.start = start;
+        parts.location.count = slash - start;
+
+        // Remove the network location from parsing.
+        start = slash;
+    }
+
+    // Parse the query.
+    {
+        // If there's a '?' in the remaining string, the substring after it to the end is the query string.
+        auto qmark = std::min(buffer.find('?', start), end);
+        parts.query.start = std::min(qmark + 1, end);
+        parts.query.count = end - parts.query.start;
+
+        // Remove the '?' and query from parsing.
+        end = qmark;
+    }
+
+    // Parse the parameters.
+    {
+        // If there's a ';' in the remaining string, the substring after it to the end is the parameters string.
+        auto semicolon = std::min(buffer.find(';', start), end);
+        parts.parameters.start = std::min(semicolon + 1, end);
+        parts.parameters.count = end - parts.parameters.start;
+
+        // Remove the ';' and parameters from parsing.
+        end = semicolon;
+    }
+
+    // Parse the path. After the preceding steps, the remaining string is the URL path.
+    parts.path.start = start;
+    parts.path.count = end - start;
+}
+
+size_t Url::removeLastSegmentFromRange(std::string& string, size_t start, size_t end) {
+    if (start >= end) { return start; }
+    size_t pos = end - 1;
+    while (pos > start && string[pos] != '/') { pos--; }
+    return pos;
+}
+
+size_t Url::removeDotSegmentsFromRange(std::string& str, size_t start, size_t count) {
+
+    // Implements https://tools.ietf.org/html/rfc3986#section-5.2.4
+    // with in-place manipulation instead of making a new buffer.
+
+    size_t end = start + count;
+    size_t pos = start; // 'input' position.
+    size_t out = pos; // 'output' position.
+
+    while (pos < end) {
+        if (pos + 2 < end &&
+                   str[pos] == '.' &&
+                   str[pos + 1] == '.' &&
+                   str[pos + 2] == '/') {
+            pos += 3;
+        } else if (pos + 1 < end &&
+                   str[pos] == '.' &&
+                   str[pos + 1] == '/') {
+            pos += 2;
+        } else if (pos + 2 < end &&
+                   str[pos] == '/' &&
+                   str[pos + 1] == '.' &&
+                   str[pos + 2] == '/') {
+            pos += 2;
+        } else if (pos + 2 == end &&
+                   str[pos] == '/' &&
+                   str[pos + 1] == '.') {
+            pos += 1;
+            str[pos] = '/';
+        } else if (pos + 3 < end &&
+                   str[pos] == '/' &&
+                   str[pos + 1] == '.' &&
+                   str[pos + 2] == '.' &&
+                   str[pos + 3] == '/') {
+            pos += 3;
+            out = removeLastSegmentFromRange(str, start, out);
+        } else if (pos + 3 == end &&
+                   str[pos] == '/' &&
+                   str[pos + 1] == '.' &&
+                   str[pos + 2] == '.') {
+            pos += 3;
+            out = removeLastSegmentFromRange(str, start, out);
+        } else if (pos + 1 == end &&
+                   str[pos] == '.') {
+            pos += 1;
+        } else if (pos + 2 == end &&
+                   str[pos] == '.' &&
+                   str[pos + 1] == '.') {
+            pos += 2;
+        } else {
+            do {
+                str[out++] = str[pos++];
+            } while (pos < end && str[pos] != '/');
+        }
+    }
+
+    return out - start;
+}
+
+std::string Url::getPathExtension(const std::string& path) {
+    std::string ext;
+
+    // Isolate the last segment of the path.
+    auto lastPathSegment = path.rfind('/');
+    if (lastPathSegment == std::string::npos) {
+        // If path has no delimiters, the whole path is the last segment.
+        lastPathSegment = 0;
+    }
+
+    // Find the last extension delimiter in the last segment.
+    auto lastDotPos = path.rfind('.');
+    if (lastDotPos != std::string::npos && lastDotPos > lastPathSegment + 1) {
+        // If an extension delimiter is found within the last segment, but not
+        // at its start, then the extension is the string between this delimiter
+        // and the end of the path.
+        ext = path.substr(lastDotPos + 1);
+    }
+
+    return ext;
+}
+
+} // namespace Tangram
diff --git a/core/src/util/util.h b/core/src/util/util.h
new file mode 100644 (file)
index 0000000..1153a78
--- /dev/null
@@ -0,0 +1,33 @@
+#pragma once
+
+#include <sstream>
+#include <string>
+#include <vector>
+
+namespace Tangram {
+
+inline std::vector<std::string> splitString(const std::string& s, char delim) {
+    std::vector<std::string> elems;
+    std::stringstream ss(s);
+    std::string item;
+
+    while (std::getline(ss, item, delim)) {
+        elems.push_back(item);
+    }
+
+    return elems;
+}
+
+template <class M, class T>
+inline bool tryFind(M& map, const std::string& key, T& out) {
+    auto it = map.find(key);
+
+    if (it != map.end()) {
+        out = it->second;
+        return true;
+    }
+
+    return false;
+}
+
+}
diff --git a/core/src/util/yamlHelper.cpp b/core/src/util/yamlHelper.cpp
new file mode 100644 (file)
index 0000000..c257dfb
--- /dev/null
@@ -0,0 +1,145 @@
+#include "util/yamlHelper.h"
+
+#include "util/floatFormatter.h"
+#include "log.h"
+#include "csscolorparser.hpp"
+
+#define MAP_DELIM '.'
+#define SEQ_DELIM '#'
+
+namespace Tangram {
+
+YamlPath YamlPathBuffer::toYamlPath() {
+    size_t length = 0;
+
+    for(auto& element : m_path) {
+        if (element.key) {
+            length += element.key->length()+1;
+        } else {
+            int c = 1;
+            while (element.index >= pow(10, c)) { c += 1; }
+            length += c + 1;
+        }
+    }
+    std::string path;
+    path.reserve(length);
+
+    for(auto& element : m_path) {
+        if (element.key) {
+            if (!path.empty()) { path += '.'; }
+            path += *element.key;
+        } else {
+            path += '#';
+            path += std::to_string(element.index);
+        }
+    }
+    return YamlPath(path);
+}
+
+YamlPath::YamlPath() {}
+
+YamlPath::YamlPath(const std::string& path)
+    : codedPath(path) {}
+
+YamlPath YamlPath::add(int index) {
+    return YamlPath(codedPath + SEQ_DELIM + std::to_string(index));
+}
+
+YamlPath YamlPath::add(const std::string& key) {
+    if (codedPath.empty()) { return YamlPath(key); }
+    return YamlPath(codedPath + MAP_DELIM + key);
+}
+
+YAML::Node YamlPath::get(YAML::Node node) {
+    size_t beginToken = 0, endToken = 0, pathSize = codedPath.size();
+    auto delimiter = MAP_DELIM; // First token must be a map key.
+    while (endToken < pathSize) {
+        beginToken = endToken;
+        endToken = pathSize;
+        endToken = std::min(endToken, codedPath.find(SEQ_DELIM, beginToken));
+        endToken = std::min(endToken, codedPath.find(MAP_DELIM, beginToken));
+        if (delimiter == SEQ_DELIM) {
+            int index = std::stoi(&codedPath[beginToken]);
+            node.reset(node[index]);
+        } else if (delimiter == MAP_DELIM) {
+            auto key = codedPath.substr(beginToken, endToken - beginToken);
+            node.reset(node[key]);
+        } else {
+            return Node(); // Path is malformed, return null node.
+        }
+        delimiter = codedPath[endToken]; // Get next character as the delimiter.
+        ++endToken; // Move past the delimiter.
+        if (endToken < pathSize && !node) {
+            return Node(); // A node in the path was missing, return null node.
+        }
+    }
+    return node;
+}
+
+glm::vec4 getColorAsVec4(const Node& node) {
+    double val;
+    if (getDouble(node, val)) {
+        return glm::vec4(val, val, val, 1.0);
+    }
+    if (node.IsSequence()) {
+        return parseVec<glm::vec4>(node);
+    }
+    if (node.IsScalar()) {
+        auto c = CSSColorParser::parse(node.Scalar());
+        return glm::vec4(c.r / 255.f, c.g / 255.f, c.b / 255.f, c.a);
+    }
+    return glm::vec4();
+}
+
+std::string parseSequence(const Node& node) {
+    if (!node.IsSequence()) {
+        LOGW("Expected a plain sequence: '%'", Dump(node).c_str());
+        return "";
+    }
+
+    std::stringstream sstream;
+    for (const auto& val : node) {
+        if (!val.IsScalar()) {
+            LOGW("Expected a plain sequence: '%'", Dump(node).c_str());
+            return "";
+        }
+        sstream << val.Scalar() << ",";
+    }
+    return sstream.str();
+}
+
+bool getDouble(const Node& node, double& value) {
+
+    if (node.IsScalar()) {
+        const std::string& s = node.Scalar();
+        int count;
+        value = ff::stod(s.c_str(), s.length(), &count);
+        if (count == int(s.length())) {
+            return true;
+        }
+    }
+
+    return false;
+}
+
+bool getDouble(const Node& node, double& value, const char* name) {
+
+    if (getDouble(node, value)) { return true; }
+
+    LOGW("Expected a floating point value for '%s' property.:\n%s\n", name, Dump(node).c_str());
+    return false;
+}
+
+bool getBool(const Node& node, bool& value, const char* name) {
+    try {
+        value = node.as<bool>();
+        return true;
+    } catch (const BadConversion& e) {}
+
+    if (name) {
+        LOGW("Expected a boolean value for '%s' property.:\n%s\n", name, Dump(node).c_str());
+    }
+    return false;
+}
+
+}
diff --git a/core/src/util/yamlHelper.h b/core/src/util/yamlHelper.h
new file mode 100644 (file)
index 0000000..746e2b4
--- /dev/null
@@ -0,0 +1,65 @@
+// Helper Functions for parsing YAML nodes
+// NOTE: To be used in multiple YAML parsing modules once SceneLoader aptly modularized
+
+#pragma once
+
+#include "yaml-cpp/yaml.h"
+#include "glm/vec4.hpp"
+
+using YAML::Node;
+using YAML::BadConversion;
+
+namespace Tangram {
+
+// A YamlPath encodes the location of a node in a yaml document in a string,
+// e.g. "lorem.ipsum#0" identifies root["lorem"]["ipsum"][0]
+struct YamlPath {
+    YamlPath();
+    YamlPath(const std::string& path);
+    YamlPath add(int index);
+    YamlPath add(const std::string& key);
+    YAML::Node get(YAML::Node root);
+    std::string codedPath;
+};
+
+struct YamlPathBuffer {
+
+    struct PathElement {
+        size_t index;
+        const std::string* key;
+        PathElement(size_t index, const std::string* key) : index(index), key(key) {}
+    };
+
+    std::vector<PathElement> m_path;
+
+    void pushMap(const std::string* _p) { m_path.emplace_back(0, _p);}
+    void pushSequence() { m_path.emplace_back(0, nullptr); }
+    void increment() { m_path.back().index++; }
+    void pop() { m_path.pop_back(); }
+    YamlPath toYamlPath();
+};
+
+template<typename T>
+inline T parseVec(const Node& node) {
+    T vec;
+    int i = 0;
+    for (const auto& nodeVal : node) {
+        if (i < vec.length()) {
+            vec[i++] = nodeVal.as<double>();
+        } else {
+            break;
+        }
+    }
+    return vec;
+}
+
+glm::vec4 getColorAsVec4(const Node& node);
+
+std::string parseSequence(const Node& node);
+
+bool getDouble(const Node& node, double& value);
+bool getDouble(const Node& node, double& value, const char* name);
+
+bool getBool(const Node& node, bool& value, const char* name = nullptr);
+
+}
diff --git a/core/src/util/zlibHelper.cpp b/core/src/util/zlibHelper.cpp
new file mode 100644 (file)
index 0000000..4a1415e
--- /dev/null
@@ -0,0 +1,56 @@
+#include "util/zlibHelper.h"
+
+#include <zlib.h>
+
+#include <assert.h>
+
+#define CHUNK 16384
+
+namespace Tangram {
+namespace zlib {
+
+int inflate(const char* _data, size_t _size, std::vector<char>& dst) {
+
+    int ret;
+    unsigned char out[CHUNK];
+
+    z_stream strm;
+    memset(&strm, 0, sizeof(z_stream));
+
+    ret = inflateInit2(&strm, 16+MAX_WBITS);
+    if (ret != Z_OK) { return ret; }
+
+    strm.avail_in = _size;
+    strm.next_in = (Bytef*)_data;
+
+    do {
+        strm.avail_out = CHUNK;
+        strm.next_out = out;
+
+        ret = inflate(&strm, Z_NO_FLUSH);
+
+         /* state not clobbered */
+        assert(ret != Z_STREAM_ERROR);
+
+        switch (ret) {
+        case Z_NEED_DICT:
+            ret = Z_DATA_ERROR;
+            /* fall through */
+        case Z_DATA_ERROR:
+        case Z_MEM_ERROR:
+            inflateEnd(&strm);
+            return ret;
+        }
+
+        size_t have = CHUNK - strm.avail_out;
+        dst.insert(dst.end(), out, out+have);
+
+    } while (ret == Z_OK);
+
+    inflateEnd(&strm);
+
+    return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR;
+}
+
+}
+}
diff --git a/core/src/util/zlibHelper.h b/core/src/util/zlibHelper.h
new file mode 100644 (file)
index 0000000..b1c5e6d
--- /dev/null
@@ -0,0 +1,12 @@
+#pragma once
+
+#include <vector>
+#include <string.h>
+
+namespace Tangram {
+namespace zlib {
+
+int inflate(const char* _data, size_t _size, std::vector<char>& dst);
+
+}
+}
diff --git a/core/src/view/view.cpp b/core/src/view/view.cpp
new file mode 100644 (file)
index 0000000..aec58c1
--- /dev/null
@@ -0,0 +1,553 @@
+#include "view/view.h"
+
+#include "log.h"
+#include "scene/stops.h"
+#include "util/rasterize.h"
+
+#include "glm/gtc/matrix_transform.hpp"
+#include "glm/gtx/rotate_vector.hpp"
+#include <cmath>
+
+#define MAX_LOD 6
+
+namespace Tangram {
+
+double invLodFunc(double d) {
+    return exp2(d) - 1.0;
+}
+
+View::View(int _width, int _height, ProjectionType _projType) :
+    m_obliqueAxis(0, 1),
+    m_width(0),
+    m_height(0),
+    m_type(CameraType::perspective),
+    m_changed(false) {
+
+    setMapProjection(_projType);
+    setSize(_width, _height);
+    setZoom(m_zoom);
+    setPosition(0.0, 0.0);
+}
+
+void View::setMapProjection(ProjectionType _projType) {
+
+    switch(_projType) {
+        case ProjectionType::mercator:
+            m_projection.reset(new MercatorProjection());
+            break;
+        default:
+            LOGE("Not a valid map projection specified.\n Setting map projection to mercator by default");
+            m_projection.reset(new MercatorProjection());
+            break;
+    }
+
+    auto bounds = m_projection->MapBounds();
+    m_constraint.setLimitsY(bounds.min.y, bounds.max.y);
+
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+void View::setPixelScale(float _pixelsPerPoint) {
+
+    m_pixelScale = _pixelsPerPoint;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+void View::setCameraType(CameraType _type) {
+
+    m_type = _type;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+ViewState View::state() const {
+
+    return {
+        m_projection.get(),
+        m_changed,
+        glm::dvec2(m_pos.x, -m_pos.y),
+        m_zoom,
+        powf(2.f, m_zoom),
+        m_zoom - std::floor(m_zoom),
+        glm::vec2(m_vpWidth, m_vpHeight),
+        s_pixelsPerTile * m_pixelScale
+    };
+}
+
+void View::setSize(int _width, int _height) {
+
+    m_vpWidth = std::max(_width, 1);
+    m_vpHeight = std::max(_height, 1);
+    m_aspect = (float)m_vpWidth/ (float)m_vpHeight;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+    // Screen space orthographic projection matrix, top left origin, y pointing down
+    m_orthoViewport = glm::ortho(0.f, (float)m_vpWidth, (float)m_vpHeight, 0.f, -1.f, 1.f);
+
+}
+
+void View::setFieldOfView(float radians) {
+
+    m_fov = radians;
+    m_fovStops = nullptr;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+void View::setFieldOfViewStops(std::shared_ptr<Stops> stops) {
+
+    m_fovStops = stops;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+float View::getFieldOfView() const {
+
+    if (m_fovStops) {
+        return m_fovStops->evalFloat(m_zoom);
+    }
+    return m_fov;
+
+}
+
+void View::setFocalLength(float length) {
+
+    setFieldOfView(focalLengthToFieldOfView(length));
+
+}
+
+void View::setFocalLengthStops(std::shared_ptr<Stops> stops) {
+
+    for (auto& frame : stops->frames) {
+        float length = frame.value.get<float>();
+        frame.value = focalLengthToFieldOfView(length);
+    }
+    setFieldOfViewStops(stops);
+
+}
+
+float View::getFocalLength() const {
+
+    return fieldOfViewToFocalLength(getFieldOfView());
+
+}
+
+
+void View::setMaxPitch(float degrees) {
+
+    m_maxPitch = degrees;
+    m_maxPitchStops = nullptr;
+    setPitch(m_pitch);
+
+}
+
+void View::setMaxPitchStops(std::shared_ptr<Stops> stops) {
+
+    m_maxPitchStops = stops;
+    setPitch(m_pitch);
+
+}
+
+float View::getMaxPitch() const {
+
+    if (m_maxPitchStops) {
+        return m_maxPitchStops->evalFloat(m_zoom);
+    }
+    return m_maxPitch;
+
+}
+
+
+void View::setPosition(double _x, double _y) {
+
+    m_pos.x = _x;
+    m_pos.y = _y;
+    m_dirtyTiles = true;
+
+}
+
+void View::setZoom(float _z) {
+    // ensure zoom value is allowed
+    m_zoom = glm::clamp(_z, s_minZoom, s_maxZoom);
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+}
+
+void View::setRoll(float _roll) {
+
+    m_roll = glm::mod(_roll, (float)TWO_PI);
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+void View::setPitch(float _pitch) {
+
+    m_pitch = _pitch;
+    m_dirtyMatrices = true;
+    m_dirtyTiles = true;
+
+}
+
+void View::translate(double _dx, double _dy) {
+
+    setPosition(m_pos.x + _dx, m_pos.y + _dy);
+
+}
+
+void View::zoom(float _dz) {
+
+    setZoom(m_zoom + _dz);
+
+}
+
+void View::roll(float _droll) {
+
+    setRoll(m_roll + _droll);
+
+}
+
+void View::pitch(float _dpitch) {
+
+    setPitch(m_pitch + _dpitch);
+
+}
+
+void View::update(bool _constrainToWorldBounds) {
+
+    m_changed = false;
+
+    if (_constrainToWorldBounds) {
+        m_constraint.setRadius(std::fmax(getWidth(), getHeight()) / pixelsPerMeter() / pixelScale());
+        m_pos.x = m_constraint.getConstrainedX(m_pos.x);
+        m_pos.y = m_constraint.getConstrainedY(m_pos.y);
+        m_zoom -= std::log(m_constraint.getConstrainedScale()) / std::log(2);
+    }
+
+    // Ensure valid pitch angle.
+    {
+        float maxPitchRadians = glm::radians(getMaxPitch());
+        if (m_type != CameraType::perspective) {
+            // Prevent projection plane from intersecting ground plane.
+            maxPitchRadians = atan2(m_pos.z, m_height * .5f);
+        }
+        m_pitch = glm::clamp(m_pitch, 0.f, maxPitchRadians);
+    }
+
+    if (m_dirtyMatrices) {
+
+        updateMatrices(); // Resets dirty flag
+        m_changed = true;
+
+    }
+
+    if (m_dirtyTiles) {
+
+        m_changed = true;
+        m_dirtyTiles = false;
+    }
+}
+
+glm::dmat2 View::getBoundsRect() const {
+
+    double hw = m_width * 0.5;
+    double hh = m_height * 0.5;
+    return glm::dmat2(m_pos.x - hw, m_pos.y - hh, m_pos.x + hw, m_pos.y + hh);
+
+}
+
+double View::screenToGroundPlane(float& _screenX, float& _screenY) {
+
+    if (m_dirtyMatrices) { updateMatrices(); } // Need the view matrices to be up-to-date
+
+    double x = _screenX, y = _screenY;
+    double t = screenToGroundPlaneInternal(x, y);
+    _screenX = x;
+    _screenY = y;
+    return t;
+}
+
+double View::screenToGroundPlane(double& _screenX, double& _screenY) {
+
+    if (m_dirtyMatrices) { updateMatrices(); } // Need the view matrices to be up-to-date
+
+    return screenToGroundPlaneInternal(_screenX, _screenY);
+}
+
+glm::vec2 View::normalizedWindowCoordinates(float _x, float _y) const {
+    return { _x / m_vpWidth, 1.0 - _y / m_vpHeight };
+}
+
+double View::screenToGroundPlaneInternal(double& _screenX, double& _screenY) const {
+
+    // Cast a ray and find its intersection with the z = 0 plane,
+    // following the technique described here: http://antongerdelan.net/opengl/raycasting.html
+
+    glm::dvec4 target_clip = { 2. * _screenX / m_vpWidth - 1., 1. - 2. * _screenY / m_vpHeight, -1., 1. };
+    glm::dvec4 target_world = m_invViewProj * target_clip;
+    target_world /= target_world.w;
+
+    glm::dvec4 origin_world;
+    switch (m_type) {
+        case CameraType::perspective:
+            origin_world = glm::dvec4(m_eye, 1);
+            break;
+        case CameraType::isometric:
+        case CameraType::flat:
+            origin_world = m_invViewProj * (target_clip * glm::dvec4(1, 1, 0, 1));
+            break;
+    }
+
+    glm::dvec4 ray_world = target_world - origin_world;
+
+    double t = 0; // Distance along ray to ground plane
+    if (ray_world.z != 0.f) {
+        t = -origin_world.z / ray_world.z;
+    }
+
+    ray_world *= std::abs(t);
+
+    // Determine the maximum distance from the view position at which tiles can be drawn; If the projected point
+    // is farther than this maximum or if the point is above the horizon (t < 0) then we set the distance of the
+    // point to always be this maximum distance.
+    double maxTileDistance = invLodFunc(MAX_LOD + 1) * 2.0 * MapProjection::HALF_CIRCUMFERENCE * pow(2, -m_zoom);
+    double rayDistanceXY = sqrt(ray_world.x * ray_world.x + ray_world.y * ray_world.y);
+    if (rayDistanceXY > maxTileDistance || t < 0) {
+        ray_world *= maxTileDistance / rayDistanceXY;
+    }
+
+    _screenX = ray_world.x + origin_world.x;
+    _screenY = ray_world.y + origin_world.y;
+
+    return t;
+}
+
+float View::pixelsPerMeter() const {
+
+    double metersPerTile = MapProjection::HALF_CIRCUMFERENCE * exp2(-m_zoom);
+    return s_pixelsPerTile / metersPerTile;
+}
+
+float View::focalLengthToFieldOfView(float length) {
+    return 2.f * atanf(1.f / length);
+}
+
+float View::fieldOfViewToFocalLength(float radians) {
+    return 1.f / tanf(radians / 2.f);
+}
+
+void View::updateMatrices() {
+
+    // find dimensions of tiles in world space at new zoom level
+    float worldTileSize = 2 * MapProjection::HALF_CIRCUMFERENCE * pow(2, -m_zoom);
+
+    // viewport height in world space is such that each tile is [m_pixelsPerTile] px square in screen space
+    float screenTileSize = s_pixelsPerTile * m_pixelScale;
+    m_height = (float)m_vpHeight * worldTileSize / screenTileSize;
+    m_width = m_height * m_aspect;
+
+    // set vertical field-of-view
+    float fovy = getFieldOfView();
+
+    // we assume portrait orientation by default, so in landscape
+    // mode we scale the vertical FOV such that the wider dimension
+    // gets the intended FOV
+    if (m_width > m_height) {
+        fovy /= m_aspect;
+    }
+
+    // set camera z to produce desired viewable area
+    m_pos.z = m_height * 0.5 / tan(fovy * 0.5);
+
+    m_eye = glm::rotateZ(glm::rotateX(glm::vec3(0.f, 0.f, m_pos.z), m_pitch), m_roll);
+    glm::vec3 at = { 0.f, 0.f, 0.f };
+    glm::vec3 up = glm::rotateZ(glm::rotateX(glm::vec3(0.f, 1.f, 0.f), m_pitch), m_roll);
+
+    // Generate view matrix
+    m_view = glm::lookAt(m_eye, at, up);
+
+    float maxTileDistance = worldTileSize * invLodFunc(MAX_LOD + 1);
+    float near = m_pos.z / 50.f;
+    float far = 1;
+    float hw = 0.5 * m_width;
+    float hh = 0.5 * m_height;
+
+    // Generate projection matrix based on camera type
+    switch (m_type) {
+        case CameraType::perspective:
+            far = 2. * m_pos.z / std::max(0., cos(m_pitch + 0.5 * fovy));
+            far = std::min(far, maxTileDistance);
+            m_proj = glm::perspective(fovy, m_aspect, near, far);
+            // Adjust for vanishing point.
+            m_proj[2][0] -= m_vanishingPoint.x / getWidth();
+            m_proj[2][1] -= m_vanishingPoint.y / getHeight();
+            break;
+        case CameraType::isometric:
+        case CameraType::flat:
+            far = 2. * (m_pos.z + hh * std::abs(tan(m_pitch)));
+            far = std::min(far, maxTileDistance);
+            m_proj = glm::ortho(-hw, hw, -hh, hh, near, far);
+            break;
+    }
+
+    if (m_type == CameraType::isometric) {
+        glm::mat4 shear = m_view;
+
+        // Add the oblique projection scaling factors to the shear matrix
+        shear[2][0] += m_obliqueAxis.x;
+        shear[2][1] += m_obliqueAxis.y;
+
+        // Remove the view from the shear matrix so we don't apply it two times
+        shear *= glm::inverse(m_view);
+
+        // Inject the shear in the projection matrix
+        m_proj *= shear;
+    }
+
+    m_viewProj = m_proj * m_view;
+    m_invViewProj = glm::inverse(m_viewProj);
+
+    // The matrix that transforms normals from world space to camera space is the transpose of the inverse of the view matrix,
+    // but since our view matrix is orthonormal transposing is equivalent to inverting, so the normal matrix is just the
+    // original view matrix (cropped to the top-left 3 rows and columns, since we're applying it to 3d vectors)
+    m_normalMatrix = glm::mat3(m_view);
+    m_invNormalMatrix = glm::inverse(m_normalMatrix);
+
+    m_dirtyMatrices = false;
+
+}
+
+glm::vec2 View::lonLatToScreenPosition(double lon, double lat, bool& clipped) const {
+    glm::dvec2 meters = m_projection->LonLatToMeters({lon, lat});
+    glm::dvec4 lonLat(meters, 0.0, 1.0);
+
+    lonLat.x = lonLat.x - m_pos.x;
+    lonLat.y = lonLat.y - m_pos.y;
+
+    glm::vec2 screenPosition = worldToScreenSpace(m_viewProj, lonLat, {m_vpWidth, m_vpHeight}, clipped);
+
+    return screenPosition;
+}
+
+void View::getVisibleTiles(const std::function<void(TileID)>& _tileCb) const {
+
+    int zoom = int(m_zoom);
+    int maxTileIndex = 1 << zoom;
+
+    // Bounds of view trapezoid in world space (i.e. view frustum projected onto z = 0 plane)
+    glm::dvec2 viewBL = { 0.f,       m_vpHeight }; // bottom left
+    glm::dvec2 viewBR = { m_vpWidth, m_vpHeight }; // bottom right
+    glm::dvec2 viewTR = { m_vpWidth, 0.f        }; // top right
+    glm::dvec2 viewTL = { 0.f,       0.f        }; // top left
+
+    double t0 = screenToGroundPlaneInternal(viewBL.x, viewBL.y);
+    double t1 = screenToGroundPlaneInternal(viewBR.x, viewBR.y);
+    double t2 = screenToGroundPlaneInternal(viewTR.x, viewTR.y);
+    double t3 = screenToGroundPlaneInternal(viewTL.x, viewTL.y);
+
+    // if all of our raycasts have a negative intersection distance, we have no area to cover
+    if (t0 < .0 && t1 < 0. && t2 < 0. && t3 < 0.) {
+        return;
+    }
+
+    // Transformation from world space to tile space
+    double hc = MapProjection::HALF_CIRCUMFERENCE;
+    double invTileSize = double(maxTileIndex) / (hc * 2);
+    glm::dvec2 tileSpaceOrigin(-hc, hc);
+    glm::dvec2 tileSpaceAxes(invTileSize, -invTileSize);
+
+    // Bounds of view trapezoid in tile space
+    glm::dvec2 a = (glm::dvec2(viewBL.x + m_pos.x, viewBL.y + m_pos.y) - tileSpaceOrigin) * tileSpaceAxes;
+    glm::dvec2 b = (glm::dvec2(viewBR.x + m_pos.x, viewBR.y + m_pos.y) - tileSpaceOrigin) * tileSpaceAxes;
+    glm::dvec2 c = (glm::dvec2(viewTR.x + m_pos.x, viewTR.y + m_pos.y) - tileSpaceOrigin) * tileSpaceAxes;
+    glm::dvec2 d = (glm::dvec2(viewTL.x + m_pos.x, viewTL.y + m_pos.y) - tileSpaceOrigin) * tileSpaceAxes;
+
+    // Location of the view center in tile space
+    glm::dvec2 e = (glm::dvec2(m_pos.x + m_eye.x, m_pos.y + m_eye.y) - tileSpaceOrigin) * tileSpaceAxes;
+
+    static const int imax = std::numeric_limits<int>::max();
+    static const int imin = std::numeric_limits<int>::min();
+
+    // Scan options - avoid heap allocation for std::function
+    // [1] http://www.drdobbs.com/cpp/efficient-use-of-lambda-expressions-and/232500059?pgno=2
+    struct ScanParams {
+        explicit ScanParams(int _zoom) : zoom(_zoom) {}
+
+        int zoom;
+        int maxZoom = int(s_maxZoom);
+
+        // Distance thresholds in tile space for levels of detail:
+        // Element [n] in each array is the minimum tile index at which level-of-detail n
+        // should be applied in that direction.
+        int x_limit_pos[MAX_LOD] = { imax };
+        int x_limit_neg[MAX_LOD] = { imin };
+        int y_limit_pos[MAX_LOD] = { imax };
+        int y_limit_neg[MAX_LOD] = { imin };
+
+        glm::ivec4 last = glm::ivec4{-1};
+    };
+
+    ScanParams opt{ zoom };
+
+    if (m_type == CameraType::perspective) {
+
+        // Determine zoom reduction for tiles far from the center of view
+        double tilesAtFullZoom = std::max(m_width, m_height) * invTileSize * 0.5;
+        double viewCenterX = (m_pos.x + hc) * invTileSize;
+        double viewCenterY = (m_pos.y - hc) * -invTileSize;
+
+        for (int i = 0; i < MAX_LOD; i++) {
+            int j = i + 1;
+            double r = invLodFunc(i) + tilesAtFullZoom;
+            opt.x_limit_neg[i] = ((int(viewCenterX - r) >> j) - 1) << j;
+            opt.y_limit_pos[i] = ((int(viewCenterY + r) >> j) + 1) << j;
+            opt.y_limit_neg[i] = ((int(viewCenterY - r) >> j) - 1) << j;
+            opt.x_limit_pos[i] = ((int(viewCenterX + r) >> j) + 1) << j;
+        }
+    }
+
+    Rasterize::ScanCallback s = [&opt, &_tileCb](int x, int y) {
+
+        int lod = 0;
+        while (lod < MAX_LOD && x >= opt.x_limit_pos[lod]) { lod++; }
+        while (lod < MAX_LOD && x <  opt.x_limit_neg[lod]) { lod++; }
+        while (lod < MAX_LOD && y >= opt.y_limit_pos[lod]) { lod++; }
+        while (lod < MAX_LOD && y <  opt.y_limit_neg[lod]) { lod++; }
+
+        x >>= lod;
+        y >>= lod;
+
+        glm::ivec4 tile;
+        tile.z = glm::clamp((opt.zoom - lod), 0, opt.maxZoom);
+
+        // Wrap x to the range [0, (1 << z))
+        tile.x = x & ((1 << tile.z) - 1);
+        tile.y = y;
+        tile.w = (x - tile.x) >> opt.zoom; // wrap
+
+        if (tile != opt.last) {
+            opt.last = tile;
+
+            _tileCb(TileID(tile.x, tile.y, tile.z, tile.z, tile.w));
+        }
+    };
+
+    // Rasterize view trapezoid into tiles
+    Rasterize::scanTriangle(a, b, c, 0, maxTileIndex, s);
+    Rasterize::scanTriangle(c, d, a, 0, maxTileIndex, s);
+
+    // Rasterize the area bounded by the point under the view center and the two nearest corners
+    // of the view trapezoid. This is necessary to not cull any geometry with height in these tiles
+    // (which should remain visible, even though the base of the tile is not).
+    Rasterize::scanTriangle(a, b, e, 0, maxTileIndex, s);
+}
+
+}
diff --git a/core/src/view/view.h b/core/src/view/view.h
new file mode 100644 (file)
index 0000000..2204625
--- /dev/null
@@ -0,0 +1,250 @@
+#pragma once
+
+#include "tile/tileID.h"
+#include "util/mapProjection.h"
+#include "view/viewConstraint.h"
+
+#include "glm/mat4x4.hpp"
+#include "glm/vec4.hpp"
+#include "glm/vec3.hpp"
+#include <functional>
+#include <memory>
+
+namespace Tangram {
+
+enum class CameraType : uint8_t {
+    perspective = 0,
+    isometric,
+    flat,
+};
+
+struct Stops;
+
+struct ViewState {
+    const MapProjection* mapProjection;
+    bool changedOnLastUpdate;
+    glm::dvec2 center;
+    float zoom;
+    double zoomScale;
+    float fractZoom;
+    glm::vec2 viewportSize;
+    float tileSize;
+};
+
+/* View
+ * 1. Stores a representation of the current view into the map world
+ * 2. Determines which tiles are visible in the current view
+ * 3. Tracks changes in the view state to determine when new rendering is needed
+*/
+
+class View {
+
+public:
+
+    View(int _width = 800, int _height = 600, ProjectionType _projType = ProjectionType::mercator);
+
+    View(const View& _view) = default;
+
+    /* Sets a new map projection with default tileSize */
+    void setMapProjection(ProjectionType _projType);
+
+    /* Gets the current map projection */
+    const MapProjection& getMapProjection() const { return *m_projection.get(); }
+
+    void setCameraType(CameraType _type);
+    auto cameraType() const { return m_type; }
+
+    void setObliqueAxis(float _x, float _y) { m_obliqueAxis = { _x, _y}; }
+    auto obliqueAxis() const { return m_obliqueAxis; }
+
+    void setVanishingPoint(float x, float y) { m_vanishingPoint = { x, y }; }
+    auto vanishingPoint() const { return m_vanishingPoint; }
+
+    // Set the vertical field-of-view angle, in radians.
+    void setFieldOfView(float radians);
+
+    // Set the vertical field-of-view angle as a series of stops over zooms.
+    void setFieldOfViewStops(std::shared_ptr<Stops> stops);
+
+    // Get the vertical field-of-view angle, in radians.
+    float getFieldOfView() const;
+
+    // Set the vertical field-of-view angle to a value that corresponds to the
+    // given focal length.
+    void setFocalLength(float length);
+
+    // Set the vertical field-of-view angle according to focal length as a
+    // series of stops over zooms.
+    void setFocalLengthStops(std::shared_ptr<Stops> stops);
+
+    // Get the focal length that corresponds to the current vertical
+    // field-of-view angle.
+    float getFocalLength() const;
+
+    // Set the maximum pitch angle in degrees.
+    void setMaxPitch(float degrees);
+
+    // Set the maximum pitch angle in degrees as a series of stops over zooms.
+    void setMaxPitchStops(std::shared_ptr<Stops> stops);
+
+    // Get the maximum pitch angle for the current zoom.
+    float getMaxPitch() const;
+
+    /* Sets the ratio of hardware pixels to logical pixels (for high-density screens)
+     * If unset, default is 1.0
+     */
+    void setPixelScale(float _pixelsPerPoint);
+
+    /* Sets the size of the viewable area in pixels */
+    void setSize(int _width, int _height);
+
+    /* Sets the position of the view within the world (in projection units) */
+    void setPosition(double _x, double _y);
+    void setPosition(const glm::dvec3 pos) { setPosition(pos.x, pos.y); }
+    void setPosition(const glm::dvec2 pos) { setPosition(pos.x, pos.y); }
+
+    /* Sets the zoom level of the view */
+    void setZoom(float _z);
+
+    /* Sets the roll angle of the view in radians (default is 0) */
+    void setRoll(float _rad);
+
+    /* Sets the pitch angle of the view in radians (default is 0) */
+    void setPitch(float _rad);
+
+    /* Moves the position of the view */
+    void translate(double _dx, double _dy);
+
+    /* Changes zoom by the given amount */
+    void zoom(float _dz);
+
+    /* Changes the roll angle by the given amount in radians */
+    void roll(float _drad);
+
+    /* Changes the pitch angle by the given amount in radians */
+    void pitch(float _drad);
+
+    /* Gets the current zoom */
+    float getZoom() const { return m_zoom; }
+
+    /* Get the current roll angle in radians */
+    float getRoll() const { return m_roll; }
+
+    /* Get the current pitch angle in radians */
+    float getPitch() const { return m_pitch; }
+
+    /* Updates the view and projection matrices if properties have changed */
+    void update(bool _constrainToWorldBounds = true);
+
+    /* Gets the position of the view in projection units (z is the effective 'height' determined from zoom) */
+    const glm::dvec3& getPosition() const { return m_pos; }
+
+    /* Gets the transformation from global space into view (camera) space; Due to precision limits, this
+       does not contain the translation of the view from the global origin (you must apply that separately) */
+    const glm::mat4& getViewMatrix() const { return m_view; }
+
+    /* Gets the transformation from view space into screen space */
+    const glm::mat4& getProjectionMatrix() const { return m_proj; }
+
+    /* Gets the combined view and projection transformation */
+    const glm::mat4 getViewProjectionMatrix() const { return m_viewProj; }
+
+    /* Gets the normal matrix; transforms surface normals from model space to camera space */
+    const glm::mat3& getNormalMatrix() const { return m_normalMatrix; }
+
+    const glm::mat3& getInverseNormalMatrix() const { return m_invNormalMatrix; }
+
+    /* Returns the eye position in world space */
+    const glm::vec3& getEye() const { return m_eye; }
+
+    /* Returns the window coordinates [0,1], lower left corner of the window is (0, 0) */
+    glm::vec2 normalizedWindowCoordinates(float _x, float _y) const;
+
+    ViewState state() const;
+
+    /* Returns a rectangle of the current view range as [[x_min, y_min], [x_max, y_max]] */
+    glm::dmat2 getBoundsRect() const;
+
+    float getWidth() const { return m_vpWidth; }
+
+    float getHeight() const { return m_vpHeight; }
+
+    /* Calculate the position on the ground plane (z = 0) under the given screen space coordinates,
+     * replacing the input coordinates with world-space coordinates
+     * @return the un-normalized distance 'into the screen' to the ground plane
+     * (if < 0, intersection is behind the screen)
+     */
+    double screenToGroundPlane(float& _screenX, float& _screenY);
+    double screenToGroundPlane(double& _screenX, double& _screenY);
+
+    /* Gets the screen position from a latitude/longitude */
+    glm::vec2 lonLatToScreenPosition(double lon, double lat, bool& clipped) const;
+
+    /* Returns the set of all tiles visible at the current position and zoom */
+    void getVisibleTiles(const std::function<void(TileID)>& _tileCb) const;
+
+    /* Returns true if the view properties have changed since the last call to update() */
+    bool changedOnLastUpdate() const { return m_changed; }
+
+    /* TODO: API for setting these */
+    constexpr static float s_maxZoom = 20.5;
+    constexpr static float s_minZoom = 0.0;
+    constexpr static float s_pixelsPerTile = 256.0;
+
+    const glm::mat4& getOrthoViewportMatrix() const { return m_orthoViewport; };
+
+    float pixelScale() const { return m_pixelScale; }
+    float pixelsPerMeter() const;
+
+    static float focalLengthToFieldOfView(float length);
+    static float fieldOfViewToFocalLength(float radians);
+
+protected:
+
+    void updateMatrices();
+
+    double screenToGroundPlaneInternal(double& _screenX, double& _screenY) const;
+
+    std::shared_ptr<MapProjection> m_projection;
+    std::shared_ptr<Stops> m_fovStops;
+    std::shared_ptr<Stops> m_maxPitchStops;
+
+    ViewConstraint m_constraint;
+
+    glm::dvec3 m_pos;
+    glm::vec3 m_eye;
+    glm::vec2 m_obliqueAxis;
+    glm::vec2 m_vanishingPoint;
+
+    glm::mat4 m_view;
+    glm::mat4 m_orthoViewport;
+    glm::mat4 m_proj;
+    glm::mat4 m_viewProj;
+    glm::mat4 m_invViewProj;
+    glm::mat3 m_normalMatrix;
+    glm::mat3 m_invNormalMatrix;
+
+    float m_roll = 0.f;
+    float m_pitch = 0.f;
+
+    float m_zoom = 0.f;
+
+    float m_width;
+    float m_height;
+
+    int m_vpWidth;
+    int m_vpHeight;
+    float m_aspect;
+    float m_pixelScale = 1.0f;
+    float m_fov = 0.25 * PI;
+    float m_maxPitch = 0.5 * PI;
+
+    CameraType m_type;
+
+    bool m_dirtyMatrices;
+    bool m_dirtyTiles;
+    bool m_changed;
+
+};
+
+}
diff --git a/core/src/view/viewConstraint.cpp b/core/src/view/viewConstraint.cpp
new file mode 100644 (file)
index 0000000..af051f9
--- /dev/null
@@ -0,0 +1,68 @@
+#include "view/viewConstraint.h"
+
+namespace Tangram {
+
+void ViewConstraint::setLimitsY(double yMin, double yMax) {
+
+    m_yMin = yMin;
+    m_yMax = yMax;
+
+}
+
+void ViewConstraint::setLimitsX(double xMin, double xMax) {
+
+    m_xMin = xMin;
+    m_xMax = xMax;
+
+}
+
+void ViewConstraint::setRadius(double r) {
+
+    m_radius = r;
+
+}
+
+auto ViewConstraint::getConstrainedX(double x) -> double {
+
+    return constrain(x, m_radius, m_xMin, m_xMax);
+
+}
+
+auto ViewConstraint::getConstrainedY(double y) -> double {
+
+    return constrain(y, m_radius, m_yMin, m_yMax);
+
+}
+
+auto ViewConstraint::getConstrainedScale() -> double {
+
+    double xScale = 1.0, yScale = 1.0;
+    double xRange = m_xMax - m_xMin;
+    double yRange = m_yMax - m_yMin;
+    double diameter = 2.0 * m_radius;
+
+    if (diameter > yRange) { yScale = yRange / diameter; }
+    if (diameter > xRange) { xScale = xRange / diameter; }
+
+    return std::fmin(xScale, yScale);
+
+}
+
+auto ViewConstraint::constrain(double pos, double radius, double min, double max) -> double {
+
+    double upperSpace = max - (pos + radius);
+    double lowerSpace = (pos - radius) - min;
+
+    if (upperSpace < 0.0 && lowerSpace < 0.0) {
+        return 0.5 * (max + min);
+    } else if (upperSpace < 0.0) {
+        return max - radius;
+    } else if (lowerSpace < 0.0) {
+        return min + radius;
+    }
+
+    return pos;
+
+}
+
+}
diff --git a/core/src/view/viewConstraint.h b/core/src/view/viewConstraint.h
new file mode 100644 (file)
index 0000000..3a52748
--- /dev/null
@@ -0,0 +1,29 @@
+#pragma once
+#include <cmath>
+
+namespace Tangram {
+
+class ViewConstraint {
+
+public:
+
+    void setLimitsY(double yMin, double yMax);
+    void setLimitsX(double xMin, double xMax);
+    void setRadius(double r);
+    auto getConstrainedX(double x) -> double;
+    auto getConstrainedY(double y) -> double;
+    auto getConstrainedScale() -> double;
+
+private:
+
+    auto constrain(double pos, double radius, double min, double max) -> double;
+
+    double m_xMax = INFINITY;
+    double m_yMax = INFINITY;
+    double m_xMin = -INFINITY;
+    double m_yMin = -INFINITY;
+    double m_radius = 0.0;
+
+};
+
+}
diff --git a/images/clion-tangram-target.png b/images/clion-tangram-target.png
new file mode 100644 (file)
index 0000000..78b3f75
Binary files /dev/null and b/images/clion-tangram-target.png differ
diff --git a/images/default-point.png b/images/default-point.png
new file mode 100644 (file)
index 0000000..bd29cff
Binary files /dev/null and b/images/default-point.png differ
diff --git a/images/screenshot.png b/images/screenshot.png
new file mode 100644 (file)
index 0000000..19afea5
Binary files /dev/null and b/images/screenshot.png differ
diff --git a/package-submodules.sh b/package-submodules.sh
new file mode 100755 (executable)
index 0000000..af82590
--- /dev/null
@@ -0,0 +1,10 @@
+tar -czvf packaging/deps.tar.gz \
+       --anchored core/deps/alfons \
+       --anchored core/deps/css-color-parser-cpp \
+       --anchored core/deps/duktape \
+       --anchored core/deps/earcut --exclude core/deps/earcut/glfw \
+       --anchored core/deps/geojson-vt-cpp --exclude core/deps/geojson-vt-cpp/.mason \
+       --anchored core/deps/isect2d \
+       --anchored core/deps/SQLiteCpp --exclude core/deps/SQLiteCpp/googletest \
+       --anchored core/deps/variant --exclude core/deps/variant/.mason \
+       --anchored core/deps/yaml-cpp --exclude core/deps/yaml-cpp/test
diff --git a/packaging/tangram-es.spec b/packaging/tangram-es.spec
new file mode 100644 (file)
index 0000000..f7e13b4
--- /dev/null
@@ -0,0 +1,91 @@
+Name:       tangram-es
+Summary:    Tangram-ES Map Library
+Version:    0.0.1
+Release:    1
+Group:      Framework/maps
+License:    MIT
+Source0:    %{name}-%{version}.tar.gz
+Source1:    deps.tar.gz
+
+BuildRequires:  cmake
+BuildRequires:  pkgconfig(dlog)
+BuildRequires:         pkgconfig(libcurl)
+BuildRequires:         pkgconfig(icu-uc)
+BuildRequires:         pkgconfig(freetype2)
+BuildRequires:         pkgconfig(harfbuzz)
+BuildRequires:         pkgconfig(evas)
+BuildRequires:         pkgconfig(fontconfig)
+BuildRequires:         pkgconfig(sqlite3)
+
+Requires(post):  /sbin/ldconfig
+Requires(postun):  /sbin/ldconfig
+
+%ifarch %arm
+%define ARCH arm
+%endif
+
+%ifarch aarch64
+%define ARCH aarch64
+%endif
+
+%ifarch %ix86
+%define ARCH i586
+%endif
+
+%ifarch x86_64
+%define ARCH x86_64
+%endif
+
+%description
+Tangram-ES Map Library.
+
+%prep
+%setup -q
+
+rmdir core/deps/alfons
+rmdir core/deps/css-color-parser-cpp
+rmdir core/deps/duktape
+rmdir core/deps/earcut
+rmdir core/deps/geojson-vt-cpp
+rmdir core/deps/isect2d
+rmdir core/deps/SQLiteCpp
+rmdir core/deps/variant
+rmdir core/deps/yaml-cpp
+
+%setup -q -T -D -a 1
+
+
+%build
+%if 0%{?tizen_build_binary_release_type_eng}
+export CFLAGS="$CFLAGS -DTIZEN_ENGINEER_MODE -g"
+export CXXFLAGS="$CXXFLAGS -DTIZEN_ENGINEER_MODE -g"
+export FFLAGS="$FFLAGS -DTIZEN_ENGINEER_MODE"
+%endif
+
+MAJORVER=`echo %{version} | awk 'BEGIN {FS="."}{print $1}'`
+#echo "-------------------------------->>"
+#find .
+#echo "--------------------------------<<"
+cmake .  -DCMAKE_BUILD_TYPE=Debug -DARCH=%{ARCH} -DPLATFORM_TARGET=tizen-lib -DCMAKE_INSTALL_PREFIX=%{_prefix} -DMAJORVER=${MAJORVER} -DFULLVER=%{version}
+make %{?jobs:-j%jobs}
+
+%install
+rm -rf %{buildroot}
+%make_install
+
+mkdir -p %{buildroot}/usr/share/license
+cp LICENSE %{buildroot}/usr/share/license/%{name}
+# cp external/yaml-cpp/LICENSE %{buildroot}/usr/share/license/%{name}-yaml-cpp
+# ... or embed the other licenses in LICENSE
+
+%post
+/sbin/ldconfig
+
+%postun
+/sbin/ldconfig
+
+%files
+%manifest tangram-es.manifest
+%defattr(-,root,root,-)
+%{_libdir}/libtangram.so
+/usr/share/license/tangram-es
diff --git a/platforms/android/.gitignore b/platforms/android/.gitignore
new file mode 100644 (file)
index 0000000..ce778c1
--- /dev/null
@@ -0,0 +1,3 @@
+# Android Studio
+*.iml
+.idea/
diff --git a/platforms/android/README.md b/platforms/android/README.md
new file mode 100644 (file)
index 0000000..d7420d5
--- /dev/null
@@ -0,0 +1,60 @@
+Android
+=======
+
+The recommended way use tangram-es in an Android project is to add it as a Gradle dependency. The library is hosted on Maven Central in the package 'com.mapzen.tangram'. To find the latest version number, check [Maven Central](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.mapzen.tangram%22).
+
+If Maven Central is not set up as a dependency repository, add it in your project's 'build.gradle' file:
+
+```
+allprojects {
+  dependencies {
+    repositories {
+      mavenCentral()
+    }
+  }
+}
+```
+
+Then add tangram-es in the 'dependencies' section of your module's 'build.gradle' file:
+
+```
+dependencies {
+  compile 'com.mapzen.tangram:tangram:0.5.0'
+}
+```
+
+That's it! If you want to build tangram-es for Android from scratch, continue reading.
+
+## Setup ##
+
+To build for Android you'll need [Android Studio](https://developer.android.com/studio/index.html) version 2.2 or newer on Mac OS X, Ubuntu, or Windows 10. Using the Android Studio SDK Manager, install or update the 'CMake', 'LLDB', and 'NDK' packages from the 'SDK Tools' tab.
+
+The demo application uses the Mapzen vector tile service, so you will need a Mapzen API key to build and run the demo. 
+
+ 1. Visit https://mapzen.com/documentation/overview/#get-started-developing-with-mapzen to get an API key.
+
+ 2. In your local Gradle properties file (`~/.gradle/gradle.properties`) add the following line, substituting your API key: `mapzenApiKey=YOUR-API-KEY-HERE`
+
+## Build ##
+
+After installing dependencies in Android Studio, you can execute Android builds from either the command line or the Android Studio interface.
+
+### Command Line ###
+
+The Android project is executed with Gradle commands from the 'platforms/android' folder. To build the demo application for the ARMv7 architecture (covers most Android devices), run:
+
+```bash
+./gradlew demo:assembleDebug
+```
+
+To install the demo on a connected Android device, run:
+
+```bash
+./gradlew demo:installDebug
+```
+
+### Android Studio ###
+
+Open the project in Android Studio, select 'demo' from the Configurations menu, then press the 'Run' button (^R).
+
+Android Studio supports debugging both the Java and C++ parts of tangram-es on a connected device or emulator. Choose one of the 'debug' build variants, set your desired breakpoints, and press the 'Debug' button (^D).
diff --git a/platforms/android/build.gradle b/platforms/android/build.gradle
new file mode 100644 (file)
index 0000000..377602f
--- /dev/null
@@ -0,0 +1,19 @@
+allprojects {
+  buildscript {
+    repositories {
+      mavenCentral()
+      jcenter()
+    }
+    dependencies {
+      classpath 'com.android.tools.build:gradle:2.2.3'
+      classpath 'com.github.dcendents:android-maven-gradle-plugin:1.5'
+    }
+  }
+
+  dependencies {
+    repositories {
+      mavenCentral()
+      jcenter()
+    }
+  }
+}
diff --git a/platforms/android/demo/build.gradle b/platforms/android/demo/build.gradle
new file mode 100644 (file)
index 0000000..b055875
--- /dev/null
@@ -0,0 +1,35 @@
+apply plugin: 'com.android.application'
+
+android {
+  compileSdkVersion 25
+  buildToolsVersion '25.0.2'
+
+  def apiKey = project.hasProperty('mapzenApiKey') ? mapzenApiKey : System.getenv('MAPZEN_API_KEY')
+
+  assert apiKey != null : "To run the demo, you must provide a Mapzen API key as an environment\
+    variable named 'MAPZEN_API_KEY' or a Gradle property named 'mapzenApiKey'"
+
+  defaultConfig {
+    minSdkVersion 15
+    targetSdkVersion 25
+    buildConfigField 'String', 'MAPZEN_API_KEY', '"' + apiKey + '"'
+  }
+
+  sourceSets.main {
+    assets.srcDirs = ['../../../scenes']
+  }
+
+  aaptOptions.ignoreAssetsPattern "!*.ttf"
+
+  buildTypes {
+    debug {
+      debuggable true
+      jniDebuggable true
+    }
+  }
+}
+
+dependencies {
+  compile project(path: ':tangram')
+  compile 'com.android.support:design:25.3.1'
+}
diff --git a/platforms/android/demo/proguard-project.txt b/platforms/android/demo/proguard-project.txt
new file mode 100644 (file)
index 0000000..f2fe155
--- /dev/null
@@ -0,0 +1,20 @@
+# To enable ProGuard in your project, edit project.properties
+# to define the proguard.config property as described in that file.
+#
+# Add project specific ProGuard rules here.
+# By default, the flags in this file are appended to flags specified
+# in ${sdk.dir}/tools/proguard/proguard-android.txt
+# You can edit the include path and order by changing the ProGuard
+# include property in project.properties.
+#
+# For more details, see
+#   http://developer.android.com/guide/developing/tools/proguard.html
+
+# Add any project specific keep options here:
+
+# If your project uses WebView with JS, uncomment the following
+# and specify the fully qualified class name to the JavaScript interface
+# class:
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
+#   public *;
+#}
diff --git a/platforms/android/demo/src/main/AndroidManifest.xml b/platforms/android/demo/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..52f7441
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.mapzen.tangram.android"
+      android:versionCode="1"
+      android:versionName="1.0">
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+    <application android:label="@string/app_name" android:icon="@drawable/ic_launcher" android:theme="@style/Theme.AppCompat.Light">
+        <activity android:name="MainActivity"
+                  android:label="@string/app_name"
+                  android:theme="@style/Theme.AppCompat.NoActionBar">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+            </intent-filter>
+        </activity>
+    </application>
+</manifest>
diff --git a/platforms/android/demo/src/main/java/com/mapzen/tangram/android/MainActivity.java b/platforms/android/demo/src/main/java/com/mapzen/tangram/android/MainActivity.java
new file mode 100644 (file)
index 0000000..952604f
--- /dev/null
@@ -0,0 +1,266 @@
+package com.mapzen.tangram.android;
+
+import android.graphics.PointF;
+import android.os.Bundle;
+import android.support.v7.app.AppCompatActivity;
+import android.util.Log;
+import android.view.Window;
+import android.widget.Toast;
+
+import com.mapzen.tangram.HttpHandler;
+import com.mapzen.tangram.LabelPickResult;
+import com.mapzen.tangram.LngLat;
+import com.mapzen.tangram.MapController;
+import com.mapzen.tangram.MapController.FeaturePickListener;
+import com.mapzen.tangram.MapController.LabelPickListener;
+import com.mapzen.tangram.MapController.MarkerPickListener;
+import com.mapzen.tangram.MapController.SceneUpdateErrorListener;
+import com.mapzen.tangram.MapController.ViewCompleteListener;
+import com.mapzen.tangram.MapData;
+import com.mapzen.tangram.MapView;
+import com.mapzen.tangram.MapView.OnMapReadyCallback;
+import com.mapzen.tangram.Marker;
+import com.mapzen.tangram.MarkerPickResult;
+import com.mapzen.tangram.SceneUpdate;
+import com.mapzen.tangram.SceneUpdateError;
+import com.mapzen.tangram.TouchInput.DoubleTapResponder;
+import com.mapzen.tangram.TouchInput.LongPressResponder;
+import com.mapzen.tangram.TouchInput.TapResponder;
+
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+public class MainActivity extends AppCompatActivity implements OnMapReadyCallback, TapResponder,
+        DoubleTapResponder, LongPressResponder, FeaturePickListener, LabelPickListener, MarkerPickListener, SceneUpdateErrorListener {
+
+    private static final String MAPZEN_API_KEY = BuildConfig.MAPZEN_API_KEY;
+
+    private static final String[] SCENE_PRESETS = {
+            "asset:///scene.yaml",
+            "https://mapzen.com/carto/bubble-wrap-style-more-labels/bubble-wrap-style-more-labels.zip",
+            "https://mapzen.com/carto/refill-style-more-labels/refill-style-more-labels.zip",
+            "https://mapzen.com/carto/walkabout-style-more-labels/walkabout-style-more-labels.zip",
+            "https://mapzen.com/carto/tron-style-more-labels/tron-style-more-labels.zip",
+            "https://mapzen.com/carto/cinnabar-style-more-labels/cinnabar-style-more-labels.zip",
+            "https://mapzen.com/carto/zinc-style-more-labels/zinc-style-more-labels.zip"
+    };
+
+    private ArrayList<SceneUpdate> sceneUpdates = new ArrayList<>();
+
+    MapController map;
+    MapView view;
+    LngLat lastTappedPoint;
+    MapData markers;
+
+    PresetSelectionTextView sceneSelector;
+
+    String pointStylingPath = "layers.touch.point.draw.icons";
+    ArrayList<Marker> pointMarkers = new ArrayList<Marker>();
+
+    boolean showTileInfo = false;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        requestWindowFeature(Window.FEATURE_NO_TITLE);
+
+        setContentView(R.layout.main);
+
+        // Create a scene update to apply our API key in the scene.
+        sceneUpdates.add(new SceneUpdate("global.sdk_mapzen_api_key", MAPZEN_API_KEY));
+
+        // Set up a text view to allow selecting preset and custom scene URLs.
+        sceneSelector = (PresetSelectionTextView)findViewById(R.id.sceneSelector);
+        sceneSelector.setText(SCENE_PRESETS[0]);
+        sceneSelector.setPresetStrings(Arrays.asList(SCENE_PRESETS));
+        sceneSelector.setOnSelectionListener(new PresetSelectionTextView.OnSelectionListener() {
+            @Override
+            public void onSelection(String selection) {
+                map.loadSceneFile(selection, sceneUpdates);
+            }
+        });
+
+        // Grab a reference to our map view.
+        view = (MapView)findViewById(R.id.map);
+    }
+
+    @Override
+    public void onPostCreate(Bundle savedInstanceState) {
+        super.onPostCreate(savedInstanceState);
+        // The AutoCompleteTextView preserves its contents from previous instances, so if a URL was
+        // set previously we want to apply it again. The text is restored in onRestoreInstanceState,
+        // which occurs after onCreate and onStart, but before onPostCreate, so we get the URL here.
+        String sceneUrl = sceneSelector.getCurrentString();
+        view.getMapAsync(this, sceneUrl, sceneUpdates);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        view.onResume();
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        view.onPause();
+    }
+
+    @Override
+    public void onDestroy() {
+        super.onDestroy();
+        view.onDestroy();
+    }
+
+    @Override
+    public void onLowMemory() {
+        super.onLowMemory();
+        view.onLowMemory();
+    }
+
+
+    @Override
+    public void onMapReady(MapController mapController) {
+        map = mapController;
+        map.setZoom(16);
+        map.setPosition(new LngLat(-74.00976419448854, 40.70532700869127));
+        map.setHttpHandler(getHttpHandler());
+        map.setTapResponder(this);
+        map.setDoubleTapResponder(this);
+        map.setLongPressResponder(this);
+        map.setFeaturePickListener(this);
+        map.setLabelPickListener(this);
+        map.setMarkerPickListener(this);
+        map.setSceneUpdateErrorListener(this);
+
+        map.setViewCompleteListener(new ViewCompleteListener() {
+                public void onViewComplete() {
+                    Log.d("Tangram", "View complete");
+                }});
+        markers = map.addDataLayer("touch");
+    }
+
+    HttpHandler getHttpHandler() {
+        File cacheDir = getExternalCacheDir();
+        if (cacheDir != null && cacheDir.exists()) {
+            return new HttpHandler(new File(cacheDir, "tile_cache"), 30 * 1024 * 1024);
+        }
+        return new HttpHandler();
+    }
+
+    @Override
+    public boolean onSingleTapUp(float x, float y) {
+        return false;
+    }
+
+    @Override
+    public boolean onSingleTapConfirmed(float x, float y) {
+        LngLat tappedPoint = map.screenPositionToLngLat(new PointF(x, y));
+
+        if (lastTappedPoint != null) {
+            Map<String, String> props = new HashMap<>();
+            props.put("type", "line");
+            props.put("color", "#D2655F");
+
+            List<LngLat> line = new ArrayList<>();
+            line.add(lastTappedPoint);
+            line.add(tappedPoint);
+            markers.addPolyline(line, props);
+
+            Marker p = map.addMarker();
+            p.setStylingFromPath(pointStylingPath);
+            p.setPoint(tappedPoint);
+            pointMarkers.add(p);
+        }
+
+        lastTappedPoint = tappedPoint;
+
+        map.pickFeature(x, y);
+        map.pickLabel(x, y);
+        map.pickMarker(x, y);
+
+        map.setPositionEased(tappedPoint, 1000);
+
+        return true;
+    }
+
+    @Override
+    public boolean onDoubleTap(float x, float y) {
+        map.setZoomEased(map.getZoom() + 1.f, 500);
+        LngLat tapped = map.screenPositionToLngLat(new PointF(x, y));
+        LngLat current = map.getPosition();
+        LngLat next = new LngLat(
+                .5 * (tapped.longitude + current.longitude),
+                .5 * (tapped.latitude + current.latitude));
+        map.setPositionEased(next, 500);
+        return true;
+    }
+
+    @Override
+    public void onLongPress(float x, float y) {
+        map.removeAllMarkers();
+        pointMarkers.clear();
+        markers.clear();
+        showTileInfo = !showTileInfo;
+        map.setDebugFlag(MapController.DebugFlag.TILE_INFOS, showTileInfo);
+    }
+
+    @Override
+    public void onFeaturePick(Map<String, String> properties, float positionX, float positionY) {
+        if (properties.isEmpty()) {
+            Log.d("Tangram", "Empty selection");
+            return;
+        }
+
+        String name = properties.get("name");
+        if (name.isEmpty()) {
+            name = "unnamed";
+        }
+
+        Log.d("Tangram", "Picked: " + name);
+        final String message = name;
+        Toast.makeText(getApplicationContext(), "Selected: " + message, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
+    public void onLabelPick(LabelPickResult labelPickResult, float positionX, float positionY) {
+        if (labelPickResult == null) {
+            Log.d("Tangram", "Empty label selection");
+            return;
+        }
+
+        String name = labelPickResult.getProperties().get("name");
+        if (name.isEmpty()) {
+            name = "unnamed";
+        }
+
+        Log.d("Tangram", "Picked label: " + name);
+        final String message = name;
+        Toast.makeText(getApplicationContext(), "Selected label: " + message, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
+    public void onMarkerPick(MarkerPickResult markerPickResult, float positionX, float positionY) {
+        if (markerPickResult == null) {
+            Log.d("Tangram", "Empty marker selection");
+            return;
+        }
+
+        Log.d("Tangram", "Picked marker: " + markerPickResult.getMarker().getMarkerId());
+        final String message = String.valueOf(markerPickResult.getMarker().getMarkerId());
+        Toast.makeText(getApplicationContext(), "Selected Marker: " + message, Toast.LENGTH_SHORT).show();
+    }
+
+    @Override
+    public void onSceneUpdateError(SceneUpdateError sceneUpdateError) {
+        Log.d("Tangram", "Scene update errors "
+                + sceneUpdateError.getSceneUpdate().toString()
+                + " " + sceneUpdateError.getError().toString());
+    }
+}
+
diff --git a/platforms/android/demo/src/main/java/com/mapzen/tangram/android/PresetSelectionTextView.java b/platforms/android/demo/src/main/java/com/mapzen/tangram/android/PresetSelectionTextView.java
new file mode 100644 (file)
index 0000000..ae20b71
--- /dev/null
@@ -0,0 +1,115 @@
+package com.mapzen.tangram.android;
+
+import android.content.Context;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.view.KeyEvent;
+import android.view.View;
+import android.view.inputmethod.EditorInfo;
+import android.view.inputmethod.InputMethodManager;
+import android.widget.AdapterView;
+import android.widget.ArrayAdapter;
+import android.widget.Filter;
+import android.widget.TextView;
+
+import java.util.ArrayList;
+import java.util.List;
+
+public class PresetSelectionTextView extends android.support.v7.widget.AppCompatAutoCompleteTextView {
+
+    public interface OnSelectionListener {
+        void onSelection(String selection);
+    }
+
+    // Custom ArrayAdaptor that displays any suggestions that contain the input as a substring.
+    private class PartialMatchArrayAdapter extends ArrayAdapter {
+
+        List<String> presets;
+        List<String> suggestions = new ArrayList<>();
+
+        Filter partialMatchFilter = new Filter() {
+            @Override
+            public CharSequence convertResultToString(Object resultValue) {
+                return resultValue.toString().toLowerCase();
+            }
+
+            @Override
+            protected FilterResults performFiltering(CharSequence constraint) {
+                FilterResults results = new FilterResults();
+                if (constraint != null) {
+                    suggestions.clear();
+                    String substring = constraint.toString().toLowerCase();
+                    for (String preset: presets) {
+                        if (preset.toLowerCase().contains(substring)) {
+                            suggestions.add(preset);
+                        }
+                    }
+                    results.values = suggestions;
+                    results.count = suggestions.size();
+                }
+                return results;
+            }
+
+            @Override
+            protected void publishResults(CharSequence constraint, FilterResults results) {
+                if (results != null && results.count > 0) {
+                    List<String> filterList = (ArrayList<String>)results.values;
+                    clear();
+                    addAll(filterList);
+                    notifyDataSetChanged();
+                }
+            }
+        };
+
+        PartialMatchArrayAdapter(Context context, List<String> presets) {
+            super(context, android.R.layout.simple_list_item_1);
+            this.presets = presets;
+        }
+
+        @Override @NonNull
+        public Filter getFilter() {
+            return partialMatchFilter;
+        }
+    }
+
+    public PresetSelectionTextView(Context context, AttributeSet attr) {
+        super(context, attr);
+        setOnEditorActionListener(new OnEditorActionListener() {
+            @Override
+            public boolean onEditorAction(TextView textView, int action, KeyEvent keyEvent) {
+                finishEntry();
+                return false;
+            }
+        });
+        setOnItemClickListener(new AdapterView.OnItemClickListener() {
+            @Override
+            public void onItemClick(AdapterView<?> adapterView, View view, int i, long l) {
+                finishEntry();
+            }
+        });
+    }
+
+    public void setPresetStrings(List<String> presets) {
+        setAdapter(new PartialMatchArrayAdapter(getContext(), presets));
+    }
+
+    public void setOnSelectionListener(OnSelectionListener listener) {
+        this.onSelectionListener = listener;
+    }
+
+    public String getCurrentString() {
+        return getText().toString();
+    }
+
+    private OnSelectionListener onSelectionListener;
+
+    private void finishEntry() {
+        clearFocus();
+        InputMethodManager imm = (InputMethodManager)getContext().getSystemService(Context.INPUT_METHOD_SERVICE);
+        imm.hideSoftInputFromWindow(getWindowToken(), 0);
+        if (onSelectionListener != null) {
+            onSelectionListener.onSelection(getCurrentString());
+        }
+    }
+
+}
diff --git a/platforms/android/demo/src/main/res/drawable-hdpi/ic_launcher.png b/platforms/android/demo/src/main/res/drawable-hdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..96a442e
Binary files /dev/null and b/platforms/android/demo/src/main/res/drawable-hdpi/ic_launcher.png differ
diff --git a/platforms/android/demo/src/main/res/drawable-ldpi/ic_launcher.png b/platforms/android/demo/src/main/res/drawable-ldpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..9923872
Binary files /dev/null and b/platforms/android/demo/src/main/res/drawable-ldpi/ic_launcher.png differ
diff --git a/platforms/android/demo/src/main/res/drawable-mdpi/ic_launcher.png b/platforms/android/demo/src/main/res/drawable-mdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..359047d
Binary files /dev/null and b/platforms/android/demo/src/main/res/drawable-mdpi/ic_launcher.png differ
diff --git a/platforms/android/demo/src/main/res/drawable-xhdpi/ic_launcher.png b/platforms/android/demo/src/main/res/drawable-xhdpi/ic_launcher.png
new file mode 100644 (file)
index 0000000..71c6d76
Binary files /dev/null and b/platforms/android/demo/src/main/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/platforms/android/demo/src/main/res/layout/main.xml b/platforms/android/demo/src/main/res/layout/main.xml
new file mode 100644 (file)
index 0000000..6476f33
--- /dev/null
@@ -0,0 +1,25 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:focusableInTouchMode="true"
+    tools:context=".MainActivity">
+
+    <com.mapzen.tangram.android.PresetSelectionTextView
+        android:id="@+id/sceneSelector"
+        android:layout_width="match_parent"
+        android:layout_height="80dp"
+        android:imeOptions="actionGo"
+        android:completionThreshold="1"
+        android:inputType="textUri"
+        android:selectAllOnFocus="true"/>
+
+    <com.mapzen.tangram.MapView
+        android:id="@+id/map"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:layout_below="@+id/sceneSelector">
+
+    </com.mapzen.tangram.MapView>
+
+</RelativeLayout>
diff --git a/platforms/android/demo/src/main/res/values/strings.xml b/platforms/android/demo/src/main/res/values/strings.xml
new file mode 100644 (file)
index 0000000..4855d10
--- /dev/null
@@ -0,0 +1,4 @@
+<?xml version="1.0" encoding="utf-8"?>
+<resources>
+    <string name="app_name">Tangram</string>
+</resources>
diff --git a/platforms/android/gradle.properties b/platforms/android/gradle.properties
new file mode 100644 (file)
index 0000000..8f2eaf2
--- /dev/null
@@ -0,0 +1,3 @@
+org.gradle.daemon=true
+org.gradle.parallel=true
+org.gradle.jvmargs=-Xmx2048m
diff --git a/platforms/android/gradle/wrapper/gradle-wrapper.jar b/platforms/android/gradle/wrapper/gradle-wrapper.jar
new file mode 100644 (file)
index 0000000..8c0fb64
Binary files /dev/null and b/platforms/android/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/platforms/android/gradle/wrapper/gradle-wrapper.properties b/platforms/android/gradle/wrapper/gradle-wrapper.properties
new file mode 100644 (file)
index 0000000..6aa93a1
--- /dev/null
@@ -0,0 +1,6 @@
+#Wed Sep 14 20:10:31 EDT 2016
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip
diff --git a/platforms/android/gradlew b/platforms/android/gradlew
new file mode 100755 (executable)
index 0000000..91a7e26
--- /dev/null
@@ -0,0 +1,164 @@
+#!/usr/bin/env bash
+
+##############################################################################
+##
+##  Gradle start up script for UN*X
+##
+##############################################################################
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn ( ) {
+    echo "$*"
+}
+
+die ( ) {
+    echo
+    echo "$*"
+    echo
+    exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+case "`uname`" in
+  CYGWIN* )
+    cygwin=true
+    ;;
+  Darwin* )
+    darwin=true
+    ;;
+  MINGW* )
+    msys=true
+    ;;
+esac
+
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
+if $cygwin ; then
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
+fi
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+    ls=`ls -ld "$PRG"`
+    link=`expr "$ls" : '.*-> \(.*\)$'`
+    if expr "$link" : '/.*' > /dev/null; then
+        PRG="$link"
+    else
+        PRG=`dirname "$PRG"`"/$link"
+    fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >&-
+APP_HOME="`pwd -P`"
+cd "$SAVED" >&-
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+        # IBM's JDK on AIX uses strange locations for the executables
+        JAVACMD="$JAVA_HOME/jre/sh/java"
+    else
+        JAVACMD="$JAVA_HOME/bin/java"
+    fi
+    if [ ! -x "$JAVACMD" ] ; then
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+    fi
+else
+    JAVACMD="java"
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
+    MAX_FD_LIMIT=`ulimit -H -n`
+    if [ $? -eq 0 ] ; then
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+            MAX_FD="$MAX_FD_LIMIT"
+        fi
+        ulimit -n $MAX_FD
+        if [ $? -ne 0 ] ; then
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
+        fi
+    else
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+    fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+    # We build the pattern for arguments to be converted via cygpath
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+    SEP=""
+    for dir in $ROOTDIRSRAW ; do
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
+        SEP="|"
+    done
+    OURCYGPATTERN="(^($ROOTDIRS))"
+    # Add a user-defined pattern to the cygpath arguments
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+    fi
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
+    i=0
+    for arg in "$@" ; do
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
+
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+        else
+            eval `echo args$i`="\"$arg\""
+        fi
+        i=$((i+1))
+    done
+    case $i in
+        (0) set -- ;;
+        (1) set -- "$args0" ;;
+        (2) set -- "$args0" "$args1" ;;
+        (3) set -- "$args0" "$args1" "$args2" ;;
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+    esac
+fi
+
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
+function splitJvmOpts() {
+    JVM_OPTS=("$@")
+}
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
+
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"
diff --git a/platforms/android/release-checklist.md b/platforms/android/release-checklist.md
new file mode 100644 (file)
index 0000000..c2e07c0
--- /dev/null
@@ -0,0 +1,38 @@
+# Tangram ES (Android) Release Checklist
+
+Steps to build and release the Tangram ES (AAR) to Maven Central:
+
+### 1. Prepare release commit
+Remove `-SNAPSHOT` tag from the version name in `gradle.properties`. Commit and push to master.
+```
+GROUP=com.mapzen.tangram
+VERSION_NAME=1.0.0
+```
+
+### 2. Tag release commit
+Tag commit with release version and push tag to GitHub.
+```
+$ git tag tangram-1.0.0
+$ git push origin tangram-1.0.0
+```
+
+### 3. Prepare next development cycle
+Update version name and restore `-SNAPSHOT` tag to prepare next development cycle. Commit and push to master.
+```
+GROUP=com.mapzen.tangram
+VERSION_NAME=1.0.1-SNAPSHOT
+```
+
+### 4. Promote artifact to production
+Once [Travis CI][1] completes the release build, log into [Sonatype Staging Repository][2] and promote the artifact to production. For more information see the [Sonatype OSSRH Guide][3].
+
+**Note: It can several hours for a newly promoted artifact to appear in [Maven Central][4].**
+
+### 5. Document release
+Document release notes at [https://github.com/tangrams/tangram-es/releases][5].
+
+[1]: https://travis-ci.org/tangrams/tangram-es
+[2]: https://oss.sonatype.org/#stagingRepositories
+[3]: http://central.sonatype.org/pages/ossrh-guide.html
+[4]: http://search.maven.org/#search%7Cga%7C1%7Ctangram
+[5]: https://github.com/tangrams/tangram-es/releases
diff --git a/platforms/android/run.sh b/platforms/android/run.sh
new file mode 100755 (executable)
index 0000000..285b18a
--- /dev/null
@@ -0,0 +1,3 @@
+adb uninstall com.mapzen.tangram.android
+adb install android/demo/build/outputs/apk/demo-debug.apk
+adb shell am start -a android.intent.action.MAIN -n com.mapzen.tangram.android/.MainActivity
diff --git a/platforms/android/settings.gradle b/platforms/android/settings.gradle
new file mode 100644 (file)
index 0000000..71740ff
--- /dev/null
@@ -0,0 +1 @@
+include 'tangram', 'demo'
diff --git a/platforms/android/tangram/build.gradle b/platforms/android/tangram/build.gradle
new file mode 100644 (file)
index 0000000..517fc25
--- /dev/null
@@ -0,0 +1,80 @@
+apply plugin: 'com.android.library'
+apply plugin: 'com.github.dcendents.android-maven'
+
+group = GROUP
+version = VERSION_NAME
+
+apply from: 'versioning.gradle'
+
+android {
+  compileSdkVersion 25
+  buildToolsVersion '25.0.2'
+
+  defaultConfig {
+    minSdkVersion 15
+    targetSdkVersion 25
+    versionCode buildVersionCode()
+    versionName VERSION_NAME
+    externalNativeBuild {
+      cmake {
+        targets 'tangram'
+        arguments '-DPLATFORM_TARGET=android',
+                  '-DANDROID_TOOLCHAIN=clang',
+                  '-DANDROID_STL=c++_shared'
+        cppFlags '-std=c++14',
+                 '-pedantic',
+                 '-fPIC',
+                 '-fexceptions',
+                 '-frtti',
+                 //warnings
+                 '-Wall',
+                 '-Wignored-qualifiers',
+                 '-Wtype-limits',
+                 '-Wmissing-field-initializers'
+
+        abiFilters 'armeabi-v7a'
+      }
+    }
+  }
+
+  externalNativeBuild {
+    cmake {
+      path '../../../CMakeLists.txt'
+    }
+  }
+
+  buildTypes {
+    debug {
+      externalNativeBuild {
+        cmake.cppFlags '-g'
+      }
+    }
+    release {
+      externalNativeBuild {
+        cmake.cppFlags'-g0'
+      }
+    }
+  }
+  productFlavors {
+    slim {
+      // Default configuration
+    }
+    full {
+      externalNativeBuild.cmake.abiFilters 'armeabi', 'arm64-v8a', 'x86'
+    }
+  }
+
+  if (project.hasProperty('doFullRelease')) {
+    defaultPublishConfig 'fullRelease'
+  } else {
+    defaultPublishConfig 'slimDebug'
+  }
+}
+
+dependencies {
+  compile 'com.squareup.okhttp3:okhttp:3.5.0'
+  compile 'xmlpull:xmlpull:1.1.3.1'
+  compile 'com.android.support:support-annotations:25.0.0'
+}
+
+apply from: file('gradle-mvn-push.gradle')
diff --git a/platforms/android/tangram/gradle-mvn-push.gradle b/platforms/android/tangram/gradle-mvn-push.gradle
new file mode 100644 (file)
index 0000000..f3d9389
--- /dev/null
@@ -0,0 +1,114 @@
+/*
+ * Copyright 2013 Chris Banes
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+apply plugin: 'maven'
+apply plugin: 'signing'
+
+def isReleaseBuild() {
+  return VERSION_NAME.contains("SNAPSHOT") == false
+}
+
+def getRepositoryUsername() {
+  return hasProperty('sonatypeUsername') ? sonatypeUsername : ""
+}
+
+def getRepositoryPassword() {
+  return hasProperty('sonatypePassword') ? sonatypePassword : ""
+}
+
+afterEvaluate { project ->
+  uploadArchives {
+    repositories {
+      mavenDeployer {
+        beforeDeployment { MavenDeployment deployment -> signing.signPom(deployment) }
+
+        pom.groupId = GROUP
+        pom.artifactId = POM_ARTIFACT_ID
+        pom.version = VERSION_NAME
+
+        repository(url: "https://oss.sonatype.org/service/local/staging/deploy/maven2/") {
+          authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
+        }
+        snapshotRepository(url: "https://oss.sonatype.org/content/repositories/snapshots/") {
+          authentication(userName: getRepositoryUsername(), password: getRepositoryPassword())
+        }
+
+        pom.project {
+          name POM_NAME
+          packaging POM_PACKAGING
+          description POM_DESCRIPTION
+          url POM_URL
+
+          scm {
+            url POM_SCM_URL
+            connection POM_SCM_CONNECTION
+            developerConnection POM_SCM_DEV_CONNECTION
+          }
+
+          licenses {
+            license {
+              name POM_LICENCE_NAME
+              url POM_LICENCE_URL
+              distribution POM_LICENCE_DIST
+            }
+          }
+
+          developers {
+            developer {
+              id POM_DEVELOPER_ID
+              name POM_DEVELOPER_NAME
+            }
+          }
+        }
+      }
+    }
+  }
+
+  signing {
+    required { isReleaseBuild() && gradle.taskGraph.hasTask("uploadArchives") }
+    sign configurations.archives
+  }
+
+  task androidJavadocs(type: Javadoc) {
+    source = android.sourceSets.main.java.srcDirs
+    classpath += project.files(android.getBootClasspath().join(File.pathSeparator))
+    exclude '**/*.kt'
+    exclude 'com/almeros/android/multitouch'
+
+    if (JavaVersion.current().isJava8Compatible()) {
+      allprojects {
+        tasks.withType(Javadoc) {
+          options.addStringOption('Xdoclint:none', '-quiet')
+        }
+      }
+    }
+  }
+
+  task androidJavadocsJar(type: Jar, dependsOn: androidJavadocs) {
+    classifier = 'javadoc'
+    from androidJavadocs.destinationDir
+  }
+
+  task androidSourcesJar(type: Jar) {
+    classifier = 'sources'
+    from android.sourceSets.main.java.sourceFiles
+  }
+
+  artifacts {
+    archives androidSourcesJar
+    archives androidJavadocsJar
+  }
+}
diff --git a/platforms/android/tangram/gradle.properties b/platforms/android/tangram/gradle.properties
new file mode 100644 (file)
index 0000000..e4f848d
--- /dev/null
@@ -0,0 +1,20 @@
+GROUP=com.mapzen.tangram
+VERSION_NAME=0.7.0
+
+POM_ARTIFACT_ID=tangram
+
+POM_NAME=Tangram ES
+POM_PACKAGING=aar
+POM_DESCRIPTION=Tangram Android SDK
+
+POM_URL=http://github.com/tangrams/tangram-es
+POM_SCM_URL=http://github.com/tangrams/tangram-es
+POM_SCM_CONNECTION=scm:git:git://github.com/tangrams/tangram-es.git
+POM_SCM_DEV_CONNECTION=scm:git:ssh://git@github.com/tangrams/tangram-es.git
+
+POM_LICENCE_NAME=The MIT License (MIT)
+POM_LICENCE_URL=http://opensource.org/licenses/MIT
+POM_LICENCE_DIST=repo
+
+POM_DEVELOPER_ID=Mapzen
+POM_DEVELOPER_NAME=Mapzen
diff --git a/platforms/android/tangram/src/main/AndroidManifest.xml b/platforms/android/tangram/src/main/AndroidManifest.xml
new file mode 100644 (file)
index 0000000..ee58ec1
--- /dev/null
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+      package="com.mapzen.tangram">
+    <uses-feature android:glEsVersion="0x00020000" android:required="true" />
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+</manifest>
diff --git a/platforms/android/tangram/src/main/cpp/jniExports.cpp b/platforms/android/tangram/src/main/cpp/jniExports.cpp
new file mode 100644 (file)
index 0000000..92f0e6a
--- /dev/null
@@ -0,0 +1,538 @@
+#include "tangram.h"
+#include "platform_android.h"
+#include "data/clientGeoJsonSource.h"
+
+#include <cassert>
+
+extern "C" {
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetPosition(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jdouble lon, jdouble lat) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setPosition(lon, lat);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetPositionEased(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jdouble lon, jdouble lat, jfloat duration, jint ease) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setPositionEased(lon, lat, duration, static_cast<Tangram::EaseType>(ease));
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeGetPosition(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jdoubleArray lonLat) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        jdouble* arr = jniEnv->GetDoubleArrayElements(lonLat, NULL);
+        map->getPosition(arr[0], arr[1]);
+        jniEnv->ReleaseDoubleArrayElements(lonLat, arr, 0);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetZoom(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat zoom) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setZoom(zoom);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetZoomEased(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat zoom, jfloat duration, jint ease) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setZoomEased(zoom, duration, static_cast<Tangram::EaseType>(ease));
+    }
+
+    JNIEXPORT jfloat JNICALL Java_com_mapzen_tangram_MapController_nativeGetZoom(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        return map->getZoom();
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetRotation(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat radians) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setRotation(radians);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetRotationEased(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat radians, jfloat duration, jint ease) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setRotationEased(radians, duration, static_cast<Tangram::EaseType>(ease));
+    }
+
+    JNIEXPORT jfloat JNICALL Java_com_mapzen_tangram_MapController_nativeGetRotation(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        return map->getRotation();
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetTilt(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat radians) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setTilt(radians);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetTiltEased(JNIEnv* jniEnv, jobject obj,  jlong mapPtr, jfloat radians, jfloat duration, jint ease) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setTiltEased(radians, duration, static_cast<Tangram::EaseType>(ease));
+    }
+
+    JNIEXPORT jfloat JNICALL Java_com_mapzen_tangram_MapController_nativeGetTilt(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        return map->getTilt();
+    }
+
+    JNIEXPORT jboolean JNICALL Java_com_mapzen_tangram_MapController_nativeScreenPositionToLngLat(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jdoubleArray coordinates) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        jdouble* arr = jniEnv->GetDoubleArrayElements(coordinates, NULL);
+        bool ret = map->screenPositionToLngLat(arr[0], arr[1], &arr[0], &arr[1]);
+        jniEnv->ReleaseDoubleArrayElements(coordinates, arr, 0);
+        return ret;
+    }
+
+    JNIEXPORT jboolean JNICALL Java_com_mapzen_tangram_MapController_nativeLngLatToScreenPosition(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jdoubleArray coordinates) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        jdouble* arr = jniEnv->GetDoubleArrayElements(coordinates, NULL);
+        bool ret = map->lngLatToScreenPosition(arr[0], arr[1], &arr[0], &arr[1]);
+        jniEnv->ReleaseDoubleArrayElements(coordinates, arr, 0);
+        return ret;
+    }
+
+    JNIEXPORT jlong JNICALL Java_com_mapzen_tangram_MapController_nativeInit(JNIEnv* jniEnv, jobject obj, jobject tangramInstance, jobject assetManager) {
+        setupJniEnv(jniEnv);
+        auto map = new Tangram::Map(std::shared_ptr<Tangram::Platform>(new Tangram::AndroidPlatform(jniEnv, assetManager, tangramInstance)));
+        return reinterpret_cast<jlong>(map);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeDispose(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        // Don't dispose MapController ref before map is teared down,
+        // delete map or worker threads might call back to it (e.g. requestRender)
+        auto platform = map->getPlatform();
+
+        delete map;
+
+        static_cast<Tangram::AndroidPlatform&>(*platform).dispose(jniEnv);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeLoadScene(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jobject updateErrorCallback, jstring path, jobjectArray updateStrings) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        const char* cPath = jniEnv->GetStringUTFChars(path, NULL);
+        size_t nUpdateStrings = (updateStrings == NULL) ? 0 : jniEnv->GetArrayLength(updateStrings);
+
+        std::vector<Tangram::SceneUpdate> sceneUpdates;
+        for (size_t i = 0; i < nUpdateStrings;) {
+            jstring path = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++));
+            jstring value = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++));
+            sceneUpdates.emplace_back(stringFromJString(jniEnv, path), stringFromJString(jniEnv, value));
+            jniEnv->DeleteLocalRef(path);
+            jniEnv->DeleteLocalRef(value);
+        }
+
+        auto updateErrorCallbackRef = jniEnv->NewGlobalRef(updateErrorCallback);
+        map->loadScene(resolveScenePath(cPath).c_str(), false, sceneUpdates, [updateErrorCallbackRef](auto sceneUpdateErrorStatus) {
+            Tangram::sceneUpdateErrorCallback(updateErrorCallbackRef, sceneUpdateErrorStatus);
+        });
+        jniEnv->ReleaseStringUTFChars(path, cPath);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeResize(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jint width, jint height) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->resize(width, height);
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeUpdate(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat dt) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        return map->update(dt);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeRender(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->render();
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetupGL(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        bindJniEnvToThread(jniEnv);
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setupGL();
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetPixelScale(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat scale) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setPixelScale(scale);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetCameraType(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jint type) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setCameraType(type);
+    }
+
+    JNIEXPORT jint JNICALL Java_com_mapzen_tangram_MapController_nativeGetCameraType(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        return map->getCameraType();
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandleTapGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handleTapGesture(posX, posY);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandleDoubleTapGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handleDoubleTapGesture(posX, posY);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandlePanGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat startX, jfloat startY, jfloat endX, jfloat endY) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handlePanGesture(startX, startY, endX, endY);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandleFlingGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY, jfloat velocityX, jfloat velocityY) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handleFlingGesture(posX, posY, velocityX, velocityY);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandlePinchGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY, jfloat scale, jfloat velocity) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handlePinchGesture(posX, posY, scale, velocity);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandleRotateGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY, jfloat rotation) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handleRotateGesture(posX, posY, rotation);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeHandleShoveGesture(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat distance) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->handleShoveGesture(distance);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeOnUrlSuccess(JNIEnv* jniEnv, jobject obj, jbyteArray fetchedBytes, jlong callbackPtr) {
+        onUrlSuccess(jniEnv, fetchedBytes, callbackPtr);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeOnUrlFailure(JNIEnv* jniEnv, jobject obj, jlong callbackPtr) {
+        onUrlFailure(jniEnv, callbackPtr);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetPickRadius(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat radius) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->setPickRadius(radius);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativePickFeature(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY, jobject listener) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto object = jniEnv->NewGlobalRef(listener);
+        map->pickFeatureAt(posX, posY, [object](auto pickResult) {
+            Tangram::featurePickCallback(object, pickResult);
+        });
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativePickMarker(JNIEnv* jniEnv, jobject obj, jobject tangramInstance, jlong mapPtr, jfloat posX, jfloat posY, jobject listener) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto object = jniEnv->NewGlobalRef(listener);
+        auto instance = jniEnv->NewGlobalRef(tangramInstance);
+        map->pickMarkerAt(posX, posY, [object, instance](auto pickMarkerResult) {
+            Tangram::markerPickCallback(object, instance, pickMarkerResult);
+        });
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativePickLabel(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jfloat posX, jfloat posY, jobject listener) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto object = jniEnv->NewGlobalRef(listener);
+        map->pickLabelAt(posX, posY, [object](auto pickResult) {
+            Tangram::labelPickCallback(object, pickResult);
+        });
+    }
+
+    // NOTE unsigned int to jlong for precision... else we can do jint return
+    JNIEXPORT jlong JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerAdd(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto markerID = map->markerAdd();
+        return static_cast<jlong>(markerID);
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerRemove(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto result = map->markerRemove(static_cast<unsigned int>(markerID));
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetStylingFromString(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jstring styling) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto styleString = stringFromJString(jniEnv, styling);
+        auto result = map->markerSetStylingFromString(static_cast<unsigned int>(markerID), styleString.c_str());
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetStylingFromPath(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jstring path) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto pathString = stringFromJString(jniEnv, path);
+        auto result = map->markerSetStylingFromPath(static_cast<unsigned int>(markerID), pathString.c_str());
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetBitmap(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jint width, jint height, jintArray data) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        jint* ptr = jniEnv->GetIntArrayElements(data, NULL);
+        unsigned int* imgData = reinterpret_cast<unsigned int*>(ptr);
+        jniEnv->ReleaseIntArrayElements(data, ptr, JNI_ABORT);
+        auto result = map->markerSetBitmap(static_cast<unsigned int>(markerID), width, height, imgData);
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetPoint(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jdouble lng, jdouble lat) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto result = map->markerSetPoint(static_cast<unsigned int>(markerID), Tangram::LngLat(lng, lat));
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetPointEased(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jdouble lng, jdouble lat, jfloat duration, jint ease) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto result = map->markerSetPointEased(static_cast<unsigned int>(markerID), Tangram::LngLat(lng, lat), duration, static_cast<Tangram::EaseType>(ease));
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetPolyline(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jdoubleArray jcoordinates, jint count) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        if (!jcoordinates || count == 0) { return false; }
+
+        auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL);
+        std::vector<Tangram::LngLat> polyline;
+        polyline.reserve(count);
+
+        for (size_t i = 0; i < count; ++i) {
+            polyline.emplace_back(coordinates[2 * i], coordinates[2 * i + 1]);
+        }
+
+        auto result = map->markerSetPolyline(static_cast<unsigned int>(markerID), polyline.data(), count);
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetPolygon(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jdoubleArray jcoordinates, jintArray jcounts, jint rings) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        if (!jcoordinates || !jcounts || rings == 0) { return false; }
+
+        auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL);
+
+        auto* counts = jniEnv->GetIntArrayElements(jcounts, NULL);
+
+        std::vector<Tangram::LngLat> polygonCoords;
+
+        size_t coordsCount = 0;
+        for (size_t i = 0; i < rings; i++) {
+            size_t ringCount = *(counts+i);
+            for (size_t j = 0; j < ringCount; j++) {
+                polygonCoords.emplace_back(coordinates[coordsCount + 2 * j], coordinates[coordsCount + 2 * j + 1]);
+            }
+            coordsCount += ringCount;
+        }
+
+        auto result = map->markerSetPolygon(static_cast<unsigned int>(markerID), polygonCoords.data(), counts, rings);
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetVisible(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jboolean visible) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto result = map->markerSetVisible(static_cast<unsigned int>(markerID), visible);
+        return result;
+    }
+
+    JNIEXPORT bool JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerSetDrawOrder(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong markerID, jint drawOrder) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto result = map->markerSetDrawOrder(markerID, drawOrder);
+        return result;
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeMarkerRemoveAll(JNIEnv* jniEnv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->markerRemoveAll();
+    }
+
+    JNIEXPORT jlong JNICALL Java_com_mapzen_tangram_MapController_nativeAddTileSource(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jstring name) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto sourceName = stringFromJString(jniEnv, name);
+        auto source = std::shared_ptr<Tangram::TileSource>(new Tangram::ClientGeoJsonSource(map->getPlatform(), sourceName, ""));
+        map->addTileSource(source);
+        return reinterpret_cast<jlong>(source.get());
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeRemoveTileSource(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong sourcePtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        assert(sourcePtr > 0);
+        auto source = reinterpret_cast<Tangram::TileSource*>(sourcePtr);
+        map->removeTileSource(*source);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeClearTileSource(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong sourcePtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        assert(sourcePtr > 0);
+        auto source = reinterpret_cast<Tangram::TileSource*>(sourcePtr);
+        map->clearTileSource(*source, true, true);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeAddFeature(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong sourcePtr,
+        jdoubleArray jcoordinates, jintArray jrings, jobjectArray jproperties) {
+
+        assert(mapPtr > 0);
+        assert(sourcePtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto source = reinterpret_cast<Tangram::ClientGeoJsonSource*>(map->getPlatform(), sourcePtr);
+
+        size_t n_points = jniEnv->GetArrayLength(jcoordinates) / 2;
+        size_t n_rings = (jrings == NULL) ? 0 : jniEnv->GetArrayLength(jrings);
+        size_t n_properties = (jproperties == NULL) ? 0 : jniEnv->GetArrayLength(jproperties) / 2;
+
+        Tangram::Properties properties;
+
+        for (size_t i = 0; i < n_properties; ++i) {
+            jstring jkey = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i));
+            jstring jvalue = (jstring) (jniEnv->GetObjectArrayElement(jproperties, 2 * i + 1));
+            auto key = stringFromJString(jniEnv, jkey);
+            auto value = stringFromJString(jniEnv, jvalue);
+            properties.set(key, value);
+            jniEnv->DeleteLocalRef(jkey);
+            jniEnv->DeleteLocalRef(jvalue);
+        }
+
+        auto* coordinates = jniEnv->GetDoubleArrayElements(jcoordinates, NULL);
+
+        if (n_rings > 0) {
+            // If rings are defined, this is a polygon feature.
+            auto* rings = jniEnv->GetIntArrayElements(jrings, NULL);
+            std::vector<std::vector<Tangram::LngLat>> polygon;
+            size_t ring_start = 0, ring_end = 0;
+            for (size_t i = 0; i < n_rings; ++i) {
+                ring_end += rings[i];
+                std::vector<Tangram::LngLat> ring;
+                for (; ring_start < ring_end; ++ring_start) {
+                    ring.push_back({coordinates[2 * ring_start], coordinates[2 * ring_start + 1]});
+                }
+                polygon.push_back(std::move(ring));
+            }
+            source->addPoly(properties, polygon);
+            jniEnv->ReleaseIntArrayElements(jrings, rings, JNI_ABORT);
+        } else if (n_points > 1) {
+            // If no rings defined but multiple points, this is a polyline feature.
+            std::vector<Tangram::LngLat> polyline;
+            for (size_t i = 0; i < n_points; ++i) {
+                polyline.push_back({coordinates[2 * i], coordinates[2 * i + 1]});
+            }
+            source->addLine(properties, polyline);
+        } else {
+            // This is a point feature.
+            auto point = Tangram::LngLat(coordinates[0], coordinates[1]);
+            source->addPoint(properties, point);
+        }
+
+        jniEnv->ReleaseDoubleArrayElements(jcoordinates, coordinates, JNI_ABORT);
+
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeAddGeoJson(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jlong sourcePtr, jstring geojson) {
+        assert(mapPtr > 0);
+        assert(sourcePtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto source = reinterpret_cast<Tangram::ClientGeoJsonSource*>(map->getPlatform(), sourcePtr);
+        auto data = stringFromJString(jniEnv, geojson);
+        source->addData(data);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeSetDebugFlag(JNIEnv* jniEnv, jobject obj, jint flag, jboolean on) {
+        Tangram::setDebugFlag(static_cast<Tangram::DebugFlags>(flag), on);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeUseCachedGlState(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jboolean use) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->useCachedGlState(use);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeCaptureSnapshot(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jintArray buffer) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        jint* ptr = jniEnv->GetIntArrayElements(buffer, NULL);
+        unsigned int* data = reinterpret_cast<unsigned int*>(ptr);
+        map->captureSnapshot(data);
+        jniEnv->ReleaseIntArrayElements(buffer, ptr, JNI_ABORT);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeQueueSceneUpdate(JNIEnv* jnienv, jobject obj, jlong mapPtr, jstring path, jstring value) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        const char* cPath = jnienv->GetStringUTFChars(path, NULL);
+        const char* cValue = jnienv->GetStringUTFChars(value, NULL);
+        map->queueSceneUpdate(cPath, cValue);
+        jnienv->ReleaseStringUTFChars(path, cPath);
+        jnienv->ReleaseStringUTFChars(value, cValue);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeQueueSceneUpdates(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jobjectArray updateStrings) {
+        assert(mapPtr > 0);
+        size_t nUpdateStrings = (updateStrings == NULL)? 0 : jniEnv->GetArrayLength(updateStrings);
+
+        std::vector<Tangram::SceneUpdate> sceneUpdates;
+        for (size_t i = 0; i < nUpdateStrings;) {
+            jstring path = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++));
+            jstring value = (jstring) (jniEnv->GetObjectArrayElement(updateStrings, i++));
+            sceneUpdates.emplace_back(stringFromJString(jniEnv, path), stringFromJString(jniEnv, value));
+            jniEnv->DeleteLocalRef(path);
+            jniEnv->DeleteLocalRef(value);
+        }
+
+        if (sceneUpdates.empty()) { return; }
+
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->queueSceneUpdate(sceneUpdates);
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeApplySceneUpdates(JNIEnv* jniEnv, jobject obj, jlong mapPtr, jobject updateErrorCallback) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        auto updateErrorCallbackRef = jniEnv->NewGlobalRef(updateErrorCallback);
+        map->applySceneUpdates([updateErrorCallbackRef](auto sceneUpdateErrorStatus) {
+            Tangram::sceneUpdateErrorCallback(updateErrorCallbackRef, sceneUpdateErrorStatus);
+        });
+    }
+
+    JNIEXPORT void JNICALL Java_com_mapzen_tangram_MapController_nativeOnLowMemory(JNIEnv* jnienv, jobject obj, jlong mapPtr) {
+        assert(mapPtr > 0);
+        auto map = reinterpret_cast<Tangram::Map*>(mapPtr);
+        map->onMemoryWarning();
+    }
+}
diff --git a/platforms/android/tangram/src/main/cpp/platform_android.cpp b/platforms/android/tangram/src/main/cpp/platform_android.cpp
new file mode 100644 (file)
index 0000000..1637246
--- /dev/null
@@ -0,0 +1,481 @@
+#ifdef PLATFORM_ANDROID
+
+#include "platform_android.h"
+
+#include "data/properties.h"
+#include "data/propertyItem.h"
+#include "log.h"
+#include "util/url.h"
+#include "tangram.h"
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES 1
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <GLES2/gl2platform.h>
+#include <android/log.h>
+#include <android/asset_manager_jni.h>
+#include <cstdarg>
+#include <dlfcn.h> // dlopen, dlsym
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/resource.h>
+
+#include "sqlite3ndk.h"
+
+/* Followed the following document for JavaVM tips when used with native threads
+ * http://android.wooyd.org/JNIExample/#NWD1sCYeT-I
+ * http://developer.android.com/training/articles/perf-jni.html and
+ * http://www.ibm.com/developerworks/library/j-jni/
+ * http://docs.oracle.com/javase/7/docs/technotes/guides/jni/spec/invocation.html
+ */
+
+static JavaVM* jvm = nullptr;
+// JNI Env bound on androids render thread (our native main thread)
+static jobject tangramInstance = nullptr;
+static jmethodID requestRenderMethodID = 0;
+static jmethodID setRenderModeMethodID = 0;
+static jmethodID startUrlRequestMID = 0;
+static jmethodID cancelUrlRequestMID = 0;
+static jmethodID getFontFilePath = 0;
+static jmethodID getFontFallbackFilePath = 0;
+static jmethodID onFeaturePickMID = 0;
+static jmethodID onLabelPickMID = 0;
+static jmethodID onMarkerPickMID = 0;
+static jmethodID labelPickResultInitMID = 0;
+static jmethodID markerPickResultInitMID = 0;
+static jmethodID onSceneUpdateErrorMID = 0;
+static jmethodID sceneUpdateErrorInitMID = 0;
+
+static jclass labelPickResultClass = nullptr;
+static jclass sceneUpdateErrorClass = nullptr;
+static jclass markerPickResultClass = nullptr;
+
+static jclass hashmapClass = nullptr;
+static jmethodID hashmapInitMID = 0;
+static jmethodID hashmapPutMID = 0;
+
+static jmethodID markerByIDMID = 0;
+
+static bool glExtensionsLoaded = false;
+
+PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT = 0;
+PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT = 0;
+PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT = 0;
+
+// Android assets are distinguished from file paths by the "asset" scheme.
+static const char* aaPrefix = "asset:///";
+static const size_t aaPrefixLen = 9;
+
+void bindJniEnvToThread(JNIEnv* jniEnv) {
+    jniEnv->GetJavaVM(&jvm);
+}
+
+void setupJniEnv(JNIEnv* jniEnv) {
+    bindJniEnvToThread(jniEnv);
+
+    jclass tangramClass = jniEnv->FindClass("com/mapzen/tangram/MapController");
+    startUrlRequestMID = jniEnv->GetMethodID(tangramClass, "startUrlRequest", "(Ljava/lang/String;J)Z");
+    cancelUrlRequestMID = jniEnv->GetMethodID(tangramClass, "cancelUrlRequest", "(Ljava/lang/String;)V");
+    getFontFilePath = jniEnv->GetMethodID(tangramClass, "getFontFilePath", "(Ljava/lang/String;)Ljava/lang/String;");
+    getFontFallbackFilePath = jniEnv->GetMethodID(tangramClass, "getFontFallbackFilePath", "(II)Ljava/lang/String;");
+    requestRenderMethodID = jniEnv->GetMethodID(tangramClass, "requestRender", "()V");
+    setRenderModeMethodID = jniEnv->GetMethodID(tangramClass, "setRenderMode", "(I)V");
+
+    jclass featurePickListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$FeaturePickListener");
+    onFeaturePickMID = jniEnv->GetMethodID(featurePickListenerClass, "onFeaturePick", "(Ljava/util/Map;FF)V");
+    jclass labelPickListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$LabelPickListener");
+    onLabelPickMID = jniEnv->GetMethodID(labelPickListenerClass, "onLabelPick", "(Lcom/mapzen/tangram/LabelPickResult;FF)V");
+
+    if (labelPickResultClass) {
+        jniEnv->DeleteGlobalRef(labelPickResultClass);
+    }
+    labelPickResultClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/mapzen/tangram/LabelPickResult"));
+    labelPickResultInitMID = jniEnv->GetMethodID(labelPickResultClass, "<init>", "(DDILjava/util/Map;)V");
+
+    if (markerPickResultClass) {
+        jniEnv->DeleteGlobalRef(markerPickResultClass);
+    }
+    markerPickResultClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/mapzen/tangram/MarkerPickResult"));
+    markerPickResultInitMID = jniEnv->GetMethodID(markerPickResultClass, "<init>", "(Lcom/mapzen/tangram/Marker;DD)V");
+
+    if (sceneUpdateErrorClass) {
+        jniEnv->DeleteGlobalRef(sceneUpdateErrorClass);
+    }
+    sceneUpdateErrorClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("com/mapzen/tangram/SceneUpdateError"));
+    sceneUpdateErrorInitMID = jniEnv->GetMethodID(sceneUpdateErrorClass, "<init>", "(Ljava/lang/String;Ljava/lang/String;I)V");
+    jclass sceneUpdateErrorListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$SceneUpdateErrorListener");
+    onSceneUpdateErrorMID = jniEnv->GetMethodID(sceneUpdateErrorListenerClass, "onSceneUpdateError", "(Lcom/mapzen/tangram/SceneUpdateError;)V");
+
+    if (hashmapClass) {
+        jniEnv->DeleteGlobalRef(hashmapClass);
+    }
+    hashmapClass = (jclass)jniEnv->NewGlobalRef(jniEnv->FindClass("java/util/HashMap"));
+    hashmapInitMID = jniEnv->GetMethodID(hashmapClass, "<init>", "()V");
+    hashmapPutMID = jniEnv->GetMethodID(hashmapClass, "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;");
+
+    markerByIDMID = jniEnv->GetMethodID(tangramClass, "markerById", "(J)Lcom/mapzen/tangram/Marker;");
+
+    jclass markerPickListenerClass = jniEnv->FindClass("com/mapzen/tangram/MapController$MarkerPickListener");
+    onMarkerPickMID = jniEnv->GetMethodID(markerPickListenerClass, "onMarkerPick", "(Lcom/mapzen/tangram/MarkerPickResult;FF)V");
+}
+
+void onUrlSuccess(JNIEnv* _jniEnv, jbyteArray _jBytes, jlong _jCallbackPtr) {
+
+    size_t length = _jniEnv->GetArrayLength(_jBytes);
+    std::vector<char> content;
+    content.resize(length);
+
+    _jniEnv->GetByteArrayRegion(_jBytes, 0, length, reinterpret_cast<jbyte*>(content.data()));
+
+    Tangram::UrlCallback* callback = reinterpret_cast<Tangram::UrlCallback*>(_jCallbackPtr);
+    (*callback)(std::move(content));
+    delete callback;
+}
+
+void onUrlFailure(JNIEnv* _jniEnv, jlong _jCallbackPtr) {
+    std::vector<char> empty;
+
+    Tangram::UrlCallback* callback = reinterpret_cast<Tangram::UrlCallback*>(_jCallbackPtr);
+    (*callback)(std::move(empty));
+    delete callback;
+}
+
+std::string stringFromJString(JNIEnv* jniEnv, jstring string) {
+    size_t length = jniEnv->GetStringLength(string);
+    std::string out(length, 0);
+    jniEnv->GetStringUTFRegion(string, 0, length, &out[0]);
+    return out;
+}
+
+std::string resolveScenePath(const char* path) {
+    // If the path is an absolute URL (like a file:// or http:// URL)
+    // then resolving it will return the same URL. Otherwise, we resolve
+    // it against the "asset" scheme to know later that this path is in
+    // the asset bundle.
+    return Tangram::Url(path).resolved("asset:///").string();
+}
+
+class JniThreadBinding {
+private:
+    JavaVM* jvm;
+    JNIEnv *jniEnv;
+    int status;
+public:
+    JniThreadBinding(JavaVM* _jvm) : jvm(_jvm) {
+        status = jvm->GetEnv((void**)&jniEnv, JNI_VERSION_1_6);
+        if (status == JNI_EDETACHED) { jvm->AttachCurrentThread(&jniEnv, NULL);}
+    }
+    ~JniThreadBinding() {
+        if (status == JNI_EDETACHED) { jvm->DetachCurrentThread(); }
+    }
+
+    JNIEnv* operator->() const {
+        return jniEnv;
+    }
+
+    operator JNIEnv*() const {
+        return jniEnv;
+    }
+};
+
+namespace Tangram {
+
+void logMsg(const char* fmt, ...) {
+
+    va_list args;
+    va_start(args, fmt);
+    __android_log_vprint(ANDROID_LOG_DEBUG, "Tangram", fmt, args);
+    va_end(args);
+
+}
+
+std::string AndroidPlatform::fontPath(const std::string& _family, const std::string& _weight, const std::string& _style) const {
+
+    JniThreadBinding jniEnv(jvm);
+
+    std::string key = _family + "_" + _weight + "_" + _style;
+
+    jstring jkey = jniEnv->NewStringUTF(key.c_str());
+    jstring returnStr = (jstring) jniEnv->CallObjectMethod(m_tangramInstance, getFontFilePath, jkey);
+
+    auto resultStr = stringFromJString(jniEnv, returnStr);
+    jniEnv->DeleteLocalRef(returnStr);
+    jniEnv->DeleteLocalRef(jkey);
+
+    return resultStr;
+}
+
+AndroidPlatform::AndroidPlatform(JNIEnv* _jniEnv, jobject _assetManager, jobject _tangramInstance) {
+    m_tangramInstance = _jniEnv->NewGlobalRef(_tangramInstance);
+
+    m_assetManager = AAssetManager_fromJava(_jniEnv, _assetManager);
+
+    if (m_assetManager == nullptr) {
+        LOGE("Could not obtain Asset Manager reference");
+        return;
+    }
+
+    sqlite3_ndk_init(m_assetManager);
+}
+
+void AndroidPlatform::dispose(JNIEnv* _jniEnv) {
+    _jniEnv->DeleteGlobalRef(m_tangramInstance);
+}
+
+void AndroidPlatform::requestRender() const {
+
+    JniThreadBinding jniEnv(jvm);
+
+    jniEnv->CallVoidMethod(m_tangramInstance, requestRenderMethodID);
+}
+
+std::string AndroidPlatform::fontFallbackPath(int _importance, int _weightHint) const {
+
+    JniThreadBinding jniEnv(jvm);
+
+    jstring returnStr = (jstring) jniEnv->CallObjectMethod(m_tangramInstance, getFontFallbackFilePath, _importance, _weightHint);
+
+    auto resultStr = stringFromJString(jniEnv, returnStr);
+    jniEnv->DeleteLocalRef(returnStr);
+
+    return resultStr;
+}
+
+std::vector<FontSourceHandle> AndroidPlatform::systemFontFallbacksHandle() const {
+    std::vector<FontSourceHandle> handles;
+
+    int importance = 0;
+    int weightHint = 400;
+
+    std::string fallbackPath = fontFallbackPath(importance, weightHint);
+
+    while (!fallbackPath.empty()) {
+        handles.emplace_back(fallbackPath);
+
+        fallbackPath = fontFallbackPath(importance++, weightHint);
+    }
+
+    return handles;
+}
+
+std::vector<char> AndroidPlatform::systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const {
+    std::string path = fontPath(_name, _weight, _face);
+
+    if (path.empty()) { return {}; }
+
+    auto data = bytesFromFile(path.c_str());
+
+    return data;
+}
+
+void AndroidPlatform::setContinuousRendering(bool _isContinuous) {
+    Platform::setContinuousRendering(_isContinuous);
+
+    JniThreadBinding jniEnv(jvm);
+
+    jniEnv->CallVoidMethod(m_tangramInstance, setRenderModeMethodID, _isContinuous ? 1 : 0);
+}
+
+bool AndroidPlatform::bytesFromAssetManager(const char* _path, std::function<char*(size_t)> _allocator) const {
+
+    AAsset* asset = AAssetManager_open(m_assetManager, _path, AASSET_MODE_UNKNOWN);
+    if (asset == nullptr) {
+        LOGW("Failed to open asset at path: %s", _path);
+        return false;
+    }
+
+    size_t size = AAsset_getLength(asset);
+    unsigned char* data = reinterpret_cast<unsigned char*>(_allocator(size));
+
+    int read = AAsset_read(asset, data, size);
+    if (read <= 0) {
+        LOGW("Failed to read asset at path: %s", _path);
+    }
+    AAsset_close(asset);
+
+    return read > 0;
+}
+
+std::string AndroidPlatform::stringFromFile(const char* _path) const {
+
+    std::string data;
+
+    auto allocator = [&](size_t size) {
+        data.resize(size);
+        return &data[0];
+    };
+
+    if (strncmp(_path, aaPrefix, aaPrefixLen) == 0) {
+        bytesFromAssetManager(_path + aaPrefixLen, allocator);
+    } else {
+        Platform::bytesFromFileSystem(_path, allocator);
+    }
+    return data;
+}
+
+std::vector<char> AndroidPlatform::bytesFromFile(const char* _path) const {
+    std::vector<char> data;
+
+    auto allocator = [&](size_t size) {
+        data.resize(size);
+        return data.data();
+    };
+
+    if (strncmp(_path, aaPrefix, aaPrefixLen) == 0) {
+        bytesFromAssetManager(_path + aaPrefixLen, allocator);
+    } else {
+        Platform::bytesFromFileSystem(_path, allocator);
+    }
+
+    return data;
+}
+
+bool AndroidPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+
+    JniThreadBinding jniEnv(jvm);
+    jstring jUrl = jniEnv->NewStringUTF(_url.c_str());
+
+    // This is probably super dangerous. In order to pass a reference to our callback we have to convert it
+    // to a Java type. We allocate a new callback object and then reinterpret the pointer to it as a Java long.
+    // In Java, we associate this long with the current network request and pass it back to native code when
+    // the request completes (either in onUrlSuccess or onUrlFailure), reinterpret the long back into a
+    // pointer, call the callback function if the request succeeded, and delete the heap-allocated UrlCallback
+    // to make sure nothing is leaked.
+    jlong jCallbackPtr = reinterpret_cast<jlong>(new UrlCallback(_callback));
+
+    jboolean methodResult = jniEnv->CallBooleanMethod(m_tangramInstance, startUrlRequestMID, jUrl, jCallbackPtr);
+
+    return methodResult;
+}
+
+void AndroidPlatform::cancelUrlRequest(const std::string& _url) {
+    JniThreadBinding jniEnv(jvm);
+    jstring jUrl = jniEnv->NewStringUTF(_url.c_str());
+    jniEnv->CallVoidMethod(m_tangramInstance, cancelUrlRequestMID, jUrl);
+}
+
+void setCurrentThreadPriority(int priority) {
+    int  tid = gettid();
+    setpriority(PRIO_PROCESS, tid, priority);
+}
+
+void sceneUpdateErrorCallback(jobject updateCallbackRef, const SceneUpdateError& sceneUpdateError) {
+
+    if (!updateCallbackRef) {
+        return;
+    }
+
+    JniThreadBinding jniEnv(jvm);
+
+    jstring jUpdateStatusPath = jniEnv->NewStringUTF(sceneUpdateError.update.path.c_str());
+    jstring jUpdateStatusValue = jniEnv->NewStringUTF(sceneUpdateError.update.value.c_str());
+    jint jError = (jint)sceneUpdateError.error;
+    jobject jUpdateErrorStatus = jniEnv->NewObject(sceneUpdateErrorClass, sceneUpdateErrorInitMID,
+                                                   jUpdateStatusPath, jUpdateStatusValue, jError);
+
+    jniEnv->CallVoidMethod(updateCallbackRef, onSceneUpdateErrorMID, jUpdateErrorStatus);
+    jniEnv->DeleteGlobalRef(updateCallbackRef);
+}
+
+void labelPickCallback(jobject listener, const Tangram::LabelPickResult* labelPickResult) {
+
+    JniThreadBinding jniEnv(jvm);
+
+    float position[2] = {0.0, 0.0};
+
+    jobject labelPickResultObject = nullptr;
+
+    if (labelPickResult) {
+        auto properties = labelPickResult->touchItem.properties;
+
+        position[0] = labelPickResult->touchItem.position[0];
+        position[1] = labelPickResult->touchItem.position[1];
+
+        jobject hashmap = jniEnv->NewObject(hashmapClass, hashmapInitMID);
+
+        for (const auto& item : properties->items()) {
+            jstring jkey = jniEnv->NewStringUTF(item.key.c_str());
+            jstring jvalue = jniEnv->NewStringUTF(properties->asString(item.value).c_str());
+            jniEnv->CallObjectMethod(hashmap, hashmapPutMID, jkey, jvalue);
+        }
+
+        labelPickResultObject = jniEnv->NewObject(labelPickResultClass, labelPickResultInitMID, labelPickResult->coordinates.longitude,
+            labelPickResult->coordinates.latitude, labelPickResult->type, hashmap);
+    }
+
+    jniEnv->CallVoidMethod(listener, onLabelPickMID, labelPickResultObject, position[0], position[1]);
+    jniEnv->DeleteGlobalRef(listener);
+}
+
+void markerPickCallback(jobject listener, jobject tangramInstance, const Tangram::MarkerPickResult* markerPickResult) {
+
+    JniThreadBinding jniEnv(jvm);
+    float position[2] = {0.0, 0.0};
+
+    jobject markerPickResultObject = nullptr;
+
+    if (markerPickResult) {
+        jobject marker = nullptr;
+
+        position[0] = markerPickResult->position[0];
+        position[1] = markerPickResult->position[1];
+
+        marker = jniEnv->CallObjectMethod(tangramInstance, markerByIDMID, static_cast<jlong>(markerPickResult->id));
+
+        if (marker) {
+            markerPickResultObject = jniEnv->NewObject(markerPickResultClass,
+                                                       markerPickResultInitMID, marker,
+                                                       markerPickResult->coordinates.longitude,
+                                                       markerPickResult->coordinates.latitude);
+        }
+    }
+
+    jniEnv->CallVoidMethod(listener, onMarkerPickMID, markerPickResultObject, position[0], position[1]);
+    jniEnv->DeleteGlobalRef(listener);
+    jniEnv->DeleteGlobalRef(tangramInstance);
+}
+
+void featurePickCallback(jobject listener, const Tangram::FeaturePickResult* featurePickResult) {
+
+    JniThreadBinding jniEnv(jvm);
+
+    jobject hashmap = jniEnv->NewObject(hashmapClass, hashmapInitMID);
+    float position[2] = {0.0, 0.0};
+
+    if (featurePickResult) {
+        auto properties = featurePickResult->properties;
+
+        position[0] = featurePickResult->position[0];
+        position[1] = featurePickResult->position[1];
+
+        for (const auto& item : properties->items()) {
+            jstring jkey = jniEnv->NewStringUTF(item.key.c_str());
+            jstring jvalue = jniEnv->NewStringUTF(properties->asString(item.value).c_str());
+            jniEnv->CallObjectMethod(hashmap, hashmapPutMID, jkey, jvalue);
+        }
+    }
+
+    jniEnv->CallVoidMethod(listener, onFeaturePickMID, hashmap, position[0], position[1]);
+    jniEnv->DeleteGlobalRef(listener);
+}
+
+void initGLExtensions() {
+    if (glExtensionsLoaded) {
+        return;
+    }
+
+    void* libhandle = dlopen("libGLESv2.so", RTLD_LAZY);
+
+    glBindVertexArrayOESEXT = (PFNGLBINDVERTEXARRAYOESPROC) dlsym(libhandle, "glBindVertexArrayOES");
+    glDeleteVertexArraysOESEXT = (PFNGLDELETEVERTEXARRAYSOESPROC) dlsym(libhandle, "glDeleteVertexArraysOES");
+    glGenVertexArraysOESEXT = (PFNGLGENVERTEXARRAYSOESPROC) dlsym(libhandle, "glGenVertexArraysOES");
+
+    glExtensionsLoaded = true;
+}
+
+} // namespace Tangram
+
+#endif
diff --git a/platforms/android/tangram/src/main/cpp/platform_android.h b/platforms/android/tangram/src/main/cpp/platform_android.h
new file mode 100644 (file)
index 0000000..2485569
--- /dev/null
@@ -0,0 +1,56 @@
+#pragma once
+
+#include "platform.h"
+
+#include <memory>
+#include <jni.h>
+#include <android/asset_manager.h>
+
+void bindJniEnvToThread(JNIEnv* jniEnv);
+void setupJniEnv(JNIEnv* _jniEnv);
+void onUrlSuccess(JNIEnv* jniEnv, jbyteArray jFetchedBytes, jlong jCallbackPtr);
+void onUrlFailure(JNIEnv* jniEnv, jlong jCallbackPtr);
+
+std::string resolveScenePath(const char* path);
+
+std::string stringFromJString(JNIEnv* jniEnv, jstring string);
+
+namespace Tangram {
+
+struct LabelPickResult;
+struct FeaturePickResult;
+struct MarkerPickResult;
+struct SceneUpdateError;
+
+void featurePickCallback(jobject listener, const Tangram::FeaturePickResult* featurePickResult);
+void markerPickCallback(jobject listener, jobject tangramInstance, const Tangram::MarkerPickResult* markerPickResult);
+void labelPickCallback(jobject listener, const Tangram::LabelPickResult* labelPickResult);
+void sceneUpdateErrorCallback(jobject updateStatusCallbackRef, const SceneUpdateError& sceneUpdateErrorStatus);
+
+class AndroidPlatform : public Platform {
+
+public:
+
+    AndroidPlatform(JNIEnv* _jniEnv, jobject _assetManager, jobject _tangramInstance);
+    void dispose(JNIEnv* _jniEnv);
+    void requestRender() const override;
+    std::vector<char> bytesFromFile(const char* _path) const override;
+    void setContinuousRendering(bool _isContinuous) override;
+    std::string stringFromFile(const char* _path) const override;
+    std::vector<char> systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const override;
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+
+private:
+
+    bool bytesFromAssetManager(const char* _path, std::function<char*(size_t)> _allocator) const;
+    std::string fontPath(const std::string& _family, const std::string& _weight, const std::string& _style) const;
+    std::string fontFallbackPath(int _importance, int _weightHint) const;
+
+    jobject m_tangramInstance;
+    AAssetManager* m_assetManager;
+
+};
+
+} // namespace Tangram
diff --git a/platforms/android/tangram/src/main/cpp/sqlite3ndk.cpp b/platforms/android/tangram/src/main/cpp/sqlite3ndk.cpp
new file mode 100755 (executable)
index 0000000..29a6c7a
--- /dev/null
@@ -0,0 +1,525 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Krystian Bigaj code.
+ *
+ * The Initial Developer of the Original Code is
+ * Krystian Bigaj (krystian.bigaj@gmail.com).
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "sqlite3ndk.h"
+
+#include <string.h>
+#include <sqlite3.h>
+
+#ifndef SQLITE_DEFAULT_SECTOR_SIZE
+# define SQLITE_DEFAULT_SECTOR_SIZE 512
+#endif
+
+/**
+ * The ndk_vfs structure is subclass of sqlite3_vfs specific
+ * to the Android NDK AAssetManager VFS implementations
+ */
+typedef struct ndk_vfs ndk_vfs;
+struct ndk_vfs
+{
+       sqlite3_vfs vfs; /*** Must be first ***/
+       sqlite3_vfs* vfsDefault;
+       const struct sqlite3_io_methods *pMethods;
+
+       AAssetManager* mgr;
+};
+
+/**
+ * The ndk_file structure is subclass of sqlite3_file specific
+ * to the Android NDK AAsset VFS implementations
+ */
+typedef struct ndk_file ndk_file;
+struct ndk_file
+{
+       const sqlite3_io_methods *pMethod; /*** Must be first ***/
+
+       // Pointer to AAsset obtained by AAssetManager_open
+       AAsset* asset;
+
+       // Pointer to database content (AAsset_getBuffer)
+       const void* buf;
+
+       // Total lenght of database file (AAsset_getLength)
+       off_t len;
+};
+
+/*
+ * sqlite3_vfs.xOpen - open database file.
+ * Implemented using AAssetManager_open
+ */
+static int ndkOpen(sqlite3_vfs *pVfs, const char *zPath, sqlite3_file *pFile,
+               int flags, int *pOutFlags)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+       ndk_file *ndkFile = (ndk_file*) pFile;
+
+       // pMethod must be set to NULL, even if xOpen call fails.
+       //
+       // http://www.sqlite.org/c3ref/io_methods.html
+       // "The only way to prevent a call to xClose following a failed sqlite3_vfs.xOpen
+       // is for the sqlite3_vfs.xOpen to set the sqlite3_file.pMethods element to NULL."
+       ndkFile->pMethod = NULL;
+
+       // Allow only for opening main database file as read-only.
+       // Opening JOURNAL/TEMP/WAL/etc. files will make call fails.
+       // We don't need it, as DB opened from 'assets' .apk cannot
+       // be modified
+       if (
+                       !zPath ||
+                       (flags & SQLITE_OPEN_DELETEONCLOSE) ||
+
+                       !(flags & SQLITE_OPEN_READONLY) ||
+                       (flags & SQLITE_OPEN_READWRITE) ||
+                       (flags & SQLITE_OPEN_CREATE) ||
+
+                       !(flags & SQLITE_OPEN_MAIN_DB)
+               )
+       {
+               return SQLITE_PERM;
+       }
+
+       // Try top open database file
+       AAsset* asset = AAssetManager_open(ndk->mgr, zPath, AASSET_MODE_RANDOM);
+       if (!asset)
+       {
+               return SQLITE_CANTOPEN;
+       }
+
+       // Get pointer to database. This call can fail in case for example
+       // out of memory. If file inside .apk is compressed, then whole
+       // file must be allocated and read into memory.
+       // If file is not compressed (inside .apk/zip), then this functions returns pointer
+       // to memory-mapped address in .apk file, so doesn't need to allocate
+       // explicit additional memory.
+       // As for today there is no simple way to set if specific file
+       // must be compressed or not. You can control it only by file extension.
+       // Google for: android kNoCompressExt
+       const void* buf = AAsset_getBuffer(asset);
+       if (!buf)
+       {
+               AAsset_close(asset);
+               return SQLITE_ERROR;
+       }
+
+       ndkFile->pMethod = ndk->pMethods;
+       ndkFile->asset = asset;
+       ndkFile->buf = buf;
+       ndkFile->len = AAsset_getLength(asset);
+       if (pOutFlags)
+       {
+               *pOutFlags = flags;
+       }
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_vfs.xDelete - not implemented. Assets in .apk are read only
+ */
+static int ndkDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync)
+{
+       return SQLITE_ERROR;
+}
+
+/*
+ * sqlite3_vfs.xAccess - tests if file exists and/or can be read.
+ * Implemented using AAssetManager_open
+ */
+static int ndkAccess(sqlite3_vfs *pVfs, const char *zPath, int flags,
+               int *pResOut)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+
+       *pResOut = 0;
+
+       switch (flags)
+       {
+       case SQLITE_ACCESS_EXISTS:
+       case SQLITE_ACCESS_READ:
+               AAsset* asset = AAssetManager_open(ndk->mgr, zPath, AASSET_MODE_RANDOM);
+               if (asset)
+               {
+                       AAsset_close(asset);
+                       *pResOut = 1;
+               }
+
+               break;
+       }
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_vfs.xFullPathname - all paths are root paths to 'assets' directory,
+ * so just return copy of input path
+ */
+static int ndkFullPathname(sqlite3_vfs *pVfs, const char *zPath, int nOut,
+               char *zOut)
+{
+       if (!zPath)
+       {
+               return SQLITE_ERROR;
+       }
+
+       int pos = 0;
+       while (zPath[pos] && (pos < nOut))
+       {
+               zOut[pos] = zPath[pos];
+               ++pos;
+       }
+       if (pos >= nOut)
+       {
+               return SQLITE_ERROR;
+       }
+       zOut[pos] = '\0';
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_vfs.xRandomness - call redirected to default VFS.
+ * See: sqlite3_ndk_init(..., ..., ..., osVfs)
+ */
+static int ndkRandomness(sqlite3_vfs *pVfs, int nBuf, char *zBuf)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+
+       return ndk->vfsDefault->xRandomness(ndk->vfsDefault, nBuf, zBuf);
+}
+
+/*
+ * sqlite3_vfs.xSleep - call redirected to default VFS.
+ * See: sqlite3_ndk_init(..., ..., ..., osVfs)
+ */
+static int ndkSleep(sqlite3_vfs *pVfs, int microseconds)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+
+       return ndk->vfsDefault->xSleep(ndk->vfsDefault, microseconds);
+}
+
+/*
+ * sqlite3_vfs.xCurrentTime - call redirected to default VFS.
+ * See: sqlite3_ndk_init(..., ..., ..., osVfs)
+ */
+static int ndkCurrentTime(sqlite3_vfs *pVfs, double *prNow)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+
+       return ndk->vfsDefault->xCurrentTime(ndk->vfsDefault, prNow);
+}
+
+/*
+ * sqlite3_vfs.xGetLastError - not implemented (no additional information)
+ */
+static int ndkGetLastError(sqlite3_vfs *NotUsed1, int NotUsed2, char *NotUsed3)
+{
+       return 0;
+}
+
+/*
+ * sqlite3_vfs.xCurrentTimeInt64 - call redirected to default VFS.
+ * See: sqlite3_ndk_init(..., ..., ..., osVfs)
+ */
+static int ndkCurrentTimeInt64(sqlite3_vfs *pVfs, sqlite3_int64 *piNow)
+{
+       const ndk_vfs* ndk = (ndk_vfs*) pVfs;
+
+       return ndk->vfsDefault->xCurrentTimeInt64(ndk->vfsDefault, piNow);
+}
+
+/*
+ * sqlite3_file.xClose - closing file opened in sqlite3_vfs.xOpen function.
+ * Implemented using AAsset_close
+ */
+static int ndkFileClose(sqlite3_file *pFile)
+{
+       ndk_file* file = (ndk_file*) pFile;
+
+       if (file->asset)
+       {
+               AAsset_close(file->asset);
+               file->asset = NULL;
+               file->buf = NULL;
+               file->len = 0;
+       }
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_file.xRead - database read from asset memory.
+ * See: AAsset_getBuffer in ndkOpen
+ */
+static int ndkFileRead(sqlite3_file *pFile, void *pBuf, int amt,
+               sqlite3_int64 offset)
+{
+       const ndk_file* file = (ndk_file*) pFile;
+       int got, off;
+       int rc;
+
+       off = (int) offset;
+
+       // Sanity check
+       if (file->asset == NULL)
+       {
+               return SQLITE_IOERR_READ;
+       }
+
+       if (off + amt <= file->len)
+       {
+               got = amt;
+               rc = SQLITE_OK;
+       }
+       else
+       {
+               got = file->len - off;
+               if (got < 0)
+               {
+                       rc = SQLITE_IOERR_READ;
+               }
+               else
+               {
+                       // http://www.sqlite.org/c3ref/io_methods.html
+                       // "If xRead() returns SQLITE_IOERR_SHORT_READ it must also
+                       // fill in the unread portions of the buffer with zeros.
+                       // A VFS that fails to zero-fill short reads might seem to work.
+                       // However, failure to zero-fill short reads will eventually lead
+                       // to database corruption."
+                       //
+                       // It might be not a problem in read-only databases,
+                       // but do it as documentation says
+                       rc = SQLITE_IOERR_SHORT_READ;
+                       memset(&((char*) pBuf)[got], 0, amt - got);
+               }
+       }
+
+       if (got > 0)
+       {
+               memcpy(pBuf, (char*) file->buf + off, got);
+       }
+
+       return rc;
+}
+
+/*
+ * sqlite3_file.xWrite - not implemented (.apk is read-only)
+ */
+static int ndkFileWrite(sqlite3_file *, const void *, int, sqlite3_int64)
+{
+       return SQLITE_IOERR_WRITE;
+}
+
+/*
+ * sqlite3_file.xTruncate - not implemented (.apk is read-only)
+ */
+static int ndkFileTruncate(sqlite3_file *, sqlite3_int64)
+{
+       return SQLITE_IOERR_TRUNCATE;
+}
+
+/*
+ * sqlite3_file.xSync - not implemented (.apk is read-only)
+ */
+static int ndkFileSync(sqlite3_file *, int flags)
+{
+       return SQLITE_IOERR_FSYNC;
+}
+
+/*
+ * sqlite3_file.xFileSize - get database file size.
+ * See: AAsset_getLength in ndkOpen
+ */
+static int ndkFileSize(sqlite3_file *pFile, sqlite3_int64 *pSize)
+{
+       ndk_file* file = (ndk_file*) pFile;
+       *pSize = file->len;
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_file.xLock - not implemented (.apk is read-only)
+ */
+static int ndkFileLock(sqlite3_file *, int)
+{
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_file.xUnlock - not implemented (.apk is read-only)
+ */
+static int ndkFileUnlock(sqlite3_file *, int)
+{
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_file.xCheckReservedLock - not implemented (.apk is read-only)
+ */
+static int ndkFileCheckReservedLock(sqlite3_file *, int *pResOut)
+{
+       *pResOut = 0;
+
+       return SQLITE_OK;
+}
+
+/*
+ * sqlite3_file.xFileControl - not implemented (no special codes needed for now)
+ */
+static int ndkFileControl(sqlite3_file *, int, void *)
+{
+       return SQLITE_NOTFOUND;
+}
+
+/*
+ * sqlite3_file.xSectorSize - use same value as in os_unix.c
+ */
+static int ndkFileSectorSize(sqlite3_file *)
+{
+       return SQLITE_DEFAULT_SECTOR_SIZE;
+}
+
+/*
+ * sqlite3_file.xDeviceCharacteristics - not implemented (.apk is read-only)
+ */
+static int ndkFileDeviceCharacteristics(sqlite3_file *)
+{
+       return 0;
+}
+
+/*
+ * Register into SQLite. For more information see sqlite3ndk.h
+ */
+int sqlite3_ndk_init(AAssetManager* assetMgr, const char* vfsName,
+               int makeDflt, const char *osVfs)
+{
+       static ndk_vfs ndkVfs;
+       int rc;
+
+       // assetMgr is required parameter
+       if (!assetMgr)
+       {
+               return SQLITE_ERROR;
+       }
+
+       // Check if there was successful call to sqlite3_ndk_init before
+       if (ndkVfs.mgr)
+       {
+               if (ndkVfs.mgr == assetMgr)
+               {
+                       return SQLITE_OK;
+               }
+               else
+               {
+                       // Second call to sqlite3_ndk_init cannot change assetMgr
+                       return SQLITE_ERROR;
+               }
+       }
+
+       // Find os VFS. Used to redirect xRandomness, xSleep, xCurrentTime, ndkCurrentTimeInt64 calls
+       ndkVfs.vfsDefault = sqlite3_vfs_find(osVfs);
+       if (ndkVfs.vfsDefault == NULL)
+       {
+               return SQLITE_ERROR;
+       }
+
+       // vfsFile
+       static const sqlite3_io_methods ndkFileMethods =
+       {
+               1,
+               ndkFileClose,
+               ndkFileRead,
+               ndkFileWrite,
+               ndkFileTruncate,
+               ndkFileSync,
+               ndkFileSize,
+               ndkFileLock,
+               ndkFileUnlock,
+               ndkFileCheckReservedLock,
+               ndkFileControl,
+               ndkFileSectorSize,
+               ndkFileDeviceCharacteristics
+       };
+
+       // pMethods will be used in ndkOpen
+       ndkVfs.pMethods = &ndkFileMethods;
+
+       // vfs
+       ndkVfs.vfs.iVersion = 3;
+       ndkVfs.vfs.szOsFile = sizeof(ndk_file);
+       ndkVfs.vfs.mxPathname = SQLITE_NDK_VFS_MAX_PATH;
+       ndkVfs.vfs.pNext = 0;
+       if (vfsName)
+       {
+               ndkVfs.vfs.zName = vfsName;
+       }
+       else
+       {
+               ndkVfs.vfs.zName = SQLITE_NDK_VFS_NAME;
+       }
+       ndkVfs.vfs.pAppData = 0;
+       ndkVfs.vfs.xOpen = ndkOpen;
+       ndkVfs.vfs.xDelete = ndkDelete;
+       ndkVfs.vfs.xAccess = ndkAccess;
+       ndkVfs.vfs.xFullPathname = ndkFullPathname;
+       ndkVfs.vfs.xDlOpen = 0;
+       ndkVfs.vfs.xDlError = 0;
+       ndkVfs.vfs.xDlSym = 0;
+       ndkVfs.vfs.xDlClose = 0;
+       ndkVfs.vfs.xRandomness = ndkRandomness;
+       ndkVfs.vfs.xSleep = ndkSleep;
+       ndkVfs.vfs.xCurrentTime = ndkCurrentTime;
+       ndkVfs.vfs.xGetLastError = ndkGetLastError;
+       ndkVfs.vfs.xCurrentTimeInt64 = ndkCurrentTimeInt64;
+       ndkVfs.vfs.xSetSystemCall = 0;
+       ndkVfs.vfs.xGetSystemCall = 0;
+       ndkVfs.vfs.xNextSystemCall = 0;
+
+       // Asset manager
+       ndkVfs.mgr = assetMgr;
+
+       // Last part, try to register VFS
+       rc = sqlite3_vfs_register(&ndkVfs.vfs, makeDflt);
+   
+       if (rc != SQLITE_OK)
+       {
+               // sqlite3_vfs_register could fails in case of sqlite3_initialize failure
+               ndkVfs.mgr = 0;
+       }
+
+       return rc;
+}
diff --git a/platforms/android/tangram/src/main/cpp/sqlite3ndk.h b/platforms/android/tangram/src/main/cpp/sqlite3ndk.h
new file mode 100755 (executable)
index 0000000..03fe114
--- /dev/null
@@ -0,0 +1,94 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Krystian Bigaj code.
+ *
+ * The Initial Developer of the Original Code is
+ * Krystian Bigaj (krystian.bigaj@gmail.com).
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef _SQLITE3_NDK_H_
+#define _SQLITE3_NDK_H_
+
+#include <sys/types.h>
+#include <android/asset_manager.h>
+
+#ifndef SQLITE_NDK_VFS_NAME
+// Default name for VFS
+#define SQLITE_NDK_VFS_NAME "ndk-asset"
+#endif
+
+#ifndef SQLITE_NDK_VFS_MAKE_DEFAULT
+// Default sqlite3_ndk_init parameter
+#define SQLITE_NDK_VFS_MAKE_DEFAULT 0
+#endif
+
+// Default sqlite3_ndk_init parameter
+#define SQLITE_NDK_VFS_PARENT_VFS NULL
+
+#ifndef SQLITE_NDK_VFS_MAX_PATH
+// Maximum path name for database files
+#define SQLITE_NDK_VFS_MAX_PATH 512
+#endif
+
+/*
+ * This function registers VFS into SQLite.
+ * It should be called only once (before SQLite-NDK usage).
+ *
+ * Params:
+ * - assetMgr - pointer to AAssetManager. In most cases it will be:
+ *   app->activity->assetManager (see example below).
+ *   This parameter is required
+ * - vfsName - name of VFS that can be used in sqlite3_open_v2
+ *   as 4th parameter (http://www.sqlite.org/c3ref/open.html)
+ *   or in URI filename (http://www.sqlite.org/uri.html).
+ *   If NULL then default name "ndk-asset" is used (SQLITE_NDK_VFS_NAME)
+ * - makeDflt - flag used to register SQLite-NDK as a default VFS.
+ *   See: sqlite3_vfs_register at http://www.sqlite.org/c3ref/vfs_find.html
+ *   Disabled by default (SQLITE_NDK_VFS_MAKE_DEFAULT)
+ * - osVfs - name of VFS that will used only to redirect few sqlite calls.
+ *   If NULL passed, then default VFS will be used (SQLITE_NDK_VFS_PARENT_VFS)
+ *
+ * Example:
+ * void android_main(struct android_app* app)
+ * {
+ *   sqlite3_ndk_init(app->activity->assetManager);
+ *   ...
+ *   if (sqlite3_open_v2("data.sqlite3", &db, SQLITE_OPEN_READONLY,
+ *     SQLITE_NDK_VFS_NAME) == SQLITE_OK)
+ *   {
+ *     ...
+ */
+int sqlite3_ndk_init(AAssetManager* assetMgr,
+               const char* vfsName = SQLITE_NDK_VFS_NAME,
+               int makeDflt = SQLITE_NDK_VFS_MAKE_DEFAULT,
+               const char *osVfs = SQLITE_NDK_VFS_PARENT_VFS);
+
+#endif
diff --git a/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/BaseGestureDetector.java b/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/BaseGestureDetector.java
new file mode 100644 (file)
index 0000000..02b9ee6
--- /dev/null
@@ -0,0 +1,150 @@
+package com.almeros.android.multitouch;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+/**
+ * @author Almer Thie (code.almeros.com)
+ * Copyright (c) 2013, Almer Thie (code.almeros.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+ */
+public abstract class BaseGestureDetector {
+    protected final Context mContext;
+    protected boolean mGestureInProgress;
+
+    protected MotionEvent mPrevEvent;
+    protected MotionEvent mCurrEvent;
+
+    protected float mCurrPressure;
+    protected float mPrevPressure;
+    protected long mTimeDelta;
+
+
+    /**
+     * This value is the threshold ratio between the previous combined pressure
+     * and the current combined pressure. When pressure decreases rapidly
+     * between events the position values can often be imprecise, as it usually
+     * indicates that the user is in the process of lifting a pointer off of the
+     * device. This value was tuned experimentally.
+     */
+    protected static final float PRESSURE_THRESHOLD = 0.67f;
+
+
+    public BaseGestureDetector(Context context) {
+        mContext = context;
+    }
+
+    /**
+     * All gesture detectors need to be called through this method to be able to
+     * detect gestures. This method delegates work to handler methods
+     * (handleStartProgressEvent, handleInProgressEvent) implemented in
+     * extending classes.
+     *
+     * @param event
+     * @return Always true
+     */
+    public boolean onTouchEvent(MotionEvent event) {
+        final int actionCode = event.getActionMasked();
+        if (!mGestureInProgress) {
+            handleStartProgressEvent(actionCode, event);
+        } else {
+            handleInProgressEvent(actionCode, event);
+        }
+        return true;
+    }
+
+    /**
+     * Called when the current event occurred when NO gesture is in progress
+     * yet. The handling in this implementation may set the gesture in progress
+     * (via mGestureInProgress) or out of progress
+     * @param actionCode
+     * @param event
+     */
+    protected abstract void handleStartProgressEvent(int actionCode, MotionEvent event);
+
+    /**
+     * Called when the current event occurred when a gesture IS in progress. The
+     * handling in this implementation may set the gesture out of progress (via
+     * mGestureInProgress).
+     * @param actionCode
+     * @param event
+     */
+    protected abstract void handleInProgressEvent(int actionCode, MotionEvent event);
+
+
+    protected void updateStateByEvent(MotionEvent curr) {
+        final MotionEvent prev = mPrevEvent;
+
+        // Reset mCurrEvent
+        if (mCurrEvent != null) {
+            mCurrEvent.recycle();
+            mCurrEvent = null;
+        }
+        mCurrEvent = MotionEvent.obtain(curr);
+
+
+        // Delta time
+        mTimeDelta = curr.getEventTime() - prev.getEventTime();
+
+        // Pressure
+        mCurrPressure = curr.getPressure(curr.getActionIndex());
+        mPrevPressure = prev.getPressure(prev.getActionIndex());
+    }
+
+    protected void resetState() {
+        if (mPrevEvent != null) {
+            mPrevEvent.recycle();
+            mPrevEvent = null;
+        }
+        if (mCurrEvent != null) {
+            mCurrEvent.recycle();
+            mCurrEvent = null;
+        }
+        mGestureInProgress = false;
+    }
+
+
+    /**
+     * Returns {@code true} if a gesture is currently in progress.
+     * @return {@code true} if a gesture is currently in progress, {@code false} otherwise.
+     */
+    public boolean isInProgress() {
+        return mGestureInProgress;
+    }
+
+    /**
+     * Return the time difference in milliseconds between the previous accepted
+     * GestureDetector event and the current GestureDetector event.
+     *
+     * @return Time difference since the last move event in milliseconds.
+     */
+    public long getTimeDelta() {
+        return mTimeDelta;
+    }
+
+    /**
+     * Return the event time of the current GestureDetector event being
+     * processed.
+     *
+     * @return Current GestureDetector event time in milliseconds.
+     */
+    public long getEventTime() {
+        return mCurrEvent.getEventTime();
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/MoveGestureDetector.java b/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/MoveGestureDetector.java
new file mode 100644 (file)
index 0000000..034c4a4
--- /dev/null
@@ -0,0 +1,174 @@
+package com.almeros.android.multitouch;
+
+import android.content.Context;
+import android.graphics.PointF;
+import android.view.MotionEvent;
+import com.almeros.android.multitouch.BaseGestureDetector;
+
+/**
+ * @author Almer Thie (code.almeros.com)
+ * Copyright (c) 2013, Almer Thie (code.almeros.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+ */
+public class MoveGestureDetector extends BaseGestureDetector {
+
+    /**
+     * Listener which must be implemented which is used by MoveGestureDetector
+     * to perform callbacks to any implementing class which is registered to a
+     * MoveGestureDetector via the constructor.
+     *
+     * @see MoveGestureDetector.SimpleOnMoveGestureListener
+     */
+    public interface OnMoveGestureListener {
+        boolean onMove(MoveGestureDetector detector);
+        boolean onMoveBegin(MoveGestureDetector detector);
+        void onMoveEnd(MoveGestureDetector detector);
+    }
+
+    /**
+     * Helper class which may be extended and where the methods may be
+     * implemented. This way it is not necessary to implement all methods
+     * of OnMoveGestureListener.
+     */
+    public static class SimpleOnMoveGestureListener implements OnMoveGestureListener {
+        public boolean onMove(MoveGestureDetector detector) {
+            return false;
+        }
+
+        public boolean onMoveBegin(MoveGestureDetector detector) {
+            return true;
+        }
+
+        public void onMoveEnd(MoveGestureDetector detector) {
+            // Do nothing, overridden implementation may be used
+        }
+    }
+
+    private static final PointF FOCUS_DELTA_ZERO = new PointF();
+
+    private final OnMoveGestureListener mListener;
+
+    private PointF mCurrFocusInternal;
+    private PointF mPrevFocusInternal;
+    private PointF mFocusExternal = new PointF();
+    private PointF mFocusDeltaExternal = new PointF();
+
+
+    public MoveGestureDetector(Context context, OnMoveGestureListener listener) {
+        super(context);
+        mListener = listener;
+    }
+
+    @Override
+    protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_DOWN:
+                resetState(); // In case we missed an UP/CANCEL event
+
+                mPrevEvent = MotionEvent.obtain(event);
+                mTimeDelta = 0;
+
+                updateStateByEvent(event);
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                mGestureInProgress = mListener.onMoveBegin(this);
+                break;
+        }
+    }
+
+    @Override
+    protected void handleInProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_UP:
+            case MotionEvent.ACTION_CANCEL:
+                mListener.onMoveEnd(this);
+                resetState();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                updateStateByEvent(event);
+
+                // Only accept the event if our relative pressure is within
+                // a certain limit. This can help filter shaky data as a
+                // finger is lifted.
+                if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
+                    final boolean updatePrevious = mListener.onMove(this);
+                    if (updatePrevious) {
+                        mPrevEvent.recycle();
+                        mPrevEvent = MotionEvent.obtain(event);
+                    }
+                }
+                break;
+        }
+    }
+
+    protected void updateStateByEvent(MotionEvent curr) {
+        super.updateStateByEvent(curr);
+
+        final MotionEvent prev = mPrevEvent;
+
+        // Focus intenal
+        mCurrFocusInternal = determineFocalPoint(curr);
+        mPrevFocusInternal = determineFocalPoint(prev);
+
+        // Focus external
+        // - Prevent skipping of focus delta when a finger is added or removed
+        boolean mSkipNextMoveEvent = prev.getPointerCount() != curr.getPointerCount();
+        mFocusDeltaExternal = mSkipNextMoveEvent ? FOCUS_DELTA_ZERO : new PointF(mCurrFocusInternal.x - mPrevFocusInternal.x,  mCurrFocusInternal.y - mPrevFocusInternal.y);
+
+        // - Don't directly use mFocusInternal (or skipping will occur). Add
+        //   unskipped delta values to mFocusExternal instead.
+        mFocusExternal.x += mFocusDeltaExternal.x;
+        mFocusExternal.y += mFocusDeltaExternal.y;
+    }
+
+    /**
+     * Determine (multi)finger focal point (a.k.a. center point between all
+     * fingers)
+     *
+     * @param MotionEvent e
+     * @return PointF focal point
+     */
+    private PointF determineFocalPoint(MotionEvent e) {
+        // Number of fingers on screen
+        final int pCount = e.getPointerCount();
+        float x = 0f;
+        float y = 0f;
+
+        for(int i = 0; i < pCount; i++) {
+            x += e.getX(i);
+            y += e.getY(i);
+        }
+
+        return new PointF(x/pCount, y/pCount);
+    }
+
+    public float getFocusX() {
+        return mFocusExternal.x;
+    }
+
+    public float getFocusY() {
+        return mFocusExternal.y;
+    }
+
+    public PointF getFocusDelta() {
+        return mFocusDeltaExternal;
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/RotateGestureDetector.java b/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/RotateGestureDetector.java
new file mode 100644 (file)
index 0000000..5d47aa5
--- /dev/null
@@ -0,0 +1,213 @@
+package com.almeros.android.multitouch;
+
+import android.content.Context;
+import android.view.MotionEvent;
+
+/**
+ * @author Almer Thie (code.almeros.com)
+ * Copyright (c) 2013, Almer Thie (code.almeros.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+ */
+public class RotateGestureDetector extends TwoFingerGestureDetector {
+
+    /**
+     * Listener which must be implemented which is used by RotateGestureDetector
+     * to perform callbacks to any implementing class which is registered to a
+     * RotateGestureDetector via the constructor.
+     *
+     * @see RotateGestureDetector.SimpleOnRotateGestureListener
+     */
+    public interface OnRotateGestureListener {
+        boolean onRotate(RotateGestureDetector detector);
+        boolean onRotateBegin(RotateGestureDetector detector);
+        void onRotateEnd(RotateGestureDetector detector);
+    }
+
+    /**
+     * Helper class which may be extended and where the methods may be
+     * implemented. This way it is not necessary to implement all methods
+     * of OnRotateGestureListener.
+     */
+    public static class SimpleOnRotateGestureListener implements OnRotateGestureListener {
+        public boolean onRotate(RotateGestureDetector detector) {
+            return false;
+        }
+
+        public boolean onRotateBegin(RotateGestureDetector detector) {
+            return true;
+        }
+
+        public void onRotateEnd(RotateGestureDetector detector) {
+            // Do nothing, overridden implementation may be used
+        }
+    }
+
+    private static final float ROTATION_THRESHOLD = 0.25f; // Minimum radians of rotation to recognize
+
+    private final OnRotateGestureListener mListener;
+    private boolean mSloppyGesture;
+    private boolean mRecognized;
+
+    private float mTotalRotation;
+    private float mFocusX;
+    private float mFocusY;
+
+    public RotateGestureDetector(Context context, OnRotateGestureListener listener) {
+        super(context);
+        mListener = listener;
+    }
+
+    private void determineFocusPoint(MotionEvent curr) {
+        mFocusX = (curr.getX(0) + curr.getX(1)) * 0.5f;
+        mFocusY = (curr.getY(0) + curr.getY(1)) * 0.5f;
+    }
+
+    @Override
+    protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_POINTER_DOWN:
+                // At least the second finger is on screen now
+
+                resetState(); // In case we missed an UP/CANCEL event
+                mPrevEvent = MotionEvent.obtain(event);
+                mTimeDelta = 0;
+
+                updateStateByEvent(event);
+
+                // See if we have a sloppy gesture
+                mSloppyGesture = isSloppyGesture(event);
+                if (!mSloppyGesture) {
+                    // No, start listening for gesture now
+                    mGestureInProgress = true;
+                }
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                if (!mSloppyGesture) {
+                    break;
+                }
+
+                // See if we still have a sloppy gesture
+                mSloppyGesture = isSloppyGesture(event);
+                if (!mSloppyGesture) {
+                    // No, start listening for gesture now
+                    mGestureInProgress = true;
+                }
+                break;
+        }
+    }
+
+
+    @Override
+    protected void handleInProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_POINTER_UP:
+                // Gesture ended with up event, update and finalize state
+                updateStateByEvent(event);
+
+                if (!mSloppyGesture && mRecognized) {
+                    mListener.onRotateEnd(this);
+                }
+
+                resetState();
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                // Gesture ended with no up event, finalize state
+                if (!mSloppyGesture && mRecognized) {
+                    mListener.onRotateEnd(this);
+                }
+
+                resetState();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                updateStateByEvent(event);
+
+                // Only accept the event if our relative pressure is within
+                // a certain limit. This can help filter shaky data as a
+                // finger is lifted.
+                if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD) {
+                    determineFocusPoint(event);
+                    boolean updatePrevious;
+                    if (mRecognized) {
+                        updatePrevious = mListener.onRotate(this);
+                    } else {
+                        updatePrevious = true;
+                        mRecognized =
+                                Math.abs(mTotalRotation) >= ROTATION_THRESHOLD &&
+                                mListener.onRotateBegin(this);
+                    }
+                    if (updatePrevious) {
+                        mPrevEvent.recycle();
+                        mPrevEvent = MotionEvent.obtain(event);
+                    }
+                }
+                break;
+        }
+    }
+
+    @Override
+    protected void resetState() {
+        super.resetState();
+        mSloppyGesture = false;
+        mRecognized = false;
+        mTotalRotation = 0;
+    }
+
+    @Override
+    protected void updateStateByEvent(MotionEvent event) {
+        super.updateStateByEvent(event);
+        mTotalRotation += getRotationRadiansDelta();
+    }
+
+    /**
+     */
+    public float getFocusX() {
+        return mFocusX;
+    }
+
+
+    /**
+     */
+    public float getFocusY() {
+        return mFocusY;
+    }
+
+    /**
+     * Return the rotation difference from the previous rotate event to the current
+     * event. (radians)
+     *
+     * @return The current rotation //difference in degrees.
+     */
+    public float getRotationRadiansDelta() {
+        double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
+        return (float) (diffRadians);
+    }
+
+    /**
+     * Return the rotation difference from the previous rotate event to the current
+     * event. (degrees)
+     *
+     * @return The current rotation //difference in degrees.
+     */
+    public float getRotationDegreesDelta() {
+        double diffRadians = Math.atan2(mPrevFingerDiffY, mPrevFingerDiffX) - Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX);
+        return (float) (diffRadians * 180 / Math.PI);
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/ShoveGestureDetector.java b/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/ShoveGestureDetector.java
new file mode 100644 (file)
index 0000000..cda5602
--- /dev/null
@@ -0,0 +1,266 @@
+package com.almeros.android.multitouch;
+
+import android.content.Context;
+import android.view.MotionEvent;
+import android.util.DisplayMetrics;
+
+/**
+ * @author Robert Nordan (robert.nordan@norkart.no)
+ *
+ * Copyright (c) 2013, Norkart AS
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+ */
+public class ShoveGestureDetector extends TwoFingerGestureDetector {
+
+    /**
+     * Listener which must be implemented which is used by ShoveGestureDetector
+     * to perform callbacks to any implementing class which is registered to a
+     * ShoveGestureDetector via the constructor.
+     *
+     * @see ShoveGestureDetector.SimpleOnShoveGestureListener
+     */
+    public interface OnShoveGestureListener {
+        boolean onShove(ShoveGestureDetector detector);
+        boolean onShoveBegin(ShoveGestureDetector detector);
+        void onShoveEnd(ShoveGestureDetector detector);
+    }
+
+    /**
+     * Helper class which may be extended and where the methods may be
+     * implemented. This way it is not necessary to implement all methods
+     * of OnShoveGestureListener.
+     */
+    public static class SimpleOnShoveGestureListener implements OnShoveGestureListener {
+        public boolean onShove(ShoveGestureDetector detector) {
+            return false;
+        }
+
+        public boolean onShoveBegin(ShoveGestureDetector detector) {
+            return true;
+        }
+
+        public void onShoveEnd(ShoveGestureDetector detector) {
+            // Do nothing, overridden implementation may be used
+        }
+    }
+
+    private DisplayMetrics displayMetrics;
+
+    private float mPrevFinger0Y;
+    private float mCurrFinger0Y;
+    private float mPrevFinger1Y;
+    private float mCurrFinger1Y;
+
+    private float mStartY0;
+    private float mStartY1;
+
+    private final OnShoveGestureListener mListener;
+    private boolean mSloppyGesture;
+    private boolean mInitiated;
+
+    // Make sure there is sufficient drag in the 2 fingers (4.5% of minDim)
+    private final float DRAG_THRESHOLD = 0.045f;
+    // Make sure xSpan between 2 fingers is not increasing and is more or less consistent (1% of minDim)
+    private final float XSPAN_THRESHOLD = 0.01f;
+
+    public ShoveGestureDetector(Context context, OnShoveGestureListener listener) {
+        super(context);
+        displayMetrics = context.getResources().getDisplayMetrics();
+        mListener = listener;
+    }
+
+    @Override
+    protected void handleStartProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_POINTER_DOWN:
+                // At least the second finger is on screen now
+
+                resetState(); // In case we missed an UP/CANCEL event
+                mPrevEvent = MotionEvent.obtain(event);
+                mTimeDelta = 0;
+
+                mStartY0 = event.getY(0);
+                mStartY1 = event.getY(1);
+
+                updateStateByEvent(event);
+
+                // Make this event explicitly sloppy
+                mInitiated = isSloppyGesture(event);
+                mSloppyGesture = true;
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+
+                // Check for previous MOVE events (stop doing when last MOVE was not sloppy and shove started)
+                if (!mSloppyGesture && mInitiated) {
+                    break;
+                }
+
+                // Update Previous
+                if (mPrevEvent != null) {
+                    mPrevEvent.recycle();
+                }
+                mPrevEvent = MotionEvent.obtain(event);
+
+                if (mPrevEvent.getPointerCount() != 2) {
+                    break;
+                }
+
+                updateStateByEvent(event);
+
+                // See if we still have a sloppy gesture
+                mSloppyGesture = isSloppyGesture(event);
+                if (!mSloppyGesture) {
+                    // No, start normal gesture now
+                    mGestureInProgress = mListener.onShoveBegin(this);
+                }
+
+                break;
+
+            case MotionEvent.ACTION_POINTER_UP:
+                if (!mSloppyGesture) {
+                    break;
+                }
+
+                break;
+        }
+    }
+
+
+    @Override
+    protected void handleInProgressEvent(int actionCode, MotionEvent event) {
+        switch (actionCode) {
+            case MotionEvent.ACTION_POINTER_UP:
+                // Gesture ended but
+                updateStateByEvent(event);
+
+                if (!mSloppyGesture) {
+                    mListener.onShoveEnd(this);
+                }
+
+                resetState();
+                break;
+
+            case MotionEvent.ACTION_CANCEL:
+                if (!mSloppyGesture) {
+                    mListener.onShoveEnd(this);
+                }
+
+                resetState();
+                break;
+
+            case MotionEvent.ACTION_MOVE:
+                updateStateByEvent(event);
+
+                // Only accept the event if our relative pressure is within
+                // a certain limit. This can help filter shaky data as a
+                // finger is lifted. Also check that shove is meaningful.
+                if (mCurrPressure / mPrevPressure > PRESSURE_THRESHOLD
+                        && Math.abs(getShovePixelsDelta()) > 0.5f) {
+                    final boolean updatePrevious = mListener.onShove(this);
+                    if (updatePrevious) {
+                        mPrevEvent.recycle();
+                        mPrevEvent = MotionEvent.obtain(event);
+                    }
+                }
+                break;
+        }
+    }
+
+    @Override
+    protected void resetState() {
+        super.resetState();
+        mSloppyGesture = false;
+        mInitiated = false;
+
+        //mimic google map behavior (and use the first finger down for getting pixelDelta
+        mCurrFinger0Y = 0.0f;
+        mPrevFinger0Y = 0.0f;
+        mCurrFinger1Y = 0.0f;
+        mPrevFinger1Y = 0.0f;
+    }
+
+    @Override
+    protected void updateStateByEvent(MotionEvent curr) {
+        super.updateStateByEvent(curr);
+
+        final MotionEvent prev = mPrevEvent;
+        float py0 = prev.getY(0);
+        float py1 = prev.getY(1);
+
+        float cy0 = curr.getY(0);
+        float cy1 = curr.getY(1);
+        mCurrFinger0Y = cy0;
+        mPrevFinger0Y = py0;
+        mCurrFinger1Y = cy1;
+        mPrevFinger1Y = py1;
+    }
+
+    @Override
+    protected boolean isSloppyGesture(MotionEvent event) {
+        boolean sloppy = super.isSloppyGesture(event);
+        if (sloppy) {
+            return true;
+        }
+
+        final float drag0 = event.getY(0) - mStartY0;
+        final float drag1 = event.getY(1) - mStartY1;
+
+        final float xSpanDiff = Math.abs(mCurrFingerDiffX - mPrevFingerDiffX);
+        final float minDim = Math.min(displayMetrics.widthPixels, displayMetrics.heightPixels);
+        final float minDrag = DRAG_THRESHOLD * minDim;
+
+        if (drag0 * drag1 < 0.0f) { // Sloppy if fingers moving in opposite y direction
+            return true;
+        } else if (Math.abs(drag0) < minDrag || Math.abs(drag1) < minDrag) {
+            return true;
+        } else if (xSpanDiff > XSPAN_THRESHOLD * minDim) {
+            return true;
+        }
+
+        // Do angle check post drag check!!
+        double angle = Math.abs(Math.atan2(mCurrFingerDiffY, mCurrFingerDiffX));
+        //about 35 degrees, left or right
+        boolean badAngle = !(( 0.0f < angle && angle < 0.611f)
+                || 2.53f < angle && angle < Math.PI);
+
+        return badAngle;
+    }
+
+
+    /**
+     * Return the distance in pixels from the previous shove event to the current
+     * event.
+     *
+     * @return The current distance in pixels.
+     */
+    public float getShovePixelsDelta() {
+
+        /* Prefer first finger unless 2nd finger absolute difference is overpowering.
+         * This is better than oscillating between the 2 finger differences */
+
+        float diff0 = mCurrFinger0Y - mPrevFinger0Y;
+        float diff1 = mCurrFinger1Y - mPrevFinger1Y;
+        if (Math.abs(diff1) > Math.abs(diff0) && Math.abs(diff0) < 2) {
+            return diff1;
+        } else {
+            return diff0;
+        }
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/TwoFingerGestureDetector.java b/platforms/android/tangram/src/main/java/com/almeros/android/multitouch/TwoFingerGestureDetector.java
new file mode 100644 (file)
index 0000000..9518f8c
--- /dev/null
@@ -0,0 +1,220 @@
+package com.almeros.android.multitouch;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.MotionEvent;
+import android.view.ViewConfiguration;
+import java.lang.Math;
+
+/**
+ * @author Almer Thie (code.almeros.com)
+ * Copyright (c) 2013, Almer Thie (code.almeros.com)
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer
+ *  in the documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
+ * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
+ * OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+ */
+public abstract class TwoFingerGestureDetector extends BaseGestureDetector {
+
+    private final float mEdgeSlop;
+    private float mRightSlopEdge;
+    private float mBottomSlopEdge;
+
+    protected float mPrevFingerDiffX;
+    protected float mPrevFingerDiffY;
+    protected float mCurrFingerDiffX;
+    protected float mCurrFingerDiffY;
+
+    private float mCurrLen;
+    private float mPrevLen;
+
+    public TwoFingerGestureDetector(Context context) {
+        super(context);
+
+        ViewConfiguration config = ViewConfiguration.get(context);
+        mEdgeSlop = config.getScaledEdgeSlop();
+    }
+
+    @Override
+    protected abstract void handleStartProgressEvent(int actionCode, MotionEvent event);
+
+    @Override
+    protected abstract void handleInProgressEvent(int actionCode, MotionEvent event);
+
+    protected void updateStateByEvent(MotionEvent curr) {
+        super.updateStateByEvent(curr);
+
+        final MotionEvent prev = mPrevEvent;
+
+        mCurrLen = -1;
+        mPrevLen = -1;
+
+        // Previous
+        final float px0 = prev.getX(0);
+        final float py0 = prev.getY(0);
+        final float px1 = prev.getX(1);
+        final float py1 = prev.getY(1);
+        final float pvx = px1 - px0;
+        final float pvy = py1 - py0;
+        mPrevFingerDiffX = pvx;
+        mPrevFingerDiffY = pvy;
+
+        // Current
+        final float cx0 = curr.getX(0);
+        final float cy0 = curr.getY(0);
+        final float cx1 = curr.getX(1);
+        final float cy1 = curr.getY(1);
+        final float cvx = cx1 - cx0;
+        final float cvy = cy1 - cy0;
+        mCurrFingerDiffX = cvx;
+        mCurrFingerDiffY = cvy;
+    }
+
+    /**
+     * Return the current x-distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Distance between pointers in pixels.
+     */
+    public float getCurrentSpanX() {
+        return mCurrFingerDiffX;
+    }
+
+    /**
+     * Return the current y-distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Distance between pointers in pixels.
+     */
+    public float getCurrentSpanY() {
+        return mCurrFingerDiffY;
+    }
+
+    /**
+     * Return the previous x-distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Distance between pointers in pixels.
+     */
+    public float getPreviousSpanX() {
+        return mPrevFingerDiffX;
+    }
+
+    /**
+     * Return the previous y-distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Distance between pointers in pixels.
+     */
+    public float getPreviousSpanY() {
+        return mPrevFingerDiffY;
+    }
+
+    /**
+     * Return the current distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Distance between pointers in pixels.
+     */
+    public float getCurrentSpan() {
+        if (mCurrLen == -1) {
+            final float cvx = mCurrFingerDiffX;
+            final float cvy = mCurrFingerDiffY;
+            mCurrLen = (float)Math.sqrt(cvx*cvx + cvy*cvy);
+        }
+        return mCurrLen;
+    }
+
+    /**
+     * Return the previous distance between the two pointers forming the
+     * gesture in progress.
+     *
+     * @return Previous distance between pointers in pixels.
+     */
+    public float getPreviousSpan() {
+        if (mPrevLen == -1) {
+            final float pvx = mPrevFingerDiffX;
+            final float pvy = mPrevFingerDiffY;
+            mPrevLen = (float)Math.sqrt(pvx*pvx + pvy*pvy);
+        }
+        return mPrevLen;
+    }
+
+    /**
+     * MotionEvent has no getRawX(int) method; simulate it pending future API approval.
+     * @param event
+     * @param pointerIndex
+     * @return Raw X coordinate in pixels
+     */
+    protected static float getRawX(MotionEvent event, int pointerIndex) {
+        float offset = event.getX() - event.getRawX();
+        if (pointerIndex < event.getPointerCount()) {
+            return event.getX(pointerIndex) + offset;
+        }
+        return 0f;
+    }
+
+    /**
+     * MotionEvent has no getRawY(int) method; simulate it pending future API approval.
+     * @param event
+     * @param pointerIndex
+     * @return Raw Y coordinate in pixels
+     */
+    protected static float getRawY(MotionEvent event, int pointerIndex) {
+        float offset = event.getY() - event.getRawY();
+        if (pointerIndex < event.getPointerCount()) {
+            return event.getY(pointerIndex) + offset;
+        }
+        return 0f;
+    }
+
+    /**
+     * Check if we have a sloppy gesture. Sloppy gestures can happen if the edge
+     * of the user's hand is touching the screen, for example.
+     *
+     * @param event
+     * @return True if gesture is sloppy, else false
+     */
+    protected boolean isSloppyGesture(MotionEvent event) {
+        // As orientation can change, query the metrics in touch down
+        DisplayMetrics metrics = mContext.getResources().getDisplayMetrics();
+        mRightSlopEdge = metrics.widthPixels - mEdgeSlop;
+        mBottomSlopEdge = metrics.heightPixels - mEdgeSlop;
+
+        final float edgeSlop = mEdgeSlop;
+        final float rightSlop = mRightSlopEdge;
+        final float bottomSlop = mBottomSlopEdge;
+
+        final float x0 = event.getRawX();
+        final float y0 = event.getRawY();
+        final float x1 = getRawX(event, 1);
+        final float y1 = getRawY(event, 1);
+
+        boolean p0sloppy = x0 < edgeSlop || y0 < edgeSlop
+                || x0 > rightSlop || y0 > bottomSlop;
+        boolean p1sloppy = x1 < edgeSlop || y1 < edgeSlop
+                || x1 > rightSlop || y1 > bottomSlop;
+
+        if (p0sloppy && p1sloppy) {
+            return true;
+        } else if (p0sloppy) {
+             return true;
+        } else if (p1sloppy) {
+             return true;
+        }
+        return false;
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/ConfigChooser.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/ConfigChooser.java
new file mode 100644 (file)
index 0000000..713c6db
--- /dev/null
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2009 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the
+ * License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS"
+ * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language
+ * governing permissions and limitations under the License.
+ */
+
+package com.mapzen.tangram;
+
+import javax.microedition.khronos.egl.EGL10;
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.egl.EGLDisplay;
+
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.EGLConfigChooser;
+import android.util.Log;
+
+/**
+ * {@code ConfigChooser} is a convenience class for configuring a {@code GLSurfaceView}.
+ */
+public class ConfigChooser implements GLSurfaceView.EGLConfigChooser {
+
+    /**
+     * Construct a {@code ConfigChooser} to match the given framebuffer parameters
+     * @param r Red bits
+     * @param g Green bits
+     * @param b Blue bits
+     * @param a Alpha bits
+     * @param depth Depth bits
+     * @param stencil Stencil bits
+     */
+    public ConfigChooser (int r, int g, int b, int a, int depth, int stencil) {
+        mRedSize = r;
+        mGreenSize = g;
+        mBlueSize = b;
+        mAlphaSize = a;
+        mDepthSize = depth;
+        mStencilSize = stencil;
+    }
+
+    /*
+     * This EGL config specification is used to specify 2.0 rendering. We use a minimum size of 4 bits for red/green/blue, but
+     * will perform actual matching in chooseConfig() below.
+     */
+    private static int EGL_OPENGL_ES2_BIT = 4;
+    private static int[] s_configAttribs = {EGL10.EGL_RED_SIZE, 4, EGL10.EGL_GREEN_SIZE, 4, EGL10.EGL_BLUE_SIZE, 4,
+        EGL10.EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT, EGL10.EGL_NONE};
+
+    @Override
+    public EGLConfig chooseConfig (EGL10 egl, EGLDisplay display) {
+
+        // Get the number of minimally matching EGL configurations
+        int[] num_config = new int[1];
+        egl.eglChooseConfig(display, s_configAttribs, null, 0, num_config);
+
+        int numConfigs = num_config[0];
+
+        if (numConfigs <= 0) {
+            throw new IllegalArgumentException("No configs match configSpec");
+        }
+
+        // Allocate then read the array of minimally matching EGL configs
+        EGLConfig[] configs = new EGLConfig[numConfigs];
+        egl.eglChooseConfig(display, s_configAttribs, configs, numConfigs, num_config);
+
+        // Now return the "best" one
+        return chooseConfig(egl, display, configs);
+    }
+
+    public EGLConfig chooseConfig (EGL10 egl, EGLDisplay display, EGLConfig[] configs) {
+
+        EGLConfig bestConfig = null;
+        int bestDepth = 0;
+        int bestStencil = 0;
+
+        for (EGLConfig config : configs) {
+            int d = findConfigAttrib(egl, display, config, EGL10.EGL_DEPTH_SIZE, 0);
+            int s = findConfigAttrib(egl, display, config, EGL10.EGL_STENCIL_SIZE, 0);
+
+            // We need at least mDepthSize and mStencilSize bits
+            if (d < mDepthSize || s < mStencilSize) { continue; }
+
+            // We want an *exact* match for red/green/blue/alpha
+            int r = findConfigAttrib(egl, display, config, EGL10.EGL_RED_SIZE, 0);
+            int g = findConfigAttrib(egl, display, config, EGL10.EGL_GREEN_SIZE, 0);
+            int b = findConfigAttrib(egl, display, config, EGL10.EGL_BLUE_SIZE, 0);
+            int a = findConfigAttrib(egl, display, config, EGL10.EGL_ALPHA_SIZE, 0);
+
+            if (r == mRedSize && g == mGreenSize && b == mBlueSize && a == mAlphaSize &&
+                d >= bestDepth && s >= bestStencil) {
+
+                bestConfig = config;
+                bestDepth = d;
+                bestStencil = s;
+
+            }
+        }
+        return bestConfig;
+    }
+
+    private int findConfigAttrib (EGL10 egl, EGLDisplay display, EGLConfig config, int attribute, int defaultValue) {
+
+        if (egl.eglGetConfigAttrib(display, config, attribute, mValue)) {
+            return mValue[0];
+        }
+        return defaultValue;
+    }
+
+    // Subclasses can adjust these values:
+    protected int mRedSize;
+    protected int mGreenSize;
+    protected int mBlueSize;
+    protected int mAlphaSize;
+    protected int mDepthSize;
+    protected int mStencilSize;
+    private int[] mValue = new int[1];
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/FontFileParser.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/FontFileParser.java
new file mode 100644 (file)
index 0000000..8f0702d
--- /dev/null
@@ -0,0 +1,347 @@
+package com.mapzen.tangram;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.FileNotFoundException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.ArrayList;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import android.util.Xml;
+
+class FontFileParser {
+
+    private Map<String, String> fontDict = new HashMap<String, String>();
+    private Map<Integer, ArrayList<String>> fallbackFontDict = new HashMap<Integer, ArrayList<String>>();
+
+    private static String systemFontPath = "/system/fonts/";
+    // Android version >= 5.0
+    private static String fontXMLPath = "/system/etc/fonts.xml";
+
+    // Android version < 5.0
+    private static String oldFontXMLPath = "/system/etc/system_fonts.xml";
+    private static String oldFontXMLFallbackPath = "/system/etc/fallback_fonts.xml";
+
+    private void addFallback(Integer weight, String filename) {
+        String fullFileName = systemFontPath + filename;
+        if (!new File(fullFileName).exists()) {
+            return;
+        }
+
+        if (!fallbackFontDict.containsKey(weight)) {
+            fallbackFontDict.put(weight, new ArrayList<String>());
+        }
+
+        fallbackFontDict.get(weight).add(fullFileName);
+    }
+
+
+    private void processDocumentPreLollipop(XmlPullParser parser) throws XmlPullParserException, IOException {
+        parser.nextTag();
+        parser.require(XmlPullParser.START_TAG, null, "familyset");
+
+        ArrayList<String> namesets = new ArrayList<>();
+        ArrayList<String> filesets = new ArrayList<>();
+
+        while (parser.next() != XmlPullParser.END_DOCUMENT) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+
+            if (!"family".equals(parser.getName())) {
+                skip(parser);
+                continue;
+            }
+
+            namesets.clear();
+            filesets.clear();
+
+            while (parser.next() != XmlPullParser.END_TAG) {
+                if (parser.getEventType() != XmlPullParser.START_TAG) {
+                    continue;
+                }
+
+                if ("nameset".equals(parser.getName())) {
+                    while (parser.next() != XmlPullParser.END_TAG) {
+                        if (parser.getEventType() != XmlPullParser.START_TAG) {
+                            continue;
+                        }
+
+                        String name = parser.nextText();
+                        namesets.add(name.toLowerCase());
+                    }
+                    continue;
+                }
+
+                if ("fileset".equals(parser.getName())) {
+                    while (parser.next() != XmlPullParser.END_TAG) {
+                        if (parser.getEventType() != XmlPullParser.START_TAG) {
+                            continue;
+                        }
+                        String filename = parser.nextText();
+                        // Don't use UI fonts
+                        if (filename.contains("UI-")) {
+                            continue;
+                        }
+                        // Sorry - not yet supported
+                        if (filename.contains("Emoji")) {
+                            continue;
+                        }
+                        filesets.add(filename);
+                    }
+                } else {
+                    skip(parser);
+                }
+
+                // fallback_fonts.xml entries have no names
+                if (namesets.isEmpty()) { namesets.add("sans-serif"); }
+
+                for (String filename : filesets) {
+                    for (String fontname : namesets) {
+
+                        String style = "normal";
+                        // The file structure in `/etc/system_fonts.xml` is quite undescriptive
+                        // which makes it hard to make a matching from a font style to a font file
+                        // e.g. italic -> font file, instead we extract this information from the
+                        // font file name itself
+                        String[] fileSplit = filename.split("-");
+                        if (fileSplit.length > 1) {
+                            style = fileSplit[fileSplit.length - 1].toLowerCase();
+                            // Remove extension .ttf
+                            style = style.substring(0, style.lastIndexOf('.'));
+
+                            if (style.equals("regular")) {
+                                style = "normal";
+                            }
+                        }
+
+                        // Same here, font boldness is non-available for android < 5.0 file
+                        // description, we default to integer boldness of 400 by default
+                        String key = fontname + "_400_" + style;
+                        fontDict.put(key, systemFontPath + filename);
+
+                        if ("sans-serif".equals(fontname) && "normal".equals(style)) {
+                            addFallback(400, filename);
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    private void processDocument(XmlPullParser parser) throws XmlPullParserException, IOException {
+
+        ArrayList<String> familyWeights = new ArrayList<String>();
+
+        parser.nextTag();
+        // Parse Families
+        parser.require(XmlPullParser.START_TAG, null, "familyset");
+        while (parser.next() != XmlPullParser.END_DOCUMENT) {
+            if (parser.getEventType() != XmlPullParser.START_TAG) {
+                continue;
+            }
+            if ("family".equals(parser.getName())) {
+                familyWeights.clear();
+                // Parse this family:
+                String name = parser.getAttributeValue(null, "name");
+                String lang = parser.getAttributeValue(null, "lang");
+
+                // fallback fonts
+                if (name == null) {
+                    while (parser.next() != XmlPullParser.END_TAG) {
+                        if (parser.getEventType() != XmlPullParser.START_TAG) {
+                            continue;
+                        }
+                        String tag = parser.getName();
+                        if ("font".equals(tag)) {
+                            String weightStr = parser.getAttributeValue(null, "weight");
+                            if (weightStr != null) { familyWeights.add(weightStr); }
+                            weightStr = (weightStr == null) ? "400" : weightStr;
+
+                            String filename = parser.nextText();
+
+                            // Don't use UI fonts
+                            if (filename.contains("UI-")) {
+                                continue;
+                            }
+                            // Sorry - not yet supported
+                            if (filename.contains("Emoji")) {
+                                continue;
+                            }
+
+                            addFallback(Integer.valueOf(weightStr), filename);
+                        } else {
+                            skip(parser);
+                        }
+                    }
+
+                } else {
+                    while (parser.next() != XmlPullParser.END_TAG) {
+                        if (parser.getEventType() != XmlPullParser.START_TAG) {
+                            continue;
+                        }
+                        String tag = parser.getName();
+                        if ("font".equals(tag)) {
+                            String weightStr = parser.getAttributeValue(null, "weight");
+                            if (weightStr != null) {
+                                familyWeights.add(weightStr);
+                            }
+                            weightStr = (weightStr == null) ? "400" : weightStr;
+
+                            String styleStr = parser.getAttributeValue(null, "style");
+                            styleStr = (styleStr == null) ? "normal" : styleStr;
+
+                            String filename = parser.nextText();
+                            String fullFileName = systemFontPath + filename;
+
+                            String key = name + "_" + weightStr + "_" + styleStr;
+                            fontDict.put(key, fullFileName);
+
+                            if ("sans-serif".equals(name) && "normal".equals(styleStr)) {
+                                addFallback(Integer.valueOf(weightStr), filename);
+                            }
+
+                        } else {
+                            skip(parser);
+                        }
+                    }
+                }
+            } else if ("alias".equals(parser.getName())) {
+                // Parse this alias to font to fileName
+                String aliasName = parser.getAttributeValue(null, "name");
+                String toName = parser.getAttributeValue(null, "to");
+                String weightStr = parser.getAttributeValue(null, "weight");
+                ArrayList<String> aliasWeights = new ArrayList<String>();
+                String fontFilename;
+
+                if (weightStr == null) {
+                    aliasWeights = familyWeights;
+                } else {
+                    aliasWeights.add(weightStr);
+                }
+
+                for (String weight : aliasWeights) {
+                    // Only 2 styles possible based on /etc/fonts.xml
+                    // Normal style
+                    fontFilename = fontDict.get(toName + "_" + weight + "_normal");
+                    fontDict.put(aliasName + "_" + weight + "_normal", fontFilename);
+                    // Italic style
+                    fontFilename = fontDict.get(toName + "_" + weight + "_italic");
+                    fontDict.put(aliasName + "_" + weight + "_italic", fontFilename);
+                }
+            } else {
+                skip(parser);
+            }
+        }
+    }
+
+    private void skip(XmlPullParser parser) throws XmlPullParserException, IOException {
+        int depth = 1;
+        while (depth > 0) {
+            switch (parser.next()) {
+                case XmlPullParser.START_TAG:
+                    depth++;
+                    break;
+                case XmlPullParser.END_TAG:
+                    depth--;
+                    break;
+            }
+        }
+    }
+
+    public void parse() {
+
+        File fontFile = new File(fontXMLPath);
+
+        if (fontFile.exists()) {
+            parse(fontFile.getAbsolutePath(), false);
+            return;
+        }
+
+        fontFile = new File(oldFontXMLPath);
+        if (fontFile.exists()) {
+            parse(fontFile.getAbsolutePath(), true);
+        }
+        fontFile = new File(oldFontXMLFallbackPath);
+        if (fontFile.exists()) {
+            parse(fontFile.getAbsolutePath(), true);
+        }
+    }
+
+    private void parse(String fileXml, boolean oldXML) {
+
+        InputStream in;
+
+        try {
+            in = new FileInputStream(fileXml);
+        } catch (FileNotFoundException e) {
+            e.printStackTrace();
+            return;
+        }
+
+        XmlPullParser parser = Xml.newPullParser();
+
+        try {
+            parser.setInput(in, null);
+
+            if (oldXML) {
+                processDocumentPreLollipop(parser);
+            } else {
+                processDocument(parser);
+            }
+        } catch(XmlPullParserException e) {
+            e.printStackTrace();
+        } catch(IOException e) {
+            e.printStackTrace();
+        }
+
+        try {
+            in.close();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+    public String getFontFile(String _key) {
+        if (fontDict.containsKey(_key)) {
+            return fontDict.get(_key);
+        } else {
+            return "";
+        }
+    }
+
+    /*
+     * Returns the next available font fallback, or empty string if not found
+     * The integer value determines the fallback priority (lower is higher)
+     * The weightHint value determines the closest fallback hint for boldness
+     * See /etc/fonts/font_fallback for documentation
+     */
+    public String getFontFallback(int importance, int weightHint) {
+        Iterator it = fallbackFontDict.entrySet().iterator();
+        Integer diffWeight = Integer.MAX_VALUE;
+        String fallback = "";
+
+        while (it.hasNext()) {
+            Map.Entry<Integer, ArrayList<String>> pair = (Map.Entry)it.next();
+            Integer diff = Math.abs(pair.getKey() - weightHint);
+
+            if (diff < diffWeight) {
+                ArrayList<String> fallbacks = pair.getValue();
+
+                if (importance < fallbacks.size()) {
+                    fallback = fallbacks.get(importance);
+                    diffWeight = diff;
+                }
+            }
+        }
+        return fallback;
+    }
+
+}
+
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/HttpHandler.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/HttpHandler.java
new file mode 100644 (file)
index 0000000..6ac1f89
--- /dev/null
@@ -0,0 +1,177 @@
+package com.mapzen.tangram;
+
+import android.os.Build;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+import okhttp3.Cache;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.OkHttpClient;
+import okhttp3.Request;
+import javax.net.ssl.SSLContext;
+import okhttp3.ConnectionSpec;
+import okhttp3.TlsVersion;
+
+/**
+ * {@code HttpHandler} is a class for customizing HTTP requests for map resources, it can be
+ * extended to override the request or caching behavior.
+ */
+public class HttpHandler {
+
+    private OkHttpClient okClient;
+
+    /**
+     * Enables TLS v1.2 when creating SSLSockets.
+     * <p/>
+     * For some reason, android supports TLS v1.2 from API 16, but enables it by
+     * default only from API 20.
+     *
+     * @link https://developer.android.com/reference/javax/net/ssl/SSLSocket.html
+     * @see SSLSocketFactory
+     */
+    private class Tls12SocketFactory extends SSLSocketFactory {
+        private final String[] TLS_V12_ONLY = {"TLSv1.2"};
+
+        final SSLSocketFactory delegate;
+
+        public Tls12SocketFactory(SSLSocketFactory base) {
+            this.delegate = base;
+        }
+
+        @Override
+        public String[] getDefaultCipherSuites() {
+            return delegate.getDefaultCipherSuites();
+        }
+
+        @Override
+        public String[] getSupportedCipherSuites() {
+            return delegate.getSupportedCipherSuites();
+        }
+
+        @Override
+        public Socket createSocket(Socket s, String host, int port, boolean autoClose) throws IOException {
+            return patch(delegate.createSocket(s, host, port, autoClose));
+        }
+
+        @Override
+        public Socket createSocket(String host, int port) throws IOException, UnknownHostException {
+            return patch(delegate.createSocket(host, port));
+        }
+
+        @Override
+        public Socket createSocket(String host, int port, InetAddress localHost, int localPort) throws IOException, UnknownHostException {
+            return patch(delegate.createSocket(host, port, localHost, localPort));
+        }
+
+        @Override
+        public Socket createSocket(InetAddress host, int port) throws IOException {
+            return patch(delegate.createSocket(host, port));
+        }
+
+        @Override
+        public Socket createSocket(InetAddress address, int port, InetAddress localAddress, int localPort) throws IOException {
+            return patch(delegate.createSocket(address, port, localAddress, localPort));
+        }
+
+        private Socket patch(Socket s) {
+            if (s instanceof SSLSocket) {
+                ((SSLSocket) s).setEnabledProtocols(TLS_V12_ONLY);
+            }
+            return s;
+        }
+    }
+
+    /**
+     * Construct an {@code HttpHandler} with default options.
+     */
+    public HttpHandler() {
+        this(null, 0);
+    }
+
+    /**
+     * Construct an {@code HttpHandler} with cache.
+     * Cache map data in a directory with a specified size limit
+     * @param directory Directory in which map data will be cached
+     * @param maxSize Maximum size of data to cache, in bytes
+     */
+    public HttpHandler(File directory, long maxSize) {
+        OkHttpClient.Builder builder = new OkHttpClient.Builder()
+                .connectTimeout(10, TimeUnit.SECONDS)
+                .writeTimeout(10, TimeUnit.SECONDS)
+                .readTimeout(30, TimeUnit.SECONDS);
+
+        if (directory != null && maxSize > 0) {
+            builder.cache(new Cache(directory, maxSize));
+        }
+
+        if (Build.VERSION.SDK_INT >= 16 && Build.VERSION.SDK_INT < 22) {
+            try {
+                SSLContext sc = SSLContext.getInstance("TLSv1.2");
+                sc.init(null, null, null);
+                builder.sslSocketFactory(new Tls12SocketFactory(sc.getSocketFactory()));
+
+                ConnectionSpec cs = new ConnectionSpec.Builder(ConnectionSpec.MODERN_TLS)
+                        .tlsVersions(TlsVersion.TLS_1_2)
+                        .build();
+
+                List<ConnectionSpec> specs = new ArrayList<>();
+                specs.add(cs);
+                specs.add(ConnectionSpec.COMPATIBLE_TLS);
+                specs.add(ConnectionSpec.CLEARTEXT);
+
+                builder.connectionSpecs(specs);
+            } catch (Exception exc) {
+                android.util.Log.e("Tangram", "Error while setting TLS 1.2", exc);
+            }
+        }
+
+        okClient = builder.build();
+    }
+
+    /**
+     * Begin an HTTP request
+     * @param url URL for the requested resource
+     * @param cb Callback for handling request result
+     * @return true if request was successfully started
+     */
+    public boolean onRequest(String url, Callback cb) {
+        Request request = new Request.Builder()
+                .url(url)
+                .build();
+        okClient.newCall(request).enqueue(cb);
+        return true;
+    }
+
+    /**
+     * Cancel an HTTP request
+     * @param url URL of the request to be cancelled
+     */
+    public void onCancel(String url) {
+
+        // check and cancel running call
+        for (Call runningCall : okClient.dispatcher().runningCalls()) {
+            if (runningCall.request().url().toString().equals(url)) {
+                runningCall.cancel();
+            }
+        }
+
+        // check and cancel queued call
+        for (Call queuedCall : okClient.dispatcher().queuedCalls()) {
+            if (queuedCall.request().url().toString().equals(url)) {
+                queuedCall.cancel();
+            }
+        }
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/LabelPickResult.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/LabelPickResult.java
new file mode 100644 (file)
index 0000000..d4d6297
--- /dev/null
@@ -0,0 +1,45 @@
+package com.mapzen.tangram;
+
+import java.util.Map;
+
+/**
+ * {@code LabelPickResult} represents labels that can be selected on the screen
+ */
+public class LabelPickResult {
+
+    /**
+     * Options for the type of LabelPickResult
+     */
+    public enum LabelType {
+        ICON,
+        TEXT,
+    }
+
+    private LngLat coordinates;
+    private LabelType type;
+    private Map<String, String> properties;
+
+    private LabelPickResult(double longitude, double latitude, int type, Map<String, String> properties) {
+        this.properties = properties;
+        this.coordinates = new LngLat(longitude, latitude);
+        this.type = LabelType.values()[type];
+    }
+
+    public LabelType getType() {
+        return this.type;
+    }
+
+    /**
+     * @return The coordinate of the feature for which this label has been created
+     */
+    public LngLat getCoordinates() {
+        return this.coordinates;
+    }
+
+    /**
+     * @return A mapping of string keys to string or number values
+     */
+    public Map<String, String> getProperties() {
+        return this.properties;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/LngLat.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/LngLat.java
new file mode 100644 (file)
index 0000000..bfb3127
--- /dev/null
@@ -0,0 +1,41 @@
+package com.mapzen.tangram;
+
+/**
+ * {@code LngLat} represents a geographic coordinate with longitude and latitude.
+ */
+public class LngLat {
+
+    public double longitude; // Degrees longitude
+    public double latitude;  // Degrees latitude
+
+    public LngLat() {
+        this(0, 0);
+    }
+
+    public LngLat(LngLat other) {
+        set(other);
+    }
+
+    public LngLat(double lng, double lat) {
+        set(lng, lat);
+    }
+
+    public LngLat set(double lng, double lat) {
+        longitude = lng;
+        latitude = lat;
+        return this;
+    }
+
+    public LngLat set(LngLat other) {
+        set(other.longitude, other.latitude);
+        return this;
+    }
+
+    public boolean equals(Object other) {
+        if (other instanceof LngLat) {
+            return longitude == ((LngLat) other).longitude
+                && latitude == ((LngLat) other).latitude;
+        }
+        return false;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapController.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapController.java
new file mode 100644 (file)
index 0000000..1ad49c3
--- /dev/null
@@ -0,0 +1,1256 @@
+package com.mapzen.tangram;
+
+import android.content.res.AssetManager;
+import android.graphics.Bitmap;
+import android.graphics.PointF;
+import android.opengl.GLSurfaceView;
+import android.opengl.GLSurfaceView.Renderer;
+import android.os.Handler;
+import android.util.DisplayMetrics;
+
+import com.mapzen.tangram.TouchInput.Gestures;
+import okhttp3.Call;
+import okhttp3.Callback;
+import okhttp3.Response;
+
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+
+import javax.microedition.khronos.egl.EGLConfig;
+import javax.microedition.khronos.opengles.GL10;
+
+/**
+ * {@code MapController} is the main class for interacting with a Tangram map.
+ */
+public class MapController implements Renderer {
+
+    /**
+     * Options for interpolating map parameters
+     */
+    public enum EaseType {
+        LINEAR,
+        CUBIC,
+        QUINT,
+        SINE,
+    }
+
+    /**
+     * Options for changing the appearance of 3D geometry
+     */
+    public enum CameraType {
+        PERSPECTIVE,
+        ISOMETRIC,
+        FLAT,
+    }
+
+    /**
+     * Options representing an error generated after from the map controller
+     */
+    public enum Error {
+        SCENE_UPDATE_PATH_NOT_FOUND,
+        SCENE_UPDATE_PATH_YAML_SYNTAX_ERROR,
+        SCENE_UPDATE_VALUE_YAML_SYNTAX_ERROR,
+    }
+
+    protected static EaseType DEFAULT_EASE_TYPE = EaseType.CUBIC;
+
+    /**
+     * Options for enabling debug rendering features
+     */
+    public enum DebugFlag {
+        FREEZE_TILES,
+        PROXY_COLORS,
+        TILE_BOUNDS,
+        TILE_INFOS,
+        LABELS,
+        TANGRAM_INFOS,
+        DRAW_ALL_LABELS,
+        TANGRAM_STATS,
+        SELECTION_BUFFER,
+    }
+
+    /**
+     * Interface for a callback to receive information about features picked from the map
+     * Triggered after a call of {@link #pickFeature(float, float)}
+     * Listener should be set with {@link #setFeaturePickListener(FeaturePickListener)}
+     * The callback will be run on the main (UI) thread.
+     */
+    public interface FeaturePickListener {
+        /**
+         * Receive information about features found in a call to {@link #pickFeature(float, float)}
+         * @param properties A mapping of string keys to string or number values
+         * @param positionX The horizontal screen coordinate of the picked location
+         * @param positionY The vertical screen coordinate of the picked location
+         */
+        void onFeaturePick(Map<String, String> properties, float positionX, float positionY);
+    }
+    /**
+     * Interface for a callback to receive information about labels picked from the map
+     * Triggered after a call of {@link #pickLabel(float, float)}
+     * Listener should be set with {@link #setLabelPickListener(LabelPickListener)}
+     * The callback will be run on the main (UI) thread.
+     */
+    public interface LabelPickListener {
+        /**
+         * Receive information about labels found in a call to {@link #pickLabel(float, float)}
+         * @param labelPickResult The {@link LabelPickResult} that has been selected
+         * @param positionX The horizontal screen coordinate of the picked location
+         * @param positionY The vertical screen coordinate of the picked location
+         */
+        void onLabelPick(LabelPickResult labelPickResult, float positionX, float positionY);
+    }
+
+    /**
+     * Interface for a callback to receive the picked {@link Marker}
+     * Triggered after a call of {@link #pickMarker(float, float)}
+     * Listener should be set with {@link #setMarkerPickListener(MarkerPickListener)}
+     * The callback will be run on the main (UI) thread.
+     */
+    public interface MarkerPickListener {
+        /**
+         * Receive information about marker found in a call to {@link #pickMarker(float, float)}
+         * @param markerPickResult The {@link MarkerPickResult} the marker that has been selected
+         * @param positionX The horizontal screen coordinate of the picked location
+         * @param positionY The vertical screen coordinate of the picked location
+         */
+        void onMarkerPick(MarkerPickResult markerPickResult, float positionX, float positionY);
+    }
+
+    public interface ViewCompleteListener {
+        /**
+         * Called on the UI thread at the end of whenever the view is stationary, fully loaded, and
+         * no animations are running.
+         */
+        void onViewComplete();
+    }
+
+    /**
+     * Interface for a callback to received additional error information in a {@link SceneUpdateError}
+     * Triggered after a call of {@link #applySceneUpdates()} or {@link #loadSceneFile(String, List<SceneUpdate>)}
+     * Listener should be set with {@link #setSceneUpdateErrorListener(SceneUpdateErrorListener)}
+     * The callback will be run on the main (UI) thread.
+     */
+    public interface SceneUpdateErrorListener {
+        /**
+         * Receive error status when a scene update failed
+         * @param sceneUpdateError The  {@link SceneUpdateError} holding error informations
+         */
+        void onSceneUpdateError(SceneUpdateError sceneUpdateError);
+    }
+
+    /**
+     * Callback for {@link #captureFrame(FrameCaptureCallback, boolean) }
+     */
+    public interface FrameCaptureCallback {
+        /**
+         * Called on the render-thread when a frame was captured.
+         */
+        void onCaptured(Bitmap bitmap);
+    }
+
+    /**
+     * Capture MapView as Bitmap.
+     * @param waitForCompleteView Delay the capture until the view is fully loaded and
+     *                            no ease- or label-animation is running.
+     */
+    public void captureFrame(FrameCaptureCallback callback, boolean waitForCompleteView) {
+        frameCaptureCallback = callback;
+        frameCaptureAwaitCompleteView = waitForCompleteView;
+        requestRender();
+    }
+
+    private Bitmap capture() {
+        int w = mapView.getWidth();
+        int h = mapView.getHeight();
+
+        int b[] = new int[w * h];
+        int bt[] = new int[w * h];
+
+        nativeCaptureSnapshot(mapPointer, b);
+
+        for (int i = 0; i < h; i++) {
+            for (int j = 0; j < w; j++) {
+                int pix = b[i * w + j];
+                int pb = (pix >> 16) & 0xff;
+                int pr = (pix << 16) & 0x00ff0000;
+                int pix1 = (pix & 0xff00ff00) | pr | pb;
+                bt[(h - i - 1) * w + j] = pix1;
+            }
+        }
+
+        return Bitmap.createBitmap(bt, w, h, Bitmap.Config.ARGB_8888);
+    }
+
+    /**
+     * Construct a MapController using a custom scene file
+     * @param view GLSurfaceView for the map display; input events from this
+     * view will be handled by the MapController's TouchInput gesture detector.
+     * It also provides the Context in which the map will function; the asset
+     * bundle for this activity must contain all the local files that the map
+     * will need.
+     */
+    protected MapController(GLSurfaceView view) {
+
+        // Set up MapView
+        mapView = view;
+        view.setRenderer(this);
+        view.setRenderMode(GLSurfaceView.RENDERMODE_WHEN_DIRTY);
+        view.setPreserveEGLContextOnPause(true);
+
+        // Set a default HTTPHandler
+        httpHandler = new HttpHandler();
+
+        touchInput = new TouchInput(view.getContext());
+        view.setOnTouchListener(touchInput);
+
+        setPanResponder(null);
+        setScaleResponder(null);
+        setRotateResponder(null);
+        setShoveResponder(null);
+
+        touchInput.setSimultaneousDetectionAllowed(Gestures.SHOVE, Gestures.ROTATE, false);
+        touchInput.setSimultaneousDetectionAllowed(Gestures.ROTATE, Gestures.SHOVE, false);
+        touchInput.setSimultaneousDetectionAllowed(Gestures.SHOVE, Gestures.SCALE, false);
+        touchInput.setSimultaneousDetectionAllowed(Gestures.SHOVE, Gestures.PAN, false);
+        touchInput.setSimultaneousDetectionAllowed(Gestures.SCALE, Gestures.LONG_PRESS, false);
+
+        uiThreadHandler = new Handler(view.getContext().getMainLooper());
+    }
+
+    /**
+     * Initialize native Tangram component. This must be called before any use
+     * of the MapController!
+     * This function is separated from MapController constructor to allow
+     * initialization and loading of the Scene on a background thread.
+     */
+    void init() {
+        // Get configuration info from application
+        displayMetrics = mapView.getContext().getResources().getDisplayMetrics();
+        assetManager = mapView.getContext().getAssets();
+
+        fontFileParser = new FontFileParser();
+
+        // Parse font file desription
+        fontFileParser.parse();
+
+        mapPointer = nativeInit(this, assetManager);
+        if (mapPointer <= 0) {
+            throw new RuntimeException("Unable to create a native Map object! There may be insufficient memory available.");
+        }
+    }
+
+    void dispose() {
+        // Disposing native resources involves GL calls, so we need to run on the GL thread.
+        queueEvent(new Runnable() {
+            @Override
+            public void run() {
+                // Dispose each data sources by first removing it from the HashMap values and then
+                // calling remove(), so that we don't improperly modify the HashMap while iterating.
+                for (Iterator<MapData> it = clientTileSources.values().iterator(); it.hasNext();) {
+                    MapData mapData = it.next();
+                    it.remove();
+                    mapData.remove();
+                }
+                nativeDispose(mapPointer);
+                mapPointer = 0;
+                clientTileSources.clear();
+                markers.clear();
+            }
+        });
+    }
+
+    static MapController getInstance(GLSurfaceView view) {
+        return new MapController(view);
+    }
+
+    /**
+     * Load a new scene file
+     * @param path Location of the YAML scene file within the application assets
+     */
+    public void loadSceneFile(String path) {
+        loadSceneFile(path, null);
+    }
+
+    /**
+     * Load a new scene file
+     * If scene updates triggers an error, they won't be applied.
+     * @param path Location of the YAML scene file within the application assets
+     * @param sceneUpdates List of {@code SceneUpdate}
+     */
+    public void loadSceneFile(String path, List<SceneUpdate> sceneUpdates) {
+        String[] updateStrings = bundleSceneUpdates(sceneUpdates);
+        scenePath = path;
+        checkPointer(mapPointer);
+        nativeLoadScene(mapPointer, sceneUpdateErrorListener, path, updateStrings);
+        removeAllMarkers();
+        requestRender();
+    }
+
+    /**
+     * Set the {@link HttpHandler} for retrieving remote map resources; a default-constructed
+     * HttpHandler is suitable for most cases, but methods can be extended to modify resource URLs
+     * @param handler the HttpHandler to use
+     */
+    public void setHttpHandler(HttpHandler handler) {
+        this.httpHandler = handler;
+    }
+
+    /**
+     * Set the geographic position of the center of the map view
+     * @param position LngLat of the position to set
+     */
+    public void setPosition(LngLat position) {
+        checkPointer(mapPointer);
+        nativeSetPosition(mapPointer, position.longitude, position.latitude);
+    }
+
+    /**
+     * Set the geographic position of the center of the map view with default easing
+     * @param position LngLat of the position to set
+     * @param duration Time in milliseconds to ease to the given position
+     */
+    public void setPositionEased(LngLat position, int duration) {
+        setPositionEased(position, duration, DEFAULT_EASE_TYPE);
+    }
+
+    /**
+     * Set the geographic position of the center of the map view with custom easing
+     * @param position LngLat of the position to set
+     * @param duration Time in milliseconds to ease to the given position
+     * @param ease Type of easing to use
+     */
+    public void setPositionEased(LngLat position, int duration, EaseType ease) {
+        float seconds = duration / 1000.f;
+        checkPointer(mapPointer);
+        nativeSetPositionEased(mapPointer, position.longitude, position.latitude, seconds, ease.ordinal());
+    }
+
+    /**
+     * Get the geographic position of the center of the map view
+     * @return The current map position in a LngLat
+     */
+    public LngLat getPosition() {
+        return getPosition(new LngLat());
+    }
+
+    /**
+     * Get the geographic position of the center of the map view
+     * @param out LngLat to be reused as the output
+     * @return LngLat of the center of the map view
+     */
+    public LngLat getPosition(LngLat out) {
+        double[] tmp = { 0, 0 };
+        checkPointer(mapPointer);
+        nativeGetPosition(mapPointer, tmp);
+        return out.set(tmp[0], tmp[1]);
+    }
+
+    /**
+     * Set the zoom level of the map view
+     * @param zoom Zoom level; lower values show more area
+     */
+    public void setZoom(float zoom) {
+        checkPointer(mapPointer);
+        nativeSetZoom(mapPointer, zoom);
+    }
+
+    /**
+     * Set the zoom level of the map view with default easing
+     * @param zoom Zoom level; lower values show more area
+     * @param duration Time in milliseconds to ease to given zoom
+     */
+    public void setZoomEased(float zoom, int duration) {
+        setZoomEased(zoom, duration, DEFAULT_EASE_TYPE);
+    }
+
+    /**
+     * Set the zoom level of the map view with custom easing
+     * @param zoom Zoom level; lower values show more area
+     * @param duration Time in milliseconds to ease to given zoom
+     * @param ease Type of easing to use
+     */
+    public void setZoomEased(float zoom, int duration, EaseType ease) {
+        float seconds = duration / 1000.f;
+        checkPointer(mapPointer);
+        nativeSetZoomEased(mapPointer, zoom, seconds, ease.ordinal());
+    }
+
+    /**
+     * Get the zoom level of the map view
+     * @return Zoom level; lower values show more area
+     */
+    public float getZoom() {
+        checkPointer(mapPointer);
+        return nativeGetZoom(mapPointer);
+    }
+
+    /**
+     * Set the rotation of the view
+     * @param rotation Counter-clockwise rotation in radians; 0 corresponds to North pointing up
+     */
+    public void setRotation(float rotation) {
+        checkPointer(mapPointer);
+        nativeSetRotation(mapPointer, rotation);
+    }
+
+    /**
+     * Set the rotation of the view with default easing
+     * @param rotation Counter-clockwise rotation in radians; 0 corresponds to North pointing up
+     * @param duration Time in milliseconds to ease to the given rotation
+     */
+    public void setRotationEased(float rotation, int duration) {
+        setRotationEased(rotation, duration, DEFAULT_EASE_TYPE);
+    }
+
+    /**
+     * Set the rotation of the view with custom easing
+     * @param rotation Counter-clockwise rotation in radians; 0 corresponds to North pointing up
+     * @param duration Time in milliseconds to ease to the given rotation
+     * @param ease Type of easing to use
+     */
+    public void setRotationEased(float rotation, int duration, EaseType ease) {
+        float seconds = duration / 1000.f;
+        checkPointer(mapPointer);
+        nativeSetRotationEased(mapPointer, rotation, seconds, ease.ordinal());
+    }
+
+    /**
+     * Get the rotation of the view
+     * @return Counter-clockwise rotation in radians; 0 corresponds to North pointing up
+     */
+    public float getRotation() {
+        checkPointer(mapPointer);
+        return nativeGetRotation(mapPointer);
+    }
+
+    /**
+     * Set the tilt angle of the view
+     * @param tilt Tilt angle in radians; 0 corresponds to straight down
+     */
+    public void setTilt(float tilt) {
+        checkPointer(mapPointer);
+        nativeSetTilt(mapPointer, tilt);
+    }
+
+    /**
+     * Set the tilt angle of the view with default easing
+     * @param tilt Tilt angle in radians; 0 corresponds to straight down
+     * @param duration Time in milliseconds to ease to the given tilt
+     */
+    public void setTiltEased(float tilt, int duration) {
+        setTiltEased(tilt, duration, DEFAULT_EASE_TYPE);
+    }
+
+    /**
+     * Set the tilt angle of the view with custom easing
+     * @param tilt Tilt angle in radians; 0 corresponds to straight down
+     * @param duration Time in milliseconds to ease to the given tilt
+     * @param ease Type of easing to use
+     */
+    public void setTiltEased(float tilt, int duration, EaseType ease) {
+        float seconds = duration / 1000.f;
+        checkPointer(mapPointer);
+        nativeSetTiltEased(mapPointer, tilt, seconds, ease.ordinal());
+    }
+
+    /**
+     * Get the tilt angle of the view
+     * @return Tilt angle in radians; 0 corresponds to straight down
+     */
+    public float getTilt() {
+        checkPointer(mapPointer);
+        return nativeGetTilt(mapPointer);
+    }
+
+    /**
+     * Set the camera type for the map view
+     * @param type A {@code CameraType}
+     */
+    public void setCameraType(CameraType type) {
+        checkPointer(mapPointer);
+        nativeSetCameraType(mapPointer, type.ordinal());
+    }
+
+    /**
+     * Get the camera type currently in use for the map view
+     * @return A {@code CameraType}
+     */
+    public CameraType getCameraType() {
+        checkPointer(mapPointer);
+        return CameraType.values()[nativeGetCameraType(mapPointer)];
+    }
+
+    /**
+     * Find the geographic coordinates corresponding to the given position on screen
+     * @param screenPosition Position in pixels from the top-left corner of the map area
+     * @return LngLat corresponding to the given point, or null if the screen position
+     * does not intersect a geographic location (this can happen at high tilt angles).
+     */
+    public LngLat screenPositionToLngLat(PointF screenPosition) {
+        double[] tmp = { screenPosition.x, screenPosition.y };
+        checkPointer(mapPointer);
+        if (nativeScreenPositionToLngLat(mapPointer, tmp)) {
+            return new LngLat(tmp[0], tmp[1]);
+        }
+        return null;
+    }
+
+    /**
+     * Find the position on screen corresponding to the given geographic coordinates
+     * @param lngLat Geographic coordinates
+     * @return Position in pixels from the top-left corner of the map area (the point
+     * may not lie within the viewable screen area)
+     */
+    public PointF lngLatToScreenPosition(LngLat lngLat) {
+        double[] tmp = { lngLat.longitude, lngLat.latitude };
+        checkPointer(mapPointer);
+        nativeLngLatToScreenPosition(mapPointer, tmp);
+        return new PointF((float)tmp[0], (float)tmp[1]);
+    }
+
+    /**
+     * Construct a collection of drawable map features.
+     * @param name The name of the data collection. Once added to a map, features from this
+     * {@code MapData} will be available from a data source with this name, just like a data source
+     * specified in a scene file. You cannot create more than one data source with the same name.
+     * If you call {@code addDataLayer} with the same name more than once, the same {@code MapData}
+     * object will be returned.
+     */
+    public MapData addDataLayer(String name) {
+        MapData mapData = clientTileSources.get(name);
+        if (mapData != null) {
+            return mapData;
+        }
+        checkPointer(mapPointer);
+        long pointer = nativeAddTileSource(mapPointer, name);
+        if (pointer <= 0) {
+            throw new RuntimeException("Unable to create new data source");
+        }
+        mapData = new MapData(name, pointer, this);
+        clientTileSources.put(name, mapData);
+        return mapData;
+    }
+
+    /**
+     * For package-internal use only; remove a {@code MapData} from this map
+     * @param mapData The {@code MapData} to remove
+     */
+    void removeDataLayer(MapData mapData) {
+        clientTileSources.remove(mapData.name);
+        checkPointer(mapPointer);
+        checkPointer(mapData.pointer);
+        nativeRemoveTileSource(mapPointer, mapData.pointer);
+    }
+
+    /**
+     * Manually trigger a re-draw of the map view
+     *
+     * Typically this does not need to be called from outside Tangram, see {@link #setRenderMode(int)}.
+     */
+    public void requestRender() {
+        mapView.requestRender();
+    }
+
+    /**
+     * Set whether the map view re-draws continuously
+     *
+     * Typically this does not need to be called from outside Tangram. The map automatically re-renders when the view
+     * changes or when any animation in the map requires rendering.
+     * @param renderMode Either 1, to render continuously, or 0, to render only when needed.
+     */
+    public void setRenderMode(int renderMode) {
+        mapView.setRenderMode(renderMode);
+    }
+
+    /**
+     * Set a responder for tap gestures
+     * @param responder TapResponder to call
+     */
+    public void setTapResponder(final TouchInput.TapResponder responder) {
+        touchInput.setTapResponder(new TouchInput.TapResponder() {
+            @Override
+            public boolean onSingleTapUp(float x, float y) {
+                return responder != null && responder.onSingleTapUp(x, y);
+            }
+
+            @Override
+            public boolean onSingleTapConfirmed(float x, float y) {
+                return responder != null && responder.onSingleTapConfirmed(x, y);
+            }
+        });
+    }
+
+    /**
+     * Set a responder for double-tap gestures
+     * @param responder DoubleTapResponder to call
+     */
+    public void setDoubleTapResponder(final TouchInput.DoubleTapResponder responder) {
+        touchInput.setDoubleTapResponder(new TouchInput.DoubleTapResponder() {
+            @Override
+            public boolean onDoubleTap(float x, float y) {
+                return responder != null && responder.onDoubleTap(x, y);
+            }
+        });
+    }
+
+    /**
+     * Set a responder for long press gestures
+     * @param responder LongPressResponder to call
+     */
+    public void setLongPressResponder(final TouchInput.LongPressResponder responder) {
+        touchInput.setLongPressResponder(new TouchInput.LongPressResponder() {
+            @Override
+            public void onLongPress(float x, float y) {
+                if (responder != null) {
+                    responder.onLongPress(x, y);
+                }
+            }
+        });
+    }
+
+    /**
+     * Set a responder for pan gestures
+     * @param responder PanResponder to call; if onPan returns true, normal panning behavior will not occur
+     */
+    public void setPanResponder(final TouchInput.PanResponder responder) {
+        touchInput.setPanResponder(new TouchInput.PanResponder() {
+            @Override
+            public boolean onPan(float startX, float startY, float endX, float endY) {
+                if (responder == null || !responder.onPan(startX, startY, endX, endY)) {
+                    nativeHandlePanGesture(mapPointer, startX, startY, endX, endY);
+                }
+                return true;
+            }
+
+            @Override
+            public boolean onFling(float posX, float posY, float velocityX, float velocityY) {
+                if (responder == null || !responder.onFling(posX, posY, velocityX, velocityY)) {
+                    nativeHandleFlingGesture(mapPointer, posX, posY, velocityX, velocityY);
+                }
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Set a responder for rotate gestures
+     * @param responder RotateResponder to call; if onRotate returns true, normal rotation behavior will not occur
+     */
+    public void setRotateResponder(final TouchInput.RotateResponder responder) {
+        touchInput.setRotateResponder(new TouchInput.RotateResponder() {
+            @Override
+            public boolean onRotate(float x, float y, float rotation) {
+                if (responder == null || !responder.onRotate(x, y, rotation)) {
+                    nativeHandleRotateGesture(mapPointer, x, y, rotation);
+                }
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Set a responder for scale gestures
+     * @param responder ScaleResponder to call; if onScale returns true, normal scaling behavior will not occur
+     */
+    public void setScaleResponder(final TouchInput.ScaleResponder responder) {
+        touchInput.setScaleResponder(new TouchInput.ScaleResponder() {
+            @Override
+            public boolean onScale(float x, float y, float scale, float velocity) {
+                if (responder == null || !responder.onScale(x, y, scale, velocity)) {
+                    nativeHandlePinchGesture(mapPointer, x, y, scale, velocity);
+                }
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Set a responder for shove (vertical two-finger drag) gestures
+     * @param responder ShoveResponder to call; if onShove returns true, normal tilting behavior will not occur
+     */
+    public void setShoveResponder(final TouchInput.ShoveResponder responder) {
+        touchInput.setShoveResponder(new TouchInput.ShoveResponder() {
+            @Override
+            public boolean onShove(float distance) {
+                if (responder == null || !responder.onShove(distance)) {
+                    nativeHandleShoveGesture(mapPointer, distance);
+                }
+                return true;
+            }
+        });
+    }
+
+    /**
+     * Set whether the gesture {@code second} can be recognized while {@code first} is in progress
+     * @param first Initial gesture type
+     * @param second Subsequent gesture type
+     * @param allowed True if {@code second} should be recognized, else false
+     */
+    public void setSimultaneousGestureAllowed(Gestures first, Gestures second, boolean allowed) {
+        touchInput.setSimultaneousDetectionAllowed(first, second, allowed);
+    }
+
+    /**
+     * Get whether the gesture {@code second} can be recognized while {@code first} is in progress
+     * @param first Initial gesture type
+     * @param second Subsequent gesture type
+     * @return True if {@code second} will be recognized, else false
+     */
+    public boolean isSimultaneousGestureAllowed(Gestures first, Gestures second) {
+        return touchInput.isSimultaneousDetectionAllowed(first, second);
+    }
+
+    /**
+     * Set the radius to use when picking features on the map. The default radius is 0.5 dp.
+     * @param radius The radius in dp (density-independent pixels).
+     */
+    public void setPickRadius(float radius) {
+        checkPointer(mapPointer);
+        nativeSetPickRadius(mapPointer, radius);
+    }
+
+    /**
+     * Set a listener for feature pick events
+     * @param listener The {@link FeaturePickListener} to call
+     */
+    public void setFeaturePickListener(final FeaturePickListener listener) {
+        featurePickListener = new FeaturePickListener() {
+            @Override
+            public void onFeaturePick(final Map<String, String> properties, final float positionX, final float positionY) {
+                uiThreadHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onFeaturePick(properties, positionX, positionY);
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Set a listener for scene update error statuses
+     * @param listener The {@link SceneUpdateErrorListener} to call after scene update have failed
+     */
+    public void setSceneUpdateErrorListener(final SceneUpdateErrorListener listener) {
+        sceneUpdateErrorListener = new SceneUpdateErrorListener() {
+            @Override
+            public void onSceneUpdateError(final SceneUpdateError sceneUpdateError) {
+                uiThreadHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onSceneUpdateError(sceneUpdateError);
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Set a listener for label pick events
+     * @param listener The {@link LabelPickListener} to call
+     */
+    public void setLabelPickListener(final LabelPickListener listener) {
+        labelPickListener = new LabelPickListener() {
+            @Override
+            public void onLabelPick(final LabelPickResult labelPickResult, final float positionX, final float positionY) {
+                uiThreadHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onLabelPick(labelPickResult, positionX, positionY);
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Set a listener for marker pick events
+     * @param listener The {@link MarkerPickListener} to call
+     */
+    public void setMarkerPickListener(final MarkerPickListener listener) {
+        markerPickListener = new MarkerPickListener() {
+            @Override
+            public void onMarkerPick(final MarkerPickResult markerPickResult, final float positionX, final float positionY) {
+                uiThreadHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onMarkerPick(markerPickResult, positionX, positionY);
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Query the map for geometry features at the given screen coordinates; results will be returned
+     * in a callback to the object set by {@link #setFeaturePickListener(FeaturePickListener)}
+     * @param posX The horizontal screen coordinate
+     * @param posY The vertical screen coordinate
+     */
+    public void pickFeature(float posX, float posY) {
+        if (featurePickListener != null) {
+            checkPointer(mapPointer);
+            nativePickFeature(mapPointer, posX, posY, featurePickListener);
+        }
+    }
+
+    /**
+     * Query the map for labeled features at the given screen coordinates; results will be returned
+     * in a callback to the object set by {@link #setLabelPickListener(LabelPickListener)}
+     * @param posX The horizontal screen coordinate
+     * @param posY The vertical screen coordinate
+     */
+    public void pickLabel(float posX, float posY) {
+        if (labelPickListener != null) {
+            checkPointer(mapPointer);
+            nativePickLabel(mapPointer, posX, posY, labelPickListener);
+        }
+    }
+
+    /**
+     * Query the map for a {@link Marker} at the given screen coordinates; results will be returned
+     * in a callback to the object set by {@link #setMarkerPickListener(MarkerPickListener)}
+     * @param posX The horizontal screen coordinate
+     * @param posY The vertical screen coordinate
+     */
+    public void pickMarker(float posX, float posY) {
+        if (markerPickListener != null) {
+            checkPointer(mapPointer);
+            nativePickMarker(this, mapPointer, posX, posY, markerPickListener);
+        }
+    }
+
+    /**
+     * Adds a {@link Marker} to the map which can be used to dynamically add points and polylines
+     * to the map.
+     * @return Newly created {@link Marker} object.
+     */
+    public Marker addMarker() {
+        checkPointer(mapPointer);
+        long markerId = nativeMarkerAdd(mapPointer);
+
+        Marker marker = new Marker(mapView.getContext(), markerId, this);
+        markers.put(markerId, marker);
+
+        return marker;
+    }
+
+    /**
+     * Removes the passed in {@link Marker} from the map.
+     * @param marker to remove from the map.
+     * @return whether or not the marker was removed
+     */
+    public boolean removeMarker(Marker marker) {
+        checkPointer(mapPointer);
+        checkId(marker.getMarkerId());
+        markers.remove(marker.getMarkerId());
+        return nativeMarkerRemove(mapPointer, marker.getMarkerId());
+    }
+
+    /**
+     * Remove all the {@link Marker} objects from the map.
+     */
+    public void removeAllMarkers() {
+        checkPointer(mapPointer);
+        nativeMarkerRemoveAll(mapPointer);
+
+        // Invalidate all markers so their ids are unusable
+        for (Marker marker : markers.values()) {
+            marker.invalidate();
+        }
+
+        markers.clear();
+    }
+
+    /**
+     * Set a listener for view complete events.
+     * @param listener The {@link ViewCompleteListener} to call when the view is complete
+     */
+    public void setViewCompleteListener(final ViewCompleteListener listener) {
+        viewCompleteListener = new ViewCompleteListener() {
+            @Override
+            public void onViewComplete() {
+                uiThreadHandler.post(new Runnable() {
+                    @Override
+                    public void run() {
+                        listener.onViewComplete();
+                    }
+                });
+            }
+        };
+    }
+
+    /**
+     * Enqueue a Runnable to be executed synchronously on the rendering thread
+     * @param r Runnable to run
+     */
+    public void queueEvent(Runnable r) {
+        mapView.queueEvent(r);
+    }
+
+    /**
+     * Make a debugging feature active or inactive
+     * @param flag The feature to set
+     * @param on True to activate the feature, false to deactivate
+     */
+    public void setDebugFlag(DebugFlag flag, boolean on) {
+        nativeSetDebugFlag(flag.ordinal(), on);
+    }
+
+    /**
+     * Enqueue a scene component update with its corresponding YAML node value
+     * @param sceneUpdate A {@code SceneUpdate}
+     */
+    public void queueSceneUpdate(SceneUpdate sceneUpdate) {
+        checkPointer(mapPointer);
+        if (sceneUpdate == null) {
+            throw new IllegalArgumentException("sceneUpdate can not be null in queueSceneUpdates");
+        }
+        nativeQueueSceneUpdate(mapPointer, sceneUpdate.getPath(), sceneUpdate.getValue());
+    }
+
+    /**
+     * Enqueue a scene component update with its corresponding YAML node value
+     * @param sceneUpdates List of {@code SceneUpdate}
+     */
+    public void queueSceneUpdate(List<SceneUpdate> sceneUpdates) {
+        checkPointer(mapPointer);
+        if (sceneUpdates == null || sceneUpdates.size() == 0) {
+            throw new IllegalArgumentException("sceneUpdates can not be null or empty in queueSceneUpdates");
+        }
+        String[] updateStrings = bundleSceneUpdates(sceneUpdates);
+        nativeQueueSceneUpdates(mapPointer, updateStrings);
+    }
+
+    /**
+     * Apply updates queued by queueSceneUpdate; this empties the current queue of updates
+     * If a scene update is triggered, scene updates won't be applied.
+     */
+    public void applySceneUpdates() {
+        checkPointer(mapPointer);
+        nativeApplySceneUpdates(mapPointer, sceneUpdateErrorListener);
+    }
+
+    /**
+     * Set whether the OpenGL state will be cached between subsequent frames. This improves
+     * rendering efficiency, but can cause errors if your application code makes OpenGL calls.
+     * @param use Whether to use a cached OpenGL state; false by default
+     */
+    public void useCachedGlState(boolean use) {
+        checkPointer(mapPointer);
+        nativeUseCachedGlState(mapPointer, use);
+    }
+
+
+    // Package private methods
+    // =======================
+
+    void onLowMemory() {
+        checkPointer(mapPointer);
+        nativeOnLowMemory(mapPointer);
+    }
+
+    void removeTileSource(long sourcePtr) {
+        checkPointer(mapPointer);
+        checkPointer(sourcePtr);
+        nativeRemoveTileSource(mapPointer, sourcePtr);
+    }
+
+    void clearTileSource(long sourcePtr) {
+        checkPointer(mapPointer);
+        checkPointer(sourcePtr);
+        nativeClearTileSource(mapPointer, sourcePtr);
+    }
+
+    void addFeature(long sourcePtr, double[] coordinates, int[] rings, String[] properties) {
+        checkPointer(mapPointer);
+        checkPointer(sourcePtr);
+        nativeAddFeature(mapPointer, sourcePtr, coordinates, rings, properties);
+    }
+
+    void addGeoJson(long sourcePtr, String geoJson) {
+        checkPointer(mapPointer);
+        checkPointer(sourcePtr);
+        nativeAddGeoJson(mapPointer, sourcePtr, geoJson);
+    }
+
+    void checkPointer(long ptr) {
+        if (ptr <= 0) {
+            throw new RuntimeException("Tried to perform an operation on an invalid pointer! This means you may have used an object that has been disposed and is no longer valid.");
+        }
+    }
+
+    void checkId(long id) {
+        if (id <= 0) {
+            throw new RuntimeException("Tried to perform an operation on an invalid id! This means you may have used an object that has been disposed and is no longer valid.");
+        }
+    }
+
+    private String[] bundleSceneUpdates(List<SceneUpdate> sceneUpdates) {
+
+        String[] updateStrings = null;
+
+        if (sceneUpdates != null) {
+            updateStrings = new String[sceneUpdates.size() * 2];
+            int index = 0;
+            for (SceneUpdate sceneUpdate : sceneUpdates) {
+                updateStrings[index++] = sceneUpdate.getPath();
+                updateStrings[index++] = sceneUpdate.getValue();
+            }
+        }
+
+        return updateStrings;
+    }
+
+    boolean setMarkerStylingFromString(long markerId, String styleString) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetStylingFromString(mapPointer, markerId, styleString);
+    }
+
+    boolean setMarkerStylingFromPath(long markerId, String path) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetStylingFromPath(mapPointer, markerId, path);
+    }
+
+    boolean setMarkerBitmap(long markerId, int width, int height, int[] data) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetBitmap(mapPointer, markerId, width, height, data);
+    }
+
+    boolean setMarkerPoint(long markerId, double lng, double lat) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetPoint(mapPointer, markerId, lng, lat);
+    }
+
+    boolean setMarkerPointEased(long markerId, double lng, double lat, int duration, EaseType ease) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        float seconds = duration / 1000.f;
+        return nativeMarkerSetPointEased(mapPointer, markerId, lng, lat, seconds, ease.ordinal());
+    }
+
+    boolean setMarkerPolyline(long markerId, double[] coordinates, int count) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetPolyline(mapPointer, markerId, coordinates, count);
+    }
+
+    boolean setMarkerPolygon(long markerId, double[] coordinates, int[] rings, int count) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetPolygon(mapPointer, markerId, coordinates, rings, count);
+    }
+
+    boolean setMarkerVisible(long markerId, boolean visible) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetVisible(mapPointer, markerId, visible);
+    }
+
+    boolean setMarkerDrawOrder(long markerId, int drawOrder) {
+        checkPointer(mapPointer);
+        checkId(markerId);
+        return nativeMarkerSetDrawOrder(mapPointer, markerId, drawOrder);
+    }
+
+    Marker markerById(long markerId) {
+        return markers.get(markerId);
+    }
+
+    // Native methods
+    // ==============
+
+    static {
+        System.loadLibrary("c++_shared");
+        System.loadLibrary("tangram");
+    }
+
+    private synchronized native void nativeOnLowMemory(long mapPtr);
+    private synchronized native long nativeInit(MapController instance, AssetManager assetManager);
+    private synchronized native void nativeDispose(long mapPtr);
+    private synchronized native void nativeLoadScene(long mapPtr, SceneUpdateErrorListener listener, String path, String[] updateStrings);
+    private synchronized native void nativeSetupGL(long mapPtr);
+    private synchronized native void nativeResize(long mapPtr, int width, int height);
+    private synchronized native boolean nativeUpdate(long mapPtr, float dt);
+    private synchronized native void nativeRender(long mapPtr);
+    private synchronized native void nativeSetPosition(long mapPtr, double lon, double lat);
+    private synchronized native void nativeSetPositionEased(long mapPtr, double lon, double lat, float seconds, int ease);
+    private synchronized native void nativeGetPosition(long mapPtr, double[] lonLatOut);
+    private synchronized native void nativeSetZoom(long mapPtr, float zoom);
+    private synchronized native void nativeSetZoomEased(long mapPtr, float zoom, float seconds, int ease);
+    private synchronized native float nativeGetZoom(long mapPtr);
+    private synchronized native void nativeSetRotation(long mapPtr, float radians);
+    private synchronized native void nativeSetRotationEased(long mapPtr, float radians, float seconds, int ease);
+    private synchronized native float nativeGetRotation(long mapPtr);
+    private synchronized native void nativeSetTilt(long mapPtr, float radians);
+    private synchronized native void nativeSetTiltEased(long mapPtr, float radians, float seconds, int ease);
+    private synchronized native float nativeGetTilt(long mapPtr);
+    private synchronized native boolean nativeScreenPositionToLngLat(long mapPtr, double[] coordinates);
+    private synchronized native boolean nativeLngLatToScreenPosition(long mapPtr, double[] coordinates);
+    private synchronized native void nativeSetPixelScale(long mapPtr, float scale);
+    private synchronized native void nativeSetCameraType(long mapPtr, int type);
+    private synchronized native int nativeGetCameraType(long mapPtr);
+    private synchronized native void nativeHandleTapGesture(long mapPtr, float posX, float posY);
+    private synchronized native void nativeHandleDoubleTapGesture(long mapPtr, float posX, float posY);
+    private synchronized native void nativeHandlePanGesture(long mapPtr, float startX, float startY, float endX, float endY);
+    private synchronized native void nativeHandleFlingGesture(long mapPtr, float posX, float posY, float velocityX, float velocityY);
+    private synchronized native void nativeHandlePinchGesture(long mapPtr, float posX, float posY, float scale, float velocity);
+    private synchronized native void nativeHandleRotateGesture(long mapPtr, float posX, float posY, float rotation);
+    private synchronized native void nativeHandleShoveGesture(long mapPtr, float distance);
+    private synchronized native void nativeQueueSceneUpdate(long mapPtr, String componentPath, String componentValue);
+    private synchronized native void nativeQueueSceneUpdates(long mapPtr, String[] updateStrings);
+    private synchronized native void nativeApplySceneUpdates(long mapPtr, SceneUpdateErrorListener listener);
+    private synchronized native void nativeSetPickRadius(long mapPtr, float radius);
+    private synchronized native void nativePickFeature(long mapPtr, float posX, float posY, FeaturePickListener listener);
+    private synchronized native void nativePickLabel(long mapPtr, float posX, float posY, LabelPickListener listener);
+    private synchronized native void nativePickMarker(MapController instance, long mapPtr, float posX, float posY, MarkerPickListener listener);
+    private synchronized native long nativeMarkerAdd(long mapPtr);
+    private synchronized native boolean nativeMarkerRemove(long mapPtr, long markerID);
+    private synchronized native boolean nativeMarkerSetStylingFromString(long mapPtr, long markerID, String styling);
+    private synchronized native boolean nativeMarkerSetStylingFromPath(long mapPtr, long markerID, String path);
+    private synchronized native boolean nativeMarkerSetBitmap(long mapPtr, long markerID, int width, int height, int[] data);
+    private synchronized native boolean nativeMarkerSetPoint(long mapPtr, long markerID, double lng, double lat);
+    private synchronized native boolean nativeMarkerSetPointEased(long mapPtr, long markerID, double lng, double lat, float duration, int ease);
+    private synchronized native boolean nativeMarkerSetPolyline(long mapPtr, long markerID, double[] coordinates, int count);
+    private synchronized native boolean nativeMarkerSetPolygon(long mapPtr, long markerID, double[] coordinates, int[] rings, int count);
+    private synchronized native boolean nativeMarkerSetVisible(long mapPtr, long markerID, boolean visible);
+    private synchronized native boolean nativeMarkerSetDrawOrder(long mapPtr, long markerID, int drawOrder);
+    private synchronized native void nativeMarkerRemoveAll(long mapPtr);
+
+    private synchronized native void nativeUseCachedGlState(long mapPtr, boolean use);
+    private synchronized native void nativeCaptureSnapshot(long mapPtr, int[] buffer);
+
+    private native void nativeOnUrlSuccess(byte[] rawDataBytes, long callbackPtr);
+    private native void nativeOnUrlFailure(long callbackPtr);
+
+    synchronized native long nativeAddTileSource(long mapPtr, String name);
+    synchronized native void nativeRemoveTileSource(long mapPtr, long sourcePtr);
+    synchronized native void nativeClearTileSource(long mapPtr, long sourcePtr);
+    synchronized native void nativeAddFeature(long mapPtr, long sourcePtr, double[] coordinates, int[] rings, String[] properties);
+    synchronized native void nativeAddGeoJson(long mapPtr, long sourcePtr, String geoJson);
+
+    native void nativeSetDebugFlag(int flag, boolean on);
+
+    // Private members
+    // ===============
+
+    private String scenePath;
+    private long mapPointer;
+    private long time = System.nanoTime();
+    private GLSurfaceView mapView;
+    private AssetManager assetManager;
+    private TouchInput touchInput;
+    private FontFileParser fontFileParser;
+    private DisplayMetrics displayMetrics = new DisplayMetrics();
+    private HttpHandler httpHandler;
+    private FeaturePickListener featurePickListener;
+    private SceneUpdateErrorListener sceneUpdateErrorListener;
+    private LabelPickListener labelPickListener;
+    private MarkerPickListener markerPickListener;
+    private ViewCompleteListener viewCompleteListener;
+    private FrameCaptureCallback frameCaptureCallback;
+    private boolean frameCaptureAwaitCompleteView;
+    private Map<String, MapData> clientTileSources = new HashMap<>();
+    private Map<Long, Marker> markers = new HashMap<>();
+    private Handler uiThreadHandler;
+
+    // GLSurfaceView.Renderer methods
+    // ==============================
+
+    @Override
+    public void onDrawFrame(GL10 gl) {
+        long newTime = System.nanoTime();
+        float delta = (newTime - time) / 1000000000.0f;
+        time = newTime;
+
+        if (mapPointer <= 0) {
+            // No native instance is initialized, so stop here. This can happen during Activity
+            // shutdown when the map has been disposed but the View hasn't been destroyed yet.
+            return;
+        }
+
+        boolean viewComplete = nativeUpdate(mapPointer, delta);
+        nativeRender(mapPointer);
+
+        if (viewComplete && viewCompleteListener != null) {
+            viewCompleteListener.onViewComplete();
+        }
+        if (frameCaptureCallback != null) {
+            if (!frameCaptureAwaitCompleteView || viewComplete) {
+                frameCaptureCallback.onCaptured(capture());
+                frameCaptureCallback = null;
+            }
+        }
+    }
+
+    @Override
+    public void onSurfaceChanged(GL10 gl, int width, int height) {
+        nativeSetPixelScale(mapPointer, displayMetrics.density);
+        nativeResize(mapPointer, width, height);
+    }
+
+    @Override
+    public void onSurfaceCreated(GL10 gl, EGLConfig config) {
+        nativeSetupGL(mapPointer);
+    }
+
+    // Networking methods
+    // ==================
+
+    void cancelUrlRequest(String url) {
+        if (httpHandler == null) {
+            return;
+        }
+        httpHandler.onCancel(url);
+    }
+
+    boolean startUrlRequest(final String url, final long callbackPtr) throws Exception {
+        if (httpHandler == null) {
+            return false;
+        }
+
+        httpHandler.onRequest(url, new Callback() {
+            @Override
+            public void onFailure(Call call, IOException e) {
+                android.util.Log.e("Tangram", "Failed url request: " + url + " " + e.toString());
+                nativeOnUrlFailure(callbackPtr);
+            }
+
+            @Override
+            public void onResponse(Call call, Response response) throws IOException {
+
+                if (!response.isSuccessful()) {
+                    android.util.Log.e("Tangram", "Failed url request: " + url +
+                            " Unexpected response code: " + response);
+                    nativeOnUrlFailure(callbackPtr);
+                    return;
+                }
+                byte[] bytes = response.body().bytes();
+
+                nativeOnUrlSuccess(bytes, callbackPtr);
+            }
+        });
+        return true;
+    }
+
+    // Font Fetching
+    // =============
+    String getFontFilePath(String key) {
+
+        return fontFileParser.getFontFile(key);
+
+    }
+
+    String getFontFallbackFilePath(int importance, int weightHint) {
+
+        return fontFileParser.getFontFallback(importance, weightHint);
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapData.java
new file mode 100644 (file)
index 0000000..e501715
--- /dev/null
@@ -0,0 +1,120 @@
+package com.mapzen.tangram;
+
+import com.mapzen.tangram.geometry.Geometry;
+import com.mapzen.tangram.geometry.Point;
+import com.mapzen.tangram.geometry.Polygon;
+import com.mapzen.tangram.geometry.Polyline;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@code MapData} is a named collection of drawable map features.
+ */
+public class MapData {
+
+    String name;
+    long pointer = 0;
+    MapController map;
+
+    /**
+     * For package-internal use only; create a new {@code MapData}
+     * @param name The name of the associated data source
+     * @param pointer The markerId to the native data source, encoded as a long
+     * @param map The {@code MapController} associated with this data source
+     */
+    MapData(String name, long pointer, MapController map) {
+        this.name = name;
+        this.pointer = pointer;
+        this.map = map;
+    }
+
+    /**
+     * Add a geometry feature to this data collection
+     * @param geometry The feature to add
+     */
+    protected void addFeature(Geometry geometry) {
+        map.addFeature(pointer,
+                geometry.getCoordinateArray(),
+                geometry.getRingArray(),
+                geometry.getPropertyArray());
+    }
+
+    /**
+     * Get the name of this {@code MapData}.
+     * @return The name.
+     */
+    public String name() {
+        return name;
+    }
+
+    /**
+     * Remove this {@code MapData} from the map it is currently associated with. Using this object
+     * after {@code remove} is called will cause an exception to be thrown. {@code remove} is called
+     * on every {@code MapData} associated with a map when its {@code MapController} is destroyed.
+     */
+    public void remove() {
+        map.removeDataLayer(this);
+        pointer = 0;
+        map = null;
+    }
+
+    /**
+     * Add a point feature to this collection.
+     * @param point The coordinates of the feature.
+     * @param properties The properties of the feature, used for filtering and styling according to
+     * the scene file used by the map; may be null.
+     * @return This object, for chaining.
+     */
+    public MapData addPoint(LngLat point, Map<String, String> properties) {
+        addFeature(new Point(point, properties));
+        return this;
+    }
+
+    /**
+     * Add a polyline feature to this collection.
+     * @param polyline A list of coordinates that define the line segments of the feature.
+     * @param properties The properties of the feature, used for filtering and styling according to
+     * the scene file used by the map; may be null.
+     * @return This object, for chaining.
+     */
+    public MapData addPolyline(List<LngLat> polyline, Map<String, String> properties) {
+        addFeature(new Polyline(polyline, properties));
+        return this;
+    }
+
+    /**
+     * Add a polygon feature to this collection.
+     * @param polygon A list of rings describing the shape of the feature. Each
+     * ring is a list of coordinates in which the first point is the same as the last point. The
+     * first ring is taken as the "exterior" of the polygon and rings with opposite winding are
+     * considered "holes".
+     * @param properties The properties of the feature, used for filtering and styling according to
+     * the scene file used by the map; may be null.
+     * @return This object, for chaining.
+     */
+    public MapData addPolygon(List<List<LngLat>> polygon, Map<String, String> properties) {
+        addFeature(new Polygon(polygon, properties));
+        return this;
+    }
+
+    /**
+     * Add features described in a GeoJSON string to this collection.
+     * @param data A string containing a <a href="http://geojson.org/">GeoJSON</a> FeatureCollection
+     * @return This object, for chaining.
+     */
+    public MapData addGeoJson(String data) {
+        map.addGeoJson(pointer, data);
+        return this;
+    }
+
+    /**
+     * Remove all features from this collection.
+     * @return This object, for chaining.
+     */
+    public MapData clear() {
+        map.clearTileSource(pointer);
+        return this;
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapView.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MapView.java
new file mode 100644 (file)
index 0000000..212ee7d
--- /dev/null
@@ -0,0 +1,177 @@
+package com.mapzen.tangram;
+
+import android.content.Context;
+import android.opengl.GLSurfaceView;
+import android.os.AsyncTask;
+import android.os.Bundle;
+import android.support.annotation.NonNull;
+import android.util.AttributeSet;
+import android.widget.FrameLayout;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * {@code MapView} is a View for displaying a Tangram map.
+ */
+public class MapView extends FrameLayout {
+
+    protected GLSurfaceView glSurfaceView;
+    protected MapController mapController;
+    protected AsyncTask<Void, Void, Boolean> getMapTask;
+
+    public MapView(Context context) {
+
+        super(context);
+
+        configureGLSurfaceView();
+
+    }
+
+    public MapView(Context context, AttributeSet attrs) {
+
+        super(context, attrs);
+
+        configureGLSurfaceView();
+
+    }
+
+    /**
+     * Interface for receiving a {@code MapController} once it is ready to be used
+     */
+    public interface OnMapReadyCallback {
+
+        /**
+         * Called when the map is ready to be used
+         * @param mapController A non-null {@code MapController} instance for this {@code MapView}
+         */
+        void onMapReady(MapController mapController);
+
+    }
+
+    /**
+     * Construct a {@code MapController} asynchronously; may only be called from the UI thread
+     * @param callback The object to receive the resulting MapController in a callback;
+     * the callback will be made on the UI thread
+     * @param sceneFilePath Location of the YAML scene file within the asset bundle
+     */
+    public void getMapAsync(@NonNull final OnMapReadyCallback callback,
+                            @NonNull final String sceneFilePath) {
+
+        getMapAsync(callback, sceneFilePath, null);
+    }
+
+    /**
+     * Construct a {@code MapController} asynchronously; may only be called from the UI thread
+     * @param callback The object to receive the resulting MapController in a callback;
+     * the callback will be made on the UI thread
+     * @param sceneFilePath Location of the YAML scene file within the asset bundle
+     * @param sceneUpdates List of SceneUpdate to be applied when loading this scene
+     */
+    public void getMapAsync(@NonNull final OnMapReadyCallback callback,
+                            @NonNull final String sceneFilePath,
+                            final List<SceneUpdate> sceneUpdates) {
+
+        disposeTask();
+
+        final MapController mapInstance = getMapInstance();
+
+        getMapTask = new AsyncTask<Void, Void, Boolean>() {
+
+            @Override
+            @SuppressWarnings("WrongThread")
+            protected Boolean doInBackground(Void... params) {
+                mapInstance.init();
+                mapInstance.loadSceneFile(sceneFilePath, sceneUpdates);
+                return true;
+            }
+
+            @Override
+            protected void onPostExecute(Boolean ok) {
+                addView(glSurfaceView);
+                disposeMap();
+                mapController = mapInstance;
+                callback.onMapReady(mapController);
+            }
+
+            @Override
+            protected void onCancelled(Boolean ok) {
+                mapInstance.dispose();
+            }
+
+        }.execute();
+
+    }
+
+    protected MapController getMapInstance() {
+        return MapController.getInstance(glSurfaceView);
+    }
+
+    protected void configureGLSurfaceView() {
+
+        glSurfaceView = new GLSurfaceView(getContext());
+        glSurfaceView.setEGLContextClientVersion(2);
+        glSurfaceView.setPreserveEGLContextOnPause(true);
+        glSurfaceView.setEGLConfigChooser(new ConfigChooser(8, 8, 8, 0, 16, 0));
+
+    }
+
+    protected void disposeTask() {
+
+        if (getMapTask != null) {
+            // MapController is being initialized, so we'll dispose it in the onCancelled callback.
+            getMapTask.cancel(true);
+        }
+        getMapTask = null;
+
+    }
+
+    protected void disposeMap() {
+
+        if (mapController != null) {
+            // MapController has been initialized, so we'll dispose it now.
+            mapController.dispose();
+        }
+        mapController = null;
+
+    }
+
+    /**
+     * You must call this method from the parent Activity/Fragment's corresponding method.
+     */
+    public void onCreate(Bundle savedInstanceState) {
+
+    }
+
+    /**
+     * You must call this method from the parent Activity/Fragment's corresponding method.
+     */
+    public void onResume() {
+
+    }
+
+    /**
+     * You must call this method from the parent Activity/Fragment's corresponding method.
+     */
+    public void onPause() {
+
+    }
+
+    /**
+     * You must call this method from the parent Activity/Fragment's corresponding method.
+     */
+    public void onDestroy() {
+
+        disposeTask();
+        disposeMap();
+
+    }
+
+    /**
+     * You must call this method from the parent Activity/Fragment's corresponding method.
+     */
+    public void onLowMemory() {
+        mapController.onLowMemory();
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/Marker.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/Marker.java
new file mode 100644 (file)
index 0000000..7ed5116
--- /dev/null
@@ -0,0 +1,234 @@
+package com.mapzen.tangram;
+
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.graphics.drawable.BitmapDrawable;
+import android.graphics.drawable.Drawable;
+import android.util.DisplayMetrics;
+
+import com.mapzen.tangram.geometry.Polygon;
+import com.mapzen.tangram.geometry.Polyline;
+
+/**
+ * Class used to display points, polylines, and bitmaps dynamically on a map. Do not create one of
+ * these objects directly, instead use {@link MapController#addMarker()}.
+ */
+public class Marker {
+
+    private Context context;
+    private long markerId = 0;
+    private MapController map;
+    private boolean visible = true;
+    private Object userData = null;
+
+    /**
+     * Package private constructor for creating a new {@link Marker}.
+     * @param context the context to use for decoding bitmap resources
+     * @param markerId the marker id
+     * @param map the map this marker is added to
+     */
+    Marker(Context context, long markerId, MapController map) {
+        this.context = context;
+        this.markerId = markerId;
+        this.map = map;
+    }
+
+    /**
+     * Custom user data storage.
+     * @param userData The user data to hold in this marker.
+     */
+    public void setUserData(Object userData) {
+        this.userData = userData;
+    }
+
+    /**
+     * Gets custom user data.
+     * @return The user data held by this marker.
+     */
+    public Object getUserData() {
+        return this.userData;
+    }
+
+    /**
+     * Returns the {@link Marker} id
+     * @return marker id
+     */
+    public long getMarkerId() {
+        return markerId;
+    }
+
+    /**
+     * Used to style the marker
+     * Sets draw rules from a draw group of a scene layer in the scene file, used to load the scene.
+     * This draw group must be defined in the loaded scene file.
+     *
+     * <ul>
+     * <li>layers.layer_a.layer_b.draw.some_draw_rule</li>
+     * <li>layers.layer_c.draw.another_draw_rule</li>
+     * </ul>
+     *
+     * @param path Absolute path to a draw rule in the current scene, delimited with "."
+     * @return whether the styling was successfully set on the marker.
+     */
+    public boolean setStylingFromPath(String path) {
+        return map.setMarkerStylingFromPath(markerId, path);
+    }
+
+    /**
+     * Used to style the marker
+     * Sets the styling to be used to display either a point, polyline, or bitmap for this marker.
+     * If the marker is going to be used to display a bitmap, a 'points' style must be set.
+     *
+     * <ul>
+     * <li>{ style: 'points', color: 'white', size: [50px, 50px], order: 2000, collide: false }</li>
+     * <li>{ style: 'lines', color: '#06a6d4', width: 5px, order: 2000 }</li>
+     * <li>{ style: 'polygons', color: '#06a6d4', width: 5px, order: 2000 }</li>
+     * </ul>
+     *
+     * @param styleStr the style string
+     * @return whether the style was successfully set
+     */
+    public boolean setStylingFromString(String styleString) {
+        return map.setMarkerStylingFromString(markerId, styleString);
+    }
+
+    /**
+     * Sets the drawable resource id to be used to load a bitmap. When displaying a drawable, a
+     * 'points' style must also be set on the marker (see {@link Marker#setStyling(String)}.
+     *
+     * @param drawableId the drawable resource id
+     * @return whether the drawable's bitmap was successfully set
+     */
+    public boolean setDrawable(int drawableId) {
+        BitmapFactory.Options options = new BitmapFactory.Options();
+        options.inTargetDensity = context.getResources().getDisplayMetrics().densityDpi;
+        Bitmap bitmap = BitmapFactory.decodeResource(context.getResources(), drawableId, options);
+        return setBitmap(bitmap);
+    }
+
+    /**
+     * Sets the drawable to be used to load a bitmap. When displaying a drawable, a
+     * 'points' style must also be set on the marker (see {@link Marker#setStyling(String)}.
+     *
+     * @param drawable the drawable
+     * @return whether the drawable's bitmap was successfully set
+     */
+    public boolean setDrawable(Drawable drawable) {
+        int density = context.getResources().getDisplayMetrics().densityDpi;
+        BitmapDrawable bitmapDrawable = (BitmapDrawable) drawable;
+        bitmapDrawable.setTargetDensity(density);
+        Bitmap bitmap = bitmapDrawable.getBitmap();
+        bitmap.setDensity(density);
+        return setBitmap(bitmap);
+    }
+
+    /**
+     * Sets the coordinate location, where the marker should be displayed.
+     * @param point lat/lng location
+     * @return whether the point was successfully set
+     */
+    public boolean setPoint(LngLat point) {
+        return map.setMarkerPoint(markerId, point.longitude, point.latitude);
+    }
+
+    /**
+     * Sets the coordinate location, where the marker should be displayed with animation.
+     * @param point lat/lng location
+     * @param duration animation duration in milliseconds
+     * @param ease animation type
+     * @return whether the point was successfully set
+     */
+    public boolean setPointEased(LngLat point, int duration, MapController.EaseType ease) {
+        if (point == null) {
+            return false;
+        }
+        return map.setMarkerPointEased(markerId, point.longitude, point.latitude, duration, ease);
+    }
+
+    /**
+     * Sets the polyline to be displayed. When using this method, a 'polyline' style must also be
+     * set. See {@link Marker#setStyling(String)}.
+     * @param polyline the polyline to display
+     * @return whether the polyline was successfully set
+     */
+    public boolean setPolyline(Polyline polyline) {
+        if (polyline == null) {
+            return false;
+        }
+        return map.setMarkerPolyline(markerId, polyline.getCoordinateArray(),
+                polyline.getCoordinateArray().length/2);
+    }
+
+    /**
+     * Sets the polygon to be displayed. When using this method, a 'polygon' style must also be
+     * set. See {@link Marker#setStyling(String)}.
+     * @param polygon the polygon to display
+     * @return whether the polygon was successfully set
+     */
+    public boolean setPolygon(Polygon polygon) {
+        if (polygon == null) {
+            return false;
+        }
+        return map.setMarkerPolygon(markerId, polygon.getCoordinateArray(),
+                polygon.getRingArray(), polygon.getRingArray().length);
+    }
+
+    /**
+     * Changes the marker's visibility on the map.
+     * @param visible whether or not the marker should be visible
+     * @return whether the marker's visibility was successfully set
+     */
+    public boolean setVisible(boolean visible) {
+        boolean success = map.setMarkerVisible(markerId, visible);
+        if (success) {
+            this.visible = visible;
+        }
+        return success;
+    }
+
+    /**
+     * Sets the draw order for the marker to be used in z-order collisions.
+     * @param drawOrder the draw order to set
+     * @return whether the marker's draw order was successfully set
+     */
+    public boolean setDrawOrder(int drawOrder) {
+        return map.setMarkerDrawOrder(markerId, drawOrder);
+    }
+
+    /**
+     * Returns whether or not the marker is visible on the map.
+     * @return whether the marker is visible on the map
+     */
+    public boolean isVisible() {
+        return visible;
+    }
+
+    private boolean setBitmap(Bitmap bitmap) {
+        int density = context.getResources().getDisplayMetrics().densityDpi;
+        int width = bitmap.getScaledWidth(density);
+        int height = bitmap.getScaledHeight(density);
+
+        int[] argb = new int[width * height];
+        bitmap.getPixels(argb, 0, width, 0, 0, width, height);
+
+        int[] abgr = new int[width * height];
+        int row, col;
+        for (int i = 0; i < argb.length; i++) {
+            col = i % width;
+            row = i / width;
+            int pix = argb[i];
+            int pb = (pix >> 16) & 0xff;
+            int pr = (pix << 16) & 0x00ff0000;
+            int pix1 = (pix & 0xff00ff00) | pr | pb;
+            int flippedIndex = (height - 1 - row) * width + col;
+            abgr[flippedIndex] = pix1;
+        }
+
+        return map.setMarkerBitmap(markerId, width, height, abgr);
+    }
+
+    void invalidate() {
+        this.markerId = 0;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/MarkerPickResult.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/MarkerPickResult.java
new file mode 100644 (file)
index 0000000..90436b5
--- /dev/null
@@ -0,0 +1,31 @@
+package com.mapzen.tangram;
+
+/**
+ * {@code MarkerPickResult} represents labels that can be selected on the screen
+ */
+
+public class MarkerPickResult {
+
+    private Marker marker;
+    private LngLat coordinates;
+
+    private MarkerPickResult(Marker marker, double longitude, double latitude) {
+        this.marker = marker;
+        this.coordinates = new LngLat(longitude, latitude);
+    }
+
+    /**
+     * @return The marker associated with the selection
+     */
+    public Marker getMarker() {
+        return this.marker;
+    }
+
+    /**
+     * @return The coordinate of the feature for which this label has been created
+     */
+    public LngLat getCoordinates() {
+        return this.coordinates;
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdate.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdate.java
new file mode 100644 (file)
index 0000000..7f08cd9
--- /dev/null
@@ -0,0 +1,29 @@
+package com.mapzen.tangram;
+
+/**
+ * {@code SceneUpdate} Represents a DataStructure to specify a yaml path and the corresponding value for a Scene Update.
+ */
+
+public class SceneUpdate {
+
+    private String componentPath;
+    private String componentValue;
+
+    /**
+     * Add a point feature to this collection.
+     * @param path Series of yaml keys separated by a ".". Represents the scene path to be updated
+     * @param value A yaml string which will update the value at the specified path
+     */
+    public SceneUpdate(String path, String value) {
+        this.componentPath = path;
+        this.componentValue = value;
+    }
+
+    public String getPath() { return componentPath; }
+    public String getValue() { return componentValue; }
+
+    @Override
+    public String toString() {
+        return componentPath + " " + componentValue;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdateError.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/SceneUpdateError.java
new file mode 100644 (file)
index 0000000..531abe9
--- /dev/null
@@ -0,0 +1,27 @@
+package com.mapzen.tangram;
+
+import com.mapzen.tangram.MapController.Error;
+
+/**
+ * {@code SceneUpdateError} Holds an error status and its associated scene updated
+ */
+
+public class SceneUpdateError {
+
+
+    private SceneUpdate sceneUpdate;
+    private Error error;
+
+    private SceneUpdateError(String sceneUpdatePath, String sceneUpdateValue, int error) {
+        this.sceneUpdate = new SceneUpdate(sceneUpdatePath, sceneUpdateValue);
+        this.error = Error.values()[error];
+    }
+
+    public SceneUpdate getSceneUpdate() {
+        return this.sceneUpdate;
+    }
+
+    public Error getError() {
+        return this.error;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/TouchInput.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/TouchInput.java
new file mode 100644 (file)
index 0000000..49b94ce
--- /dev/null
@@ -0,0 +1,524 @@
+package com.mapzen.tangram;
+
+import android.content.Context;
+import android.os.SystemClock;
+import android.view.GestureDetector;
+import android.view.GestureDetector.OnDoubleTapListener;
+import android.view.GestureDetector.OnGestureListener;
+import android.view.MotionEvent;
+import android.view.ScaleGestureDetector;
+import android.view.ScaleGestureDetector.OnScaleGestureListener;
+import android.view.View;
+import android.view.View.OnTouchListener;
+import android.view.ViewConfiguration;
+
+import com.almeros.android.multitouch.RotateGestureDetector;
+import com.almeros.android.multitouch.RotateGestureDetector.OnRotateGestureListener;
+import com.almeros.android.multitouch.ShoveGestureDetector;
+import com.almeros.android.multitouch.ShoveGestureDetector.OnShoveGestureListener;
+
+import java.util.EnumMap;
+import java.util.EnumSet;
+
+/**
+ * {@code TouchInput} collects touch data, applies gesture detectors, resolves simultaneous
+ * detection, and calls the appropriate input responders.
+ */
+public class TouchInput implements OnTouchListener, OnScaleGestureListener,
+        OnRotateGestureListener, OnGestureListener, OnDoubleTapListener, OnShoveGestureListener {
+
+    /**
+     * List of gestures that can be detected and responded to
+     */
+    public enum Gestures {
+        TAP,
+        DOUBLE_TAP,
+        LONG_PRESS,
+        PAN,
+        ROTATE,
+        SCALE,
+        SHOVE,
+        ;
+
+        /**
+         * Whether a gesture uses multiple touch points simultaneously
+         * @return True if the gesture is multi-touch, otherwise false
+         */
+        public boolean isMultiTouch() {
+            switch(this) {
+                case ROTATE:
+                case SCALE:
+                case SHOVE:
+                    return true;
+                default:
+                    return false;
+            }
+        }
+    }
+
+    /**
+     * Interface for responding to a tap gesture
+     */
+    public interface TapResponder {
+        /**
+         * Called immediately after a touch is lifted in a tap gesture; may be part of a double tap
+         * @param x The x screen coordinate of the tapped point
+         * @param y The y screen coordinate of the tapped point
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onSingleTapUp(float x, float y);
+
+        /**
+         * Called after a touch is lifted and determined to not be part of a double tap
+         *
+         * The timeout duration for a double tap is determined by {@link ViewConfiguration}
+         * @param x The x screen coordinate of the tapped point
+         * @param y The y screen coordinate of the tapped point
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onSingleTapConfirmed(float x, float y);
+    }
+
+    /**
+     * Interface for responding to a double-tap gesture
+     */
+    public interface DoubleTapResponder {
+        /**
+         * Called immediately after the second time a touch is lifted in a double tap gesture
+         *
+         * The allowable duration between taps is determined by {@link ViewConfiguration}
+         * @param x The x screen coordinate of the tapped point
+         * @param y The y screen coordinate of the tapped point
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onDoubleTap(float x, float y);
+    }
+
+    /**
+     * Interface for responding to a long press gesture
+     */
+    public interface LongPressResponder {
+        /**
+         * Called immediately after a long press is detected
+         *
+         * The duration threshold for a long press is determined by {@link ViewConfiguration}
+         * @param x The x screen coordinate of the pressed point
+         * @param y The y screen coordinate of the pressed point
+         */
+        void onLongPress(float x, float y);
+    }
+
+    /**
+     * Interface for responding to a panning (dragging) gesture
+     */
+    public interface PanResponder {
+        /**
+         * Called repeatedly while a touch point is dragged
+         * @param startX The starting x screen coordinate for an interval of motion
+         * @param startY The starting y screen coordinate for an interval of motion
+         * @param endX The ending x screen coordinate for an interval of motion
+         * @param endY The ending y screen coordinate for an interval of motion
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onPan(float startX, float startY, float endX, float endY);
+
+        /**
+         * Called when a dragged touch point with non-zero velocity is lifted
+         * @param posX The x screen coordinate where the touch was lifted
+         * @param posY The y screen coordinate where the touch was lifted
+         * @param velocityX The x velocity of the gesture in screen coordinates per second
+         * @param velocityY The y velocity of the gesture in screen coordinates per second
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onFling(float posX, float posY, float velocityX, float velocityY);
+    }
+
+    /**
+     * Interface for responding to a scaling (pinching) gesture
+     */
+    public interface ScaleResponder {
+        /**
+         * Called repeatedly while two touch points are moved closer to or further from each other
+         * @param x The x screen coordinate of the point between the two touch points
+         * @param y The y screen coordinate of the point between the two touch points
+         * @param scale The scale factor relative to the previous scaling event
+         * @param velocity The rate of scale change in units per second
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onScale(float x, float y, float scale, float velocity);
+    }
+
+    /**
+     * Interface for responding to a rotation gesture
+     */
+    public interface RotateResponder {
+        /**
+         * Called repeatedly while two touch points are rotated around a point
+         * @param x The x screen coordinate of the center of rotation
+         * @param y The y screen coordinate of the center of rotation
+         * @param rotation The change in rotation of the touch points relative to the previous
+         * rotation event, in counter-clockwise radians
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onRotate(float x, float y, float rotation);
+    }
+
+    /**
+     * Interface for responding to a shove (two-finger vertical drag) gesture
+     */
+    public interface ShoveResponder {
+        /**
+         * Called repeatedly while two touch points are moved together vertically
+         * @param distance The vertical distance moved by the two touch points relative to the last
+         * shoving event, in screen coordinates
+         * @return True if the event is consumed, false if the event should continue to propagate
+         */
+        boolean onShove(float distance);
+    }
+
+    private static final long MULTITOUCH_BUFFER_TIME = 256; // milliseconds
+    private static final long DOUBLE_TAP_TIMEOUT = ViewConfiguration.getDoubleTapTimeout(); // milliseconds
+
+    private GestureDetector panTapGestureDetector;
+    private ScaleGestureDetector scaleGestureDetector;
+    private RotateGestureDetector rotateGestureDetector;
+    private ShoveGestureDetector shoveGestureDetector;
+
+    private TapResponder tapResponder;
+    private DoubleTapResponder doubleTapResponder;
+    private LongPressResponder longPressResponder;
+    private PanResponder panResponder;
+    private ScaleResponder scaleResponder;
+    private RotateResponder rotateResponder;
+    private ShoveResponder shoveResponder;
+
+    private EnumSet<Gestures> detectedGestures;
+    private EnumMap<Gestures, EnumSet<Gestures>> allowedSimultaneousGestures;
+
+    private long lastMultiTouchEndTime = -MULTITOUCH_BUFFER_TIME;
+
+    /**
+     * Construct a new touch input manager; this may only be called on the UI thread
+     * @param context A {@link Context} whose {@code Handler} will be used for deferred events
+     */
+    public TouchInput(Context context) {
+
+        this.panTapGestureDetector = new GestureDetector(context, this);
+        this.scaleGestureDetector = new ScaleGestureDetector(context, this);
+        this.rotateGestureDetector = new RotateGestureDetector(context, this);
+        this.shoveGestureDetector = new ShoveGestureDetector(context, this);
+
+        this.detectedGestures = EnumSet.noneOf(Gestures.class);
+        this.allowedSimultaneousGestures = new EnumMap<>(Gestures.class);
+
+        // By default, all gestures are allowed to detect simultaneously
+        for (Gestures g : Gestures.values()) {
+            allowedSimultaneousGestures.put(g, EnumSet.allOf(Gestures.class));
+        }
+    }
+
+    /**
+     * Set a {@link TapResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setTapResponder(TapResponder responder) {
+        this.tapResponder = responder;
+    }
+
+    /**
+     * Set a {@link DoubleTapResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setDoubleTapResponder(DoubleTapResponder responder) {
+        this.doubleTapResponder = responder;
+    }
+
+    /**
+     * Set a {@link LongPressResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setLongPressResponder(LongPressResponder responder) {
+        this.longPressResponder = responder;
+    }
+
+    /**
+     * Set a {@link PanResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setPanResponder(PanResponder responder) {
+        this.panResponder = responder;
+    }
+
+    /**
+     * Set a {@link ScaleResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setScaleResponder(ScaleResponder responder) {
+        this.scaleResponder = responder;
+    }
+
+    /**
+     * Set a {@link RotateResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setRotateResponder(RotateResponder responder) {
+        this.rotateResponder = responder;
+    }
+
+    /**
+     * Set a {@link ShoveResponder}
+     * @param responder The responder object, or null to leave these gesture events unchanged
+     */
+    public void setShoveResponder(ShoveResponder responder) {
+        this.shoveResponder = responder;
+    }
+
+    /**
+     * Set whether the gesture {@code second} can be recognized while {@code first} is in progress
+     * @param first Initial gesture type
+     * @param second Subsequent gesture type
+     * @param allowed True if {@code second} should be recognized, else false
+     */
+    public void setSimultaneousDetectionAllowed(Gestures first, Gestures second, boolean allowed) {
+        if (first != second) {
+            if (allowed) {
+                allowedSimultaneousGestures.get(second).add(first);
+            } else {
+                allowedSimultaneousGestures.get(second).remove(first);
+            }
+        }
+    }
+
+    /**
+     * Get whether the gesture {@code second} can be recognized while {@code first} is in progress
+     * @param first Initial gesture type
+     * @param second Subsequent gesture type
+     * @return True if {@code second} will be recognized, else false
+     */
+    public boolean isSimultaneousDetectionAllowed(Gestures first, Gestures second) {
+        return allowedSimultaneousGestures.get(second).contains(first);
+    }
+
+    private boolean isDetectionAllowed(Gestures g) {
+        if (!allowedSimultaneousGestures.get(g).containsAll(detectedGestures)) {
+            return false;
+        }
+        if (!g.isMultiTouch()) {
+            // Return false if a multitouch gesture has finished within a time threshold
+            long t = SystemClock.uptimeMillis() - lastMultiTouchEndTime;
+            if (t < MULTITOUCH_BUFFER_TIME) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private void setGestureDetected(Gestures g, boolean detected) {
+        if (detected) {
+            detectedGestures.add(g);
+        } else {
+            detectedGestures.remove(g);
+        }
+        if (!detected && g.isMultiTouch()) {
+            lastMultiTouchEndTime = SystemClock.uptimeMillis();
+        }
+    }
+
+    // View.OnTouchListener implementation
+    // ===================================
+
+    @Override
+    public boolean onTouch(View v, MotionEvent event) {
+
+        panTapGestureDetector.onTouchEvent(event);
+        scaleGestureDetector.onTouchEvent(event);
+        shoveGestureDetector.onTouchEvent(event);
+        rotateGestureDetector.onTouchEvent(event);
+
+        return true;
+    }
+
+    // GestureDetector.OnDoubleTapListener implementation
+    // ==================================================
+
+    @Override
+    public boolean onSingleTapConfirmed(MotionEvent e) {
+        if (isDetectionAllowed(Gestures.TAP) && tapResponder != null) {
+            return tapResponder.onSingleTapConfirmed(e.getX(), e.getY());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onDoubleTap(MotionEvent e) {
+        // This event handles the second 'down' of a double tap, which is not a confirmed double tap
+        // (e.g. it could be the start of a 'quick scale' gesture). We ignore this callback and
+        // check for the 'up' event that follows.
+        return false;
+    }
+
+    @Override
+    public boolean onDoubleTapEvent(MotionEvent e) {
+        int action = e.getActionMasked();
+        long time = e.getEventTime() - e.getDownTime();
+        if (action != MotionEvent.ACTION_UP || time > DOUBLE_TAP_TIMEOUT) {
+            // The detector sends back only the first 'down' and the second 'up' so we only need to
+            // respond when we receive an 'up' action. We also discard the gesture if the second tap
+            // lasts longer than the permitted duration between taps.
+            return false;
+        }
+        if (isDetectionAllowed(Gestures.DOUBLE_TAP) && doubleTapResponder != null) {
+            return doubleTapResponder.onDoubleTap(e.getX(), e.getY());
+        }
+        return false;
+    }
+
+    // GestureDetector.OnGestureListener implementation
+    // ================================================
+
+    @Override
+    public boolean onDown(MotionEvent e) {
+        // When new touch is placed, dispatch a zero-distance pan;
+        // this provides an opportunity to halt any current motion.
+        if (isDetectionAllowed(Gestures.PAN) && panResponder != null) {
+            final float x = e.getX();
+            final float y = e.getY();
+            return panResponder.onPan(x, y, x, y);
+        }
+        return false;
+    }
+
+    @Override
+    public void onShowPress(MotionEvent e) {
+        // Ignored
+    }
+
+    @Override
+    public boolean onSingleTapUp(MotionEvent e) {
+        if (isDetectionAllowed(Gestures.TAP) && tapResponder != null) {
+            return tapResponder.onSingleTapUp(e.getX(), e.getY());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
+        if (isDetectionAllowed(Gestures.PAN)) {
+            int action = e2.getActionMasked();
+            boolean detected = !(action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP);
+            setGestureDetected(Gestures.PAN, detected);
+
+            if (panResponder == null) {
+                return false;
+            }
+
+            // TODO: Predictive panning
+            // Use estimated velocity to counteract input->render lag
+
+            float x = 0, y = 0;
+            int n = e2.getPointerCount();
+            for (int i = 0; i < n; i++) {
+                x += e2.getX(i) / n;
+                y += e2.getY(i) / n;
+            }
+            return panResponder.onPan(x + distanceX, y + distanceY, x, y);
+        }
+        return false;
+    }
+
+    @Override
+    public void onLongPress(MotionEvent e) {
+        if (isDetectionAllowed(Gestures.LONG_PRESS) && longPressResponder != null) {
+            longPressResponder.onLongPress(e.getX(), e.getY());
+        }
+    }
+
+    @Override
+    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
+        if (isDetectionAllowed(Gestures.PAN) && panResponder != null) {
+            return panResponder.onFling(e2.getX(), e2.getY(), velocityX, velocityY);
+        }
+        return false;
+    }
+
+    // RotateGestureDetector.OnRotateGestureListener implementation
+    // ============================================================
+
+    @Override
+    public boolean onRotate(RotateGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.ROTATE) && rotateResponder != null) {
+            float rotation = -detector.getRotationRadiansDelta();
+            float x = detector.getFocusX();
+            float y = detector.getFocusY();
+            return rotateResponder.onRotate(x, y, rotation);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onRotateBegin(RotateGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.ROTATE)) {
+            setGestureDetected(Gestures.ROTATE, true);
+        }
+        return true;
+    }
+
+    @Override
+    public void onRotateEnd(RotateGestureDetector detector) {
+        setGestureDetected(Gestures.ROTATE, false);
+    }
+
+    // ScaleGestureDetector.OnScaleGestureListener implementation
+    // ==========================================================
+
+    @Override
+    public boolean onScale(ScaleGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.SCALE) && scaleResponder != null) {
+            long ms = detector.getTimeDelta();
+            float dt = ms > 0 ? ms / 1000.f : 1.f;
+            float scale = detector.getScaleFactor();
+            float velocity = (scale - 1.f) / dt;
+            float x = detector.getFocusX();
+            float y = detector.getFocusY();
+            return scaleResponder.onScale(x, y, scale, velocity);
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onScaleBegin(ScaleGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.SCALE)) {
+            setGestureDetected(Gestures.SCALE, true);
+        }
+        return true;
+    }
+
+    @Override
+    public void onScaleEnd(ScaleGestureDetector detector) {
+        setGestureDetected(Gestures.SCALE, false);
+    }
+
+    // ShoveGestureDetector.OnShoveGestureListener implementation
+    // ==========================================================
+
+    @Override
+    public boolean onShove(ShoveGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.SHOVE) && shoveResponder != null) {
+            return shoveResponder.onShove(detector.getShovePixelsDelta());
+        }
+        return false;
+    }
+
+    @Override
+    public boolean onShoveBegin(ShoveGestureDetector detector) {
+        if (isDetectionAllowed(Gestures.SHOVE)) {
+            setGestureDetected(Gestures.SHOVE, true);
+        }
+        return true;
+    }
+
+    @Override
+    public void onShoveEnd(ShoveGestureDetector detector) {
+        setGestureDetected(Gestures.SHOVE, false);
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Geometry.java
new file mode 100644 (file)
index 0000000..63426b1
--- /dev/null
@@ -0,0 +1,35 @@
+package com.mapzen.tangram.geometry;
+
+import java.util.Map;
+
+/**
+ * {@code Geometry} is an abstract container of LngLat points and associated properties.
+ */
+public abstract class Geometry {
+
+    protected double[] coordinates;
+    protected int[] rings;
+    protected String[] properties;
+
+    public double[] getCoordinateArray() {
+        return coordinates;
+    }
+
+    public int[] getRingArray() {
+        return rings;
+    }
+
+    public String[] getPropertyArray() {
+        return properties;
+    }
+
+    protected String[] getStringMapAsArray(Map<String, String> properties) {
+        String[] out = new String[properties.size() * 2];
+        int i = 0;
+        for (Map.Entry<String, String> entry : properties.entrySet()) {
+            out[i++] = entry.getKey();
+            out[i++] = entry.getValue();
+        }
+        return out;
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Point.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Point.java
new file mode 100644 (file)
index 0000000..ce179f1
--- /dev/null
@@ -0,0 +1,21 @@
+package com.mapzen.tangram.geometry;
+
+import com.mapzen.tangram.LngLat;
+
+import java.util.Map;
+
+/**
+ * {@code Point} is a single LngLat and its properties.
+ */
+public class Point extends Geometry {
+
+    public Point(LngLat point, Map<String, String> properties) {
+        this.coordinates = new double[2];
+        coordinates[0] = point.longitude;
+        coordinates[1] = point.latitude;
+        if (properties != null) {
+            this.properties = getStringMapAsArray(properties);
+        }
+
+    }
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polygon.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polygon.java
new file mode 100644 (file)
index 0000000..2039424
--- /dev/null
@@ -0,0 +1,34 @@
+package com.mapzen.tangram.geometry;
+
+import com.mapzen.tangram.LngLat;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@code Polygon} is a sequence of rings of LngLat points and its properties.
+ */
+public class Polygon extends Geometry {
+
+    public Polygon(List<List<LngLat>> polygon, Map<String, String> properties) {
+        this.rings = new int[polygon.size()];
+        int i = 0;
+        int n_points = 0;
+        for (List<LngLat> ring : polygon) {
+            n_points += ring.size();
+            rings[i++] = ring.size();
+        }
+        this.coordinates = new double[2 * n_points];
+        int j = 0;
+        for (List<LngLat> ring : polygon) {
+            for (LngLat point : ring) {
+                coordinates[j++] = point.longitude;
+                coordinates[j++] = point.latitude;
+            }
+        }
+        if (properties != null) {
+            this.properties = getStringMapAsArray(properties);
+        }
+    }
+
+}
diff --git a/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java b/platforms/android/tangram/src/main/java/com/mapzen/tangram/geometry/Polyline.java
new file mode 100644 (file)
index 0000000..070d431
--- /dev/null
@@ -0,0 +1,25 @@
+package com.mapzen.tangram.geometry;
+
+import com.mapzen.tangram.LngLat;
+
+import java.util.List;
+import java.util.Map;
+
+/**
+ * {@code Polyline} is a sequence of LngLat points and its properties.
+ */
+public class Polyline extends Geometry {
+
+    public Polyline(List<LngLat> polyline, Map<String, String> properties) {
+        this.coordinates = new double[polyline.size() * 2];
+        int i = 0;
+        for (LngLat point : polyline) {
+            coordinates[i++] = point.longitude;
+            coordinates[i++] = point.latitude;
+        }
+        if (properties != null) {
+            this.properties = getStringMapAsArray(properties);
+        }
+    }
+
+}
diff --git a/platforms/android/tangram/versioning.gradle b/platforms/android/tangram/versioning.gradle
new file mode 100644 (file)
index 0000000..dfbcb36
--- /dev/null
@@ -0,0 +1,40 @@
+ext {
+  /**
+   * Builds an Android version code from the version of the project.
+   * This is designed to handle the -SNAPSHOT and -RC format.
+   *
+   * I.e. during development the version ends with -SNAPSHOT. As the code stabilizes and release nears
+   * one or many Release Candidates are tagged. These all end with "-RC1", "-RC2" etc.
+   * And the final release is without any suffix.
+   *
+   * http://www.jayway.com/2015/03/11/automatic-versioncode-generation-in-android-gradle/
+   */
+  buildVersionCode = {
+    //The rules is as follows:
+    //-SNAPSHOT counts as 0
+    //-RC* counts as the RC number, i.e. 1 to 98
+    //final release counts as 99.
+    //Thus you can only have 98 Release Candidates, which ought to be enough for everyone
+
+    def candidate = "99"
+    def (major, minor, patch) = VERSION_NAME.toLowerCase().replaceAll('-', '').tokenize('.')
+
+    if (patch == null) {
+        patch = 0;
+        candidate = 0;
+    } else if (patch.endsWith("snapshot")) {
+      candidate = "0"
+      patch = patch.replaceAll("[^0-9]","")
+    } else {
+      def rc
+      (patch, rc) = patch.tokenize("rc")
+      if (rc) {
+        candidate = rc
+      }
+    }
+
+    (major, minor, patch, candidate) = [major, minor, patch, candidate].collect{it.toInteger()}
+
+    (major * 1000000) + (minor * 10000) + (patch * 100) + candidate;
+  }
+}
diff --git a/platforms/common/glfwApp.cpp b/platforms/common/glfwApp.cpp
new file mode 100644 (file)
index 0000000..b3760d7
--- /dev/null
@@ -0,0 +1,427 @@
+#include "glfwApp.h"
+#include "data/clientGeoJsonSource.h"
+#include "debug/textDisplay.h"
+#include <GLFW/glfw3.h>
+#include "log.h"
+#include <cstdlib>
+
+namespace Tangram {
+
+namespace GlfwApp {
+
+// Forward-declare our callback functions.
+void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods);
+void cursorMoveCallback(GLFWwindow* window, double x, double y);
+void scrollCallback(GLFWwindow* window, double scrollx, double scrolly);
+void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods);
+void dropCallback(GLFWwindow* window, int count, const char** paths);
+void framebufferResizeCallback(GLFWwindow* window, int fWidth, int fHeight);
+
+constexpr double double_tap_time = 0.5; // seconds
+constexpr double scroll_span_multiplier = 0.05; // scaling for zoom and rotation
+constexpr double scroll_distance_multiplier = 5.0; // scaling for shove
+constexpr double single_tap_time = 0.25; //seconds (to avoid a long press being considered as a tap)
+
+std::shared_ptr<Platform> platform;
+
+std::string sceneFile;
+
+std::string markerStylingPath = "layers.touch.point.draw.icons";
+std::string polylineStyle = "{ style: lines, interactive: true, color: red, width: 20px, order: 5000 }";
+
+GLFWwindow* main_window = nullptr;
+Tangram::Map* map = nullptr;
+int width = 800;
+int height = 600;
+float density = 1.0;
+float pixel_scale = 1.0;
+bool recreate_context = false;
+
+bool was_panning = false;
+double last_time_released = -double_tap_time; // First click should never trigger a double tap
+double last_time_pressed = 0.0;
+double last_time_moved = 0.0;
+double last_x_down = 0.0;
+double last_y_down = 0.0;
+double last_x_velocity = 0.0;
+double last_y_velocity = 0.0;
+
+Tangram::MarkerID marker = 0;
+Tangram::MarkerID poiMarker = 0;
+Tangram::MarkerID polyline = 0;
+
+bool keepRunning = true;
+
+void create(std::shared_ptr<Platform> p, std::string f, int w, int h) {
+
+    platform = p;
+    sceneFile = f;
+    width = w;
+    height = h;
+
+    if (!glfwInit()) {
+        assert(false);
+        return;
+    }
+
+#ifndef MAPZEN_API_KEY
+    LOG("Environment variable MAPZEN_API_KEY not set. Kindly set this environment variable and relaunch.");
+    exit(1);
+#endif
+
+    // Setup tangram
+    if (!map) {
+        map = new Tangram::Map(platform);
+        map->loadSceneAsync(sceneFile.c_str(), true, {}, nullptr,
+                {SceneUpdate("global.sdk_mapzen_api_key", MAPZEN_API_KEY)});
+    }
+
+    // Create a windowed mode window and its OpenGL context
+    glfwWindowHint(GLFW_SAMPLES, 2);
+    if (!main_window) {
+        main_window = glfwCreateWindow(width, height, "Tangram ES", NULL, NULL);
+    }
+    if (!main_window) {
+        glfwTerminate();
+    }
+
+    // Make the main_window's context current
+    glfwMakeContextCurrent(main_window);
+
+    // Set input callbacks
+    glfwSetFramebufferSizeCallback(main_window, framebufferResizeCallback);
+    glfwSetMouseButtonCallback(main_window, mouseButtonCallback);
+    glfwSetCursorPosCallback(main_window, cursorMoveCallback);
+    glfwSetScrollCallback(main_window, scrollCallback);
+    glfwSetKeyCallback(main_window, keyCallback);
+    glfwSetDropCallback(main_window, dropCallback);
+
+    // Setup graphics
+    map->setupGL();
+    int fWidth = 0, fHeight = 0;
+    glfwGetFramebufferSize(main_window, &fWidth, &fHeight);
+    framebufferResizeCallback(main_window, fWidth, fHeight);
+
+}
+
+void run() {
+
+    double lastTime = glfwGetTime();
+
+    // Loop until the user closes the window
+    while (keepRunning && !glfwWindowShouldClose(main_window)) {
+
+        double currentTime = glfwGetTime();
+        double delta = currentTime - lastTime;
+        lastTime = currentTime;
+
+        // Render
+        map->update(delta);
+        map->render();
+
+        // Swap front and back buffers
+        glfwSwapBuffers(main_window);
+
+        // Poll for and process events
+        if (platform->isContinuousRendering()) {
+            glfwPollEvents();
+        } else {
+            glfwWaitEvents();
+        }
+    }
+}
+
+void stop(int) {
+    if (keepRunning) {
+        logMsg("shutdown\n");
+        keepRunning = false;
+        glfwPostEmptyEvent();
+    } else {
+        logMsg("killed!\n");
+        exit(1);
+    }
+}
+
+void destroy() {
+    if (map) {
+        delete map;
+        map = nullptr;
+    }
+    if (main_window) {
+        glfwDestroyWindow(main_window);
+        main_window = nullptr;
+    }
+    glfwTerminate();
+}
+
+template<typename T>
+static constexpr T clamp(T val, T min, T max) {
+    return val > max ? max : val < min ? min : val;
+}
+
+void mouseButtonCallback(GLFWwindow* window, int button, int action, int mods) {
+
+    if (button != GLFW_MOUSE_BUTTON_1) {
+        return; // This event is for a mouse button that we don't care about
+    }
+
+    double x, y;
+    glfwGetCursorPos(window, &x, &y);
+    x *= density;
+    y *= density;
+    double time = glfwGetTime();
+
+    if (was_panning && action == GLFW_RELEASE) {
+        was_panning = false;
+        auto vx = clamp(last_x_velocity, -2000.0, 2000.0);
+        auto vy = clamp(last_y_velocity, -2000.0, 2000.0);
+        map->handleFlingGesture(x, y, vx, vy);
+        return; // Clicks with movement don't count as taps, so stop here
+    }
+
+    if (action == GLFW_PRESS) {
+        map->handlePanGesture(0.0f, 0.0f, 0.0f, 0.0f);
+        last_x_down = x;
+        last_y_down = y;
+        last_time_pressed = time;
+        return;
+    }
+
+    if ((time - last_time_released) < double_tap_time) {
+        // Double tap recognized
+        Tangram::LngLat p;
+        map->screenPositionToLngLat(x, y, &p.longitude, &p.latitude);
+        map->setPositionEased(p.longitude, p.latitude, 1.f);
+
+    } else if ((time - last_time_pressed) < single_tap_time) {
+        // Single tap recognized
+        Tangram::LngLat p;
+        map->screenPositionToLngLat(x, y, &p.longitude, &p.latitude);
+
+
+        if (!marker) {
+            marker = map->markerAdd();
+
+            map->markerSetStylingFromPath(marker, markerStylingPath.c_str());
+            map->markerSetPoint(marker, p);
+            map->markerSetDrawOrder(marker, mods);
+            logMsg("Added Marker with zOrder: %d\n", mods);
+        } else {
+            static bool visible = true;
+            map->markerSetPoint(marker, p);
+            map->markerSetVisible(marker, visible);
+            visible = !visible;
+        }
+
+        map->pickFeatureAt(x, y, [](const Tangram::FeaturePickResult* featurePickResult) {
+            if (!featurePickResult) { return; }
+            std::string name;
+            if (featurePickResult->properties->getString("name", name)) {
+                logMsg("Selected %s", name.c_str());
+            }
+        });
+
+        map->pickLabelAt(x, y, [&](const Tangram::LabelPickResult* labelPickResult) {
+            if (!labelPickResult) { return; }
+            std::string type = labelPickResult->type == Tangram::LabelType::text ? "text" : "icon";
+            std::string name;
+            if (labelPickResult->touchItem.properties->getString("name", name)) {
+                logMsg("Touched label %s %s", type.c_str(), name.c_str());
+            }
+            map->markerSetPoint(marker, labelPickResult->coordinates);
+            map->markerSetVisible(marker, true);
+        });
+
+        map->pickMarkerAt(x, y, [](const Tangram::MarkerPickResult* markerPickResult) {
+            if (!markerPickResult) { return; }
+            logMsg("Selected marker id %d", markerPickResult->id);
+        });
+
+        static double last_x = 0, last_y = 0;
+
+        if (!polyline) {
+            polyline = map->markerAdd();
+            map->markerSetStylingFromString(polyline, polylineStyle.c_str());
+        }
+
+        if (last_x != 0) {
+            Tangram::LngLat coords[2];
+            map->screenPositionToLngLat(x, y, &coords[0].longitude, &coords[0].latitude);
+            map->screenPositionToLngLat(last_x, last_y, &coords[1].longitude, &coords[1].latitude);
+
+            map->markerSetPolyline(polyline, coords, 2);
+        }
+
+        last_x = x;
+        last_y = y;
+
+        platform->requestRender();
+    }
+
+    last_time_released = time;
+
+}
+
+void cursorMoveCallback(GLFWwindow* window, double x, double y) {
+
+    x *= density;
+    y *= density;
+
+    int action = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_1);
+    double time = glfwGetTime();
+
+    if (action == GLFW_PRESS) {
+
+        if (was_panning) {
+            map->handlePanGesture(last_x_down, last_y_down, x, y);
+        }
+
+        was_panning = true;
+        last_x_velocity = (x - last_x_down) / (time - last_time_moved);
+        last_y_velocity = (y - last_y_down) / (time - last_time_moved);
+        last_x_down = x;
+        last_y_down = y;
+
+    }
+
+    last_time_moved = time;
+
+}
+
+void scrollCallback(GLFWwindow* window, double scrollx, double scrolly) {
+
+    double x, y;
+    glfwGetCursorPos(window, &x, &y);
+    x *= density;
+    y *= density;
+
+    bool rotating = glfwGetKey(window, GLFW_KEY_LEFT_ALT) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_ALT) == GLFW_PRESS;
+    bool shoving = glfwGetKey(window, GLFW_KEY_LEFT_CONTROL) == GLFW_PRESS || glfwGetKey(window, GLFW_KEY_RIGHT_CONTROL) == GLFW_PRESS;
+
+    if (shoving) {
+        map->handleShoveGesture(scroll_distance_multiplier * scrolly);
+    } else if (rotating) {
+        map->handleRotateGesture(x, y, scroll_span_multiplier * scrolly);
+    } else {
+        map->handlePinchGesture(x, y, 1.0 + scroll_span_multiplier * scrolly, 0.f);
+    }
+
+}
+
+void keyCallback(GLFWwindow* window, int key, int scancode, int action, int mods) {
+
+    if (action == GLFW_PRESS) {
+        switch (key) {
+            case GLFW_KEY_1:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::freeze_tiles);
+                break;
+            case GLFW_KEY_2:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::proxy_colors);
+                break;
+            case GLFW_KEY_3:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::tile_bounds);
+                break;
+            case GLFW_KEY_4:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::tile_infos);
+                break;
+            case GLFW_KEY_5:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::labels);
+                break;
+            case GLFW_KEY_6:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::draw_all_labels);
+                break;
+            case GLFW_KEY_7:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::tangram_infos);
+                break;
+            case GLFW_KEY_8:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::tangram_stats);
+                break;
+            case GLFW_KEY_9:
+                Tangram::toggleDebugFlag(Tangram::DebugFlags::selection_buffer);
+                break;
+            case GLFW_KEY_BACKSPACE:
+                recreate_context = true;
+                break;
+            case GLFW_KEY_R:
+                map->loadSceneAsync(sceneFile.c_str());
+                break;
+            case GLFW_KEY_Z:
+                map->setZoomEased(map->getZoom() + 1.f, 1.5f);
+                break;
+            case GLFW_KEY_N:
+                map->setRotationEased(0.f, 1.f);
+                break;
+            case GLFW_KEY_S:
+                if (pixel_scale == 1.0) {
+                    pixel_scale = 2.0;
+                } else if (pixel_scale == 2.0) {
+                    pixel_scale = 0.75;
+                } else {
+                    pixel_scale = 1.0;
+                }
+                map->setPixelScale(pixel_scale);
+                break;
+            case GLFW_KEY_P:
+                map->queueSceneUpdate("cameras", "{ main_camera: { type: perspective } }");
+                map->applySceneUpdates();
+                break;
+            case GLFW_KEY_I:
+                map->queueSceneUpdate("cameras", "{ main_camera: { type: isometric } }");
+                map->applySceneUpdates();
+                break;
+            case GLFW_KEY_G:
+                static bool geoJSON = false;
+                if (!geoJSON) {
+                    map->queueSceneUpdate("sources.osm.type", "GeoJSON");
+                    map->queueSceneUpdate("sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.json");
+                } else {
+                    map->queueSceneUpdate("sources.osm.type", "MVT");
+                    map->queueSceneUpdate("sources.osm.url", "https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt");
+                }
+                geoJSON = !geoJSON;
+                map->applySceneUpdates();
+                break;
+            case GLFW_KEY_ESCAPE:
+                glfwSetWindowShouldClose(window, true);
+                break;
+            case GLFW_KEY_F1:
+                map->setPosition(-74.00976419448854, 40.70532700869127);
+                map->setZoom(16);
+                break;
+            case GLFW_KEY_F2:
+                map->setPosition(8.82, 53.08);
+                map->setZoom(14);
+                break;
+            case GLFW_KEY_F3:
+                map->onMemoryWarning();
+                break;
+        default:
+                break;
+        }
+    }
+}
+
+void dropCallback(GLFWwindow* window, int count, const char** paths) {
+
+    sceneFile = std::string(paths[0]);
+    map->loadSceneAsync(sceneFile.c_str(), true, {}, nullptr,
+                        {SceneUpdate("global.sdk_mapzen_api_key", MAPZEN_API_KEY)});
+
+}
+
+void framebufferResizeCallback(GLFWwindow* window, int fWidth, int fHeight) {
+
+    int wWidth = 0, wHeight = 0;
+    glfwGetWindowSize(main_window, &wWidth, &wHeight);
+    float new_density = (float)fWidth / (float)wWidth;
+    if (new_density != density) {
+        recreate_context = true;
+        density = new_density;
+    }
+    map->setPixelScale(density);
+    map->resize(fWidth, fHeight);
+}
+
+} // namespace GlfwApp
+
+} // namespace Tangram
diff --git a/platforms/common/glfwApp.h b/platforms/common/glfwApp.h
new file mode 100644 (file)
index 0000000..b2f190f
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "platform.h"
+#include "tangram.h"
+#include <memory>
+
+namespace Tangram {
+
+namespace GlfwApp {
+
+void create(std::shared_ptr<Platform> platform, std::string sceneFile, int width, int height);
+void run();
+void stop(int);
+void destroy();
+
+} // namespace GlfwApp
+
+} // namespace Tangram
diff --git a/platforms/common/platform_gl.cpp b/platforms/common/platform_gl.cpp
new file mode 100644 (file)
index 0000000..de50335
--- /dev/null
@@ -0,0 +1,336 @@
+#include "platform_gl.h"
+
+#include "gl.h"
+#include "gl/glError.h"
+
+namespace Tangram {
+
+GLenum GL::getError() {
+    return glGetError();
+}
+
+const GLubyte* GL::getString(GLenum name) {
+    auto result = glGetString(name);
+    GL_CHECK();
+    return result;
+}
+
+void GL::clear(GLbitfield mask) {
+    GL_CHECK(glClear(mask));
+}
+void GL::lineWidth(GLfloat width) {
+    GL_CHECK(glLineWidth(width));
+}
+void GL::viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+    GL_CHECK(glViewport(x, y, width, height));
+}
+
+void GL::enable(GLenum id) {
+    GL_CHECK(glEnable(id));
+}
+void GL::disable(GLenum id) {
+    GL_CHECK(glDisable(id));
+}
+void GL::depthFunc(GLenum func) {
+    GL_CHECK(glDepthFunc(func));
+}
+void GL::depthMask(GLboolean flag) {
+    GL_CHECK(glDepthMask(flag));
+}
+void GL::depthRange(GLfloat n, GLfloat f) {
+    GL_CHECK(glDepthRangef(n, f));
+}
+void GL::clearDepth(GLfloat d) {
+    GL_CHECK(glClearDepthf(d));
+}
+void GL::blendFunc(GLenum sfactor, GLenum dfactor) {
+    GL_CHECK(glBlendFunc(sfactor, dfactor));
+}
+void GL::stencilFunc(GLenum func, GLint ref, GLuint mask) {
+    GL_CHECK(glStencilFunc(func, ref, mask));
+}
+void GL::stencilMask(GLuint mask) {
+    GL_CHECK(glStencilMask(mask));
+}
+void GL::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+    GL_CHECK(glStencilOp(fail, zfail, zpass));
+}
+void GL::clearStencil(GLint s) {
+    GL_CHECK(glClearStencil(s));
+}
+void GL::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+    GL_CHECK(glColorMask(red, green, blue, alpha));
+}
+void GL::cullFace(GLenum mode) {
+    GL_CHECK(glCullFace(mode));
+}
+void GL::frontFace(GLenum mode) {
+    GL_CHECK(glFrontFace(mode));
+}
+void GL::clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    GL_CHECK(glClearColor(red, green, blue, alpha));
+}
+void GL::getIntegerv(GLenum pname, GLint *params ) {
+    GL_CHECK(glGetIntegerv(pname, params ));
+}
+
+// Program
+void GL::useProgram(GLuint program) {
+    GL_CHECK(glUseProgram(program));
+}
+void GL::deleteProgram(GLuint program) {
+    GL_CHECK(glDeleteProgram(program));
+}
+void GL::deleteShader(GLuint shader) {
+    GL_CHECK(glDeleteShader(shader));
+}
+GLuint GL::createShader(GLenum type) {
+    auto result = glCreateShader(type);
+    GL_CHECK();
+    return result;
+}
+GLuint GL::createProgram() {
+    auto result = glCreateProgram();
+    GL_CHECK();
+    return result;
+}
+
+void GL::compileShader(GLuint shader) {
+    GL_CHECK(glCompileShader(shader));
+}
+void GL::attachShader(GLuint program, GLuint shader) {
+    GL_CHECK(glAttachShader(program,shader));
+}
+void GL::linkProgram(GLuint program) {
+    GL_CHECK(glLinkProgram(program));
+}
+
+void GL::shaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) {
+        auto source = const_cast<const GLchar**>(string);
+    GL_CHECK(glShaderSource(shader, count, source, length));
+}
+void GL::getShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    GL_CHECK(glGetShaderInfoLog(shader, bufSize, length, infoLog));
+}
+void GL::getProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    GL_CHECK(glGetProgramInfoLog(program, bufSize, length, infoLog));
+}
+GLint GL::getUniformLocation(GLuint program, const GLchar *name) {
+    auto result = glGetUniformLocation(program, name);
+    GL_CHECK();
+    return result;
+}
+GLint GL::getAttribLocation(GLuint program, const GLchar *name) {
+    auto result = glGetAttribLocation(program, name);
+    GL_CHECK();
+    return result;
+}
+void GL::getProgramiv(GLuint program, GLenum pname, GLint *params) {
+    GL_CHECK(glGetProgramiv(program,pname,params));
+}
+void GL::getShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    GL_CHECK(glGetShaderiv(shader,pname, params));
+}
+
+// Buffers
+void GL::bindBuffer(GLenum target, GLuint buffer) {
+    GL_CHECK(glBindBuffer(target, buffer));
+}
+void GL::deleteBuffers(GLsizei n, const GLuint *buffers) {
+    GL_CHECK(glDeleteBuffers(n, buffers));
+}
+void GL::genBuffers(GLsizei n, GLuint *buffers) {
+    GL_CHECK(glGenBuffers(n, buffers));
+}
+void GL::bufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
+    GL_CHECK(glBufferData(target, size, data, usage));
+}
+void GL::bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {
+    GL_CHECK(glBufferSubData(target, offset, size, data));
+}
+void GL::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLvoid* pixels) {
+    GL_CHECK(glReadPixels(x, y, width, height, format, type, pixels));
+}
+
+// Texture
+void GL::bindTexture(GLenum target, GLuint texture ) {
+    GL_CHECK(glBindTexture(target, texture ));
+}
+void GL::activeTexture(GLenum texture) {
+    GL_CHECK(glActiveTexture(texture));
+}
+void GL::genTextures(GLsizei n, GLuint *textures ) {
+    GL_CHECK(glGenTextures(n, textures ));
+}
+void GL::deleteTextures(GLsizei n, const GLuint *textures) {
+    GL_CHECK(glDeleteTextures(n, textures));
+}
+void GL::texParameteri(GLenum target, GLenum pname, GLint param ) {
+    GL_CHECK(glTexParameteri(target, pname, param ));
+}
+void GL::texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
+                    GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+    GL_CHECK(glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels)); }
+
+void GL::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                       GLenum format, GLenum type, const GLvoid *pixels) {
+    GL_CHECK(glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels)); }
+
+void GL::generateMipmap(GLenum target) {
+    GL_CHECK(glGenerateMipmap(target));
+}
+
+void GL::enableVertexAttribArray(GLuint index) {
+    GL_CHECK(glEnableVertexAttribArray(index));
+}
+void GL::disableVertexAttribArray(GLuint index) {
+    GL_CHECK(glDisableVertexAttribArray(index));
+}
+void GL::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
+                             GLsizei stride, const void *pointer) {
+    GL_CHECK(glVertexAttribPointer(index, size, type, normalized, stride, pointer));
+}
+
+void GL::drawArrays(GLenum mode, GLint first, GLsizei count ) {
+    GL_CHECK(glDrawArrays(mode, first, count ));
+}
+void GL::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) {
+    GL_CHECK(glDrawElements(mode, count, type, indices ));
+}
+
+void GL::uniform1f(GLint location, GLfloat v0) {
+    GL_CHECK(glUniform1f(location, v0));
+}
+void GL::uniform2f(GLint location, GLfloat v0, GLfloat v1) {
+    GL_CHECK(glUniform2f(location, v0, v1));
+}
+void GL::uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
+    GL_CHECK(glUniform3f(location, v0, v1, v2));
+}
+void GL::uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+    GL_CHECK(glUniform4f(location, v0, v1, v2, v3));
+}
+
+void GL::uniform1i(GLint location, GLint v0) {
+    GL_CHECK(glUniform1i(location, v0));
+}
+void GL::uniform2i(GLint location, GLint v0, GLint v1) {
+    GL_CHECK(glUniform2i(location, v0, v1));
+}
+void GL::uniform3i(GLint location, GLint v0, GLint v1, GLint v2) {
+    GL_CHECK(glUniform3i(location, v0, v1, v2));
+}
+void GL::uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
+    GL_CHECK(glUniform4i(location, v0, v1, v2, v3));
+}
+
+void GL::uniform1fv(GLint location, GLsizei count, const GLfloat *value) {
+    GL_CHECK(glUniform1fv(location, count, value));
+}
+void GL::uniform2fv(GLint location, GLsizei count, const GLfloat *value) {
+    GL_CHECK(glUniform2fv(location, count, value));
+}
+void GL::uniform3fv(GLint location, GLsizei count, const GLfloat *value) {
+    GL_CHECK(glUniform3fv(location, count, value));
+}
+void GL::uniform4fv(GLint location, GLsizei count, const GLfloat *value) {
+    GL_CHECK(glUniform4fv(location, count, value));
+}
+void GL::uniform1iv(GLint location, GLsizei count, const GLint *value) {
+    GL_CHECK(glUniform1iv(location, count, value));
+}
+void GL::uniform2iv(GLint location, GLsizei count, const GLint *value) {
+    GL_CHECK(glUniform2iv(location, count, value));
+}
+void GL::uniform3iv(GLint location, GLsizei count, const GLint *value) {
+    GL_CHECK(glUniform3iv(location, count, value));
+}
+void GL::uniform4iv(GLint location, GLsizei count, const GLint *value) {
+    GL_CHECK(glUniform4iv(location, count, value));
+}
+
+void GL::uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GL_CHECK(glUniformMatrix2fv(location, count, transpose, value));
+}
+void GL::uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GL_CHECK(glUniformMatrix3fv(location, count, transpose, value));
+}
+void GL::uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    GL_CHECK(glUniformMatrix4fv(location, count, transpose, value));
+}
+
+// mapbuffer
+void* GL::mapBuffer(GLenum target, GLenum access) {
+    auto result =  glMapBuffer(target, access);
+    GL_CHECK();
+    return result;
+}
+GLboolean GL::unmapBuffer(GLenum target) {
+    auto result = glUnmapBuffer(target);
+    GL_CHECK();
+    return result;
+}
+
+void GL::finish(void) {
+    GL_CHECK(glFinish());
+}
+
+// VAO
+void GL::bindVertexArray(GLuint array) {
+    GL_CHECK(glBindVertexArray(array));
+}
+void GL::deleteVertexArrays(GLsizei n, const GLuint *arrays) {
+    GL_CHECK(glDeleteVertexArrays(n, arrays));
+}
+void GL::genVertexArrays(GLsizei n, GLuint *arrays) {
+    GL_CHECK(glGenVertexArrays(n, arrays));
+}
+
+// Framebuffer
+void GL::bindFramebuffer(GLenum target, GLuint framebuffer) {
+    GL_CHECK(glBindFramebuffer(target, framebuffer));
+}
+
+void GL::genFramebuffers(GLsizei n, GLuint *framebuffers) {
+    GL_CHECK(glGenFramebuffers(n, framebuffers));
+}
+
+void GL::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
+                              GLuint texture, GLint level) {
+    GL_CHECK(glFramebufferTexture2D(target, attachment, textarget, texture, level));
+}
+
+void GL::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width,
+                             GLsizei height) {
+    GL_CHECK(glRenderbufferStorage(target, internalformat, width, height));
+}
+
+void GL::framebufferRenderbuffer(GLenum target, GLenum attachment,
+                                 GLenum renderbuffertarget, GLuint renderbuffer) {
+    GL_CHECK(glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer));
+}
+
+void GL::genRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    GL_CHECK(glGenRenderbuffers(n, renderbuffers));
+}
+
+void GL::bindRenderbuffer(GLenum target, GLuint renderbuffer) {
+    GL_CHECK(glBindRenderbuffer(target, renderbuffer));
+}
+
+void GL::deleteFramebuffers(GLsizei n, const GLuint *framebuffers) {
+    GL_CHECK(glDeleteFramebuffers(n, framebuffers));
+}
+
+void GL::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {
+    GL_CHECK(glDeleteRenderbuffers(n, renderbuffers));
+}
+
+GLenum GL::checkFramebufferStatus(GLenum target) {
+    GLenum status = glCheckFramebufferStatus(target);
+    GL_CHECK();
+    return status;
+}
+
+}
diff --git a/platforms/common/platform_gl.h b/platforms/common/platform_gl.h
new file mode 100644 (file)
index 0000000..bf1913f
--- /dev/null
@@ -0,0 +1,68 @@
+#pragma once
+
+#ifdef PLATFORM_ANDROID
+#include <GLES2/gl2platform.h>
+
+#ifndef GL_GLEXT_PROTOTYPES
+#define GL_GLEXT_PROTOTYPES 1
+#endif
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+// defined in platform_android.cpp
+extern PFNGLBINDVERTEXARRAYOESPROC glBindVertexArrayOESEXT;
+extern PFNGLDELETEVERTEXARRAYSOESPROC glDeleteVertexArraysOESEXT;
+extern PFNGLGENVERTEXARRAYSOESPROC glGenVertexArraysOESEXT;
+
+#define glDeleteVertexArrays glDeleteVertexArraysOESEXT
+#define glGenVertexArrays glGenVertexArraysOESEXT
+#define glBindVertexArray glBindVertexArrayOESEXT
+#endif
+
+#ifdef PLATFORM_IOS
+#include <OpenGLES/ES2/gl.h>
+#include <OpenGLES/ES2/glext.h>
+#define glDeleteVertexArrays glDeleteVertexArraysOES
+#define glGenVertexArrays glGenVertexArraysOES
+#define glBindVertexArray glBindVertexArrayOES
+#endif
+
+#ifdef PLATFORM_OSX
+#define GLFW_INCLUDE_GLEXT
+#include <GLFW/glfw3.h>
+/*
+ * typedef to resolve name conflict in osx
+ */
+#define glClearDepthf glClearDepth
+#define glDepthRangef glDepthRange
+#define glDeleteVertexArrays glDeleteVertexArraysAPPLE
+#define glGenVertexArrays glGenVertexArraysAPPLE
+#define glBindVertexArray glBindVertexArrayAPPLE
+#endif
+
+#ifdef PLATFORM_LINUX
+#define GL_GLEXT_PROTOTYPES
+#include <GLFW/glfw3.h>
+#endif
+
+#ifdef PLATFORM_RPI
+//  Broadcom hardware library for hijacking the GPU card without window manager
+//
+#include "bcm_host.h"
+
+#include <GLES2/gl2.h>
+#include <GLES2/gl2ext.h>
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+
+// Dummy VertexArray functions
+static void glBindVertexArray(GLuint array) {}
+static void glDeleteVertexArrays(GLsizei n, const GLuint *arrays) {}
+static void glGenVertexArrays(GLsizei n, GLuint *arrays) {}
+
+#endif
+
+#if defined(PLATFORM_ANDROID) || defined(PLATFORM_IOS) || defined(PLATFORM_RPI)
+    #define glMapBuffer glMapBufferOES
+    #define glUnmapBuffer glUnmapBufferOES
+#endif
diff --git a/platforms/common/urlClient.cpp b/platforms/common/urlClient.cpp
new file mode 100644 (file)
index 0000000..af64799
--- /dev/null
@@ -0,0 +1,195 @@
+#include "urlClient.h"
+#include "log.h"
+#include <cassert>
+#include <cstring>
+#include <curl/curl.h>
+
+namespace Tangram {
+
+
+struct CurlGlobals {
+    CurlGlobals() {
+        LOGD("curl global init");
+        curl_global_init(CURL_GLOBAL_ALL);
+    }
+    ~CurlGlobals() {
+        LOGD("curl global shutdown");
+        curl_global_cleanup();
+    }
+} s_curl;
+
+
+UrlClient::Response getCanceledResponse() {
+    UrlClient::Response response;
+    response.canceled = true;
+    return response;
+}
+
+UrlClient::UrlClient(const Options& options)
+    : m_options(options) {
+
+    assert(options.numberOfThreads > 0);
+    // Start the curl threads.
+    m_keepRunning = true;
+    m_tasks.resize(options.numberOfThreads);
+    for (uint32_t i = 0; i < options.numberOfThreads; i++) {
+        m_threads.emplace_back(&UrlClient::curlLoop, this, i);
+    }
+}
+
+UrlClient::~UrlClient() {
+    // Make all tasks cancelled.
+    {
+        std::lock_guard<std::mutex> lock(m_requestMutex);
+        for (auto& request : m_requests) {
+            if (request.callback) {
+                auto response = getCanceledResponse();
+                request.callback(std::move(response.data));
+            }
+        }
+        m_requests.clear();
+        for (auto& task : m_tasks) {
+            task.response.canceled = true;
+        }
+    }
+    // Stop the curl threads.
+    m_keepRunning = false;
+    m_requestCondition.notify_all();
+    for (auto& thread : m_threads) {
+        thread.join();
+    }
+}
+
+bool UrlClient::addRequest(const std::string& url, UrlCallback onComplete) {
+    // Create a new request.
+    Request request = {url, onComplete};
+    // Add the request to our list.
+    {
+        // Lock the mutex to prevent concurrent modification of the list by the curl loop thread.
+        std::lock_guard<std::mutex> lock(m_requestMutex);
+        m_requests.push_back(request);
+    }
+    // Notify a thread to start the transfer.
+    m_requestCondition.notify_one();
+    return true;
+}
+
+void UrlClient::cancelRequest(const std::string& url) {
+    std::lock_guard<std::mutex> lock(m_requestMutex);
+    // First check the pending request list.
+    for (auto it = m_requests.begin(), end = m_requests.end(); it != end; ++it) {
+        auto& request = *it;
+        if (request.url == url) {
+            // Found the request! Now run its callback and remove it.
+            auto response = getCanceledResponse();
+            if (request.callback) {
+                request.callback(std::move(response.data));
+            }
+            m_requests.erase(it);
+            return;
+        }
+    }
+    // Next check the active request list.
+    for (auto& task : m_tasks) {
+        if (task.request.url == url) {
+            task.response.canceled = true;
+        }
+    }
+}
+
+size_t curlWriteCallback(char* ptr, size_t size, size_t n, void* user) {
+    // Writes data received by libCURL.
+    auto* response = reinterpret_cast<UrlClient::Response*>(user);
+    auto& buffer = response->data;
+    auto addedSize = size * n;
+    auto oldSize = buffer.size();
+    buffer.resize(oldSize + addedSize);
+    std::memcpy(buffer.data() + oldSize, ptr, addedSize);
+    return addedSize;
+}
+
+int curlProgressCallback(void* user, double dltotal, double dlnow, double ultotal, double ulnow) {
+    // Signals libCURL to abort the request if marked as canceled.
+    auto* response = reinterpret_cast<UrlClient::Response*>(user);
+    return static_cast<int>(response->canceled);
+}
+
+void UrlClient::curlLoop(uint32_t index) {
+    assert(m_tasks.size() > index);
+    Task& task = m_tasks[index];
+    LOGD("curlLoop %u starting", index);
+    // Create a buffer for curl error messages.
+    char curlErrorString[CURL_ERROR_SIZE];
+    // Set up an easy handle for reuse.
+    auto handle = curl_easy_init();
+    curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, &curlWriteCallback);
+    curl_easy_setopt(handle, CURLOPT_WRITEDATA, &task.response);
+    curl_easy_setopt(handle, CURLOPT_PROGRESSFUNCTION, &curlProgressCallback);
+    curl_easy_setopt(handle, CURLOPT_PROGRESSDATA, &task.response);
+    curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
+    curl_easy_setopt(handle, CURLOPT_HEADER, 0L);
+    curl_easy_setopt(handle, CURLOPT_VERBOSE, 0L);
+    curl_easy_setopt(handle, CURLOPT_ACCEPT_ENCODING, "gzip");
+    curl_easy_setopt(handle, CURLOPT_ERRORBUFFER, curlErrorString);
+    curl_easy_setopt(handle, CURLOPT_CONNECTTIMEOUT_MS, m_options.connectionTimeoutMs);
+    curl_easy_setopt(handle, CURLOPT_TIMEOUT_MS, m_options.requestTimeoutMs);
+    if (!m_options.proxyAddress.empty()) {
+        curl_easy_setopt(handle, CURLOPT_PROXY, m_options.proxyAddress.c_str());
+    }
+
+    // Loop until the session is destroyed.
+    while (m_keepRunning) {
+        bool haveRequest = false;
+        // Wait until the condition variable is notified.
+        {
+            std::unique_lock<std::mutex> lock(m_requestMutex);
+            if (m_requests.empty()) {
+                LOGD("curlLoop %u waiting", index);
+                m_requestCondition.wait(lock);
+            }
+            LOGD("curlLoop %u notified", index);
+            // Try to get a request from the list.
+            if (!m_requests.empty()) {
+                // Take the first request from our list.
+                task.request = m_requests.front();
+                m_requests.erase(m_requests.begin());
+                haveRequest = true;
+            }
+        }
+        if (haveRequest) {
+            // Configure the easy handle.
+            const char* url = task.request.url.data();
+            curl_easy_setopt(handle, CURLOPT_URL, url);
+            LOGD("curlLoop %u starting request for url: %s", index, url);
+            // Perform the request.
+            auto result = curl_easy_perform(handle);
+            // Get the result status code.
+            long httpStatus = 0;
+            curl_easy_getinfo(handle, CURLINFO_RESPONSE_CODE, &httpStatus);
+            // Handle success or error.
+            if (result == CURLE_OK && httpStatus >= 200 && httpStatus < 300) {
+                LOGD("curlLoop %u succeeded with http status: %d for url: %s", index, httpStatus, url);
+                task.response.successful = true;
+            } else if (result == CURLE_ABORTED_BY_CALLBACK) {
+                LOGD("curlLoop %u request aborted for url: %s", index, url);
+                task.response.successful = false;
+            } else {
+                LOGE("curlLoop %u failed: '%s' with http status: %d for url: %s", index, curlErrorString, httpStatus, url);
+                task.response.successful = false;
+            }
+            if (task.request.callback) {
+                LOGD("curlLoop %u performing request callback", index);
+                task.request.callback(std::move(task.response.data));
+            }
+        }
+        // Reset the response.
+        task.response.data.clear();
+        task.response.canceled = false;
+        task.response.successful = false;
+    }
+    LOGD("curlLoop %u exiting", index);
+    // Clean up our easy handle.
+    curl_easy_cleanup(handle);
+}
+
+} // namespace Tangram
diff --git a/platforms/common/urlClient.h b/platforms/common/urlClient.h
new file mode 100644 (file)
index 0000000..0eb6cb3
--- /dev/null
@@ -0,0 +1,59 @@
+#pragma once
+
+#include "platform.h"
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+#include <string>
+#include <thread>
+#include <vector>
+
+namespace Tangram {
+
+class UrlClient {
+
+public:
+
+    struct Options {
+        uint32_t numberOfThreads = 4;
+        uint32_t connectionTimeoutMs = 3000;
+        uint32_t requestTimeoutMs = 30000;
+        std::string proxyAddress;
+    };
+
+    struct Response {
+        std::vector<char> data;
+        bool successful = false;
+        bool canceled = false;
+    };
+
+    UrlClient(const Options& options);
+    ~UrlClient();
+
+    bool addRequest(const std::string& url, UrlCallback onComplete);
+
+    void cancelRequest(const std::string& url);
+
+private:
+    struct Request {
+        std::string url;
+        UrlCallback callback;
+    };
+
+    struct Task {
+        Request request;
+        Response response;
+    };
+
+    void curlLoop(uint32_t index);
+
+    std::vector<std::thread> m_threads;
+    std::vector<Task> m_tasks;
+    std::vector<Request> m_requests;
+    std::condition_variable m_requestCondition;
+    std::mutex m_requestMutex;
+    Options m_options;
+    bool m_keepRunning = false;
+};
+
+} // namespace Tangram
diff --git a/platforms/ios/README.md b/platforms/ios/README.md
new file mode 100644 (file)
index 0000000..03c45bf
--- /dev/null
@@ -0,0 +1,69 @@
+iOS
+===
+
+The recommended way to use tangram-es in an iOS project is to add it as a CocoaPods dependency. The library is hosted in CocoaPods under the pod name 'Tangram-es'. To find the latest version, check CocoaPods: https://cocoapods.org/pods/Tangram-es.
+
+## Setup ##
+
+This project uses CMake (minimum version 3.0), you can download it [here](http://www.cmake.org/download/) or use your favorite installation package tool like [homebrew](http://brew.sh/).
+
+```bash
+brew install cmake
+```
+
+Make sure to update git submodules before you build:
+
+```bash
+git submodule update --init
+```
+
+You can optionally install xcpretty to produce much prettier and more legible output during the build process:
+
+```bash
+gem install xcpretty
+```
+
+## Build ##
+
+You will need a Mapzen API key to use the vector-tile and terrain service that is being used from the stylesheet of the demo app.
+To get an API key visit: [mapzen.com/developers/](https://mapzen.com/developers/).
+
+Building the iOS demo application requires Xcode 8.0 or newer. From the root directory of the project, run:
+
+```bash
+make ios MAPZEN_API_KEY=mapzen-xxxx
+```
+
+You can optionally append `DEBUG=1` or `RELEASE=1` to choose the build type.
+
+This will generate an Xcode project that you can use to deploy on device or simulator:
+
+```bash
+open build/ios/tangram.xcodeproj
+```
+
+Make sure to set up the code signing identity and code sign the framework on copy (select target _tangram_ > _Build Phases_ > _Copy Files_ > _TangramMap.framework_ > _Code Sign On Copy_).
+
+Note on Code Signing and Provisioning Profiles:
+* For Simulator: Does not need any code signing identity, so you can ignore any provionining profile failures on target _tangram_ > _General_ > _Signing_.
+* For Device: You will have to modify the _Bundle Identifier_ under target _tangram_ > _General_ > _Identity_ > _Bundle Identifier_, to something other than `com.mapzen.tangram`, since this needs to be unique.
+
+For development, you can use the Makefile option `TANGRAM_IOS_FRAMEWORK_SLIM` to build for simulator only and faster your build times.
+
+### iOS Binary Framework ###
+
+An iOS binary framework bundle targeted for ARM architectures can be produced by running the following:
+
+```bash
+make ios-framework
+```
+
+The framework will be output in '/build/ios-framework/lib/', in a folder named 'release' or 'debug' according to the build type.
+
+To build a universal binary working on both device and simulator architectures run the following:
+
+```bash
+make ios-framework-universal
+```
+
+The universal framework will be output in '/build/ios-framework-universal/', in a folder named 'release' or 'debug' according to the build type.
diff --git a/platforms/ios/demo/Config.plist.in b/platforms/ios/demo/Config.plist.in
new file mode 100644 (file)
index 0000000..257022a
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>MapzenApiKey</key>
+    <string>${MAPZEN_API_KEY}</string>
+</dict>
+</plist>
diff --git a/platforms/ios/demo/Info.plist b/platforms/ios/demo/Info.plist
new file mode 100644 (file)
index 0000000..d8571be
--- /dev/null
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>UILaunchStoryboardName</key>
+       <string>LaunchScreen</string>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleDisplayName</key>
+       <string>tangram</string>
+       <key>CFBundleExecutable</key>
+       <string>${EXECUTABLE_NAME}</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.mapzen.tangram</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>tangram</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>LSRequiresIPhoneOS</key>
+       <true/>
+       <key>UIMainStoryboardFile</key>
+       <string>Main_iPhone</string>
+       <key>UIMainStoryboardFile~ipad</key>
+       <string>Main_iPad</string>
+       <key>UIRequiredDeviceCapabilities</key>
+       <array>
+               <string>opengles-2</string>
+               <string>armv7</string>
+       </array>
+       <key>UIStatusBarHidden</key>
+       <true/>
+       <key>UISupportedInterfaceOrientations</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+       <key>UISupportedInterfaceOrientations~ipad</key>
+       <array>
+               <string>UIInterfaceOrientationPortrait</string>
+               <string>UIInterfaceOrientationPortraitUpsideDown</string>
+               <string>UIInterfaceOrientationLandscapeLeft</string>
+               <string>UIInterfaceOrientationLandscapeRight</string>
+       </array>
+</dict>
+</plist>
diff --git a/platforms/ios/demo/resources/LaunchScreen.xib b/platforms/ios/demo/resources/LaunchScreen.xib
new file mode 100644 (file)
index 0000000..e8d608e
--- /dev/null
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="11201" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES">
+    <dependencies>
+        <deployment identifier="iOS"/>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <objects>
+        <placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="LaunchScreen"/>
+        <placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
+        <view userInteractionEnabled="NO" contentMode="scaleToFill" id="iN0-l3-epB">
+            <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+            <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+            <color key="backgroundColor" red="0.33333333333333331" green="0.33333333333333331" blue="0.33333333333333331" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+            <nil key="simulatedStatusBarMetrics"/>
+            <point key="canvasLocation" x="517" y="561"/>
+        </view>
+    </objects>
+</document>
diff --git a/platforms/ios/demo/resources/Main_iPad.storyboard b/platforms/ios/demo/resources/Main_iPad.storyboard
new file mode 100644 (file)
index 0000000..57f44ca
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15F34" targetRuntime="iOS.CocoaTouch.iPad" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="BV1-FR-VrT">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--GLKit View Controller-->
+        <scene sceneID="tXr-a1-R10">
+            <objects>
+                <glkViewController preferredFramesPerSecond="60" id="BV1-FR-VrT" customClass="MapViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="dWe-On-idd"/>
+                        <viewControllerLayoutGuide type="bottom" id="nZC-s9-Y68"/>
+                    </layoutGuides>
+                    <glkView key="view" contentMode="scaleToFill" id="3se-qz-xqx">
+                        <rect key="frame" x="0.0" y="0.0" width="768" height="1024"/>
+                        <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </glkView>
+                </glkViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="SZV-WD-TEh" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+    <simulatedMetricsContainer key="defaultSimulatedMetrics">
+        <nil key="statusBar"/>
+        <simulatedOrientationMetrics key="orientation"/>
+        <simulatedScreenMetrics key="destination"/>
+    </simulatedMetricsContainer>
+</document>
diff --git a/platforms/ios/demo/resources/Main_iPhone.storyboard b/platforms/ios/demo/resources/Main_iPhone.storyboard
new file mode 100644 (file)
index 0000000..4ec3b8b
--- /dev/null
@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="11201" systemVersion="15F34" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" colorMatched="YES" initialViewController="LVB-YS-i5n">
+    <dependencies>
+        <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="11161"/>
+        <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
+    </dependencies>
+    <scenes>
+        <!--GLKit View Controller-->
+        <scene sceneID="CtS-rA-C9T">
+            <objects>
+                <glkViewController preferredFramesPerSecond="60" id="LVB-YS-i5n" customClass="MapViewController" sceneMemberID="viewController">
+                    <layoutGuides>
+                        <viewControllerLayoutGuide type="top" id="Xaj-7Y-aV7"/>
+                        <viewControllerLayoutGuide type="bottom" id="Rbg-pb-c98"/>
+                    </layoutGuides>
+                    <glkView key="view" contentMode="scaleToFill" id="bdc-N1-crn">
+                        <rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
+                        <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
+                        <color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
+                    </glkView>
+                </glkViewController>
+                <placeholder placeholderIdentifier="IBFirstResponder" id="btX-cZ-eVz" sceneMemberID="firstResponder"/>
+            </objects>
+        </scene>
+    </scenes>
+    <simulatedMetricsContainer key="defaultSimulatedMetrics">
+        <nil key="statusBar"/>
+        <simulatedOrientationMetrics key="orientation"/>
+        <simulatedScreenMetrics key="destination" type="retina4_7.fullscreen"/>
+    </simulatedMetricsContainer>
+</document>
diff --git a/platforms/ios/demo/src/AppDelegate.h b/platforms/ios/demo/src/AppDelegate.h
new file mode 100644 (file)
index 0000000..35dba92
--- /dev/null
@@ -0,0 +1,15 @@
+//
+//  AppDelegate.h
+//  TangramiOS
+//
+//  Created by Matt Blair on 8/25/14.
+//  Copyright (c) 2014 Mapzen. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+@interface AppDelegate : UIResponder <UIApplicationDelegate>
+
+@property (strong, nonatomic) UIWindow *window;
+
+@end
diff --git a/platforms/ios/demo/src/AppDelegate.m b/platforms/ios/demo/src/AppDelegate.m
new file mode 100644 (file)
index 0000000..357f97c
--- /dev/null
@@ -0,0 +1,46 @@
+//
+//  AppDelegate.m
+//  TangramiOS
+//
+//  Created by Matt Blair on 8/25/14.
+//  Copyright (c) 2014 Mapzen. All rights reserved.
+//
+
+#import "AppDelegate.h"
+
+@implementation AppDelegate
+
+- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
+{
+    // Override point for customization after application launch.
+    return YES;
+}
+                            
+- (void)applicationWillResignActive:(UIApplication *)application
+{
+    // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
+    // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
+}
+
+- (void)applicationDidEnterBackground:(UIApplication *)application
+{
+    // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 
+    // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
+}
+
+- (void)applicationWillEnterForeground:(UIApplication *)application
+{
+    // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
+}
+
+- (void)applicationDidBecomeActive:(UIApplication *)application
+{
+    // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
+}
+
+- (void)applicationWillTerminate:(UIApplication *)application
+{
+    // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
+}
+
+@end
diff --git a/platforms/ios/demo/src/MapViewController.h b/platforms/ios/demo/src/MapViewController.h
new file mode 100644 (file)
index 0000000..c90bea5
--- /dev/null
@@ -0,0 +1,33 @@
+//
+//  MapViewController.h
+//
+//  Created by Karim Naaji on 10/12/16.
+//  Copyright © 2016 Karim Naaji. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <TangramMap/TangramMap.h>
+
+@interface MapViewControllerDelegate : NSObject <TGMapViewDelegate>
+
+- (void)mapView:(TGMapViewController *)mapView didLoadSceneAsync:(NSString *)scene;
+- (void)mapViewDidCompleteLoading:(TGMapViewController *)mapView;
+- (void)mapView:(TGMapViewController *)mapView didSelectFeature:(NSDictionary *)feature atScreenPosition:(CGPoint)position;
+- (void)mapView:(TGMapViewController *)mapView didSelectLabel:(TGLabelPickResult *)labelPickResult atScreenPosition:(CGPoint)position;
+- (void)mapView:(TGMapViewController *)mapView didSelectMarker:(TGMarkerPickResult *)markerPickResult atScreenPosition:(TGGeoPoint)position;
+- (void)mapView:(TGMapViewController *)view didCaptureScreenshot:(UIImage *)screenshot;
+- (void)mapView:(TGMapViewController *)mapView didFailSceneUpdateWithError:(NSError *)sceneUpdateError;
+
+@end
+
+@interface MapViewControllerRecognizerDelegate : NSObject <TGRecognizerDelegate>
+
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeSingleTapGesture:(CGPoint)location;
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeLongPressGesture:(CGPoint)location;
+
+@end
+
+@interface MapViewController : TGMapViewController
+
+@end
+
diff --git a/platforms/ios/demo/src/MapViewController.m b/platforms/ios/demo/src/MapViewController.m
new file mode 100644 (file)
index 0000000..75a2a18
--- /dev/null
@@ -0,0 +1,211 @@
+//
+//  MapViewController.m
+//
+//  Created by Karim Naaji on 10/12/16.
+//  Copyright © 2016 Karim Naaji. All rights reserved.
+//
+
+#import "MapViewController.h"
+
+@interface MapViewController ()
+
+@property (assign, nonatomic) TGMarker* markerPolygon;
+@property (strong, nonatomic) TGMapData* mapData;
+
+- (void)addAlert:(NSString *)message withTitle:(NSString *)title;
+
+@end
+
+@implementation MapViewControllerDelegate
+
+- (void)mapView:(TGMapViewController *)view didCaptureScreenshot:(UIImage *)screenshot
+{
+    NSLog(@"Did capture screenshot");
+}
+
+- (void)mapView:(TGMapViewController *)mapView didFailSceneUpdateWithError:(NSError *)sceneUpdateError;
+{
+    NSLog(@"Scene update error for update with error %@", sceneUpdateError);
+}
+
+- (void)mapViewDidCompleteLoading:(TGMapViewController *)mapView
+{
+    NSLog(@"Did complete view");
+    [mapView captureScreenshot:YES];
+}
+
+- (void)mapView:(TGMapViewController *)mapView didLoadSceneAsync:(NSString *)scene
+{
+    NSLog(@"Did load scene async %@", scene);
+
+    TGGeoPoint newYork;
+    newYork.longitude = -74.00976419448854;
+    newYork.latitude = 40.70532700869127;
+
+    TGGeoPoint cairo;
+    cairo.longitude = 30.00;
+    cairo.latitude = 31.25;
+
+    [mapView setZoom:15];
+    [mapView setPosition:newYork];
+
+    // Add a client data source, named 'mz_route_line_transit'
+    MapViewController* vc = (MapViewController *)mapView;
+    vc.mapData = [mapView addDataLayer:@"mz_route_line_transit"];
+}
+
+- (void)mapView:(TGMapViewController *)mapView didSelectMarker:(TGMarkerPickResult *)markerPickResult atScreenPosition:(TGGeoPoint)position;
+{
+    if (!markerPickResult) {
+        return;
+    }
+
+    NSString* message = [NSString stringWithFormat:@"Marker %f %f",
+        markerPickResult.marker.point.latitude,
+        markerPickResult.marker.point.longitude];
+
+    [(MapViewController*)mapView addAlert:message withTitle:@"Marker pick callback"];
+}
+
+- (void)mapView:(TGMapViewController *)mapView didSelectLabel:(TGLabelPickResult *)labelPickResult atScreenPosition:(CGPoint)position
+{
+    if (!labelPickResult) { return; }
+
+    NSLog(@"Picked label:");
+
+    for (NSString* key in [labelPickResult properties]) {
+        NSLog(@"\t%@ -- %@", key, [[labelPickResult properties] objectForKey:key]);
+
+        if ([key isEqualToString:@"name"]) {
+            [(MapViewController*)mapView addAlert:[[labelPickResult properties] objectForKey:key] withTitle:@"Label selection callback"];
+        }
+    }
+}
+
+- (void)mapView:(TGMapViewController *)mapView didSelectFeature:(NSDictionary *)feature atScreenPosition:(CGPoint)position
+{
+    // Not feature selected
+    if (!feature) { return; }
+
+    NSLog(@"Picked features:");
+
+    for (id key in feature) {
+        NSLog(@"\t%@ -- %@", key, [feature objectForKey:key]);
+
+        if ([key isEqualToString:@"name"]) {
+            [(MapViewController*)mapView addAlert:[[feature objectForKey:key] objectForKey:key] withTitle:@"Feature selection callback"];
+        }
+    }
+}
+
+@end
+
+@implementation MapViewControllerRecognizerDelegate
+
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeSingleTapGesture:(CGPoint)location
+{
+    NSLog(@"Did tap at %f %f", location.x, location.y);
+
+    MapViewController* vc = (MapViewController *)view;
+
+    TGGeoPoint coordinates = [vc screenPositionToLngLat:location];
+
+    // Add polyline data layer
+    {
+        TGFeatureProperties* properties = @{ @"type" : @"line", @"color" : @"#D2655F" };
+        static TGGeoPoint lastCoordinates = {NAN, NAN};
+
+        if (!isnan(lastCoordinates.latitude)) {
+            TGGeoPolyline* line = [[TGGeoPolyline alloc] init];
+
+            [line addPoint:lastCoordinates];
+            [line addPoint:coordinates];
+
+            [vc.mapData addPolyline:line withProperties:properties];
+        }
+
+        lastCoordinates = coordinates;
+    }
+
+    // Add polygon marker
+    {
+        if (!vc.markerPolygon) {
+            vc.markerPolygon = [view markerAdd];
+            vc.markerPolygon.stylingString = @"{ style: 'polygons', color: 'blue', order: 500 }";
+        }
+        static TGGeoPolygon* polygon = nil;
+        if (!polygon) { polygon = [[TGGeoPolygon alloc] init]; }
+
+        if ([polygon count] == 0) {
+            [polygon startPath:coordinates withSize:5];
+        } else if ([polygon count] % 5 == 0) {
+            vc.markerPolygon.polygon = polygon;
+            [polygon removeAll];
+            [polygon startPath:coordinates withSize:5];
+        } else {
+            [polygon addPoint:coordinates];
+        }
+    }
+
+    // Add point marker
+    {
+        TGMarker* markerPoint = [view markerAdd];
+        markerPoint.stylingString = @"{ style: 'points', color: 'white', size: [25px, 25px], collide: false }";
+        markerPoint.point = coordinates;
+    }
+
+    // Request feature picking
+    [vc pickFeatureAt:location];
+    [vc pickLabelAt:location];
+    // [vc pickMarkerAt:location];
+}
+
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeLongPressGesture:(CGPoint)location
+{
+    NSLog(@"Did long press at %f %f", location.x, location.y);
+}
+
+@end
+
+@implementation MapViewController
+
+- (void)addAlert:(NSString *)message withTitle:(NSString *)title
+{
+    UIAlertController *alert = [[UIAlertController alloc] init];
+
+    alert.title = title;
+    alert.message = message;
+
+    UIAlertAction* okAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleCancel handler:nil];
+    [alert addAction:okAction];
+
+    [self presentViewController:alert animated:YES completion:nil];
+}
+
+- (void)viewWillAppear:(BOOL)animated
+{
+    NSString* configPListPath = [[NSBundle mainBundle] pathForResource: @"Config" ofType: @"plist"];
+    NSMutableDictionary* configDict =[[NSMutableDictionary alloc] initWithContentsOfFile:configPListPath];
+    NSString* apiKey = [configDict valueForKey:@"MapzenApiKey"];
+    NSAssert(apiKey, @"Please provide a valid API key by setting the environment variable MAPZEN_API_KEY at build time");
+
+    NSMutableArray<TGSceneUpdate *>* updates = [[NSMutableArray alloc]init];
+    [updates addObject:[[TGSceneUpdate alloc]initWithPath:@"global.sdk_mapzen_api_key" value:apiKey]];
+
+    [super loadSceneFileAsync:@"https://tangrams.github.io/walkabout-style/walkabout-style.yaml" sceneUpdates:updates];
+}
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+
+    self.mapViewDelegate = [[MapViewControllerDelegate alloc] init];
+    self.gestureDelegate = [[MapViewControllerRecognizerDelegate alloc] init];
+}
+
+- (void)didReceiveMemoryWarning
+{
+    [super didReceiveMemoryWarning];
+}
+
+@end
diff --git a/platforms/ios/demo/src/main.m b/platforms/ios/demo/src/main.m
new file mode 100644 (file)
index 0000000..bf90907
--- /dev/null
@@ -0,0 +1,18 @@
+//
+//  main.m
+//  TangramiOS
+//
+//  Created by Matt Blair on 8/25/14.
+//  Copyright (c) 2014 Mapzen. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+#import "AppDelegate.h"
+
+int main(int argc, char * argv[])
+{
+    @autoreleasepool {
+        return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
+    }
+}
diff --git a/platforms/ios/framework/Info.plist b/platforms/ios/framework/Info.plist
new file mode 100644 (file)
index 0000000..e2b28b7
--- /dev/null
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleExecutable</key>
+       <string>$(EXECUTABLE_NAME)</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.mapzen.tangramMap</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>$(PRODUCT_NAME)</string>
+       <key>CFBundlePackageType</key>
+       <string>FMWK</string>
+       <key>CFBundleShortVersionString</key>
+       <string>$(CURRENT_PROJECT_VERSION)</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>$(CURRENT_PROJECT_VERSION)</string>
+       <key>NSPrincipalClass</key>
+       <string></string>
+</dict>
+</plist>
diff --git a/platforms/ios/framework/Modules/module.modulemap b/platforms/ios/framework/Modules/module.modulemap
new file mode 100644 (file)
index 0000000..ee0baa7
--- /dev/null
@@ -0,0 +1,6 @@
+framework module TangramMap {
+  umbrella header "TangramMap.h"
+
+  export *
+  module * { export * }
+}
diff --git a/platforms/ios/framework/TangramMap.h b/platforms/ios/framework/TangramMap.h
new file mode 100644 (file)
index 0000000..df87101
--- /dev/null
@@ -0,0 +1,30 @@
+//
+//  TangramMap.h
+//  TangramMap
+//
+//  Created by Matt Smollinger on 7/8/16.
+//  Updated by Karim Naaji on 2/28/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+
+/// Project version number for TangramMap.
+FOUNDATION_EXPORT double TangramMapVersionNumber;
+
+/// Project version string for TangramMap.
+FOUNDATION_EXPORT const unsigned char TangramMapVersionString[];
+
+#import <TangramMap/TGMapViewController.h>
+#import <TangramMap/TGMapData.h>
+#import <TangramMap/TGGeoPoint.h>
+#import <TangramMap/TGGeoPolygon.h>
+#import <TangramMap/TGGeoPolyline.h>
+#import <TangramMap/TGTypes.h>
+#import <TangramMap/TGHttpHandler.h>
+#import <TangramMap/TGMarker.h>
+#import <TangramMap/TGMapData.h>
+#import <TangramMap/TGSceneUpdate.h>
+#import <TangramMap/TGMarkerPickResult.h>
+#import <TangramMap/TGLabelPickResult.h>
+
diff --git a/platforms/ios/jazzy.yml b/platforms/ios/jazzy.yml
new file mode 100644 (file)
index 0000000..128a126
--- /dev/null
@@ -0,0 +1,15 @@
+module: Mapzen
+author: Mapzen
+theme: fullwidth
+author_url: https://www.mapzen.com/
+output: ../../build/ios-docs/
+github_url: https://github.com/tangrams/tangram-es
+copyright: '© 2017 [Mapzen](https://www.mapzen.com/).'
+head: |
+    <link rel='shortcut icon' href='https://mapzen.com/common/styleguide/images/favicon.ico' type='image/x-icon' />
+objc: Yes
+framework_root: ./src/
+sdk: iphonesimulator
+umbrella_header: ./framework/TangramMap.h
+skip_undocumented: Yes
+#hide_documentation_coverage: Yes
diff --git a/platforms/ios/release-checklist.md b/platforms/ios/release-checklist.md
new file mode 100644 (file)
index 0000000..f380381
--- /dev/null
@@ -0,0 +1,23 @@
+# Tangram ES (iOS) Release Checklist
+
+## Requirements
+- Have Xcode installed
+- Have cocoapods installed
+- Have ownership privileges to update the cocoapods trunk spec
+
+## Steps
+1. Update the version tag `${FRAMEWORK_VERSION}` that gets injected through CMake to the .plist file
+of the framework for the release you're doing. Submit this as a PR for release.
+2. Build the iOS universal framework for release ( `make clean  && make ios-framework-universal RELEASE=1` ).
+3. Take the *universal* framework file and copy it into a branch on the framework holding repo
+(https://github.com/tangrams/ios-framework). Submit this for PR following the convention seen in other
+PRs for release notes ( https://github.com/tangrams/ios-framework/pull/17 )
+4. Once #5's PR merges to master, tag the release with the same version number as #2.
+5. Update the Tangram-es.podspec file version number with that same tag, and run `pod spec lint` to
+make sure everything is happy. Fix issues if not happy (eventually we should document known possible
+issues). Submit to PR once lint is clean.
+6. Once #6 PR merges, push the updated pod spec to trunk: `pod trunk push Tangram-es.podspec`
+7. Submit a PR to increment the version number for #1's plist file. We add `-dev` to the end of the
+version numbers while in development.
+8. Before publishing the Tangram release, add the zipped version of both Debug and Release flavors
+to the Download attachments of the release.
diff --git a/platforms/ios/src/TangramMap/TGFontConverter.h b/platforms/ios/src/TangramMap/TGFontConverter.h
new file mode 100644 (file)
index 0000000..c103244
--- /dev/null
@@ -0,0 +1,24 @@
+//
+//  TGFontConverter.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/01/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <CoreGraphics/CoreGraphics.h>
+
+#import <vector>
+
+NS_ASSUME_NONNULL_BEGIN
+
+@interface TGFontConverter : NSObject
+
++ (std::vector<char>)fontDataForCGFont:(CGFontRef)cgFont;
+
+NS_ASSUME_NONNULL_END
+
+@end
+
+
diff --git a/platforms/ios/src/TangramMap/TGFontConverter.mm b/platforms/ios/src/TangramMap/TGFontConverter.mm
new file mode 100644 (file)
index 0000000..aed0381
--- /dev/null
@@ -0,0 +1,164 @@
+//
+//  TGFontConverter.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/01/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGFontConverter.h"
+
+#import <cstdio>
+
+struct FontHeader {
+    int32_t version;
+    uint16_t numTables;
+    uint16_t searchRange;
+    uint16_t entrySelector;
+    uint16_t rangeShift;
+};
+
+typedef struct FontHeader FontHeader;
+
+struct TableEntry {
+    uint32_t tag;
+    uint32_t checkSum;
+    uint32_t offset;
+    uint32_t length;
+};
+
+typedef struct TableEntry TableEntry;
+
+static uint32_t calcTableCheckSum(const uint32_t* table, uint32_t numberOfBytesInTable)
+{
+    uint32_t sum = 0;
+    uint32_t nLongs = (numberOfBytesInTable + 3) / 4;
+    while (nLongs-- > 0) {
+       sum += CFSwapInt32HostToBig(*table++);
+    }
+    return sum;
+}
+
+static uint32_t calcTableDataRefCheckSum(CFDataRef dataRef)
+{
+    const uint32_t* dataBuff = (const uint32_t *)CFDataGetBytePtr(dataRef);
+    uint32_t dataLength = (uint32_t)CFDataGetLength(dataRef);
+    return calcTableCheckSum(dataBuff, dataLength);
+}
+
+@implementation TGFontConverter
+
+// References:
+// https://skia.googlesource.com/skia/+/master/src/ports/SkFontHost_mac.cpp
+// https://gist.github.com/Jyczeal/1892760
+
++ (std::vector<char>)fontDataForCGFont:(CGFontRef)cgFont
+{
+    if (!cgFont) {
+        return {};
+    }
+
+    CFRetain(cgFont);
+
+    CFArrayRef tags = CGFontCopyTableTags(cgFont);
+    int tableCount = CFArrayGetCount(tags);
+
+    std::vector<size_t> tableSizes;
+    tableSizes.resize(tableCount);
+    std::vector<CFDataRef> dataRefs;
+    dataRefs.resize(tableCount);
+
+    BOOL containsCFFTable = NO;
+
+    size_t totalSize = sizeof(FontHeader) + sizeof(TableEntry) * tableCount;
+
+    for (int index = 0; index < tableCount; ++index) {
+        size_t tableSize = 0;
+        intptr_t aTag = (intptr_t)CFArrayGetValueAtIndex(tags, index);
+
+        if (aTag == 'CFF ' && !containsCFFTable) {
+            containsCFFTable = YES;
+        }
+
+        dataRefs[index] = CGFontCopyTableForTag(cgFont, aTag);
+
+        if (dataRefs[index] != NULL) {
+            tableSize = CFDataGetLength(dataRefs[index]);
+        }
+
+        totalSize += (tableSize + 3) & ~3;
+
+        tableSizes[index] = tableSize;
+    }
+
+    std::vector<char> data;
+    data.resize(totalSize);
+    unsigned char* stream = reinterpret_cast<unsigned char*>(data.data());
+
+    char* dataStart = (char*)stream;
+    char* dataPtr = dataStart;
+
+    // Write font header (also called sfnt header, offset subtable)
+    FontHeader* offsetTable = (FontHeader*)dataPtr;
+
+    // Compute font header entries
+    // c.f: Organization of an OpenType Font in:
+    // https://www.microsoft.com/typography/otspec/otff.htm
+    {
+        // (Maximum power of 2 <= numTables) x 16
+        uint16_t entrySelector = 0;
+        // Log2(maximum power of 2 <= numTables).
+        uint16_t searchRange = 1;
+
+        while (searchRange < tableCount >> 1) {
+            entrySelector++;
+            searchRange <<= 1;
+        }
+        searchRange <<= 4;
+
+        // NumTables x 16-searchRange.
+        uint16_t rangeShift = (tableCount << 4) - searchRange;
+
+        // OpenType Font contains CFF Table use 'OTTO' as version, and with .otf extension
+        // otherwise 0001 0000
+        offsetTable->version = containsCFFTable ? 'OTTO' : CFSwapInt16HostToBig(1);
+        offsetTable->numTables = CFSwapInt16HostToBig((uint16_t)tableCount);
+        offsetTable->searchRange = CFSwapInt16HostToBig((uint16_t)searchRange);
+        offsetTable->entrySelector = CFSwapInt16HostToBig((uint16_t)entrySelector);
+        offsetTable->rangeShift = CFSwapInt16HostToBig((uint16_t)rangeShift);
+    }
+
+    dataPtr += sizeof(FontHeader);
+
+    // Write tables
+    TableEntry* entry = (TableEntry*)dataPtr;
+    dataPtr += sizeof(TableEntry) * tableCount;
+
+    for (int index = 0; index < tableCount; ++index) {
+
+        intptr_t aTag = (intptr_t)CFArrayGetValueAtIndex(tags, index);
+        CFDataRef tableDataRef = dataRefs[index];
+
+        if (tableDataRef == NULL) { continue; }
+
+        size_t tableSize = CFDataGetLength(tableDataRef);
+
+        memcpy(dataPtr, CFDataGetBytePtr(tableDataRef), tableSize);
+
+        entry->tag = CFSwapInt32HostToBig((uint32_t)aTag);
+        entry->checkSum = CFSwapInt32HostToBig(calcTableCheckSum((uint32_t *)dataPtr, tableSize));
+
+        uint32_t offset = dataPtr - dataStart;
+        entry->offset = CFSwapInt32HostToBig((uint32_t)offset);
+        entry->length = CFSwapInt32HostToBig((uint32_t)tableSize);
+        dataPtr += (tableSize + 3) & ~3;
+        ++entry;
+        CFRelease(tableDataRef);
+    }
+
+    CFRelease(cgFont);
+
+    return data;
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGGeoPoint.h b/platforms/ios/src/TangramMap/TGGeoPoint.h
new file mode 100644 (file)
index 0000000..df7a062
--- /dev/null
@@ -0,0 +1,35 @@
+//
+//  TGGeoPoint.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/27/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#pragma once
+
+/// Structure holding a geographic coordinate (longitude and latitude)
+struct TGGeoPoint {
+    /// The geographic longitude
+    double longitude;
+    /// The geographic latitude
+    double latitude;
+};
+
+typedef struct TGGeoPoint TGGeoPoint;
+
+/**
+ Helper to create a `TGGeoPoint` from a longitude and latitude
+
+ @param lon the longitude coordinate
+ @param lat the latitude coordinate
+ @return a `TGGeoPoint` holding the longitude and latitude
+ */
+static inline TGGeoPoint TGGeoPointMake(double lon, double lat)
+{
+    TGGeoPoint p;
+    p.latitude = lat;
+    p.longitude = lon;
+    return p;
+}
+
diff --git a/platforms/ios/src/TangramMap/TGGeoPolygon.h b/platforms/ios/src/TangramMap/TGGeoPolygon.h
new file mode 100644 (file)
index 0000000..4fc98e9
--- /dev/null
@@ -0,0 +1,88 @@
+//
+//  TGGeoPolygon.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/27/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "TGGeoPoint.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Helper class to contain a polygon geometry for use in `-[TGMarker polygon]`.
+
+ The polygon winding order and internal polygons must be set according to the <a href="http://geojson.org/geojson-spec.html#polygon">
+ GeoJSON specification</a>.
+ */
+@interface TGGeoPolygon : NSObject
+
+/**
+ Inits a polygon and allocates enough memory to hold `size` geographic coordinates in the polygon paths.
+ */
+- (instancetype)initWithSize:(unsigned int)size;
+
+/**
+ Starts a new polygon path for a given `TGGeoPoint`.
+
+ @param latlon the coordinate to start a polygon path
+ */
+- (void)startPath:(TGGeoPoint)latlon;
+
+/**
+ Starts a new polygon path for a given `TGGeoPoint` and allocate enough memory to hold `size` coordinates
+ in the polygon geometry.
+
+ @param latlon the coordinate to start a polygon path
+ @param size the size of the polygon path
+ */
+- (void)startPath:(TGGeoPoint)latlon withSize:(unsigned int)size;
+
+/**
+ Adds a single coordinate to the current polygon path.
+
+ @param latlon the coordinate to add to the current path
+
+ @note This operation is a no-op if no polygon path were already started.
+ */
+- (void)addPoint:(TGGeoPoint)latlon;
+
+/**
+ Returns a pointer to a sequence of `TGGeoPoint` with a total array length equal to `-[TGGeoPolygon count:]`.
+
+ @return a pointer to the list of polygons coordinates
+ */
+- (TGGeoPoint*)coordinates;
+
+/**
+ The list of polygon `rings` contained in this geometry.
+ The sum of the values in `-[TGGeoPolygon rings:]` sum up to `-[TGeoPolygon count:]`.
+
+ @return a pointer to the list of polygon rings.
+ */
+- (int *)rings;
+
+/**
+ The polygon coordinates count.
+
+ @return the number of geographic coordinates of this polygon
+ */
+- (NSUInteger)count;
+
+/**
+ The polygon rings count.
+
+ @return the number of rings of this polygon
+ */
+- (NSUInteger)ringsCount;
+
+/**
+ Removes all coordinates and rings of this polygon.
+ */
+- (void)removeAll;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGGeoPolygon.mm b/platforms/ios/src/TangramMap/TGGeoPolygon.mm
new file mode 100644 (file)
index 0000000..d72028e
--- /dev/null
@@ -0,0 +1,80 @@
+//
+//  TGGeoPolygon.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/27/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGGeoPolygon.h"
+
+#include <vector>
+
+@interface TGGeoPolygon () {
+    std::vector<TGGeoPoint> coordinates;
+    std::vector<int> rings;
+}
+
+@end
+
+@implementation TGGeoPolygon
+
+- (instancetype)initWithSize:(unsigned int)size
+{
+    self = [super init];
+
+    if (self) {
+        coordinates.reserve(size);
+    }
+
+    return self;
+}
+
+- (void)startPath:(TGGeoPoint)latlon withSize:(unsigned int)size
+{
+    coordinates.reserve(coordinates.size() + size);
+    coordinates.push_back(latlon);
+
+    rings.emplace_back(1);
+}
+
+- (void)startPath:(TGGeoPoint)latlon
+{
+    [self startPath:latlon withSize:0];
+}
+
+- (void)addPoint:(TGGeoPoint)latlon
+{
+    if (rings.size() == 0) { return; }
+
+    coordinates.push_back(latlon);
+    rings.back()++;
+}
+
+- (NSUInteger)count
+{
+    return coordinates.size();
+}
+
+- (NSUInteger)ringsCount
+{
+    return rings.size();
+}
+
+- (TGGeoPoint *)coordinates
+{
+    return coordinates.data();
+}
+
+- (int *)rings
+{
+    return rings.data();
+}
+
+- (void)removeAll
+{
+    coordinates.clear();
+    rings.clear();
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGGeoPolyline.h b/platforms/ios/src/TangramMap/TGGeoPolyline.h
new file mode 100644 (file)
index 0000000..404e63a
--- /dev/null
@@ -0,0 +1,57 @@
+//
+//  TGGeoPolyline.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/27/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "TGGeoPoint.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Helper class to contain a polyline geometry for use in `-[TGMarker polyline]`.
+
+ Set the geometry of a marker to a polyline along the given coordinates; _coordinates is a
+ pointer to a sequence of _count LngLats; markers can have their geometry set multiple times
+ with possibly different geometry types; returns true if the marker ID was found and
+ successfully updated, otherwise returns false.
+ */
+@interface TGGeoPolyline : NSObject
+
+/**
+ Inits a `TGGeoPolyline` and allocate enough memory to hold `size` geographic coordinates.
+ */
+- (instancetype)initWithSize:(unsigned int)size;
+
+/**
+ Adds a geographic coordinate to the polyline.
+
+ @param latlon the geographic coordinate to add to this polyline
+ */
+- (void)addPoint:(TGGeoPoint)latlon;
+
+/**
+ Gets the number of geographic coordinates describing this polyline.
+
+ @return the number of geographic coordinates in this polyline
+ */
+- (NSUInteger)count;
+
+/**
+ Gets a pointer to the geographic coordinates describing this poyline of array length `-[TGGeoPolyline count:]`.
+
+ @return a pointer to the list of geographic coordinates describing this polyline
+ */
+- (TGGeoPoint*)coordinates;
+
+/**
+ Removes all coordinates of this polyline.
+ */
+- (void)removeAll;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGGeoPolyline.mm b/platforms/ios/src/TangramMap/TGGeoPolyline.mm
new file mode 100644 (file)
index 0000000..61aba08
--- /dev/null
@@ -0,0 +1,53 @@
+//
+//  TGGeoPolyline.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/27/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGGeoPolyline.h"
+
+#include <vector>
+
+@interface TGGeoPolyline () {
+    std::vector<TGGeoPoint> coordinates;
+}
+
+@end
+
+@implementation TGGeoPolyline
+
+- (instancetype)initWithSize:(unsigned int)size
+{
+    self = [super init];
+
+    if (self) {
+        coordinates.reserve(size);
+    }
+
+    return self;
+}
+
+- (void)addPoint:(TGGeoPoint)latlon
+{
+    coordinates.push_back(latlon);
+}
+
+- (NSUInteger)count
+{
+    return coordinates.size();
+}
+
+- (TGGeoPoint*)coordinates
+{
+    return coordinates.data();
+}
+
+- (void)removeAll
+{
+    coordinates.clear();
+}
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGHelpers.h b/platforms/ios/src/TangramMap/TGHelpers.h
new file mode 100644 (file)
index 0000000..cebf167
--- /dev/null
@@ -0,0 +1,20 @@
+//
+//  TGHelpers.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/18/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMapViewController.h"
+#import "tangram.h"
+
+@interface TGHelpers : NSObject
+
++ (Tangram::EaseType)convertEaseTypeFrom:(TGEaseType)ease;
++ (TGError)convertSceneUpdateErrorTypeFrom:(Tangram::Error)error;
++ (NSError *)errorFromSceneUpdateError:(Tangram::SceneUpdateError)updateError;
+
+@end
+
+
diff --git a/platforms/ios/src/TangramMap/TGHelpers.mm b/platforms/ios/src/TangramMap/TGHelpers.mm
new file mode 100644 (file)
index 0000000..748494b
--- /dev/null
@@ -0,0 +1,58 @@
+//
+//  TGHelpers.m
+//  TangramMap
+//
+//  Created by Karim Naaji on 10/18/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGHelpers.h"
+#import "TGTypes.h"
+
+@implementation TGHelpers
+
++ (Tangram::EaseType)convertEaseTypeFrom:(TGEaseType)ease;
+{
+    switch (ease) {
+        case TGEaseTypeLinear:
+            return Tangram::EaseType::linear;
+        case TGEaseTypeSine:
+            return Tangram::EaseType::sine;
+        case TGEaseTypeQuint:
+            return Tangram::EaseType::quint;
+        case TGEaseTypeCubic:
+            return Tangram::EaseType::cubic;
+        default:
+            return Tangram::EaseType::cubic;
+    }
+}
+
++ (TGError)convertTGErrorTypeFrom:(Tangram::Error)error
+{
+    switch (error) {
+        case Tangram::Error::scene_update_path_yaml_syntax_error:
+            return TGErrorSceneUpdatePathYAMLSyntaxError;
+        case Tangram::Error::scene_update_path_not_found:
+            return TGErrorSceneUpdatePathNotFound;
+        case Tangram::Error::scene_update_value_yaml_syntax_error:
+            return TGErrorSceneUpdateValueYAMLSyntaxError;
+    }
+}
+
++ (NSError *)errorFromSceneUpdateError:(Tangram::SceneUpdateError)updateError
+{
+    NSString* path = [NSString stringWithUTF8String:updateError.update.path.c_str()];
+    NSString* value = [NSString stringWithUTF8String:updateError.update.value.c_str()];
+    TGSceneUpdate* udpate = [[TGSceneUpdate alloc] initWithPath:path value:value];
+
+    NSMutableDictionary* userInfo = [[NSMutableDictionary alloc] init];
+    [userInfo setObject:udpate forKey:@"TGUpdate"];
+
+    NSError* error = [NSError errorWithDomain:TGErrorDomain
+                                         code:(NSInteger)updateError.error
+                                     userInfo:userInfo];
+
+    return error;
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGHttpHandler.h b/platforms/ios/src/TangramMap/TGHttpHandler.h
new file mode 100644 (file)
index 0000000..6f082cc
--- /dev/null
@@ -0,0 +1,78 @@
+//
+//  TGHttpHandler.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/23/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/**
+ A network request completion callback, called when a download request of `TGHttpHandler`
+ completed an asynchronous request.
+*/
+typedef void(^TGDownloadCompletionHandler)(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error);
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A configurable http handler used in a `TGMapViewController`.
+
+ `TGMapViewController` provides a default http handler with the following configuration:
+
+    - cache location: `/tangram_cache`
+    - cache memory capacity: 4Mb
+    - cache disk capacity: 30Mb
+
+ To change this configuration, create a new http handler and set it to the map view with
+ `-[TGMapViewController httpHandler]`.
+ */
+@interface TGHttpHandler : NSObject
+
+/**
+ Initializes a http handler with the default configuration.
+
+ @return an initialized http handler
+ */
+- (instancetype)init;
+
+/**
+ Initializes a http handler with a user defined configuration.
+
+ @param cachePath the location of the path in the client application bundle
+ @param memoryCapacity the memory capacity of the cache, in bytes
+ @param diskCapacity the disk capacity of cache, in bytes
+ @return an initalized http handler with the provided configuration
+ */
+- (instancetype)initWithCachePath:(NSString *)cachePath cacheMemoryCapacity:(NSUInteger)memoryCapacity cacheDiskCapacity:(NSUInteger)diskCapacity;
+
+/**
+ Creates an asynchronous download request.
+
+ @param url the URL of the download request
+ @param completionHandler a handler to be called once the network request completed
+
+ @note This method will be automatically called by the map view instance.
+ */
+- (void)downloadRequestAsync:(NSString *)url completionHandler:(TGDownloadCompletionHandler)completionHandler;
+
+/**
+ Cancels a download request for a specific URL.
+
+ @param url the URL to cancel the network request for
+ */
+- (void)cancelDownloadRequestAsync:(NSString *)url;
+
+/**
+ Updates the http handler cache configuration.
+
+ @param cachePath the location of the path in the client application bundle
+ @param memoryCapacity the memory capacity of the cache, in bytes
+ @param diskCapacity the disk capacity of cache, in bytes
+ */
+- (void)setCachePath:(NSString *)cachePath cacheMemoryCapacity:(NSUInteger)memoryCapacity cacheDiskCapacity:(NSUInteger)diskCapacity;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGHttpHandler.mm b/platforms/ios/src/TangramMap/TGHttpHandler.mm
new file mode 100644 (file)
index 0000000..95c5d7c
--- /dev/null
@@ -0,0 +1,87 @@
+//
+//  TGHttpHandler.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/23/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGHttpHandler.h"
+
+@interface TGHttpHandler()
+
+@property (strong, nonatomic) NSURLSession* session;
+@property (strong, nonatomic) NSURLSessionConfiguration* configuration;
+
++ (NSURLSessionConfiguration*)defaultConfiguration;
+
+@end
+
+@implementation TGHttpHandler
+
+- (instancetype)init
+{
+    self = [super init];
+
+    if (self) {
+        self.configuration = [TGHttpHandler defaultSessionConfiguration];
+        self.session = [NSURLSession sessionWithConfiguration:self.configuration];
+    }
+
+    return self;
+}
+
+- (instancetype)initWithCachePath:(NSString*)cachePath cacheMemoryCapacity:(NSUInteger)memoryCapacity cacheDiskCapacity:(NSUInteger)diskCapacity
+{
+    self = [super init];
+
+    if (self) {
+        self.configuration = [TGHttpHandler defaultSessionConfiguration];
+        [self setCachePath:cachePath cacheMemoryCapacity:memoryCapacity cacheDiskCapacity:diskCapacity];
+        self.session = [NSURLSession sessionWithConfiguration:self.configuration];
+    }
+
+    return self;
+}
+
++ (NSURLSessionConfiguration*)defaultSessionConfiguration
+{
+    NSURLSessionConfiguration* sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
+
+    sessionConfiguration.timeoutIntervalForRequest = 30;
+    sessionConfiguration.timeoutIntervalForResource = 60;
+
+    return sessionConfiguration;
+}
+
+- (void)setCachePath:(NSString*)cachePath cacheMemoryCapacity:(NSUInteger)memoryCapacity cacheDiskCapacity:(NSUInteger)diskCapacity
+{
+    NSURLCache* tileCache = [[NSURLCache alloc] initWithMemoryCapacity:memoryCapacity
+                                                          diskCapacity:diskCapacity
+                                                              diskPath:cachePath];
+
+    self.configuration.URLCache = tileCache;
+    self.configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
+}
+
+- (void)downloadRequestAsync:(NSString*)url completionHandler:(TGDownloadCompletionHandler)completionHandler
+{
+    NSURLSessionDataTask* dataTask = [self.session dataTaskWithURL:[NSURL URLWithString:url]
+                                                                      completionHandler:completionHandler];
+
+    [dataTask resume];
+}
+
+- (void)cancelDownloadRequestAsync:(NSString*)url
+{
+    [self.session getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks) {
+        for (NSURLSessionTask* task in dataTasks) {
+            if ([[task originalRequest].URL.absoluteString isEqualToString:url]) {
+                [task cancel];
+                break;
+            }
+        }
+    }];
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGLabelPickResult+Internal.h b/platforms/ios/src/TangramMap/TGLabelPickResult+Internal.h
new file mode 100644 (file)
index 0000000..3bf06f5
--- /dev/null
@@ -0,0 +1,32 @@
+//
+//  TGLabelPickResult+Internal.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/27/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGLabelPickResult.h"
+
+@interface TGLabelPickResult ()
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Initializes a `TGLabelPickResult`.
+
+ @param coordinates the geographic coordinates of the label pick result
+ @param type the type of the label (text or icon)
+ @param properties the set of properties associated to this label, keyed by their name
+
+ @return an initialized `TGLabelPickResult`
+
+ @note You shouldn't have to create a `TGLabelPickResult` yourself, those are returned as a result to
+ a selection query on the `TGMapViewController` and initialized by the latter.
+ */
+- (instancetype) initWithCoordinates:(TGGeoPoint)coordinates type:(TGLabelType)type properties:(TGFeatureProperties *)properties;
+
+NS_ASSUME_NONNULL_END
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGLabelPickResult.h b/platforms/ios/src/TangramMap/TGLabelPickResult.h
new file mode 100644 (file)
index 0000000..51ba4f6
--- /dev/null
@@ -0,0 +1,43 @@
+//
+//  TGLabelPickResult.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/02/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "TGGeoPoint.h"
+#import "TGMapData.h"
+
+/**
+ A label type used to differentiate icon and text labels when selecting them on a map view
+ */
+typedef NS_ENUM(NSInteger, TGLabelType) {
+    /// A type for icon labels (sprites)
+    TGLabelTypeIcon = 0,
+    /// A type for text labels
+    TGLabelTypeText,
+};
+
+/**
+ Data structure holding the result of a label selection that occured on the map view.
+
+ See `-[TGMapViewController pickLabelAt:]` and `[TGMapViewDelegate mapView:didSelectLabel:atScreenPosition:]`.
+ */
+@interface TGLabelPickResult : NSObject
+
+NS_ASSUME_NONNULL_BEGIN
+
+/// The geographic coordinates of the selected label
+@property (readonly, nonatomic) TGGeoPoint coordinates;
+
+/// The type of the label (text or icon)
+@property (readonly, nonatomic) TGLabelType type;
+
+/// The set of data properties attached with the label
+@property (readonly, strong, nonatomic) TGFeatureProperties* properties;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGLabelPickResult.mm b/platforms/ios/src/TangramMap/TGLabelPickResult.mm
new file mode 100644 (file)
index 0000000..48d7f67
--- /dev/null
@@ -0,0 +1,36 @@
+//
+//  TGLabelPickResult.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/02/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGLabelPickResult.h"
+#import "TGMarkerPickResult+Internal.h"
+
+@interface TGLabelPickResult ()
+
+@property (assign, nonatomic) TGGeoPoint coordinates;
+@property (assign, nonatomic) TGLabelType type;
+@property (strong, nonatomic) TGFeatureProperties* properties;
+
+@end
+
+@implementation TGLabelPickResult
+
+- (instancetype) initWithCoordinates:(TGGeoPoint)coordinates type:(TGLabelType)type properties:(TGFeatureProperties *)properties
+{
+    self = [super init];
+
+    if (self) {
+        self.coordinates = coordinates;
+        self.type = type;
+        self.properties = properties;
+    }
+
+    return self;
+}
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGMapData+Internal.h b/platforms/ios/src/TangramMap/TGMapData+Internal.h
new file mode 100644 (file)
index 0000000..f183a85
--- /dev/null
@@ -0,0 +1,21 @@
+//
+//  TGMapData+Internal.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/24/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <memory>
+#import "data/clientGeoJsonSource.h"
+
+@interface TGMapData ()
+
+NS_ASSUME_NONNULL_BEGIN
+
+- (instancetype)initWithMapView:(TGMapViewController *)mapView name:(NSString *)name source:(std::shared_ptr<Tangram::TileSource>)source;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMapData.h b/platforms/ios/src/TangramMap/TGMapData.h
new file mode 100644 (file)
index 0000000..1e3ae6a
--- /dev/null
@@ -0,0 +1,114 @@
+//
+//  TGMapData.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/24/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "TGGeoPoint.h"
+#import "TGGeoPolygon.h"
+#import "TGGeoPolyline.h"
+
+/**
+ Dictionary of feature properties keyed by their property name
+ */
+typedef NSDictionary<NSString *, NSString *> TGFeatureProperties;
+
+@class TGMapViewController;
+
+/**
+ A `TGMapData` is a convenience class to display point, polygons or polylines from a dynamic data layer.
+ The data layer will be styled according to the scene file using the provided data layer name.
+
+ In your stylesheet, add a layer with the name of the data layer you want to add in your client application:
+
+ ```
+ layers:
+     mz_route_line_transit:
+        data: { source: mz_route_line_transit }
+     draw:
+        polylines:
+            color: function() { return feature.color || '#06a6d4'; }
+            order: 500
+            width: 10px
+ ```
+
+ In your implementation, to add a polyline fitting under the `mz_route_line_transit` layer:
+
+ ```swift
+ // Create a data layer in the TGMapViewController mapView
+ var dataLayer = mapView.addDataLayer(name: "mz_Route_line_transit");
+
+ var line = TGGeoPolyline()
+
+ // Add some coordinates to the polyline
+ line.add(latlon: TGGeoPointMake(longitude0, latitude0))
+ line.add(latlon: TGGeoPointMake(longitude1, latitude1))
+
+ // Set the data properties
+ var properties = ["type": "line", "color": "#D2655F"]
+
+ // Add the line to the data layer
+ dataLayer.add(polyline: line, properties: properties);
+ ```
+ */
+@interface TGMapData : NSObject
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Adds a point coordinate to the data source.
+
+ @param coordinates the geographic coordinates of the point to add to the data source
+ @param properties the feature properties
+ */
+- (void)addPoint:(TGGeoPoint)coordinates withProperties:(TGFeatureProperties *)properties;
+
+/**
+ Adds a polygon geometry to the data source.
+
+ @param polygon the polygon geometry to add to the data source
+ @param properties the feature properties
+ */
+- (void)addPolygon:(TGGeoPolygon *)polygon withProperties:(TGFeatureProperties *)properties;
+
+/**
+ Adds a polyline to the data source.
+
+ @param polyline the polyline geometry to add to the data source
+ @param properties the feature properties
+ */
+- (void)addPolyline:(TGGeoPolyline *)polyline withProperties:(TGFeatureProperties *)properties;
+
+/**
+ Adds features described in a GeoJSON string to the data source. The string must be formatted according
+ to the <a href="http://geojson.org/geojson-spec.html">GeoJSON specifications</a>.
+
+ @param data the GeoJSON formatted string to add to the data source
+ */
+- (void)addGeoJson:(NSString *)data;
+
+/**
+ Clears the data source from all the added features.
+ */
+- (void)clear;
+
+/**
+ Definitely removes the data source from the map view.
+ Any future usage of this `MapData` object will be a no-op.
+
+ @return `YES` if removal was successful
+ */
+- (BOOL)remove;
+
+/// The name of the data source
+@property (readonly, nonatomic) NSString* name;
+
+NS_ASSUME_NONNULL_END
+
+/// The map view this data source is on
+@property (readonly, nonatomic) TGMapViewController* _Nullable map;
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMapData.mm b/platforms/ios/src/TangramMap/TGMapData.mm
new file mode 100644 (file)
index 0000000..4ba9fa4
--- /dev/null
@@ -0,0 +1,134 @@
+//
+//  TGMapData.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/24/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMapViewController+Internal.h"
+#import <memory>
+#import <vector>
+
+typedef std::vector<Tangram::LngLat> Line;
+typedef std::vector<Line> Polygon;
+
+@interface TGMapData () {
+    std::shared_ptr<Tangram::ClientGeoJsonSource> dataSource;
+}
+
+@property (copy, nonatomic) NSString* name;
+@property (weak, nonatomic) TGMapViewController* map;
+
+@end
+
+static inline void tangramProperties(TGFeatureProperties* properties, Tangram::Properties& tgProperties)
+{
+    for (NSString* key in properties) {
+        NSString* value = [properties objectForKey:key];
+        tgProperties.set(std::string([key UTF8String]), [value UTF8String]);
+    }
+}
+
+@implementation TGMapData
+
+- (instancetype)initWithMapView:(TGMapViewController *)mapView name:(NSString *)name source:(std::shared_ptr<Tangram::ClientGeoJsonSource>)source
+{
+    self = [super init];
+
+    if (self) {
+        self.name = name;
+        self.map = mapView;
+        dataSource = source;
+    }
+
+    return self;
+}
+
+- (void)addPoint:(TGGeoPoint)coordinates withProperties:(TGFeatureProperties *)properties
+{
+    if (!self.map) {
+        return;
+    }
+
+    Tangram::Properties tgProperties;
+    tangramProperties(properties, tgProperties);
+
+    Tangram::LngLat lngLat(coordinates.longitude, coordinates.latitude);
+    dataSource->addPoint(tgProperties, lngLat);
+}
+
+- (void)addPolygon:(TGGeoPolygon *)polygon withProperties:(TGFeatureProperties *)properties
+{
+    if (!self.map) {
+        return;
+    }
+
+    Tangram::Properties tgProperties;
+    tangramProperties(properties, tgProperties);
+
+    Polygon tgPolygon;
+    Tangram::LngLat* coordinates = reinterpret_cast<Tangram::LngLat*>([polygon coordinates]);
+    int* rings = reinterpret_cast<int*>([polygon rings]);
+
+    size_t ringsCount = [polygon ringsCount];
+    size_t ringStart = 0;
+    size_t ringEnd = 0;
+
+    for (size_t i = 0; i < ringsCount; ++i) {
+        tgPolygon.emplace_back();
+        auto& polygonRing = tgPolygon.back();
+
+        ringEnd += rings[i];
+        polygonRing.insert(polygonRing.begin(), coordinates + ringStart, coordinates + ringEnd);
+        ringStart = ringEnd + 1;
+    }
+
+    dataSource->addPoly(tgProperties, tgPolygon);
+}
+
+- (void)addPolyline:(TGGeoPolyline *)polyline withProperties:(TGFeatureProperties *)properties
+{
+    if (!self.map) {
+        return;
+    }
+
+    Tangram::Properties tgProperties;
+    tangramProperties(properties, tgProperties);
+
+    Line tgPolyline;
+    Tangram::LngLat* coordinates = reinterpret_cast<Tangram::LngLat*>([polyline coordinates]);
+    tgPolyline.insert(tgPolyline.begin(), coordinates, coordinates + [polyline count]);
+    dataSource->addLine(tgProperties, tgPolyline);
+}
+
+- (void)addGeoJson:(NSString *)data
+{
+    if (!self.map) {
+        return;
+    }
+
+    std::string sourceData = std::string([data UTF8String]);
+    dataSource->addData(sourceData);
+}
+
+- (void)clear
+{
+    if (!self.map) {
+        return;
+    }
+
+    [self.map clearDataSource:dataSource];
+}
+
+- (void)remove
+{
+    if (!self.map) {
+        return;
+    }
+
+    [self.map removeDataSource:dataSource name:self.name];
+    self.map = nil;
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMapViewController+Internal.h b/platforms/ios/src/TangramMap/TGMapViewController+Internal.h
new file mode 100644 (file)
index 0000000..ce8a274
--- /dev/null
@@ -0,0 +1,28 @@
+//
+//  TGMapViewController+Internal.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/17/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMapViewController.h"
+#import "tangram.h"
+#import "data/clientGeoJsonSource.h"
+#import <vector>
+#import <memory>
+
+@interface TGMapViewController ()
+
+NS_ASSUME_NONNULL_BEGIN
+
+- (BOOL)removeDataSource:(std::shared_ptr<Tangram::ClientGeoJsonSource>)tileSource name:(NSString *)name;
+
+- (void)clearDataSource:(std::shared_ptr<Tangram::TileSource>)tileSource;
+
+NS_ASSUME_NONNULL_END
+
+@property (assign, nonatomic, nullable) Tangram::Map* map;
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGMapViewController.h b/platforms/ios/src/TangramMap/TGMapViewController.h
new file mode 100644 (file)
index 0000000..45e7429
--- /dev/null
@@ -0,0 +1,674 @@
+//
+//  TGMapViewController.h
+//  TangramMap
+//
+//  Created by Matt Blair on 8/25/14.
+//  Updated by Matt Smollinger on 7/29/16.
+//  Updated by Karim Naaji on 2/15/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <UIKit/UIKit.h>
+#import <GLKit/GLKit.h>
+
+@class TGMapViewController;
+
+#import "TGMapData.h"
+#import "TGGeoPoint.h"
+#import "TGGeoPolygon.h"
+#import "TGGeoPolyline.h"
+#import "TGSceneUpdate.h"
+#import "TGHttpHandler.h"
+#import "TGLabelPickResult.h"
+#import "TGMarker.h"
+#import "TGMarkerPickResult.h"
+#import "TGTypes.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ A gesture recognizer delegate that can be implemented to receive gesture events from the map view.
+ The map view will first check whether a gestureDelegate is available, then check whether it responds
+ to any `shouldRecognize*` method:
+
+    - If the `TGRecognizerDelegate` responds to `shouldRecognize`, the map view calls it before proceeding with
+    its default implementation based on the resturn status of `shouldRecognize`.
+
+    - If the `TGRecognizerDelegate` doesn't respond to `shouldRecognize*`, the map view will proceed with
+    calling default gesture handling code.
+
+ Finally, the map view checks whether the `TGRecognizerDelegate` implements `didRecognize*` and call this
+ method if so.
+
+ @note Those methods are all **optional**.
+ All the screen positions in this interface are in _logical pixel_ or _drawing coordinate system_
+ (based on a `UIKit` coordinate system); which is independent of the phone pixel density. Refer the
+ <a href="https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html">Apple documentation</a>
+ _Coordinate Systems and Drawing in iOS_ for more informations.
+
+ */
+@protocol TGRecognizerDelegate <NSObject>
+@optional
+
+/**
+ Whether the map view should handle a single tap gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizeSingleTapGesture:(CGPoint)location;
+
+/**
+ Whether the map view should handle a double tap gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizeDoubleTapGesture:(CGPoint)location;
+
+/**
+ Whether the map view should handle a long press gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizeLongPressGesture:(CGPoint)location;
+
+/**
+ Whether the map view should handle a pan gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param displacement the logical pixel displacement of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizePanGesture:(CGPoint)displacement;
+
+/**
+ Whether the map view should handle a pinch gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizePinchGesture:(CGPoint)location;
+
+
+/**
+ Whether the map view should handle a rotation gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizeRotationGesture:(CGPoint)location;
+
+/**
+ Whether the map view should handle a shove gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param displacement the logical pixel displacement of the recognized gesture
+ @return Whether the map view should proceed by handling this gesture behavior
+ */
+- (BOOL)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer shouldRecognizeShoveGesture:(CGPoint)displacement;
+
+/**
+ Called when the map view just handled a single tap gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeSingleTapGesture:(CGPoint)location;
+
+/**
+ Called when the map view just handled a single double gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeDoubleTapGesture:(CGPoint)location;
+
+/**
+ Called when the map view just handled a long press gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeLongPressGesture:(CGPoint)location;
+
+/**
+ Called when the map view just handled a pan gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param displacement the logical pixel displacement of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizePanGesture:(CGPoint)displacement;
+
+/**
+ Called when the map view just handled a pinch gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizePinchGesture:(CGPoint)location;
+
+/**
+ Called when the map view just handled a rotation gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param location the logical pixel location of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeRotationGesture:(CGPoint)location;
+
+/**
+ Called when the map view just handled a shove gesture.
+
+ @param recognizer the `UIGestureRecognizer` associated with the gesture
+ @param displacement the logical pixel displacement of the recognized gesture
+ */
+- (void)mapView:(TGMapViewController *)view recognizer:(UIGestureRecognizer *)recognizer didRecognizeShoveGesture:(CGPoint)displacement;
+
+@end
+
+NS_ASSUME_NONNULL_END
+
+/**
+ A map view delegate that can be implemented to receive miscellaneous map event.
+
+ @note All of those methods are called from main thread, those methods are all **optional**.
+ */
+@protocol TGMapViewDelegate <NSObject>
+@optional
+/**
+ Called after a `-[TGMapViewController loadSceneFileAsync:]` or
+ `-[TGMapViewController loadSceneFileAsync:sceneUpdates:]` is completed.
+
+ @param mapView a pointer to the map view
+ @param scene the path to the scene that has been loaded
+ */
+- (void)mapView:(nonnull TGMapViewController *)mapView didLoadSceneAsync:(nonnull NSString *)scene;
+/**
+ Always called after the method `-[TGMapViewController pickFeatureAt:]` is called on the map view.
+
+ @param mapView a pointer to the map view
+ @param feature a dictionnary containing the data contained by the selected feature, may be `nil`
+ @param position the screen position at which the feature has been selected
+
+ @note If no feature have been selected, `feature` will be `nil`, and `position` `(0, 0)`.
+ */
+- (void)mapView:(nonnull TGMapViewController *)mapView didSelectFeature:(nullable TGFeatureProperties *)feature atScreenPosition:(CGPoint)position;
+ /**
+ Always called after the method `-[TGMapViewController pickLabelAt:]` is called on the map view.
+
+ @param mapView a pointer to the map view
+ @param labelPickResult the label pick result object containing information about the label being picked, may be `nil`
+ @param position the screen position at which the feature has been selected
+
+ @note If no feature have been selected, `feature` will be `nil`, and `position` `(0, 0)`.
+ */
+- (void)mapView:(nonnull TGMapViewController *)mapView didSelectLabel:(nullable TGLabelPickResult *)labelPickResult atScreenPosition:(CGPoint)position;
+/**
+ Always called after the method `-[TGMapViewController pickMarkerAt:]` is called on the map view.
+
+ @param mapView a pointer to the map view
+ @param markerPickResult the marker pick result object containing information about the marker being picked, may be `nil`
+ @param position the screen position at which the feature has been selected
+
+ @note If no feature have been selected, `feature` will be `nil`, and `position` `(0, 0)`.
+ */
+- (void)mapView:(nonnull TGMapViewController *)mapView didSelectMarker:(nullable TGMarkerPickResult *)markerPickResult atScreenPosition:(CGPoint)position;
+/**
+ Called whenever the view did complete loading and building of all of the visible tiles of the current view.
+
+ @param mapView a pointer to the map view
+ */
+- (void)mapViewDidCompleteLoading:(nonnull TGMapViewController *)mapView;
+
+/**
+ Called whenever `-[TGMapViewController captureScreenshot:] is called on the map view.
+
+ @param mapView a pointer to the map view
+ @param screenshot the image object representing the screenshot
+ */
+- (void)mapView:(nonnull TGMapViewController *)view didCaptureScreenshot:(nonnull UIImage *)screenshot;
+
+/**
+ Called whenever scene updates have been applied to the scene file.
+ The list of scene update statuses will be emtpy if all updates have been applied successfully.
+ Called whenever scene updates have failed to apply to the scene file.
+
+ @param mapView a pointer to the map view
+ @param sceneUpdateError a NSError containing information about the scene update that failed
+ */
+- (void)mapView:(nonnull TGMapViewController *)mapView didFailSceneUpdateWithError:(NSError *)sceneUpdateError;
+
+@end
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ `TGMapViewController` is a flexible and customizable map view managing the lifecycle of a
+ <a href="https://developer.apple.com/reference/glkit/glkview">GLKView</a> component.
+ This view provides default gesture handlers for tap, double tap, long press, pan,
+ pinch, rotate and shove.
+
+ The public interface provides dynamic map marker placement, change of camera view
+ settings, and map description changes through scene updates.
+
+ This view uses scenes descibed by the
+  <a href="https://mapzen.com/documentation/tangram/">Tangram YAML scene syntax</a>
+ allowing you to fully customize your map description using your own data.
+ Some pre-made basemap styles can be found
+ <a href="https://mapzen.com/documentation/cartography/styles/">here</a> using Mapzen
+ data sources.
+
+ To use basemap styles you can <a href="https://mapzen.com/developers/sign_in">sign up for
+ an API key</a> and load it through your application:
+
+ ```swift
+ let sceneURL = "https://mapzen.com/carto/walkabout-style-more-labels/walkabout-style-more-labels.yaml";
+ view.loadSceneFile(sceneURL, sceneUpdates: [ TGSceneUpdate(path: "sources.mapzen.url_params", value: "{ api_key: \(YOUR_API_KEY) }") ]);
+ ```
+ @note All the screen positions used in this inteface are in _logical pixel_ or _drawing coordinate
+ system_ (based on a `UIKit` coordinate system); which is independent of the phone pixel density. Refer the
+ <a href="https://developer.apple.com/library/content/documentation/2DDrawing/Conceptual/DrawingPrintingiOS/GraphicsDrawingOverview/GraphicsDrawingOverview.html">Apple documentation</a>
+ _Coordinate Systems and Drawing in iOS_ for more informations.
+
+ */
+@interface TGMapViewController : GLKViewController <UIGestureRecognizerDelegate>
+
+/**
+ If continuous rendering is set to `true`, the map view will render continuously, otherwise,
+ the map will render only when an event occurs on the map (gesture, animation, view update...).
+
+ Some styles can be set to be `animated` and this default value will be set appropriately,
+ see the <a href="https://mapzen.com/documentation/tangram/scene/#animated">
+ style parameter</a> for more details.
+
+ @note Any changes to this value will override the default induced value from the `animated`
+ style parameter.
+ Setting this parameter to true will negatively impact battery life if left set for extended periods
+ of time. Before setting, make sure battery usage is not something critical to your application.
+ */
+@property (assign, nonatomic) BOOL continuous;
+
+#pragma mark Delegates
+
+/// Assign a gesture recognizer delegate, may be `nil`, see `TGRecognizerDelegate` for more details
+@property (weak, nonatomic, nullable) id<TGRecognizerDelegate> gestureDelegate;
+/// Assign a map viw delegate, may be `nil`, see `TGMapViewDelegate` for more details
+@property (weak, nonatomic, nullable) id<TGMapViewDelegate> mapViewDelegate;
+
+#pragma mark Camera/View modifiers
+
+/* The following are computed property. They return sensible defaults when the above .map property is nil */
+
+/// Assign a `TGCameraType` to the view camera
+@property (assign, nonatomic) TGCameraType cameraType;
+/// Assign a longitude and latitude to the map view camera
+@property (assign, nonatomic) TGGeoPoint position;
+/// Assign a floating point zoom to the map view camera
+@property (assign, nonatomic) float zoom;
+/// Assign a rotation angle in radians to the map view camera
+@property (assign, nonatomic) float rotation;
+/// Assign a tilt angle in radians to the map view camera
+@property (assign, nonatomic) float tilt;
+/// Access the markers added to this map view
+@property (readonly, nonatomic) NSArray<TGMarker *>* markers;
+
+/**
+ Assign `TGHttpHandler` for network request management.
+ A http handler with a default configuration is already provided to the map view.
+
+ Must be non-`nil`.
+
+ @note Assigning a http handler is optional and should only be done if you want to change
+ any network related configuration (cache path and network cache size, both memory and disk,
+ or be notified when a network request completes).
+ More informations on the default provided configuration can be found on the description
+ of `TGHttpHandler`.
+ */
+@property (strong, nonatomic) TGHttpHandler* httpHandler;
+
+/**
+ Assign the default resource root for this map view.
+ The resource root is the default directory where Tangram will try to load resources and scene
+ assets.
+
+ Must be non`-nil`.
+
+ @note By default the resource root is the main bundle resource URL.
+ */
+@property (strong, nonatomic) NSURL* resourceRoot;
+
+/**
+ Adds a named data layer to the map. See `TGMapData` for more details.
+
+ @param name the name of the data layer.
+
+ @return the map data, nil if the data source can't be initialized
+
+ @note You cannot create more than one data source with the same name, otherwise the same
+ object will be returned.
+ */
+- (nullable TGMapData *)addDataLayer:(NSString *)name;
+
+/**
+ Asks to capture a screenshot of the map view buffer.
+
+ A delegate should be set to the map view and `-[TGMapViewDelegate didCaptureScreenshot:view:screenshot]`
+ implemented to receive the screenshot image data.
+
+ @param waitForViewComplete whether the view should await for all of the map tiles of the current
+ view to complete building and rendering
+ */
+- (void)captureScreenshot:(BOOL)waitForViewComplete;
+
+#pragma mark Debug toggles
+
+/**
+ Set a `TGDebugFlag` to the map view
+
+ @param debugFlag the debug flag to set
+ @param value whether the flag is on or off
+ */
+- (void)setDebugFlag:(TGDebugFlag)debugFlag value:(BOOL)on;
+
+/**
+ Get the status of a specific `TGDebugFLag`
+
+ @param debugFlag the debug flag to get the status of
+ @return whether the flag is currently on or off for the map view
+ */
+- (BOOL)getDebugFlag:(TGDebugFlag)debugFlag;
+
+/**
+ Changes the status of a debug flag.
+ If a debug flag is on, this will turn it off and vice-versa.
+
+ @param debugFlag the debug flag to toggle the status of
+ */
+- (void)toggleDebugFlag:(TGDebugFlag)debugFlag;
+
+#pragma mark Scene loading - updates interface
+
+/**
+ Loads a scene file synchronously.
+
+ If the scene file is set as a resource in your application bundle, make sure to resolve
+ the path for this URL relative to your bundle (for example `Resources/scene.yaml`).
+
+ If your scene is hosted remotely (any path starting with `https://` or `http://` is considered a remote scene file)
+ Tangram will automatically load that remote scene file.
+
+ @param path the scene path URL
+ */
+- (void)loadSceneFile:(NSString *)path;
+
+/**
+ Loads a scene file (similar to `-loadSceneFile:`), with a list of
+ updates to be applied to the scene.
+ If a scene update error happens, scene updates won't be applied.
+
+ @param path the scene path URL
+ @param sceneUpdates a list of `TGSceneUpdate` to apply to the scene
+ */
+- (void)loadSceneFile:(NSString *)path sceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates;
+
+/**
+ Loads a scene file asynchronously, may call `-[TGMapViewDelegate mapView:didLoadSceneAsync:]`
+ if a `TGMapViewDelegate` is set to the map view.
+
+ @param path the scene path URL
+ */
+- (void)loadSceneFileAsync:(NSString *)path;
+
+/**
+ Loads a scene asynchronously (similar to `-loadSceneFileAsync:`), with a
+ list of updates to be applied to the scene.
+ If a scene update error happens, scene updates won't be applied.
+
+ @param path the scene path URL
+ @param sceneUpdates a list of `TGSceneUpdate` to apply to the scene
+ */
+- (void)loadSceneFileAsync:(NSString *)path sceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates;
+
+/**
+ Queue a scene update.
+
+ The path is a series of yaml keys separated by a '.' and the value is a string
+ of yaml to replace the current value at the given path in the scene.
+
+ @param componentPath the path of the scene component to update
+ @value the value to assign to the YAML component selected with `componentPath`
+
+ @note Scene updates must be applied with `-applySceneUpdates:`
+ */
+- (void)queueSceneUpdate:(NSString*)componentPath withValue:(NSString*)value;
+
+/**
+ Queue a list of scene updates.
+
+ @param sceneUpdates a list of updates to apply to the scene, see `TGSceneUpdate` for more infos
+
+ @note Scene updates must be applied with `-applySceneUpdates:`
+ */
+- (void)queueSceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates;
+
+/**
+ Apply scene updates queued with `-queueSceneUpdate*` methods.
+ If a scene update error happens, scene udpates won't be applied.
+ */
+- (void)applySceneUpdates;
+
+#pragma mark Feature picking interface
+
+/**
+ Set the radius in logical pixels to use when picking features on the map (default is `0.5`).
+
+ This affects the way `-pick*` method will behave, the large this value is, the more selectable
+ elements would get selected.
+
+ @param logicalPixels the pixel radius in logical pixel size
+ */
+- (void)setPickRadius:(float)logicalPixels;
+
+/**
+ Selects a feature marked as <a href="https://mapzen.com/documentation/tangram/draw/#interactive">
+ `interactive`</a> in the stylesheet.
+
+ Returns the result in `[TGMapViewDelegate mapView:didSelectFeature:atScreenPosition:].
+
+ @param screenPosition the logical pixels screen position used for the feature selection query
+
+ @note to receive events you must implement set `TGMapViewDelegate` to the map view and implement
+ `[TGMapViewDelegate mapView:didSelectFeature:atScreenPosition:]`.
+ */
+- (void)pickFeatureAt:(CGPoint)screenPosition;
+
+/**
+ Selects a label (elements under <a href="https://mapzen.com/documentation/tangram/Styles-Overview/#points">
+ points style</a> or <a href="https://mapzen.com/documentation/tangram/Styles-Overview/#text">text styles</a>)
+ marked as <a href="https://mapzen.com/documentation/tangram/draw/#interactive">
+ `interactive`</a> in the stylesheet.
+
+ Returns the result in `[TGMapViewDelegate mapView:didSelectLabel:atScreenPosition:].
+
+ @param screenPosition the logical pixels screen position used for the feature selection query
+
+ @note To receive events you must set a `TGMapViewDelegate` to the map view and implement
+ `[TGMapViewDelegate mapView:didSelectLabel:atScreenPosition:]`.
+ */
+- (void)pickLabelAt:(CGPoint)screenPosition;
+
+/**
+ Selects a marker marked as <a href="https://mapzen.com/documentation/tangram/draw/#interactive">
+ `interactive`</a> and returns the result in `[TGMapViewDelegate mapView:didSelectMarker:atScreenPosition:].
+
+ To set a marker interactive, you must set it when styling it:
+
+ ```swift
+ TGMarker marker;
+ marker.styling = "{ style: 'points', interactive : true,  color: 'white', size: [30px, 30px], order: 500 }"
+ ```
+
+ @param screenPosition the logical pixels screen position used for the feature selection query
+
+ @note To receive events you must set a `TGMapViewDelegate` to the map view and implement
+ `[TGMapViewDelegate mapView:didSelectMarker:atScreenPosition:]`.
+ */
+- (void)pickMarkerAt:(CGPoint)screenPosition;
+
+#pragma mark Marker access
+
+/**
+ Removes all the markers added to the map view
+ */
+- (void)markerRemoveAll;
+
+/**
+ Creates a marker to the map and add it
+
+ @return the created marker
+
+ @note The default marker will not be usable until you set its styling, geometry or image depending
+ on your use case.
+ */
+- (TGMarker*)markerAdd;
+
+/**
+ Removes a specific marker
+
+ @param marker The marker pointer to remove
+
+ @note the marker will be unusable after being removed
+ */
+- (void)markerRemove:(TGMarker*)marker;
+
+#pragma mark Map View lifecycle
+
+/**
+ Requests the view to draw another frame
+
+ @note This method should only be called if reimplemented in a class that inherits from `TGMapViewController`
+ */
+- (void)requestRender;
+
+/**
+ Draws a frame
+
+ @note This method should only be called if reimplemented in a class that inherits from `TGMapViewController`
+ */
+- (void)renderOnce;
+
+/**
+ Requests the view to update
+
+ @note This method should only be called if reimplemented in a class that inherits from `TGMapViewController`
+ */
+- (void)update;
+
+#pragma mark Longitude/Latitude - Screen position conversions
+
+/**
+ Converts a longitude and latitude to a screen position
+
+ @param lngLat the longitude and latitude of the geographic coordinate to convert
+
+ @return the screen position, `(nil, nil)` if the value is incoherent or not visible on the screen
+ */
+- (CGPoint)lngLatToScreenPosition:(TGGeoPoint)lngLat;
+
+/**
+ Given coordinates in screen space (`x` right, `y` down), set the output longitude and
+ latitude to the geographic location corresponding to that point.
+
+ @param screenPosition the 2d screen position to convert
+
+ @return the longitude and latitude, `(nil, nil)` if the point is not visible on the screen
+ */
+- (TGGeoPoint)screenPositionToLngLat:(CGPoint)screenPosition;
+
+#pragma mark Map View animations - Position interface
+
+/**
+ Animate the map view to another geographic coordinate.
+
+ @param position the map view geographic coordinate
+ @param seconds the duration in seconds
+
+ @note default ease type for this animation is set to cubic, see `TGEaseType` for more details.
+ */
+- (void)animateToPosition:(TGGeoPoint)position withDuration:(float)seconds;
+
+/**
+ Animate the map view to another geographic coordinate with a specific animation ease.
+
+ @param position the map view geographic coordinate
+ @param seconds the duration of the animation given in seconds
+ @param easeType the ease type to use for the animation, see `TGEaseType` for more details.
+ */
+- (void)animateToPosition:(TGGeoPoint)position withDuration:(float)seconds withEaseType:(TGEaseType)easeType;
+
+/**
+ Animate the map view to another zoom.
+
+ @param zoomLevel the map view zoom level
+ @param seconds the duration of the animation given in seconds
+
+ @note default ease type for this animation is set to cubic, see `TGEaseType` for more details.
+ */
+- (void)animateToZoomLevel:(float)zoomLevel withDuration:(float)seconds;
+
+/**
+ Animate the map view to another zoom level with a specific animation ease.
+
+ @param zoomLevel the map view zoom level
+ @param seconds the duration of the animation given in seconds
+ @param easeType the ease type to use for the animation, see `TGEaseType` for more details.
+ */
+- (void)animateToZoomLevel:(float)zoomLevel withDuration:(float)seconds withEaseType:(TGEaseType)easeType;
+
+/**
+ Animate the map view to another rotation.
+
+ @param radians the map view rotation in radians
+ @param seconds the duration of the animation given in seconds
+
+ @note default ease type for this animation is set to cubic, see `TGEaseType` for more details.
+ */
+- (void)animateToRotation:(float)radians withDuration:(float)seconds;
+
+/**
+ Animate the map view to another rotation with a specific animation ease.
+
+ @param radians the map view rotation in radians
+ @param seconds the duration of the animation given in seconds
+ @param easeType the ease type to use for the animation, see `TGEaseType` for more details.
+ */
+- (void)animateToRotation:(float)radians withDuration:(float)seconds withEaseType:(TGEaseType)easeType;
+
+/**
+ Animate the map view to another tilt.
+
+ @param radians the map view tilt in radians
+ @param seconds the duration of the animation given in seconds
+
+ @note default ease type for this animation is set to cubic, see `TGEaseType` for more details.
+ */
+- (void)animateToTilt:(float)radians withDuration:(float)seconds;
+
+/**
+ Animate the map view to another tilt with a specific animation ease.
+
+ @param radians the map view tilt in radians
+ @param seconds the duration of the animation given in seconds
+ @param easeType the ease type to use for the animation, see `TGEaseType` for more details.
+ */
+- (void)animateToTilt:(float)radians withDuration:(float)seconds withEaseType:(TGEaseType)easeType;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMapViewController.mm b/platforms/ios/src/TangramMap/TGMapViewController.mm
new file mode 100644 (file)
index 0000000..03120e2
--- /dev/null
@@ -0,0 +1,904 @@
+//
+//  TGMapViewController.mm
+//  TangramMap
+//
+//  Created by Matt Blair on 8/25/14.
+//  Updated by Matt Smollinger on 7/29/16.
+//  Updated by Karim Naaji on 2/15/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMapViewController+Internal.h"
+#import "TGMapData+Internal.h"
+#import "TGMarkerPickResult+Internal.h"
+#import "TGLabelPickResult+Internal.h"
+#import "TGMarker+Internal.h"
+#import "TGHelpers.h"
+#import "platform_ios.h"
+#import "data/propertyItem.h"
+#import "tangram.h"
+
+#import <unordered_map>
+#import <functional>
+
+__CG_STATIC_ASSERT(sizeof(TGGeoPoint) == sizeof(Tangram::LngLat));
+
+@interface TGMapViewController () {
+    BOOL shouldCaptureFrame;
+    BOOL captureFrameWaitForViewComplete;
+    BOOL viewComplete;
+}
+
+@property (nullable, copy, nonatomic) NSString* scenePath;
+@property (nullable, strong, nonatomic) EAGLContext* context;
+@property (assign, nonatomic) CGFloat contentScaleFactor;
+@property (assign, nonatomic) BOOL renderRequested;
+@property (strong, nonatomic) NSMutableDictionary* markersById;
+@property (strong, nonatomic) NSMutableDictionary* dataLayersByName;
+
+@end
+
+@implementation TGMapViewController
+
+- (NSArray<TGMarker *> *)markers
+{
+    if (!self.map) {
+        NSArray* values = [[NSArray alloc] init];
+        return values;
+    }
+
+    return [self.markersById allValues];
+}
+
+- (TGMarker*)markerAdd
+{
+    TGMarker* marker = [[TGMarker alloc] initWithMap:self.map];
+    NSString* key = [NSString stringWithFormat:@"%d", (NSUInteger)marker.identifier];
+    self.markersById[key] = marker;
+    return marker;
+}
+
+- (void)markerRemove:(TGMarker *)marker
+{
+    NSString* key = [NSString stringWithFormat:@"%d", (NSUInteger)marker.identifier];
+    self.map->markerRemove(marker.identifier);
+    [self.markersById removeObjectForKey:key];
+    marker.identifier = 0;
+}
+
+- (void)markerRemoveAll
+{
+    if (!self.map) { return; }
+    for (id markerId in self.markersById) {
+        TGMarker* marker = [self.markersById objectForKey:markerId];
+        marker.identifier = 0;
+    }
+    [self.markersById removeAllObjects];
+    self.map->markerRemoveAll();
+}
+
+- (void)setDebugFlag:(TGDebugFlag)debugFlag value:(BOOL)on
+{
+    Tangram::setDebugFlag((Tangram::DebugFlags)debugFlag, on);
+}
+
+- (BOOL)getDebugFlag:(TGDebugFlag)debugFlag
+{
+    return Tangram::getDebugFlag((Tangram::DebugFlags)debugFlag);
+}
+
+- (void)toggleDebugFlag:(TGDebugFlag)debugFlag
+{
+    Tangram::toggleDebugFlag((Tangram::DebugFlags)debugFlag);
+}
+
+- (TGMapData *)addDataLayer:(NSString *)name
+{
+    if (!self.map) { return nil; }
+
+    std::string dataLayerName = std::string([name UTF8String]);
+    auto source = std::make_shared<Tangram::ClientGeoJsonSource>(self.map->getPlatform(), dataLayerName, "");
+    self.map->addTileSource(source);
+
+    TGMapData* clientData = [[TGMapData alloc] initWithMapView:self name:name source:source];
+    self.dataLayersByName[name] = clientData;
+
+    return clientData;
+}
+
+- (BOOL)removeDataSource:(std::shared_ptr<Tangram::TileSource>)tileSource name:(NSString *)name
+{
+    if (!self.map || !tileSource) { return; }
+
+    [self.dataLayersByName removeObjectForKey:name];
+    return self.map->removeTileSource(*tileSource);
+}
+
+- (void)clearDataSource:(std::shared_ptr<Tangram::TileSource>)tileSource
+{
+    if (!self.map || !tileSource) { return; }
+
+    self.map->clearTileSource(*tileSource, true, true);
+}
+
+#pragma mark Scene loading interface
+
+- (void)loadSceneFile:(NSString*)path
+{
+    [self loadSceneFile:path sceneUpdates:nil];
+}
+
+- (void)loadSceneFileAsync:(NSString*)path
+{
+    [self loadSceneFileAsync:path sceneUpdates:nil];
+}
+
+- (void)loadSceneFile:(NSString *)path sceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates
+{
+    if (!self.map) { return; }
+
+    std::vector<Tangram::SceneUpdate> updates;
+
+    if (sceneUpdates) {
+        for (TGSceneUpdate* update in sceneUpdates) {
+            updates.push_back({std::string([update.path UTF8String]), std::string([update.value UTF8String])});
+        }
+    }
+
+    self.scenePath = path;
+
+    auto updateCallbackStatus = [=](auto sceneUpdateError) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didFailSceneUpdateWithError:)]) { return; }
+        [self.mapViewDelegate mapView:self didFailSceneUpdateWithError:[TGHelpers errorFromSceneUpdateError:sceneUpdateError]];
+    };
+
+    self.map->loadScene([path UTF8String], false, updates, updateCallbackStatus);
+    [self.markersById removeAllObjects];
+
+    self.renderRequested = YES;
+}
+
+- (void)loadSceneFileAsync:(NSString *)path sceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates
+{
+    if (!self.map) { return; }
+
+    self.scenePath = path;
+
+    Tangram::MapReady onReadyCallback = [=](void* _userPtr) -> void {
+        if (self.mapViewDelegate && [self.mapViewDelegate respondsToSelector:@selector(mapView:didLoadSceneAsync:)]) {
+            [self.mapViewDelegate mapView:self didLoadSceneAsync:path];
+        }
+
+        [self.markersById removeAllObjects];
+        self.renderRequested = YES;
+    };
+
+    std::vector<Tangram::SceneUpdate> updates;
+
+    if (sceneUpdates) {
+        for (TGSceneUpdate* update in sceneUpdates) {
+            updates.push_back({std::string([update.path UTF8String]), std::string([update.value UTF8String])});
+        }
+    }
+
+    auto updateCallbackStatus = [=](auto sceneUpdateError) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didFailSceneUpdateWithError:)]) { return; }
+        [self.mapViewDelegate mapView:self didFailSceneUpdateWithError:[TGHelpers errorFromSceneUpdateError:sceneUpdateError]];
+    };
+
+    self.map->loadSceneAsync([path UTF8String], false, onReadyCallback, nullptr, updates, updateCallbackStatus);
+}
+
+#pragma mark Scene updates
+
+- (void)queueSceneUpdates:(NSArray<TGSceneUpdate *> *)sceneUpdates
+{
+    if (!self.map) { return; }
+
+    std::vector<Tangram::SceneUpdate> updates;
+
+    if (sceneUpdates) {
+        for (TGSceneUpdate* update in sceneUpdates) {
+            updates.push_back({std::string([update.path UTF8String]), std::string([update.value UTF8String])});
+        }
+    }
+
+    self.map->queueSceneUpdate(updates);
+}
+
+- (void)queueSceneUpdate:(NSString*)componentPath withValue:(NSString*)value
+{
+    if (!self.map) { return; }
+
+    self.map->queueSceneUpdate([componentPath UTF8String], [value UTF8String]);
+}
+
+- (void)applySceneUpdates
+{
+    if (!self.map) { return; }
+
+    auto updateCallbackError = [=](auto sceneUpdateError) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didFailSceneUpdateWithError:)]) { return; }
+
+        [self.mapViewDelegate mapView:self didFailSceneUpdateWithError:[TGHelpers errorFromSceneUpdateError:sceneUpdateError]];
+    };
+
+    self.map->applySceneUpdates(updateCallbackError);
+}
+
+#pragma mark Longitude/Latitude - Screen position conversions
+
+- (CGPoint)lngLatToScreenPosition:(TGGeoPoint)lngLat
+{
+    static const CGPoint nullCGPoint = {(CGFloat)NAN, (CGFloat)NAN};
+
+    if (!self.map) { return nullCGPoint; }
+
+    double screenPosition[2];
+    if (self.map->lngLatToScreenPosition(lngLat.longitude, lngLat.latitude,
+        &screenPosition[0], &screenPosition[1])) {
+
+        screenPosition[0] /= self.contentScaleFactor;
+        screenPosition[1] /= self.contentScaleFactor;
+
+        return CGPointMake((CGFloat)screenPosition[0], (CGFloat)screenPosition[1]);
+    }
+
+    return nullCGPoint;
+}
+
+- (TGGeoPoint)screenPositionToLngLat:(CGPoint)screenPosition
+{
+    static const TGGeoPoint nullTangramGeoPoint = {NAN, NAN};
+
+    if (!self.map) { return nullTangramGeoPoint; }
+
+    screenPosition.x *= self.contentScaleFactor;
+    screenPosition.y *= self.contentScaleFactor;
+
+    TGGeoPoint lngLat;
+    if (self.map->screenPositionToLngLat(screenPosition.x, screenPosition.y,
+        &lngLat.longitude, &lngLat.latitude)) {
+        return lngLat;
+    }
+
+    return nullTangramGeoPoint;
+}
+
+#pragma mark Feature picking
+
+- (void)setPickRadius:(float)logicalPixels
+{
+    if (!self.map) { return; }
+
+    self.map->setPickRadius(logicalPixels);
+}
+
+- (void)pickFeatureAt:(CGPoint)screenPosition
+{
+    if (!self.map) { return; }
+
+    screenPosition.x *= self.contentScaleFactor;
+    screenPosition.y *= self.contentScaleFactor;
+
+    self.map->pickFeatureAt(screenPosition.x, screenPosition.y, [=](const Tangram::FeaturePickResult* featureResult) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didSelectFeature:atScreenPosition:)]) {
+            return;
+        }
+
+        CGPoint position = CGPointMake(0.0, 0.0);
+
+        if (!featureResult) {
+            [self.mapViewDelegate mapView:self didSelectFeature:nil atScreenPosition:position];
+            return;
+        }
+
+        NSMutableDictionary* featureProperties = [[NSMutableDictionary alloc] init];
+
+        const auto& properties = featureResult->properties;
+        position = CGPointMake(featureResult->position[0] / self.contentScaleFactor,
+                               featureResult->position[1] / self.contentScaleFactor);
+
+        for (const auto& item : properties->items()) {
+            NSString* key = [NSString stringWithUTF8String:item.key.c_str()];
+            NSString* value = [NSString stringWithUTF8String:properties->asString(item.value).c_str()];
+            featureProperties[key] = value;
+        }
+
+        [self.mapViewDelegate mapView:self didSelectFeature:featureProperties atScreenPosition:position];
+    });
+}
+
+- (void)pickMarkerAt:(CGPoint)screenPosition
+{
+    if (!self.map) { return; }
+
+    screenPosition.x *= self.contentScaleFactor;
+    screenPosition.y *= self.contentScaleFactor;
+
+    self.map->pickMarkerAt(screenPosition.x, screenPosition.y, [=](const Tangram::MarkerPickResult* markerPickResult) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didSelectMarker:atScreenPosition:)]) {
+            return;
+        }
+
+        CGPoint position = CGPointMake(0.0, 0.0);
+
+        if (!markerPickResult) {
+            [self.mapViewDelegate mapView:self didSelectMarker:nil atScreenPosition:position];
+            return;
+        }
+
+        NSString* key = [NSString stringWithFormat:@"%d", (NSUInteger)markerPickResult->id];
+        TGMarker* marker = [self.markersById objectForKey:key];
+
+        if (!marker) {
+            [self.mapViewDelegate mapView:self didSelectMarker:nil atScreenPosition:position];
+            return;
+        }
+
+        position = CGPointMake(markerPickResult->position[0] / self.contentScaleFactor,
+                               markerPickResult->position[1] / self.contentScaleFactor);
+
+        TGGeoPoint coordinates = TGGeoPointMake(markerPickResult->coordinates.longitude,
+                                                markerPickResult->coordinates.latitude);
+
+        TGMarkerPickResult* result = [[TGMarkerPickResult alloc] initWithCoordinates:coordinates marker:marker];
+        [self.mapViewDelegate mapView:self didSelectMarker:result atScreenPosition:position];
+    });
+}
+
+- (void)pickLabelAt:(CGPoint)screenPosition
+{
+    if (!self.map) { return; }
+
+    screenPosition.x *= self.contentScaleFactor;
+    screenPosition.y *= self.contentScaleFactor;
+
+    self.map->pickLabelAt(screenPosition.x, screenPosition.y, [=](const Tangram::LabelPickResult* labelPickResult) {
+        if (!self.mapViewDelegate || ![self.mapViewDelegate respondsToSelector:@selector(mapView:didSelectLabel:atScreenPosition:)]) {
+            return;
+        }
+
+        CGPoint position = CGPointMake(0.0, 0.0);
+
+        if (!labelPickResult) {
+            [self.mapViewDelegate mapView:self didSelectLabel:nil atScreenPosition:position];
+            return;
+        }
+
+        NSMutableDictionary* featureProperties = [[NSMutableDictionary alloc] init];
+
+        const auto& touchItem = labelPickResult->touchItem;
+        const auto& properties = touchItem.properties;
+        position = CGPointMake(touchItem.position[0] / self.contentScaleFactor,
+                               touchItem.position[1] / self.contentScaleFactor);
+
+        for (const auto& item : properties->items()) {
+            NSString* key = [NSString stringWithUTF8String:item.key.c_str()];
+            NSString* value = [NSString stringWithUTF8String:properties->asString(item.value).c_str()];
+            featureProperties[key] = value;
+        }
+
+        TGGeoPoint coordinates = TGGeoPointMake(labelPickResult->coordinates.longitude, labelPickResult->coordinates.latitude);
+        TGLabelPickResult* tgLabelPickResult = [[TGLabelPickResult alloc] initWithCoordinates:coordinates
+                                                                                         type:(TGLabelType)labelPickResult->type
+                                                                                   properties:featureProperties];
+        [self.mapViewDelegate mapView:self didSelectLabel:tgLabelPickResult atScreenPosition:position];
+    });
+}
+
+#pragma mark Map position implementation
+
+- (void)setPosition:(TGGeoPoint)position {
+    if (!self.map) { return; }
+
+    self.map->setPosition(position.longitude, position.latitude);
+}
+
+- (void)animateToPosition:(TGGeoPoint)position withDuration:(float)seconds
+{
+    [self animateToPosition:position withDuration:seconds withEaseType:TGEaseTypeCubic];
+}
+
+- (void)animateToPosition:(TGGeoPoint)position withDuration:(float)seconds withEaseType:(TGEaseType)easeType
+{
+    if (!self.map) { return; }
+
+    Tangram::EaseType ease = [TGHelpers convertEaseTypeFrom:easeType];
+    self.map->setPositionEased(position.longitude, position.latitude, seconds, ease);
+}
+
+- (TGGeoPoint)position
+{
+    static const TGGeoPoint nullTangramGeoPoint = {NAN, NAN};
+
+    if (!self.map) { return nullTangramGeoPoint; }
+
+    TGGeoPoint returnVal;
+
+    self.map->getPosition(returnVal.longitude, returnVal.latitude);
+
+    return returnVal;
+}
+
+- (void)setZoom:(float)zoom
+{
+    if (!self.map) { return; }
+
+    self.map->setZoom(zoom);
+}
+
+- (void)animateToZoomLevel:(float)zoomLevel withDuration:(float)seconds
+{
+    [self animateToZoomLevel:zoomLevel withDuration:seconds withEaseType:TGEaseTypeCubic];
+}
+
+- (void)animateToZoomLevel:(float)zoomLevel withDuration:(float)seconds withEaseType:(TGEaseType)easeType
+{
+    if (!self.map) { return; }
+
+    Tangram::EaseType ease = [TGHelpers convertEaseTypeFrom:easeType];
+    self.map->setZoomEased(zoomLevel, seconds, ease);
+}
+
+- (float)zoom
+{
+    if (!self.map) { return 0.0; }
+
+    return self.map->getZoom();
+}
+
+- (void)animateToRotation:(float)radians withDuration:(float)seconds
+{
+    [self animateToRotation:radians withDuration:seconds withEaseType:TGEaseTypeCubic];
+}
+
+- (void)animateToRotation:(float)radians withDuration:(float)seconds withEaseType:(TGEaseType)easeType
+{
+    if (!self.map) { return; }
+
+    Tangram::EaseType ease = [TGHelpers convertEaseTypeFrom:easeType];
+    self.map->setRotationEased(radians, seconds, ease);
+}
+
+- (void)setRotation:(float)radians
+{
+    if (!self.map) { return; }
+
+    self.map->setRotation(radians);
+}
+
+- (float)rotation
+{
+    if (!self.map) { return 0.0; }
+
+    return self.map->getRotation();
+}
+
+- (float)tilt
+{
+    if (!self.map) { return 0.0; }
+
+    return self.map->getTilt();
+}
+
+- (void)setTilt:(float)radians
+{
+    if (!self.map) { return; }
+
+    self.map->setTilt(radians);
+}
+
+- (void)animateToTilt:(float)radians withDuration:(float)seconds
+{
+    [self animateToTilt:radians withDuration:seconds withEaseType:TGEaseType::TGEaseTypeCubic];
+}
+
+- (void)animateToTilt:(float)radians withDuration:(float)seconds withEaseType:(TGEaseType)easeType
+{
+    if (!self.map) { return; }
+
+    Tangram::EaseType ease = [TGHelpers convertEaseTypeFrom:easeType];
+    self.map->setTiltEased(radians, seconds, ease);
+}
+
+#pragma mark Camera type
+
+- (TGCameraType)cameraType
+{
+    switch (self.map->getCameraType()) {
+        case 0:
+            return TGCameraTypePerspective;
+        case 1:
+            return TGCameraTypeIsometric;
+        case 2:
+            return TGCameraTypeFlat;
+        default:
+            return TGCameraTypePerspective;
+    }
+}
+
+- (void)setCameraType:(TGCameraType)cameraType
+{
+    if (!self.map){ return; }
+
+    self.map->setCameraType(cameraType);
+}
+
+#pragma mark Gestures
+
+- (void)setupGestureRecognizers
+{
+    /* Construct Gesture Recognizers */
+    //1. Tap
+    UITapGestureRecognizer* tapRecognizer = [[UITapGestureRecognizer alloc]
+                                             initWithTarget:self action:@selector(respondToTapGesture:)];
+    tapRecognizer.numberOfTapsRequired = 1;
+    // TODO: Figure a way to have a delay set for it not to tap gesture not to wait long enough for a doubletap gesture to be recognized
+    tapRecognizer.delaysTouchesEnded = NO;
+
+    //2. DoubleTap
+    UITapGestureRecognizer* doubleTapRecognizer = [[UITapGestureRecognizer alloc]
+                                                   initWithTarget:self action:@selector(respondToDoubleTapGesture:)];
+    doubleTapRecognizer.numberOfTapsRequired = 2;
+    // Distanle single tap when double tap occurs
+    [tapRecognizer requireGestureRecognizerToFail:doubleTapRecognizer];
+
+    //3. Pan
+    UIPanGestureRecognizer* panRecognizer = [[UIPanGestureRecognizer alloc]
+                                             initWithTarget:self action:@selector(respondToPanGesture:)];
+    panRecognizer.maximumNumberOfTouches = 1;
+
+    //4. Pinch
+    UIPinchGestureRecognizer* pinchRecognizer = [[UIPinchGestureRecognizer alloc]
+                                                 initWithTarget:self action:@selector(respondToPinchGesture:)];
+
+    //5. Rotate
+    UIRotationGestureRecognizer* rotationRecognizer = [[UIRotationGestureRecognizer alloc]
+                                                       initWithTarget:self action:@selector(respondToRotationGesture:)];
+
+    //6. Shove
+    UIPanGestureRecognizer* shoveRecognizer = [[UIPanGestureRecognizer alloc]
+                                               initWithTarget:self action:@selector(respondToShoveGesture:)];
+    shoveRecognizer.minimumNumberOfTouches = 2;
+
+    //7. Long press
+    UILongPressGestureRecognizer* longPressRecognizer = [[UILongPressGestureRecognizer alloc]
+                                                         initWithTarget:self action:@selector(respondToLongPressGesture:)];
+
+    // Use the delegate method 'shouldRecognizeSimultaneouslyWithGestureRecognizer' for gestures that can be concurrent
+    panRecognizer.delegate = self;
+    pinchRecognizer.delegate = self;
+    rotationRecognizer.delegate = self;
+
+    /* Setup gesture recognizers */
+    [self.view addGestureRecognizer:tapRecognizer];
+    [self.view addGestureRecognizer:doubleTapRecognizer];
+    [self.view addGestureRecognizer:panRecognizer];
+    [self.view addGestureRecognizer:pinchRecognizer];
+    [self.view addGestureRecognizer:rotationRecognizer];
+    [self.view addGestureRecognizer:shoveRecognizer];
+    [self.view addGestureRecognizer:longPressRecognizer];
+}
+
+// Implement touchesBegan to catch down events
+- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
+    self.map->handlePanGesture(0.0f, 0.0f, 0.0f, 0.0f);
+}
+
+- (BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer
+{
+    // make shove gesture exclusive
+    if ([gestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
+        return [gestureRecognizer numberOfTouches] != 2;
+    }
+    if ([otherGestureRecognizer isKindOfClass:[UIPanGestureRecognizer class]]) {
+        return [otherGestureRecognizer numberOfTouches] != 2;
+    }
+    return YES;
+}
+
+#pragma mark - Gesture Recognizer Delegate Methods
+
+- (void)respondToLongPressGesture:(UILongPressGestureRecognizer *)longPressRecognizer
+{
+    CGPoint location = [longPressRecognizer locationInView:self.view];
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizeLongPressGesture:)] ) {
+        if (![self.gestureDelegate mapView:self recognizer:longPressRecognizer shouldRecognizeLongPressGesture:location]) { return; }
+    }
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizeLongPressGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:longPressRecognizer didRecognizeLongPressGesture:location];
+    }
+}
+
+- (void)respondToTapGesture:(UITapGestureRecognizer *)tapRecognizer
+{
+    CGPoint location = [tapRecognizer locationInView:self.view];
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizeSingleTapGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:tapRecognizer shouldRecognizeSingleTapGesture:location]) { return; }
+    }
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizeSingleTapGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:tapRecognizer didRecognizeSingleTapGesture:location];
+    }
+}
+
+- (void)respondToDoubleTapGesture:(UITapGestureRecognizer *)doubleTapRecognizer
+{
+    CGPoint location = [doubleTapRecognizer locationInView:self.view];
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizeDoubleTapGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:doubleTapRecognizer shouldRecognizeDoubleTapGesture:location]) { return; }
+    }
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizeDoubleTapGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:doubleTapRecognizer didRecognizeDoubleTapGesture:location];
+    }
+}
+
+- (void)respondToPanGesture:(UIPanGestureRecognizer *)panRecognizer
+{
+    CGPoint displacement = [panRecognizer translationInView:self.view];
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizePanGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:panRecognizer shouldRecognizePanGesture:displacement]) {
+            return;
+        }
+    }
+
+    CGPoint velocity = [panRecognizer velocityInView:self.view];
+    CGPoint end = [panRecognizer locationInView:self.view];
+    CGPoint start = {end.x - displacement.x, end.y - displacement.y};
+
+    [panRecognizer setTranslation:CGPointZero inView:self.view];
+
+    switch (panRecognizer.state) {
+        case UIGestureRecognizerStateChanged:
+            self.map->handlePanGesture(start.x * self.contentScaleFactor, start.y * self.contentScaleFactor, end.x * self.contentScaleFactor, end.y * self.contentScaleFactor);
+            break;
+        case UIGestureRecognizerStateEnded:
+            self.map->handleFlingGesture(end.x * self.contentScaleFactor, end.y * self.contentScaleFactor, velocity.x * self.contentScaleFactor, velocity.y * self.contentScaleFactor);
+            break;
+        default:
+            break;
+    }
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizePanGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:panRecognizer didRecognizePanGesture:displacement];
+    }
+}
+
+- (void)respondToPinchGesture:(UIPinchGestureRecognizer *)pinchRecognizer
+{
+    CGPoint location = [pinchRecognizer locationInView:self.view];
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizePinchGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:pinchRecognizer shouldRecognizePinchGesture:location]) {
+            return;
+        }
+    }
+
+    CGFloat scale = pinchRecognizer.scale;
+    [pinchRecognizer setScale:1.0];
+    self.map->handlePinchGesture(location.x * self.contentScaleFactor, location.y * self.contentScaleFactor, scale, pinchRecognizer.velocity);
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizePinchGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:pinchRecognizer didRecognizePinchGesture:location];
+    }
+}
+
+- (void)respondToRotationGesture:(UIRotationGestureRecognizer *)rotationRecognizer
+{
+    CGPoint position = [rotationRecognizer locationInView:self.view];
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:shouldRecognizeRotationGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:rotationRecognizer shouldRecognizeRotationGesture:position]) {
+            return;
+        }
+    }
+
+    CGFloat rotation = rotationRecognizer.rotation;
+    [rotationRecognizer setRotation:0.0];
+    self.map->handleRotateGesture(position.x * self.contentScaleFactor, position.y * self.contentScaleFactor, rotation);
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(mapView:recognizer:didRecognizeRotationGesture:)]) {
+        [self.gestureDelegate mapView:self recognizer:rotationRecognizer didRecognizeRotationGesture:position];
+    }
+}
+
+- (void)respondToShoveGesture:(UIPanGestureRecognizer *)shoveRecognizer
+{
+    CGPoint displacement = [shoveRecognizer translationInView:self.view];
+    [shoveRecognizer setTranslation:{0, 0} inView:self.view];
+
+    if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(recognizer:shouldRecognizeShoveGesture:)]) {
+        if (![self.gestureDelegate mapView:self recognizer:shoveRecognizer shouldRecognizeShoveGesture:displacement]) {
+            return;
+        }
+    }
+
+    // don't trigger shove on single touch gesture
+    if ([shoveRecognizer numberOfTouches] == 2) {
+        self.map->handleShoveGesture(displacement.y);
+
+        if (self.gestureDelegate && [self.gestureDelegate respondsToSelector:@selector(recognizer:didRecognizeShoveGesture:)]) {
+            [self.gestureDelegate mapView:self recognizer:shoveRecognizer didRecognizeShoveGesture:displacement];
+        }
+    }
+}
+#pragma mark Standard Initializer
+
+- (instancetype)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
+{
+    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
+    if (self != nil) {
+        std::shared_ptr<Tangram::Platform> platform(new Tangram::iOSPlatform(self));
+        self.map = new Tangram::Map(platform);
+    }
+    return self;
+}
+
+- (instancetype)initWithCoder:(NSCoder *)aDecoder
+{
+    self = [super initWithCoder:aDecoder];
+    if (self != nil) {
+        std::shared_ptr<Tangram::Platform> platform(new Tangram::iOSPlatform(self));
+        self.map = new Tangram::Map(platform);
+    }
+    return self;
+}
+
+#pragma mark Map view lifecycle
+
+- (void)viewDidLoad
+{
+    [super viewDidLoad];
+
+    self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
+    if (!self.context) {
+        NSLog(@"Failed to create ES context");
+    }
+
+    self->viewComplete = NO;
+    self->captureFrameWaitForViewComplete = YES;
+    self->shouldCaptureFrame = NO;
+    self.renderRequested = YES;
+    self.continuous = NO;
+    self.markersById = [[NSMutableDictionary alloc] init];
+    self.dataLayersByName = [[NSMutableDictionary alloc] init];
+
+    if (!self.httpHandler) {
+        self.httpHandler = [[TGHttpHandler alloc] initWithCachePath:@"/tangram_cache"
+                                                cacheMemoryCapacity:4*1024*1024
+                                                  cacheDiskCapacity:30*1024*1024];
+    }
+
+    GLKView* view = (GLKView *)self.view;
+    view.context = self.context;
+
+    view.drawableColorFormat = GLKViewDrawableColorFormatRGBA8888;
+    view.drawableDepthFormat = GLKViewDrawableDepthFormat24;
+    view.drawableStencilFormat = GLKViewDrawableStencilFormatNone;
+    view.drawableMultisample = GLKViewDrawableMultisampleNone;
+
+    self.contentScaleFactor = view.contentScaleFactor;
+
+    [self setupGestureRecognizers];
+    [self setupGL];
+
+}
+
+- (void)dealloc
+{
+    if ([EAGLContext currentContext] == self.context) {
+        [EAGLContext setCurrentContext:nil];
+    }
+}
+
+- (void)didReceiveMemoryWarning
+{
+    [super didReceiveMemoryWarning];
+
+    if (self.map) {
+        self.map->onMemoryWarning();
+    }
+}
+
+- (void)setupGL
+{
+    [EAGLContext setCurrentContext:self.context];
+
+    self.map->setupGL();
+    self.map->setPixelScale(self.contentScaleFactor);
+}
+
+- (void)tearDownGL
+{
+    if (!self.map) { return; }
+
+    delete self.map;
+    self.map = nullptr;
+}
+
+-(void)viewWillLayoutSubviews {
+    [super viewWillLayoutSubviews];
+    int width = self.view.bounds.size.width;
+    int height = self.view.bounds.size.height;
+    self.map->resize(width * self.contentScaleFactor, height * self.contentScaleFactor);
+}
+
+- (void)viewWillTransitionToSize:(CGSize)size withTransitionCoordinator:(id<UIViewControllerTransitionCoordinator>)coordinator
+{
+    self.map->resize(size.width * self.contentScaleFactor, size.height * self.contentScaleFactor);
+
+    [self renderOnce];
+}
+
+- (void)requestRender
+{
+    if (!self.map) { return; }
+
+    self.renderRequested = YES;
+}
+
+- (void)renderOnce
+{
+    if (!self.continuous) {
+        self.renderRequested = YES;
+        self.paused = NO;
+    }
+}
+
+- (void)setContinuous:(BOOL)c
+{
+    _continuous = c;
+    self.paused = !c;
+}
+
+- (void)setResourceRoot:(NSURL *)resourceRoot
+{
+    if (!self.map) { return; }
+
+    Tangram::iOSPlatform& platform = static_cast<Tangram::iOSPlatform&>(*self.map->getPlatform());
+
+    platform.setResourceRoot(resourceRoot);
+}
+
+- (void)captureScreenshot:(BOOL)waitForViewComplete
+{
+    self->captureFrameWaitForViewComplete = waitForViewComplete;
+    self->shouldCaptureFrame = YES;
+}
+
+- (void)update
+{
+    self->viewComplete = self.map->update([self timeSinceLastUpdate]);
+
+    if (viewComplete && [self.mapViewDelegate respondsToSelector:@selector(mapViewDidCompleteLoading:)]) {
+        [self.mapViewDelegate mapViewDidCompleteLoading:self];
+    }
+
+    if (!self.continuous && !self.renderRequested) {
+        self.paused = YES;
+    }
+
+    self.renderRequested = NO;
+}
+
+- (void)glkView:(GLKView *)view drawInRect:(CGRect)rect
+{
+    self.map->render();
+
+    if (self.mapViewDelegate && [self.mapViewDelegate respondsToSelector:@selector(mapView:didCaptureScreenshot:)]) {
+        if (self->shouldCaptureFrame && (!self->captureFrameWaitForViewComplete || self->viewComplete)) {
+            UIGraphicsBeginImageContext(self.view.frame.size);
+            [self.view drawViewHierarchyInRect:self.view.frame afterScreenUpdates:YES];
+            UIImage* screenshot = UIGraphicsGetImageFromCurrentImageContext();
+            UIGraphicsEndImageContext();
+
+            [self.mapViewDelegate mapView:self didCaptureScreenshot:screenshot];
+
+            self->shouldCaptureFrame = NO;
+        }
+    }
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMarker+Internal.h b/platforms/ios/src/TangramMap/TGMarker+Internal.h
new file mode 100644 (file)
index 0000000..6f4ce84
--- /dev/null
@@ -0,0 +1,21 @@
+//
+//  TGMarker+Internal.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 4/10/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "tangram.h"
+
+@interface TGMarker ()
+
+NS_ASSUME_NONNULL_BEGIN
+
+- (instancetype)initWithMap:(Tangram::Map*)map;
+
+NS_ASSUME_NONNULL_END
+
+@property (assign, nonatomic) Tangram::MarkerID identifier;
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMarker.h b/platforms/ios/src/TangramMap/TGMarker.h
new file mode 100644 (file)
index 0000000..b868bf4
--- /dev/null
@@ -0,0 +1,118 @@
+//
+//  TGMarker.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/17/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import <UIKit/UIKit.h>
+
+#import "TGGeoPoint.h"
+#import "TGGeoPolygon.h"
+#import "TGGeoPolyline.h"
+#import "TGTypes.h"
+
+@class TGMapViewController;
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Marker interface that makes you able to add icons, polylines and polygons to the map view.
+
+ The marker style should defined using the <a href="https://mapzen.com/documentation/tangram/Styles-Overview">
+ Tangram YAML syntax</a>.
+ */
+@interface TGMarker : NSObject
+
+/**
+ Similar to `-[TGMarker point]` except that the point will transition to the
+ geographic coordinate with a transition of time `seconds` and with an ease type function of type `ease`
+ (See `TGEaseType`) from its previous coordinate, if a point geometry hasn't been set any coordinate yet,
+ this method will act as `-[TGMarker point]`.
+
+ @param coordinates the longitude and latitude where the marker will be placed
+ @param seconds the animation duration given in seconds
+ @param ease the ease function to be used between animation timestep
+
+ @note Markers can have their geometry set multiple time with possibly different geometry types.
+ */
+- (void)pointEased:(TGGeoPoint)coordinates seconds:(float)seconds easeType:(TGEaseType)ease;
+
+/**
+ Sets the styling for a marker with a string of YAML defining a 'draw rule'.
+ See the more detailed scene <a href="https://mapzen.com/documentation/tangram/Styles-Overview/">documentation</a>
+ to get more styling informations.
+
+ @note Setting the stylingString will overwrite any previously set stylingString or stylingPath.
+ */
+@property (copy, nonatomic) NSString* stylingString;
+
+/**
+ Sets the styling for a marker with a path, delimited by '.' that specifies a 'draw rule' in the
+ current scene.
+ See the more detailed scene <a href="https://mapzen.com/documentation/tangram/Styles-Overview/">documentation</a>
+ to get more styling informations.
+
+ @note Setting the stylingPath will overwrite any previously set stylingString or stylingPath.
+ */
+@property (copy, nonatomic) NSString* stylingPath;
+
+/**
+ Sets a marker to be a single point geometry at a geographic coordinate.
+
+ @note Markers can have their geometry set multiple time with possibly different geometry types.
+ */
+@property (assign, nonatomic) TGGeoPoint point;
+
+/**
+ Sets a marker styled to be a polyline (described in a `TGGeoPolyline`).
+
+ @note Markers can have their geometry set multiple time wwith possibly different geometry types.
+ */
+@property (strong, nonatomic) TGGeoPolyline* polyline;
+
+/**
+ Sets a marker to be a polygon geometry (described in a `TGGeoPolygon`).
+
+ @note Markers can have their geometry set multiple time with possibly different geometry types.
+ */
+@property (strong, nonatomic) TGGeoPolygon* polygon;
+
+/**
+ Sets an icon loaded with a <a href="https://developer.apple.com/reference/uikit/uiimage">
+ UIImage</a> to a marker styled with a <a href="https://mapzen.com/documentation/tangram/Styles-Overview/#points">
+ points style</a>.
+ ```swift
+ TGMarker marker;
+ marker.styling = "{ style: 'points', color: 'white', size: [25px, 25px], order:500 }"
+ marker.point = TGGeoPointMake(longitude, latitude)
+ marker.icon = UIIMage(name: "marker-icon.png")
+ ```
+ @note An icon marker must be styled with a
+ <a href="https://mapzen.com/documentation/tangram/Styles-Overview/#points">point style</a>.
+ */
+@property (strong, nonatomic) UIImage* icon;
+
+/// Adjusts marker visibility
+@property (assign, nonatomic) BOOL visible;
+/// Set the ordering of point marker object relative to other markers; higher values are drawn 'above'
+@property (assign, nonatomic) NSInteger drawOrder;
+/// A custom user data
+@property (assign, nonatomic) void* userData;
+
+NS_ASSUME_NONNULL_END
+
+/*
+ Returns whether the usage of this marker resulted in internal errors
+
+ @param error a pointer to output error
+ @return YES if an error has been set to the input paramater, NO otherwise
+
+ @note The internal marker error will remain until you access it,
+ make sure to check for errors on the marker after critical API calls or property access.
+ */
+- (BOOL)getError:(NSError**)error;
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMarker.mm b/platforms/ios/src/TangramMap/TGMarker.mm
new file mode 100644 (file)
index 0000000..61d3bcc
--- /dev/null
@@ -0,0 +1,187 @@
+//
+//  TGMarker.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/17/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMarker.h"
+#import "TGMarker+Internal.h"
+#import "TGMapViewController.h"
+#import "TGMapViewController+Internal.h"
+#import "TGHelpers.h"
+#import "TGTypes.h"
+#import "tangram.h"
+
+@interface TGMarker () {
+    Tangram::Map* tangramInstance;
+    NSError* error;
+}
+
+- (void)createNSError;
+- (void)clearGeometry;
+
+@end
+
+@implementation TGMarker
+
+- (instancetype)initWithMap:(Tangram::Map*)map
+{
+    self = [super init];
+
+    if (self) {
+        tangramInstance = map;
+        self.identifier = tangramInstance->markerAdd();
+        self.visible = YES;
+        self.drawOrder = 0;
+    }
+
+    return self;
+}
+
+- (void)clearGeometry
+{
+    _polyline = nil;
+    _polygon = nil;
+    _point = {NAN, NAN};
+}
+
+- (void)createNSError
+{
+    // TODO: Check for all Tangram internal tangram error and
+    // convert it to this error string for additional infos
+    NSString* errorString = @"Tangram marker internal error";
+
+    self->error = [NSError errorWithDomain:TGErrorDomain code:TGErrorMarker userInfo:@{ NSLocalizedDescriptionKey:errorString }];
+}
+
+- (void)setStylingString:(NSString *)styling
+{
+    _stylingString = styling;
+    _stylingPath = nil;
+
+    if (!tangramInstance->markerSetStylingFromString(self.identifier, [styling UTF8String])) {
+        [self createNSError];
+    }
+}
+
+- (void)setStylingPath:(NSString *)path
+{
+    _stylingPath = path;
+    _stylingString = nil;
+
+    if (!tangramInstance->markerSetStylingFromPath(self.identifier, [path UTF8String])) {
+        [self createNSError];
+    }
+}
+
+- (void)pointEased:(TGGeoPoint)coordinates seconds:(float)seconds easeType:(TGEaseType)ease
+{
+    [self clearGeometry];
+    _point = coordinates;
+
+    Tangram::LngLat lngLat(coordinates.longitude, coordinates.latitude);
+
+    if (!tangramInstance->markerSetPointEased(self.identifier, lngLat, seconds, [TGHelpers convertEaseTypeFrom:ease])) {
+        [self createNSError];
+    }
+}
+
+- (void)setPoint:(TGGeoPoint)coordinates
+{
+    [self clearGeometry];
+    _point = coordinates;
+
+    Tangram::LngLat lngLat(coordinates.longitude, coordinates.latitude);
+
+    if (!tangramInstance->markerSetPoint(self.identifier, lngLat)) {
+        [self createNSError];
+    }
+}
+
+- (void)setPolyline:(TGGeoPolyline *)polyline
+{
+    [self clearGeometry];
+    _polyline = polyline;
+
+    auto polylineCoords = reinterpret_cast<Tangram::LngLat*>([polyline coordinates]);
+
+    if (!tangramInstance->markerSetPolyline(self.identifier, polylineCoords, polyline.count)) {
+        [self createNSError];
+    }
+}
+
+- (void)setPolygon:(TGGeoPolygon *)polygon
+{
+    [self clearGeometry];
+    _polygon = polygon;
+
+    auto polygonCoords = reinterpret_cast<Tangram::LngLat*>([polygon coordinates]);
+
+    if (!tangramInstance->markerSetPolygon(self.identifier, polygonCoords, [polygon rings], [polygon ringsCount])) {
+        [self createNSError];
+    }
+}
+
+- (void)setVisible:(BOOL)visible
+{
+    _visible = visible;
+
+    if (!tangramInstance->markerSetVisible(self.identifier, visible)) {
+        [self createNSError];
+    }
+}
+
+- (void)setDrawOrder:(NSInteger)drawOrder
+{
+    _drawOrder = drawOrder;
+
+    if (!tangramInstance->markerSetDrawOrder(self.identifier, (int)drawOrder)) {
+        [self createNSError];
+    }
+}
+
+- (void)setIcon:(UIImage *)icon
+{
+    _icon = icon;
+
+    CGImage* cgImage = [icon CGImage];
+    size_t w = CGImageGetHeight(cgImage);
+    size_t h = CGImageGetWidth(cgImage);
+    std::vector<unsigned int> bitmap;
+
+    bitmap.resize(w * h);
+
+    CGColorSpaceRef colorSpace = CGImageGetColorSpace(cgImage);
+    CGContextRef cgContext = CGBitmapContextCreate(bitmap.data(), w, h, 8, w * 4,
+        colorSpace, kCGImageAlphaPremultipliedLast);
+
+    // Flip image upside down-horizontally
+    CGAffineTransform flipAffineTransform = CGAffineTransformMake(1, 0, 0, -1, 0, h);
+    CGContextConcatCTM(cgContext, flipAffineTransform);
+
+    CGContextDrawImage(cgContext, CGRectMake(0, 0, w, h), cgImage);
+    CGContextRelease(cgContext);
+
+    if (!tangramInstance->markerSetBitmap(self.identifier, w, h, bitmap.data())) {
+        [self createNSError];
+    }
+}
+
+- (BOOL)getError:(NSError**)error
+{
+    if (self->error) {
+        if (error) {
+            *error = self->error;
+        }
+
+        self->error = nil;
+        return YES;
+    }
+
+    return NO;
+}
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGMarkerPickResult+Internal.h b/platforms/ios/src/TangramMap/TGMarkerPickResult+Internal.h
new file mode 100644 (file)
index 0000000..d881e2b
--- /dev/null
@@ -0,0 +1,31 @@
+//
+//  TGMarkerPickResult+Internal.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 2/27/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMarkerPickResult.h"
+
+@interface TGMarkerPickResult ()
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Initializes a `TGMarkerPickResult`.
+
+ @param coordinates the geographic coordinates of the label pick result
+ @param marker the marker object selected
+
+ @return an initialized `TGMarkerPickResult`
+
+ @note You shouldn't have to create a `TGMarkerPickResult` yourself, those are returned as a result to
+ a selection query on the `TGMapViewController` and initialized by the latter.
+ */
+- (instancetype) initWithCoordinates:(TGGeoPoint)coordinates marker:(TGMarker *)marker;
+
+NS_ASSUME_NONNULL_END
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGMarkerPickResult.h b/platforms/ios/src/TangramMap/TGMarkerPickResult.h
new file mode 100644 (file)
index 0000000..f0e21ef
--- /dev/null
@@ -0,0 +1,30 @@
+//
+//  TGMarkerPickResult.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 01/03/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+#import "TGGeoPoint.h"
+#import "TGMarker.h"
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Data structure holding the result of a marker selection that occured on the map view.
+
+ See `-[TGMapViewController pickMarkerAt:]` and `[TGMapViewDelegate mapView:didSelectMarker:atScreenPosition:]`.
+ */
+@interface TGMarkerPickResult : NSObject
+
+/// The geographic coordinates of the selected label
+@property (readonly, nonatomic) TGGeoPoint coordinates;
+
+/// The selected marker
+@property (readonly, nonatomic) TGMarker* marker;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGMarkerPickResult.mm b/platforms/ios/src/TangramMap/TGMarkerPickResult.mm
new file mode 100644 (file)
index 0000000..0c8de17
--- /dev/null
@@ -0,0 +1,34 @@
+//
+//  TGMarkerPickResult.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 01/03/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGMarkerPickResult.h"
+#import "TGMarkerPickResult+Internal.h"
+
+@interface TGMarkerPickResult ()
+
+@property (assign, nonatomic) TGGeoPoint coordinates;
+@property (strong, nonatomic) TGMarker* marker;
+
+@end
+
+@implementation TGMarkerPickResult
+
+- (instancetype) initWithCoordinates:(TGGeoPoint)coordinates marker:(TGMarker *)marker
+{
+    self = [super init];
+
+    if (self) {
+        self.coordinates = coordinates;
+        self.marker = marker;
+    }
+
+    return self;
+}
+
+@end
+
diff --git a/platforms/ios/src/TangramMap/TGSceneUpdate.h b/platforms/ios/src/TangramMap/TGSceneUpdate.h
new file mode 100644 (file)
index 0000000..6be3f1d
--- /dev/null
@@ -0,0 +1,53 @@
+//
+//  TGSceneUpdate.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/05/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+NS_ASSUME_NONNULL_BEGIN
+
+/**
+ Represents a data structure to specify a YAML path and the corresponding value for a Tangram scene update.
+
+ Example to update an API key for a source defined like this in your stylesheet:
+
+ ```
+ sources:
+     osm:
+         type: MVT
+         url:  https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt
+         max_zoom: 16
+         url_params:
+             api_key: vector-tiles-tyHL4AY
+ ```
+
+ ```swift
+ view.queueSceneUpdates(sceneUpdates: [ TGSceneUpdate(path: "sources.osm.url_params", value: "{ api_key: \(YOUR_API_KEY) }") ])
+ view.applySceneUpdates()
+ ```
+ */
+@interface TGSceneUpdate : NSObject
+
+/**
+ Init a scene update for a specific YAML path in the stylesheet and a new value:
+
+ @param path the YAML path within the stylesheet
+ @param value the new YAML value for the node selected by path
+
+ @return an initialized scene update
+ */
+- (instancetype)initWithPath:(NSString *)path value:(NSString *)value;
+
+/// The YAML path for which the update will occur in the stylesheet used in the map view
+@property (copy, nonatomic) NSString* path;
+
+/// The YAML value to set in the update
+@property (copy, nonatomic) NSString* value;
+
+NS_ASSUME_NONNULL_END
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGSceneUpdate.mm b/platforms/ios/src/TangramMap/TGSceneUpdate.mm
new file mode 100644 (file)
index 0000000..83fe06e
--- /dev/null
@@ -0,0 +1,25 @@
+//
+//  TGSceneUpdate.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 11/05/16.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGSceneUpdate.h"
+
+@implementation TGSceneUpdate
+
+- (instancetype)initWithPath:(NSString *)path value:(NSString *)value;
+{
+    self = [super init];
+
+    if (self) {
+        self.path = path;
+        self.value = value;
+    }
+
+    return self;
+}
+
+@end
diff --git a/platforms/ios/src/TangramMap/TGTypes.h b/platforms/ios/src/TangramMap/TGTypes.h
new file mode 100644 (file)
index 0000000..a978f59
--- /dev/null
@@ -0,0 +1,75 @@
+//
+//  TGTypes.h
+//  TangramMap
+//
+//  Created by Karim Naaji on 4/20/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import <Foundation/Foundation.h>
+
+/// Indicates an error occurred in the Tangram Framework.
+extern NSString* const TGErrorDomain;
+
+/*
+ These enumerations describe an ease type function to be used for camera or other transition animation.
+ The function is being used to interpolate between the start and end position of the animation.
+ */
+typedef NS_ENUM(NSInteger, TGEaseType) {
+    /// Linear ease type `f(t) = t`
+    TGEaseTypeLinear = 0,
+    /// Cube ease type `f(t) = (-2 * t + 3) * t * t`
+    TGEaseTypeCubic,
+    /// Quint ease type `f(t) = (6 * t * t - 15 * t + 10) * t * t * t`
+    TGEaseTypeQuint,
+    /// Sine ease type `f(t) = 0.5 - 0.5 * cos(PI * t)`
+    TGEaseTypeSine,
+};
+
+/**
+ Description for a <a href="https://mapzen.com/documentation/tangram/Cameras-Overview/#camera-types">
+ Tangram camera type</a>.
+ */
+typedef NS_ENUM(NSInteger, TGCameraType) {
+    /// Type for a <a href="https://mapzen.com/documentation/tangram/Cameras-Overview/#perspective-camera">perspective camera</a>
+    TGCameraTypePerspective = 0,
+    /// Type for an <a href="https://mapzen.com/documentation/tangram/Cameras-Overview/#isometric-camera">isometric camera</a>
+    TGCameraTypeIsometric,
+    /// Type for a <a href="https://mapzen.com/documentation/tangram/Cameras-Overview/#flat-camera">flat camera</a>
+    TGCameraTypeFlat,
+};
+
+/// Description of error status from Tangram
+typedef NS_ENUM(NSInteger, TGError) {
+    /// The path of the scene update was not found on the scene file
+    TGErrorSceneUpdatePathNotFound,
+    /// The YAML syntax of the scene udpate path has a syntax error
+    TGErrorSceneUpdatePathYAMLSyntaxError,
+    /// The YAML syntax of the scene update value has a syntax error
+    TGErrorSceneUpdateValueYAMLSyntaxError,
+    /// An error code for markers
+    TGErrorMarker,
+};
+
+/// Debug flags to render additional information about various map components
+typedef NS_ENUM(NSInteger, TGDebugFlag) {
+    /// While on, the set of tiles currently being drawn will not update to match the view
+    TGDebugFlagFreezeTiles = 0,
+    /// Apply a color change to every other zoom level to visualize proxy tile behavior
+    TGDebugFlagProxyColors,
+    /// Draw tile boundaries
+    TGDebugFlagTileBounds,
+    /// Draw tile infos (tile coordinates)
+    TGDebugFlagTileInfos,
+    /// Draw label bounding boxes and collision grid
+    TGDebugFlagLabels,
+    /// Draw tangram infos (framerate, debug log...)
+    TGDebugFlagTangramInfos,
+    /// Draw all labels (including labels being occluded)
+    TGDebugFlagDrawAllLabels,
+    /// Draw tangram frame graph stats
+    TGDebugFlagTangramStats,
+    /// Draw feature selection framebuffer
+    TGDebugFlagSelectionBuffer,
+};
+
diff --git a/platforms/ios/src/TangramMap/TGTypes.mm b/platforms/ios/src/TangramMap/TGTypes.mm
new file mode 100644 (file)
index 0000000..cc18663
--- /dev/null
@@ -0,0 +1,11 @@
+//
+//  TGTypes.mm
+//  TangramMap
+//
+//  Created by Karim Naaji on 4/20/17.
+//  Copyright (c) 2017 Mapzen. All rights reserved.
+//
+
+#import "TGTypes.h"
+
+NSString* const TGErrorDomain = @"TGErrorDomain";
diff --git a/platforms/ios/src/TangramMap/platform_ios.h b/platforms/ios/src/TangramMap/platform_ios.h
new file mode 100644 (file)
index 0000000..5966b95
--- /dev/null
@@ -0,0 +1,39 @@
+#pragma once
+
+#include "platform.h"
+
+#include <OpenGLES/ES2/gl.h>
+#include <OpenGLES/ES2/glext.h>
+
+#ifdef __OBJC__
+#import "TGMapViewController.h"
+
+namespace Tangram {
+
+class iOSPlatform : public Platform {
+
+public:
+
+    iOSPlatform(TGMapViewController* _viewController);
+    void requestRender() const override;
+    void setContinuousRendering(bool _isContinuous) override;
+    std::string resolveAssetPath(const std::string& _path) const override;
+    std::string stringFromFile(const char* _path) const override;
+    std::vector<char> bytesFromFile(const char* _path) const override;
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+    std::vector<char> systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+    void setResourceRoot(NSURL* _resourceRoot);
+
+private:
+
+    TGMapViewController* m_viewController;
+    NSURL* m_resourceRoot;
+
+};
+
+} // namespace Tangram
+
+#endif
+
diff --git a/platforms/ios/src/TangramMap/platform_ios.mm b/platforms/ios/src/TangramMap/platform_ios.mm
new file mode 100644 (file)
index 0000000..f2d7389
--- /dev/null
@@ -0,0 +1,260 @@
+#ifdef PLATFORM_IOS
+
+#import <UIKit/UIKit.h>
+#import <cstdio>
+#import <cstdarg>
+
+#import "TGMapViewController.h"
+#import "TGFontConverter.h"
+#import "TGHttpHandler.h"
+#import "platform_ios.h"
+#import "log.h"
+
+namespace Tangram {
+
+NSString* resolvePath(const char* _path, NSURL* _resourceRoot) {
+    NSString* pathString = [NSString stringWithUTF8String:_path];
+
+    NSURL* resolvedUrl = [NSURL URLWithString:pathString
+                                relativeToURL:_resourceRoot];
+
+    NSString* pathInAppBundle = [resolvedUrl path];
+
+    NSFileManager* fileManager = [NSFileManager defaultManager];
+
+    if ([fileManager fileExistsAtPath:pathInAppBundle]) {
+        return pathInAppBundle;
+    }
+
+    LOGW("Failed to resolve path: %s", _path);
+
+    return nil;
+}
+
+std::vector<char> loadUIFont(UIFont* _font) {
+    if (!_font) {
+        return {};
+    }
+
+    CGFontRef fontRef = CGFontCreateWithFontName((CFStringRef)_font.fontName);
+
+    if (!fontRef) {
+        return {};
+    }
+
+    std::vector<char> data = [TGFontConverter fontDataForCGFont:fontRef];
+
+    CGFontRelease(fontRef);
+
+    if (data.empty()) {
+        LOG("CoreGraphics font failed to decode");
+    }
+
+    return data;
+}
+
+void logMsg(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
+
+void setCurrentThreadPriority(int priority) {
+    // POSIX thread priority is between -20 (highest) and 19 (lowest),
+    // NSThread priority is between 0.0 (lowest) and 1.0 (highest).
+    double p = (20 - priority) / 40.0;
+    [[NSThread currentThread] setThreadPriority:p];
+}
+
+void initGLExtensions() {
+    // No-op
+}
+
+iOSPlatform::iOSPlatform(TGMapViewController* _viewController) :
+    Platform(),
+    m_viewController(_viewController)
+{
+    m_resourceRoot = [[NSBundle mainBundle] resourceURL];
+}
+
+void iOSPlatform::requestRender() const {
+    [m_viewController renderOnce];
+}
+
+void iOSPlatform::setResourceRoot(NSURL* _resourceRoot) {
+    m_resourceRoot = _resourceRoot;
+}
+
+void iOSPlatform::setContinuousRendering(bool _isContinuous) {
+    Platform::setContinuousRendering(_isContinuous);
+    [m_viewController setContinuous:_isContinuous];
+}
+
+std::string iOSPlatform::resolveAssetPath(const std::string& _path) const {
+    NSString* path = resolvePath(_path.c_str(), m_resourceRoot);
+    return [path UTF8String];
+}
+
+std::vector<char> iOSPlatform::bytesFromFile(const char* _path) const {
+    NSString* path = resolvePath(_path, m_resourceRoot);
+
+    if (!path) { return {}; }
+
+    auto data = Platform::bytesFromFile([path UTF8String]);
+    return data;
+}
+
+std::string iOSPlatform::stringFromFile(const char* _path) const {
+    NSString* path = resolvePath(_path, m_resourceRoot);
+    std::string data;
+
+    if (!path) { return data; }
+
+    data = Platform::stringFromFile([path UTF8String]);
+    return data;
+}
+
+bool allowedFamily(NSString* familyName) {
+    const NSArray<NSString *> *allowedFamilyList = @[ @"Hebrew", @"Kohinoor", @"Gumurki", @"Thonburi", @"Tamil",
+                                                    @"Gurmukhi", @"Kailasa", @"Sangam", @"PingFang", @"Geeza",
+                                                    @"Mishafi", @"Farah", @"Hiragino" ];
+
+    for (NSString* allowedFamily in allowedFamilyList) {
+        if ( [familyName containsString:allowedFamily] ) { return true; }
+    }
+    return false;
+}
+
+std::vector<FontSourceHandle> iOSPlatform::systemFontFallbacksHandle() const {
+    NSArray* fallbacks = [UIFont familyNames];
+
+    std::vector<FontSourceHandle> handles;
+
+    for (id fallback in fallbacks) {
+
+        handles.emplace_back([fallback]() {
+            auto data = loadUIFont([UIFont fontWithName:fallback size:1.0]);
+            return data;
+        });
+    }
+
+    return handles;
+}
+
+std::vector<char> iOSPlatform::systemFont(const std::string& _name, const std::string& _weight, const std::string& _face) const {
+    static std::map<int, CGFloat> weightTraits = {
+        {100, UIFontWeightUltraLight},
+        {200, UIFontWeightThin},
+        {300, UIFontWeightLight},
+        {400, UIFontWeightRegular},
+        {500, UIFontWeightMedium},
+        {600, UIFontWeightSemibold},
+        {700, UIFontWeightBold},
+        {800, UIFontWeightHeavy},
+        {900, UIFontWeightBlack},
+    };
+
+    static std::map<std::string, UIFontDescriptorSymbolicTraits> fontTraits = {
+        {"italic", UIFontDescriptorTraitItalic},
+        {"oblique", UIFontDescriptorTraitItalic},
+        {"bold", UIFontDescriptorTraitBold},
+        {"expanded", UIFontDescriptorTraitExpanded},
+        {"condensed", UIFontDescriptorTraitCondensed},
+        {"monospace", UIFontDescriptorTraitMonoSpace},
+    };
+
+    UIFont* font = [UIFont fontWithName:[NSString stringWithUTF8String:_name.c_str()] size:1.0];
+
+    if (font == nil) {
+        // Get the default system font
+        if (_weight.empty()) {
+            font = [UIFont systemFontOfSize:1.0];
+        } else {
+            int weight = std::atoi(_weight.c_str());
+
+            // Default to 400 boldness
+            weight = (weight == 0) ? 400 : weight;
+
+            // Map weight value to range [100..900]
+            weight = std::min(std::max(100, (int)floor(weight / 100.0 + 0.5) * 100), 900);
+
+            font = [UIFont systemFontOfSize:1.0 weight:weightTraits[weight]];
+        }
+    }
+
+    if (_face != "normal") {
+        UIFontDescriptorSymbolicTraits traits;
+        UIFontDescriptor* descriptor = [font fontDescriptor];
+
+        auto it = fontTraits.find(_face);
+        if (it != fontTraits.end()) {
+            traits = it->second;
+
+            // Create a new descriptor with the symbolic traits
+            descriptor = [descriptor fontDescriptorWithSymbolicTraits:traits];
+
+            if (descriptor != nil) {
+                font = [UIFont fontWithDescriptor:descriptor size:1.0];
+            }
+        }
+    }
+
+    return loadUIFont(font);
+}
+
+bool iOSPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+    TGHttpHandler* httpHandler = [m_viewController httpHandler];
+
+    if (!httpHandler) {
+        return false;
+    }
+
+    TGDownloadCompletionHandler handler = ^void (NSData* data, NSURLResponse* response, NSError* error) {
+
+        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
+
+        int statusCode = [httpResponse statusCode];
+
+        std::vector<char> rawDataVec;
+
+        if (error != nil) {
+
+            LOGE("Response \"%s\" with error \"%s\".", response, [error.localizedDescription UTF8String]);
+
+        } else if (statusCode < 200 || statusCode >= 300) {
+
+            LOGE("Unsuccessful status code %d: \"%s\" from: %s",
+                statusCode,
+                [[NSHTTPURLResponse localizedStringForStatusCode: statusCode] UTF8String],
+                [response.URL.absoluteString UTF8String]);
+            _callback(std::move(rawDataVec));
+
+        } else {
+
+            int dataLength = [data length];
+            rawDataVec.resize(dataLength);
+            memcpy(rawDataVec.data(), (char *)[data bytes], dataLength);
+            _callback(std::move(rawDataVec));
+
+        }
+    };
+
+    NSString* url = [NSString stringWithUTF8String:_url.c_str()];
+    [httpHandler downloadRequestAsync:url completionHandler:handler];
+
+    return true;
+}
+
+void iOSPlatform::cancelUrlRequest(const std::string& _url) {
+    TGHttpHandler* httpHandler = [m_viewController httpHandler];
+
+    if (!httpHandler) { return; }
+
+    NSString* url = [NSString stringWithUTF8String:_url.c_str()];
+    [httpHandler cancelDownloadRequestAsync:url];
+}
+
+} // namespace Tangram
+
+#endif //PLATFORM_IOS
diff --git a/platforms/linux/README.md b/platforms/linux/README.md
new file mode 100644 (file)
index 0000000..ac28861
--- /dev/null
@@ -0,0 +1,82 @@
+Ubuntu or Debian Linux
+======================
+
+## Setup ##
+
+This project uses CMake (minimum version 3.0), you can download it [here](http://www.cmake.org/download/) or install it with apt-get.
+
+```bash
+sudo apt-get install cmake
+```
+
+Make sure to update git submodules before you build:
+
+```bash
+git submodule update --init
+```
+
+To build on Ubuntu or Debian you will need a C++ toolchain with support for C++14. GCC 4.9.2 (or higher) and Clang 3.4 (or higher) are known to work.
+
+You will also need to install development packages for libcurl, x11, and opengl. On Ubuntu 16.04 or Debian Stretch all the required packages can be installed with
+
+```bash
+sudo apt-get install make g++ pkg-config libcurl4-openssl-dev \
+  libx11-dev libxrandr-dev libxinerama-dev libxcursor-dev libgl1-mesa-dev
+```
+
+The demo application uses the Mapzen vector tile service, so you will need a Mapzen API key to build and run the demo. 
+
+ 1. Visit https://mapzen.com/documentation/overview/#get-started-developing-with-mapzen to get an API key.
+
+ 2. Setup an environment variable (`MAPZEN_API_KEY`) to point to your API key.
+    ```bash
+    export MAPZEN_API_KEY=YOUR_API_KEY
+    ```
+
+## Build ##
+
+There are two ways to build the tangram-es library and demo application on Linux:
+
+### Command Line ###
+
+To build the executable demo application:
+
+```bash
+make linux
+```
+
+You can optionally use `make -j` to parallelize the build and append `DEBUG=1` or `RELEASE=1` to choose the build type.
+
+Then run it from the output folder:
+
+```bash
+cd build/linux/bin/ && ./tangram
+```
+
+You can open a different YAML scene file by dragging and dropping it into the window, or passing it as an argument:
+
+```bash
+cd build/linux/bin/ && ./tangram -f /path/to/your/scene.yaml
+```
+
+Tangram-es can optionally be built with system-installed font and GLFW libraries. You can install these libraries with:
+
+```bash
+sudo apt-get install libglfw3-dev libicu-dev libfreetype6-dev libharfbuzz-dev
+```
+
+Then compile with the following options:
+
+```bash
+CMAKE_OPTIONS=" -DUSE_SYSTEM_GLFW_LIBS=1 -DUSE_SYSTEM_FONT_LIBS=1" make linux
+```
+
+### CLion ###
+
+You can also run and debug from CLion.
+
+After cloning and updating your git submodules, open CLion and __Import Project from Sources__. Select the root of this repo. Choose __Open Project__. Do not overwrite CMakeLists.txt.
+
+CLion will automatically set everything up, all you have to do is wait a minute for the project to get initialized. Then, select the __tangram__ run configuration and hit run/debug.
+
+![CLion Tangram Target](../../images/clion-tangram-target.png)
diff --git a/platforms/linux/src/main.cpp b/platforms/linux/src/main.cpp
new file mode 100644 (file)
index 0000000..37d7b23
--- /dev/null
@@ -0,0 +1,38 @@
+#include "glfwApp.h"
+#include "log.h"
+#include "platform_linux.h"
+#include "tangram.h"
+#include <memory>
+#include <signal.h>
+#include <stdlib.h>
+
+using namespace Tangram;
+
+int main(int argc, char* argv[]) {
+
+    auto platform = std::make_shared<LinuxPlatform>();
+
+    std::string sceneFile = "scene.yaml";
+    // Load file from command line, if given.
+    int argi = 0;
+    while (++argi < argc) {
+        if (strcmp(argv[argi - 1], "-f") == 0) {
+            sceneFile = std::string(argv[argi]);
+            LOG("File from command line: %s\n", argv[argi]);
+            break;
+        }
+    }
+
+    // Create the windowed app.
+    GlfwApp::create(platform, sceneFile, 1024, 768);
+
+    // Give it a chance to shutdown cleanly on CTRL-C
+    signal(SIGINT, &GlfwApp::stop);
+
+    // Loop until the user closes the window
+    GlfwApp::run();
+
+    // Clean up.
+    GlfwApp::destroy();
+
+}
diff --git a/platforms/linux/src/platform_linux.cpp b/platforms/linux/src/platform_linux.cpp
new file mode 100644 (file)
index 0000000..0f943c4
--- /dev/null
@@ -0,0 +1,87 @@
+#include "platform_linux.h"
+#include "gl/hardware.h"
+#include "log.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#if defined(PLATFORM_LINUX)
+#include <GLFW/glfw3.h>
+#elif defined(PLATFORM_RPI)
+#include "context.h"
+#endif
+
+#define DEFAULT "fonts/NotoSans-Regular.ttf"
+#define FONT_AR "fonts/NotoNaskh-Regular.ttf"
+#define FONT_HE "fonts/NotoSansHebrew-Regular.ttf"
+#define FONT_JA "fonts/DroidSansJapanese.ttf"
+#define FALLBACK "fonts/DroidSansFallback.ttf"
+
+namespace Tangram {
+
+void logMsg(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
+
+LinuxPlatform::LinuxPlatform() :
+    m_urlClient(UrlClient::Options{}) {}
+
+LinuxPlatform::LinuxPlatform(UrlClient::Options urlClientOptions) :
+    m_urlClient(urlClientOptions) {}
+
+void LinuxPlatform::requestRender() const {
+#if defined(PLATFORM_LINUX)
+    glfwPostEmptyEvent();
+#elif defined(PLATFORM_RPI)
+    setRenderRequest(true);
+#endif
+}
+
+std::vector<FontSourceHandle> LinuxPlatform::systemFontFallbacksHandle() const {
+    std::vector<FontSourceHandle> handles;
+
+    handles.emplace_back(DEFAULT);
+    handles.emplace_back(FONT_AR);
+    handles.emplace_back(FONT_HE);
+    handles.emplace_back(FONT_JA);
+    handles.emplace_back(FALLBACK);
+
+    return handles;
+}
+
+bool LinuxPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+
+    return m_urlClient.addRequest(_url, _callback);
+}
+
+void LinuxPlatform::cancelUrlRequest(const std::string& _url) {
+
+    m_urlClient.cancelRequest(_url);
+}
+
+LinuxPlatform::~LinuxPlatform() {}
+
+void setCurrentThreadPriority(int priority) {
+#if defined(PLATFORM_LINUX)
+    int tid = syscall(SYS_gettid);
+    setpriority(PRIO_PROCESS, tid, priority);
+#elif defined(PLATFORM_RPI)
+    // no-op
+#endif
+}
+
+void initGLExtensions() {
+#if defined(PLATFORM_LINUX)
+    Tangram::Hardware::supportsMapBuffer = true;
+#elif defined(PLATFORM_RPI)
+    // no-op
+#endif
+}
+
+} // namespace Tangram
diff --git a/platforms/linux/src/platform_linux.h b/platforms/linux/src/platform_linux.h
new file mode 100644 (file)
index 0000000..437a019
--- /dev/null
@@ -0,0 +1,26 @@
+#pragma once
+
+#include "platform.h"
+#include "urlClient.h"
+
+namespace Tangram {
+
+class LinuxPlatform : public Platform {
+
+public:
+
+    LinuxPlatform();
+    LinuxPlatform(UrlClient::Options urlClientOptions);
+    ~LinuxPlatform() override;
+    void requestRender() const override;
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+
+protected:
+
+    UrlClient m_urlClient;
+
+};
+
+} // namespace Tangram
diff --git a/platforms/osx/Info.plist b/platforms/osx/Info.plist
new file mode 100644 (file)
index 0000000..53a7f21
--- /dev/null
@@ -0,0 +1,33 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+       <key>CFBundleDevelopmentRegion</key>
+       <string>en</string>
+       <key>CFBundleDisplayName</key>
+       <string>tangram</string>
+       <key>CFBundleExecutable</key>
+       <string>tangram</string>
+       <key>CFBundleIdentifier</key>
+       <string>com.mapzen.tangram</string>
+       <key>CFBundleInfoDictionaryVersion</key>
+       <string>6.0</string>
+       <key>CFBundleName</key>
+       <string>tangram</string>
+       <key>CFBundlePackageType</key>
+       <string>APPL</string>
+       <key>CFBundleShortVersionString</key>
+       <string>1.0</string>
+       <key>CFBundleSignature</key>
+       <string>????</string>
+       <key>CFBundleVersion</key>
+       <string>1.0</string>
+       <key>NSAppTransportSecurity</key>
+       <dict>
+               <key>NSAllowsArbitraryLoads</key>
+               <true/>
+       </dict>
+       <key>NSHighResolutionCapable</key>
+       <true/>
+</dict>
+</plist>
diff --git a/platforms/osx/README.md b/platforms/osx/README.md
new file mode 100644 (file)
index 0000000..fcb22ff
--- /dev/null
@@ -0,0 +1,82 @@
+Mac OS X
+========
+
+## Setup ##
+
+This project uses CMake (minimum version 3.0), you can download it [here](http://www.cmake.org/download/) or use your favorite installation package tool like [homebrew](http://brew.sh/).
+
+```bash
+brew install cmake
+```
+
+Make sure to update git submodules before you build:
+
+```bash
+git submodule update --init
+```
+
+The demo application uses the Mapzen vector tile service, so you will need a Mapzen API key to build and run the demo. 
+
+ 1. Visit https://mapzen.com/documentation/overview/#get-started-developing-with-mapzen to get an API key.
+
+ 2. Setup an environment variable (`MAPZEN_API_KEY`) to point to your API key. 
+ If you are using an IDE on osx, you need to do the following:
+    ```bash
+    launchctl setenv MAPZEN_API_KEY YOUR_API_KEY
+    ```
+ If you are running the app from a terminal you need to do the following:
+    ```bash
+    export MAPZEN_API_KEY=YOUR_API_KEY
+    ```
+
+## Build ##
+
+There are several ways you can build the tangram-es library and demo application on Mac OS X:
+
+### Command Line ###
+
+To build a runnable OS X application bundle, run:
+
+```bash
+make osx
+```
+
+You can optionally use `make -j` to parallelize the build and append `DEBUG=1` or `RELEASE=1` to choose the build type.
+
+Then open the application with:
+
+```bash
+open build/osx/bin/tangram.app
+```
+
+You can open a different YAML scene file by dragging and dropping it into the window, or passing it as an argument:
+
+```bash
+open build/osx/bin/tangram.app/Contents/MacOS/tangram -f /path/to/your/scene.yaml
+```
+
+### Xcode ###
+
+For running on OS X from Xcode you will need Xcode version 6.0 or higher. Generate and compile an Xcode project:
+
+```bash
+make xcode
+```
+
+Then just open the Xcode project and run/debug from there:
+
+```bash
+open build/xcode/tangram.xcodeproj
+```
+
+Note that any Xcode configuration change you make to the project won't be preserved when CMake runs again. Build configuration is defined only in the CMakeLists file(s).
+
+### CLion ###
+
+You can also run and debug from CLion.
+
+After cloning and updating your git submodules, open CLion and __Import Project from Sources__. Select the root of this repo. Choose __Open Project__. Do not overwrite CMakeLists.txt.
+
+CLion will automatically set everything up, all you have to do is wait a minute for the project to get initialized. Then, select the 'tangram' run configuration and hit run/debug.
+
+![CLion Tangram Target](../../images/clion-tangram-target.png)
diff --git a/platforms/osx/src/main.mm b/platforms/osx/src/main.mm
new file mode 100644 (file)
index 0000000..78ab308
--- /dev/null
@@ -0,0 +1,38 @@
+#include "glfwApp.h"
+#include "log.h"
+#include "platform_osx.h"
+#include "tangram.h"
+#include <memory>
+#include <signal.h>
+#include <stdlib.h>
+
+using namespace Tangram;
+
+int main(int argc, char* argv[]) {
+
+    auto platform = std::make_shared<OSXPlatform>();
+
+    std::string sceneFile = "scene.yaml";
+    // Load file from command line, if given.
+    int argi = 0;
+    while (++argi < argc) {
+        if (strcmp(argv[argi - 1], "-f") == 0) {
+            sceneFile = std::string(argv[argi]);
+            LOG("File from command line: %s\n", argv[argi]);
+            break;
+        }
+    }
+
+    // Create the windowed app.
+    GlfwApp::create(platform, sceneFile, 1024, 768);
+
+    // Give it a chance to shutdown cleanly on CTRL-C
+    signal(SIGINT, &GlfwApp::stop);
+
+    // Loop until the user closes the window
+    GlfwApp::run();
+
+    // Clean up.
+    GlfwApp::destroy();
+
+}
diff --git a/platforms/osx/src/platform_osx.h b/platforms/osx/src/platform_osx.h
new file mode 100644 (file)
index 0000000..e6a3df4
--- /dev/null
@@ -0,0 +1,35 @@
+#pragma once
+
+#include "platform.h"
+#define GLFW_INCLUDE_GLEXT
+#include <GLFW/glfw3.h>
+#include <mutex>
+
+#ifdef __OBJC__
+#import <Foundation/Foundation.h>
+
+namespace Tangram {
+
+class OSXPlatform : public Platform {
+
+public:
+
+    OSXPlatform();
+    ~OSXPlatform() override;
+    void requestRender() const override;
+    std::string stringFromFile(const char* _path) const override;
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+
+private:
+
+    std::mutex m_urlRequestMutex;
+    bool m_stopUrlRequests;
+    NSURLSession* m_defaultSession;
+
+};
+
+} // namespace Tangram
+
+#endif
diff --git a/platforms/osx/src/platform_osx.mm b/platforms/osx/src/platform_osx.mm
new file mode 100644 (file)
index 0000000..c5e1b62
--- /dev/null
@@ -0,0 +1,177 @@
+#ifdef PLATFORM_OSX
+
+#import <cstdio>
+#import <cstdarg>
+
+#include "platform_osx.h"
+#include "gl/hardware.h"
+#include "log.h"
+
+#define DEFAULT "fonts/NotoSans-Regular.ttf"
+#define FONT_AR "fonts/NotoNaskh-Regular.ttf"
+#define FONT_HE "fonts/NotoSansHebrew-Regular.ttf"
+#define FONT_JA "fonts/DroidSansJapanese.ttf"
+#define FALLBACK "fonts/DroidSansFallback.ttf"
+
+namespace Tangram {
+
+void logMsg(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
+
+void setCurrentThreadPriority(int priority) {
+    // POSIX thread priority is between -20 (highest) and 19 (lowest),
+    // NSThread priority is between 0.0 (lowest) and 1.0 (highest).
+    double p = (20 - priority) / 40.0;
+    [[NSThread currentThread] setThreadPriority:p];
+}
+
+void initGLExtensions() {
+    Tangram::Hardware::supportsMapBuffer = true;
+}
+
+NSString* resolvePath(const char* _path) {
+
+    NSString* pathString = [NSString stringWithUTF8String:_path];
+
+    NSURL* resourceFolderUrl = [[NSBundle mainBundle] resourceURL];
+
+    NSURL* resolvedUrl = [NSURL URLWithString:pathString
+                                relativeToURL:resourceFolderUrl];
+
+    NSFileManager* fileManager = [NSFileManager defaultManager];
+
+    NSString* pathInAppBundle = [resolvedUrl path];
+
+    if ([fileManager fileExistsAtPath:pathInAppBundle]) {
+        return pathInAppBundle;
+    }
+
+    LOGW("Failed to resolve path: %s", _path);
+
+    return nil;
+}
+
+void OSXPlatform::requestRender() const {
+    glfwPostEmptyEvent();
+}
+
+OSXPlatform::OSXPlatform() : m_stopUrlRequests(false) {
+    NSURLSessionConfiguration *defaultConfigObject = [NSURLSessionConfiguration defaultSessionConfiguration];
+
+    m_defaultSession = [NSURLSession sessionWithConfiguration: defaultConfigObject];
+
+    NSString *cachePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"/tile_cache"];
+    NSURLCache *tileCache = [[NSURLCache alloc] initWithMemoryCapacity: 4 * 1024 * 1024 diskCapacity: 30 * 1024 * 1024 diskPath: cachePath];
+    defaultConfigObject.URLCache = tileCache;
+    defaultConfigObject.requestCachePolicy = NSURLRequestUseProtocolCachePolicy;
+    defaultConfigObject.timeoutIntervalForRequest = 30;
+    defaultConfigObject.timeoutIntervalForResource = 60;
+}
+
+OSXPlatform::~OSXPlatform() {
+    {
+        std::lock_guard<std::mutex> guard(m_urlRequestMutex);
+        m_stopUrlRequests = true;
+    }
+
+    [m_defaultSession getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks) {
+        for(NSURLSessionTask* task in dataTasks) {
+            [task cancel];
+        }
+    }];
+}
+
+std::string OSXPlatform::stringFromFile(const char* _path) const {
+    NSString* path = resolvePath(_path);
+    std::string data;
+
+    if (!path) { return data; }
+
+    data = Platform::stringFromFile([path UTF8String]);
+    return data;
+}
+
+std::vector<FontSourceHandle> OSXPlatform::systemFontFallbacksHandle() const {
+    std::vector<FontSourceHandle> handles;
+
+    handles.emplace_back(DEFAULT);
+    handles.emplace_back(FONT_AR);
+    handles.emplace_back(FONT_HE);
+    handles.emplace_back(FONT_JA);
+    handles.emplace_back(FALLBACK);
+
+    return handles;
+}
+
+bool OSXPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+
+    NSString* nsUrl = [NSString stringWithUTF8String:_url.c_str()];
+
+    void (^handler)(NSData*, NSURLResponse*, NSError*) = ^void (NSData* data, NSURLResponse* response, NSError* error) {
+        {
+            std::lock_guard<std::mutex> guard(m_urlRequestMutex);
+
+            if (m_stopUrlRequests) {
+                LOGE("Response after Tangram shutdown.");
+                return;
+            }
+        }
+
+        NSHTTPURLResponse* httpResponse = (NSHTTPURLResponse*)response;
+
+        int statusCode = [httpResponse statusCode];
+
+        std::vector<char> rawDataVec;
+
+        if (error != nil) {
+
+            LOGE("Response \"%s\" with error \"%s\".", response, [error.localizedDescription UTF8String]);
+
+        } else if (statusCode < 200 || statusCode >= 300) {
+
+            LOGE("Unsuccessful status code %d: \"%s\" from: %s",
+                statusCode,
+                [[NSHTTPURLResponse localizedStringForStatusCode: statusCode] UTF8String],
+                [response.URL.absoluteString UTF8String]);
+            _callback(std::move(rawDataVec));
+
+        } else {
+
+            int dataLength = [data length];
+            rawDataVec.resize(dataLength);
+            memcpy(rawDataVec.data(), (char *)[data bytes], dataLength);
+            _callback(std::move(rawDataVec));
+
+        }
+
+    };
+
+    NSURLSessionDataTask* dataTask = [m_defaultSession dataTaskWithURL:[NSURL URLWithString:nsUrl] completionHandler:handler];
+
+    [dataTask resume];
+
+    return true;
+
+}
+
+void OSXPlatform::cancelUrlRequest(const std::string& _url) {
+
+    NSString* nsUrl = [NSString stringWithUTF8String:_url.c_str()];
+
+    [m_defaultSession getTasksWithCompletionHandler:^(NSArray* dataTasks, NSArray* uploadTasks, NSArray* downloadTasks) {
+        for(NSURLSessionTask* task in dataTasks) {
+            if([[task originalRequest].URL.absoluteString isEqualToString:nsUrl]) {
+                [task cancel];
+                break;
+            }
+        }
+    }];
+}
+
+} // namespace Tangram
+
+#endif //PLATFORM_OSX
diff --git a/platforms/rpi/README.md b/platforms/rpi/README.md
new file mode 100644 (file)
index 0000000..0c85b0f
--- /dev/null
@@ -0,0 +1,63 @@
+Raspberry Pi
+============
+
+## Setup ##
+
+This project uses CMake (minimum version 3.0), you can download it [here](http://www.cmake.org/download/) or install it with apt-get.
+
+```bash
+sudo apt-get install cmake
+```
+
+Make sure to update git submodules before you build:
+
+```bash
+git submodule update --init
+```
+
+To build on Rasberry Pi you will need a C++ toolchain with support for C++14. GCC 4.9.2 (or higher) and Clang 3.4 (or higher) are known to work (refer [here](https://community.thinger.io/t/starting-with-the-raspberry-pi/36) for instructions on getting GCC 4.9).
+
+You will also need to install development packages for libcurl:
+
+```
+sudo apt-get install libcurl4-openssl-dev
+```
+
+The demo application uses the Mapzen vector tile service, so you will need a Mapzen API key to build and run the demo. 
+
+ 1. Visit https://mapzen.com/documentation/overview/#get-started-developing-with-mapzen to get an API key.
+
+ 2. Setup an environment variable (`MAPZEN_API_KEY`) to point to your API key.
+    ```bash
+    export MAPZEN_API_KEY=YOUR_API_KEY
+    ```
+
+## Build ##
+
+Before compiling, choose which compiler to use:
+```
+export CXX=/usr/bin/g++-4.9
+```
+
+Then compile:
+
+```
+make rpi
+```
+
+You can optionally use `make -j` to parallelize the build and append `DEBUG=1` or `RELEASE=1` to choose the build type.
+
+Run the demo program from the output folder:
+```
+cd build/rpi/bin
+./tangram
+```
+
+Tangram will be rendered directly to the screen without a window manager. To show a mouse cursor, run with `-m`:
+
+```
+cd build/rpi/bin
+./tangram -m
+```
+
+You can also move the map with `w`, `a`, `s`, and `z`, zoom in and out with `-` and `=`, and quit with `q`.
diff --git a/platforms/rpi/src/context.cpp b/platforms/rpi/src/context.cpp
new file mode 100644 (file)
index 0000000..e6428af
--- /dev/null
@@ -0,0 +1,471 @@
+#include "context.h"
+
+#include <assert.h>
+#include <fcntl.h>
+#include <iostream>
+#include <string>
+#include <fstream>
+#include <termios.h>
+#include <linux/input.h>
+
+#include "glm/gtc/matrix_transform.hpp"
+#include "platform.h"
+#include "util/geom.h"
+
+// Main global variables
+//-------------------------------
+#define check() assert(glGetError() == 0)
+EGLDisplay display;
+EGLSurface surface;
+EGLContext context;
+
+static glm::ivec4 viewport;
+static glm::mat4 orthoMatrix;
+
+#define MOUSE_ID "mouse0"
+static int mouse_fd = -1;
+typedef struct {
+    float   x,y;
+    float   velX,velY;
+    int     button;
+} Mouse;
+static Mouse mouse;
+static bool bRender;
+static unsigned char keyPressed;
+
+// Mouse stuff
+//--------------------------------
+std::string searchForDevice(const std::string& _device) {
+    std::ifstream file;
+    std::string buffer;
+    std::string address = "NONE";
+
+    file.open("/proc/bus/input/devices");
+
+    if (!file.is_open())
+      return "NOT FOUND";
+
+    while (!file.eof()) {
+      getline(file, buffer);
+      std::size_t found = buffer.find(_device);
+      if(found!=std::string::npos){
+        std::string tmp = buffer.substr(found+_device.size()+1);
+        std::size_t foundBegining = tmp.find("event");
+        if(foundBegining!=std::string::npos){
+            address = "/dev/input/"+tmp.substr(foundBegining);
+            address.erase(address.size()-1,1);
+        }
+        break;
+      }
+    }
+
+    file.close();
+    return address;
+}
+
+void closeMouse(){
+    if (mouse_fd > 0)
+        close(mouse_fd);
+    mouse_fd = -1;
+}
+
+int initMouse(){
+    closeMouse();
+
+    mouse.x = viewport.z*0.5;
+    mouse.y = viewport.w*0.5;
+    std::string mouseAddress = searchForDevice(MOUSE_ID);
+    std::cout << "Mouse [" << mouseAddress << "]"<< std::endl;
+    mouse_fd = open(mouseAddress.c_str(), O_RDONLY | O_NONBLOCK);
+
+    return mouse_fd;
+}
+
+
+bool readMouseEvent(struct input_event *mousee){
+    int bytes;
+    if (mouse_fd > 0) {
+        bytes = read(mouse_fd, mousee, sizeof(struct input_event));
+        if (bytes == -1)
+            return false;
+        else if (bytes == sizeof(struct input_event))
+            return true;
+    }
+    return false;
+}
+
+bool updateMouse() {
+    if (mouse_fd < 0) {
+        return false;
+    }
+
+    struct input_event mousee;
+    while ( readMouseEvent(&mousee) ) {
+
+        mouse.velX=0;
+        mouse.velY=0;
+
+        float x,y = 0.0f;
+        int button = 0;
+
+        switch(mousee.type) {
+            // Update Mouse Event
+            case EV_KEY:
+                switch (mousee.code) {
+                    case BTN_LEFT:
+                        if (mousee.value == 1){
+                            button = 1;
+                        }
+                        break;
+                    case BTN_RIGHT:
+                        if(mousee.value == 1){
+                            button = 2;
+                        }
+                        break;
+                    case BTN_MIDDLE:
+                        if(mousee.value == 1){
+                            button = 3;
+                        }
+                        break;
+                    default:
+                        button = 0;
+                        break;
+                }
+                if (button != mouse.button) {
+                    mouse.button = button;
+                    if(mouse.button == 0){
+                        onMouseRelease(mouse.x,mouse.y);
+                    } else {
+                        onMouseClick(mouse.x,mouse.y,mouse.button);
+                    }
+                }
+                break;
+            case EV_REL:
+                switch (mousee.code) {
+                    case REL_X:
+                        mouse.velX = mousee.value;
+                        break;
+                    case REL_Y:
+                        mousee.value = mousee.value * -1;
+                        mouse.velY = mousee.value;
+                        break;
+                    // case REL_WHEEL:
+                    //     if (mousee.value > 0)
+                    //         std::cout << "Mouse wheel Forward" << std::endl;
+                    //     else if(mousee.value < 0)
+                    //         std::cout << "Mouse wheel Backward" << std::endl;
+                    //     break;
+                    default:
+                        break;
+                }
+                mouse.x+=mouse.velX;
+                mouse.y+=mouse.velY;
+
+                // Clamp values
+                if (mouse.x < 0) mouse.x=0;
+                if (mouse.y < 0) mouse.y=0;
+                if (mouse.x > viewport.z) mouse.x = viewport.z;
+                if (mouse.y > viewport.w) mouse.y = viewport.w;
+
+                if (mouse.button != 0) {
+                    onMouseDrag(mouse.x,mouse.y,mouse.button);
+                } else {
+                    onMouseMove(mouse.x,mouse.y);
+                }
+                break;
+            case EV_ABS:
+                switch (mousee.code) {
+                    case ABS_X:
+                        x = ((float)mousee.value/4095.0f)*viewport.z;
+                        mouse.velX = x - mouse.x;
+                        mouse.x = x;
+                        break;
+                    case ABS_Y:
+                        y = (1.0-((float)mousee.value/4095.0f))*viewport.w;
+                        mouse.velY = y - mouse.y;
+                        mouse.y = y;
+                        break;
+                    default:
+                        break;
+                }
+                if (mouse.button != 0) {
+                    onMouseDrag(mouse.x,mouse.y,mouse.button);
+                } else {
+                    onMouseMove(mouse.x,mouse.y);
+                }
+                break;
+            default:
+                break;
+        }
+    }
+    return true;
+}
+
+// OpenGL ES
+//--------------------------------
+
+//==============================================================================
+//  Creation of EGL context (lines 241-341) from:
+//
+//      https://github.com/raspberrypi/firmware/blob/master/opt/vc/src/hello_pi/hello_triangle2/triangle2.c#L100
+//
+/*
+Copyright (c) 2012, Broadcom Europe Ltd
+All rights reserved.
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+    * Redistributions in binary form must reproduce the above copyright
+      notice, this list of conditions and the following disclaimer in the
+      documentation and/or other materials provided with the distribution.
+    * Neither the name of the copyright holder nor the
+      names of its contributors may be used to endorse or promote products
+      derived from this software without specific prior written permission.
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "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 THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 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.
+*/
+//==============================================================================
+void initGL(int argc, char **argv){
+
+    // Start OpenGL ES
+    bcm_host_init();
+
+    // Clear application state
+    int32_t success = 0;
+    EGLBoolean result;
+    EGLint num_config;
+
+    static EGL_DISPMANX_WINDOW_T nativeviewport;
+
+    DISPMANX_ELEMENT_HANDLE_T dispman_element;
+    DISPMANX_DISPLAY_HANDLE_T dispman_display;
+    DISPMANX_UPDATE_HANDLE_T dispman_update;
+    VC_RECT_T dst_rect;
+    VC_RECT_T src_rect;
+
+    uint32_t screen_width;
+    uint32_t screen_height;
+
+    static const EGLint attribute_list[] = {
+        EGL_RED_SIZE, 8,
+        EGL_GREEN_SIZE, 8,
+        EGL_BLUE_SIZE, 8,
+        EGL_ALPHA_SIZE, 8,
+        EGL_SAMPLE_BUFFERS, 1,
+        EGL_SAMPLES, 4,
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+        EGL_RENDERABLE_TYPE, EGL_OPENGL_ES2_BIT,
+        EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
+        EGL_DEPTH_SIZE, 16,
+        EGL_NONE
+    };
+
+    static const EGLint context_attributes[] = {
+        EGL_CONTEXT_CLIENT_VERSION, 2,
+        EGL_NONE
+    };
+
+    EGLConfig config;
+
+    // get an EGL display connection
+    display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    assert(display!=EGL_NO_DISPLAY);
+    check();
+
+    // initialize the EGL display connection
+    result = eglInitialize(display, NULL, NULL);
+    assert(EGL_FALSE != result);
+    check();
+
+    // get an appropriate EGL frame buffer configuration
+    result = eglChooseConfig(display, attribute_list, &config, 1, &num_config);
+    assert(EGL_FALSE != result);
+    check();
+
+    // get an appropriate EGL frame buffer configuration
+    result = eglBindAPI(EGL_OPENGL_ES_API);
+    assert(EGL_FALSE != result);
+    check();
+
+    // create an EGL rendering context
+    context = eglCreateContext(display, config, EGL_NO_CONTEXT, context_attributes);
+    assert(context!=EGL_NO_CONTEXT);
+    check();
+
+    // create an EGL viewport surface
+    success = graphics_get_display_size(0 /* LCD */, &screen_width, &screen_height);
+    assert( success >= 0 );
+
+    //  Initially the viewport is for all the screen
+    viewport.x = 0;
+    viewport.y = 0;
+    viewport.z = screen_width;
+    viewport.w = screen_height;
+
+    dst_rect.x = viewport.x;
+    dst_rect.y = viewport.y;
+    dst_rect.width = viewport.z;
+    dst_rect.height = viewport.w;
+
+    src_rect.x = 0;
+    src_rect.y = 0;
+    src_rect.width = viewport.z << 16;
+    src_rect.height = viewport.w << 16;
+
+    dispman_display = vc_dispmanx_display_open( 0 /* LCD */);
+    dispman_update = vc_dispmanx_update_start( 0 );
+
+    dispman_element = vc_dispmanx_element_add( dispman_update, dispman_display,
+                                       0/*layer*/, &dst_rect, 0/*src*/,
+                                       &src_rect, DISPMANX_PROTECTION_NONE, 0 /*alpha*/, 0/*clamp*/, (DISPMANX_TRANSFORM_T)0/*transform*/);
+
+    nativeviewport.element = dispman_element;
+    nativeviewport.width = viewport.z;
+    nativeviewport.height = viewport.w;
+    vc_dispmanx_update_submit_sync( dispman_update );
+    check();
+
+    surface = eglCreateWindowSurface( display, config, &nativeviewport, NULL );
+    assert(surface != EGL_NO_SURFACE);
+    check();
+
+    // connect the context to the surface
+    result = eglMakeCurrent(display, surface, surface, context);
+    assert(EGL_FALSE != result);
+    check();
+
+    // Set background color and clear buffers
+    // glClearColor(0.15f, 0.25f, 0.35f, 1.0f);
+    // glClear( GL_COLOR_BUFFER_BIT );
+
+    setWindowSize(viewport.z,viewport.w);
+    mouse.x = viewport.z*0.5;
+    mouse.y = viewport.w*0.5;
+    check();
+
+    initMouse();
+    ///printf("OpenGL Initialize at %i,%i,%i,%i\n",viewport.x,viewport.y,viewport.z,viewport.w);
+}
+
+void renderGL(){
+    eglSwapBuffers(display, surface);
+}
+
+void closeGL(){
+    closeMouse();
+    eglSwapBuffers(display, surface);
+
+    // Release OpenGL resources
+    eglMakeCurrent( display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT );
+    eglDestroySurface( display, surface );
+    eglDestroyContext( display, context );
+    eglTerminate( display );
+}
+
+
+int getKey() {
+    int character;
+    struct termios orig_term_attr;
+    struct termios new_term_attr;
+
+    /* set the terminal to raw mode */
+    tcgetattr(fileno(stdin), &orig_term_attr);
+    memcpy(&new_term_attr, &orig_term_attr, sizeof(struct termios));
+    new_term_attr.c_lflag &= ~(ECHO|ICANON);
+    new_term_attr.c_cc[VTIME] = 0;
+    new_term_attr.c_cc[VMIN] = 0;
+    tcsetattr(fileno(stdin), TCSANOW, &new_term_attr);
+
+    /* read a character from the stdin stream without blocking */
+    /*   returns EOF (-1) if no character is available */
+    character = fgetc(stdin);
+
+    /* restore the original terminal attributes */
+    tcsetattr(fileno(stdin), TCSANOW, &orig_term_attr);
+
+    return character;
+}
+
+void updateGL() {
+    updateMouse();
+
+    int key = getKey();
+    if ( key != -1 && key != keyPressed ){
+        keyPressed = key;
+        onKeyPress(key);
+    }
+}
+
+void setWindowSize(int _width, int _height) {
+    viewport.z = _width;
+    viewport.w = _height;
+    glViewport((float)viewport.x, (float)viewport.y, (float)viewport.z, (float)viewport.w);
+    orthoMatrix = glm::ortho((float)viewport.x, (float)viewport.z, (float)viewport.y, (float)viewport.w);
+
+    onViewportResize(viewport.z, viewport.w);
+}
+
+int getWindowWidth(){
+    return viewport.z;
+}
+
+int getWindowHeight(){
+    return viewport.w;
+}
+
+glm::vec2 getWindowSize() {
+    return glm::vec2(viewport.w,viewport.w);
+}
+
+glm::mat4 getOrthoMatrix(){
+    return orthoMatrix;
+}
+
+float getMouseX(){
+    return mouse.x;
+}
+
+float getMouseY(){
+    return mouse.y;
+}
+
+glm::vec2 getMousePosition() {
+    return glm::vec2(mouse.x,mouse.y);
+}
+
+float getMouseVelX(){
+    return mouse.velX;
+}
+
+float getMouseVelY(){
+    return mouse.velY;
+}
+
+glm::vec2 getMouseVelocity() {
+    return glm::vec2(mouse.velX,mouse.velY);
+}
+
+int getMouseButton(){
+    return mouse.button;
+}
+
+unsigned char getKeyPressed(){
+    return keyPressed;
+}
+
+void setRenderRequest(bool _render) {
+    bRender = _render;
+}
+
+bool getRenderRequest() {
+    return bRender;
+}
diff --git a/platforms/rpi/src/context.h b/platforms/rpi/src/context.h
new file mode 100644 (file)
index 0000000..4245b8b
--- /dev/null
@@ -0,0 +1,42 @@
+#pragma once
+
+#include "platform_gl.h"
+#undef countof
+#include "glm/glm.hpp"
+
+// GL Context
+void    initGL(int argc, char **argv);
+void    updateGL();
+void    renderGL();
+void    closeGL();
+
+// SET
+void    setWindowSize(int _width, int _height);
+void    setRenderRequest(bool _render);
+
+// GET
+bool    getRenderRequest();
+int     getWindowWidth();
+int     getWindowHeight();
+glm::vec2 getWindowSize();
+glm::mat4 getOrthoMatrix();
+
+float   getMouseX();
+float   getMouseY();
+glm::vec2 getMousePosition();
+
+float   getMouseVelX();
+float   getMouseVelY();
+glm::vec2 getMouseVelocity();
+
+int     getMouseButton();
+
+unsigned char getKeyPressed();
+
+// EVENTS
+void    onKeyPress(int _key);
+void    onMouseMove(float _x, float _y);
+void    onMouseClick(float _x, float _y, int _button);
+void    onMouseDrag(float _x, float _y, int _button);
+void    onMouseRelease(float _x, float _y);
+void    onViewportResize(int _width, int _height);
diff --git a/platforms/rpi/src/main.cpp b/platforms/rpi/src/main.cpp
new file mode 100644 (file)
index 0000000..e3d4977
--- /dev/null
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <fcntl.h>
+#include <assert.h>
+#include <time.h>
+#include <sys/time.h>
+#include <sys/shm.h>
+
+#include <stdlib.h>
+#include <string.h>
+#include <termios.h>
+
+#include <curl/curl.h>
+#include <cstdlib>
+
+#include "context.h"
+#include "tangram.h"
+#include "platform_linux.h"
+#include "log.h"
+
+#include <iostream>
+#include "glm/trigonometric.hpp"
+
+
+#define KEY_ESC      113    // q
+#define KEY_ZOOM_IN  45     // -
+#define KEY_ZOOM_OUT 61     // =
+#define KEY_UP       119    // w
+#define KEY_LEFT     97     // a
+#define KEY_RIGHT    115    // s
+#define KEY_DOWN     122    // z
+
+using namespace Tangram;
+
+struct timeval tv;
+unsigned long long timePrev, timeStart;
+
+Map* map = nullptr;
+std::shared_ptr<LinuxPlatform> platform;
+
+static bool bUpdate = true;
+
+//==============================================================================
+void setup(int argc, char **argv);
+void newFrame();
+
+int main(int argc, char **argv){
+
+    UrlClient::Options urlClientOptions;
+    urlClientOptions.numberOfThreads = 4;
+
+    platform = std::make_shared<LinuxPlatform>(urlClientOptions);
+
+    // Start OpenGL context
+    initGL(argc, argv);
+
+    // Set background color and clear buffers
+    setup(argc, argv);
+
+    // Start clock
+    gettimeofday(&tv, NULL);
+    timeStart = timePrev = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
+
+    while (bUpdate) {
+        updateGL();
+        if (getRenderRequest() || platform->isContinuousRendering() ) {
+            setRenderRequest(false);
+            newFrame();
+        }
+    }
+
+    if (map) {
+        delete map;
+        map = nullptr;
+    }
+
+    closeGL();
+    return 0;
+}
+
+void setup(int argc, char **argv) {
+    int width = getWindowWidth();
+    int height = getWindowHeight();
+    float rot = 0.0f;
+    float zoom = 0.0f;
+    float tilt = 0.0f;
+    double lat = 0.0f;
+    double lon = 0.0f;
+    std::string scene = "scene.yaml";
+
+#ifndef MAPZEN_API_KEY
+    LOG("Environment variable MAPZEN_API_KEY not set. Kindly set this environment variable and relaunch.");
+    exit(1);
+#endif
+
+    for (int i = 1; i < argc - 1; i++) {
+        std::string argName(argv[i]), argValue(argv[i + 1]);
+        if (argName == "-s" || argName == "--scene") {
+            scene = argValue;
+        } else if (argName == "-lat" ) {
+            lat = std::stod(argValue);
+        } else if (argName == "-lon" ) {
+            lon = std::stod(argValue);
+        } else if (argName == "-z" || argName == "--zoom" ) {
+            zoom = std::stof(argValue);
+        } else if (argName == "-w" || argName == "--width") {
+            width = std::stoi(argValue);
+        } else if (argName == "-h" || argName == "--height") {
+            height = std::stoi(argValue);
+        } else if (argName == "-t" || argName == "--tilt") {
+            tilt = std::stof(argValue);
+        } else if (argName == "-r" || argName == "--rotation") {
+            rot = std::stof(argValue);
+        }
+    }
+
+    map = new Map(platform);
+    map->loadSceneAsync(scene.c_str(), false, {}, nullptr, {SceneUpdate("global.sdk_mapzen_api_key", MAPZEN_API_KEY)});
+    map->setupGL();
+    map->resize(width, height);
+    if (lon != 0.0f && lat != 0.0f) {
+        map->setPosition(lon,lat);
+    }
+    if (zoom != 0.0f) {
+        map->setZoom(zoom);
+    }
+    if (tilt != 0.0f) {
+        map->setTilt(glm::radians(tilt));
+    }
+    if (rot != 0.0f) {
+        map->setRotation(glm::radians(rot));
+    }
+}
+
+void newFrame() {
+
+    // Update
+    gettimeofday( &tv, NULL);
+    unsigned long long timeNow = (unsigned long long)(tv.tv_sec) * 1000 + (unsigned long long)(tv.tv_usec) / 1000;
+    double delta = ((double)timeNow - (double)timePrev)*0.001;
+
+    //logMsg("New frame (delta %d msec)\n",delta);
+
+    map->update(delta);
+    timePrev = timeNow;
+
+    // Render
+    map->render();
+
+    renderGL();
+}
+
+//======================================================================= EVENTS
+
+void onKeyPress(int _key) {
+    switch (_key) {
+        case KEY_ZOOM_IN:
+            map->handlePinchGesture(0.0,0.0,0.5,0.0);
+            break;
+        case KEY_ZOOM_OUT:
+            map->handlePinchGesture(0.0,0.0,2.0,0.0);
+            break;
+        case KEY_UP:
+            map->handlePanGesture(0.0,0.0,0.0,100.0);
+            break;
+        case KEY_DOWN:
+            map->handlePanGesture(0.0,0.0,0.0,-100.0);
+            break;
+        case KEY_LEFT:
+            map->handlePanGesture(0.0,0.0,100.0,0.0);
+            break;
+        case KEY_RIGHT:
+            map->handlePanGesture(0.0,0.0,-100.0,0.0);
+            break;
+        case KEY_ESC:
+            bUpdate = false;
+            break;
+        default:
+            logMsg(" -> %i\n",_key);
+    }
+    platform->requestRender();
+}
+
+void onMouseMove(float _x, float _y) {
+    platform->requestRender();
+}
+
+void onMouseClick(float _x, float _y, int _button) {
+    platform->requestRender();
+}
+
+void onMouseDrag(float _x, float _y, int _button) {
+    if( _button == 1 ){
+
+        map->handlePanGesture(_x - getMouseVelX(), _y + getMouseVelY(), _x, _y);
+
+    } else if( _button == 2 ){
+        if ( getKeyPressed() == 'r') {
+            float scale = -0.05;
+            float rot = atan2(getMouseVelY(),getMouseVelX());
+            if( _x < getWindowWidth()/2.0 ) {
+                scale *= -1.0;
+            }
+            map->handleRotateGesture(getWindowWidth()/2.0, getWindowHeight()/2.0, rot*scale);
+        } else if ( getKeyPressed() == 't') {
+            map->handleShoveGesture(getMouseVelY()*0.005);
+        } else {
+            map->handlePinchGesture(getWindowWidth()/2.0, getWindowHeight()/2.0, 1.0 + getMouseVelY()*0.001, 0.f);
+        }
+
+    }
+    platform->requestRender();
+}
+
+void onMouseRelease(float _x, float _y) {
+    platform->requestRender();
+}
+
+void onViewportResize(int _newWidth, int _newHeight) {
+    platform->requestRender();
+}
diff --git a/platforms/tizen/src/platform_tizen.cpp b/platforms/tizen/src/platform_tizen.cpp
new file mode 100644 (file)
index 0000000..4ad9a0e
--- /dev/null
@@ -0,0 +1,195 @@
+#include "platform_tizen.h"
+#include "gl/hardware.h"
+
+#include <algorithm>
+#include <stdio.h>
+#include <stdarg.h>
+#include <libgen.h>
+#include <unistd.h>
+#include <sys/resource.h>
+#include <sys/syscall.h>
+
+#include "tizen_gl.h"
+
+#include <dlog.h>
+#include <fontconfig/fontconfig.h>
+
+#ifdef  LOG_TAG
+#undef  LOG_TAG
+#endif
+#define LOG_TAG "Tangram"
+
+namespace Tangram {
+
+static std::vector<std::string> s_fallbackFonts;
+static FcConfig* s_fcConfig = nullptr;
+
+void logMsg(const char* fmt, ...) {
+    va_list vl;
+    va_start(vl, fmt);
+    dlog_vprint(DLOG_WARN, LOG_TAG, fmt, vl);
+    va_end(vl);
+}
+
+void setEvasGlAPI(Evas_GL_API *glApi) {
+    __evas_gl_glapi = glApi;
+}
+
+TizenPlatform::TizenPlatform() :
+    m_urlClient(UrlClient::Options{}) {}
+
+TizenPlatform::TizenPlatform(UrlClient::Options urlClientOptions) :
+    m_urlClient(urlClientOptions) {}
+
+TizenPlatform::~TizenPlatform() {}
+
+void TizenPlatform::setRenderCallbackFunction(std::function<void()> callback) {
+    m_renderCallbackFunction = callback;
+}
+
+void TizenPlatform::requestRender() const {
+    m_update = true;
+    if (m_renderCallbackFunction) {
+        m_renderCallbackFunction();
+    }
+}
+
+bool TizenPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+
+    return m_urlClient.addRequest(_url, _callback);
+}
+
+void TizenPlatform::cancelUrlRequest(const std::string& _url) {
+
+    m_urlClient.cancelRequest(_url);
+}
+
+void TizenPlatform::initPlatformFontSetup() const {
+
+    static bool s_platformFontsInit = false;
+    if (s_platformFontsInit) { return; }
+
+    s_fcConfig = FcInitLoadConfigAndFonts();
+
+    std::string style = "Regular";
+
+    FcStrSet* fcLangs = FcGetLangs();
+    FcStrList* fcLangList = FcStrListCreate(fcLangs);
+    FcChar8* fcLang;
+    while ((fcLang = FcStrListNext(fcLangList))) {
+        FcValue fcStyleValue, fcLangValue;
+
+        fcStyleValue.type = fcLangValue.type = FcType::FcTypeString;
+        fcStyleValue.u.s = reinterpret_cast<const FcChar8*>(style.c_str());
+        fcLangValue.u.s = fcLang;
+
+        // create a pattern with style and family font properties
+        FcPattern* pat = FcPatternCreate();
+
+        FcPatternAdd(pat, FC_STYLE, fcStyleValue, true);
+        FcPatternAdd(pat, FC_LANG, fcLangValue, true);
+        //FcPatternPrint(pat);
+
+        FcConfigSubstitute(s_fcConfig, pat, FcMatchPattern);
+        FcDefaultSubstitute(pat);
+
+        FcResult res;
+        FcPattern* font = FcFontMatch(s_fcConfig, pat, &res);
+        if (font) {
+            FcChar8* file = nullptr;
+            if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch) {
+                // Make sure this font file is not previously added.
+                if (std::find(s_fallbackFonts.begin(), s_fallbackFonts.end(),
+                              reinterpret_cast<char*>(file)) == s_fallbackFonts.end()) {
+                    s_fallbackFonts.emplace_back(reinterpret_cast<char*>(file));
+                }
+            }
+            FcPatternDestroy(font);
+        }
+        FcPatternDestroy(pat);
+    }
+    FcStrListDone(fcLangList);
+    s_platformFontsInit = true;
+}
+
+std::vector<FontSourceHandle> TizenPlatform::systemFontFallbacksHandle() const {
+
+    initPlatformFontSetup();
+
+    std::vector<FontSourceHandle> handles;
+
+    for (auto& path : s_fallbackFonts) {
+        handles.emplace_back(path);
+    }
+
+    return handles;
+}
+
+std::string TizenPlatform::fontPath(const std::string& _name, const std::string& _weight,
+                                    const std::string& _face) const {
+
+    initPlatformFontSetup();
+
+    if (!s_fcConfig) {
+        return "";
+    }
+
+    std::string fontFile = "";
+    FcValue fcFamily, fcFace, fcWeight;
+
+    fcFamily.type = fcFace.type = fcWeight.type = FcType::FcTypeString;
+    fcFamily.u.s = reinterpret_cast<const FcChar8*>(_name.c_str());
+    fcWeight.u.s = reinterpret_cast<const FcChar8*>(_weight.c_str());
+    fcFace.u.s = reinterpret_cast<const FcChar8*>(_face.c_str());
+
+    // Create a pattern with family, style and weight font properties
+    FcPattern* pattern = FcPatternCreate();
+
+    FcPatternAdd(pattern, FC_FAMILY, fcFamily, true);
+    FcPatternAdd(pattern, FC_STYLE, fcFace, true);
+    FcPatternAdd(pattern, FC_WEIGHT, fcWeight, true);
+    //FcPatternPrint(pattern);
+
+    FcConfigSubstitute(s_fcConfig, pattern, FcMatchPattern);
+    FcDefaultSubstitute(pattern);
+
+    FcResult res;
+    FcPattern* font = FcFontMatch(s_fcConfig, pattern, &res);
+    if (font) {
+        FcChar8* file = nullptr;
+        FcChar8* fontFamily = nullptr;
+        if (FcPatternGetString(font, FC_FILE, 0, &file) == FcResultMatch &&
+            FcPatternGetString(font, FC_FAMILY, 0, &fontFamily) == FcResultMatch) {
+            // We do not want the "best" match, but an "exact" or at least the same "family" match
+            // We have fallbacks to cover rest here.
+            if (strcmp(reinterpret_cast<const char*>(fontFamily), _name.c_str()) == 0) {
+                fontFile = reinterpret_cast<const char*>(file);
+            }
+        }
+        FcPatternDestroy(font);
+    }
+
+    FcPatternDestroy(pattern);
+
+    return fontFile;
+}
+
+std::vector<char> TizenPlatform::systemFont(const std::string& _name, const std::string& _weight,
+                                            const std::string& _face) const {
+    std::string path = fontPath(_name, _weight, _face);
+
+    if (path.empty()) { return {}; }
+
+    return bytesFromFile(path.c_str());
+}
+
+
+void setCurrentThreadPriority(int priority) {
+    int tid = syscall(SYS_gettid);
+    setpriority(PRIO_PROCESS, tid, priority);
+}
+
+void initGLExtensions() {
+}
+
+} // namespace Tangram
diff --git a/platforms/tizen/src/platform_tizen.h b/platforms/tizen/src/platform_tizen.h
new file mode 100644 (file)
index 0000000..b8a9b59
--- /dev/null
@@ -0,0 +1,47 @@
+#pragma once
+
+#include "platform.h"
+#include "urlClient.h"
+
+#include <functional>
+#include <Evas_GL.h>
+
+namespace Tangram {
+
+void setEvasGlAPI(Evas_GL_API *glApi);
+
+class TizenPlatform : public Platform {
+
+public:
+
+    TizenPlatform();
+    TizenPlatform(UrlClient::Options urlClientOptions);
+    ~TizenPlatform() override;
+    void requestRender() const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+
+
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+
+    std::vector<char> systemFont(const std::string& _name, const std::string& _weight,
+                                 const std::string& _face) const override;
+
+    void setRenderCallbackFunction(std::function<void()> callback);
+
+    
+protected:
+
+    void initPlatformFontSetup() const;
+
+    std::string fontPath(const std::string& _name, const std::string& _weight,
+                         const std::string& _face) const;
+
+    UrlClient m_urlClient;
+
+    std::function<void()> m_renderCallbackFunction = nullptr;
+
+    mutable bool m_update = false;
+};
+
+} // namespace Tangram
diff --git a/platforms/tizen/src/tizen_gl.cpp b/platforms/tizen/src/tizen_gl.cpp
new file mode 100644 (file)
index 0000000..434de08
--- /dev/null
@@ -0,0 +1,319 @@
+#include "tizen_gl.h"
+
+ELEMENTARY_GLVIEW_GLOBAL_DEFINE()
+
+namespace Tangram {
+
+GLenum GL::getError() {
+    return __evas_gl_glapi->glGetError();
+}
+
+const GLubyte* GL::getString(GLenum name) {
+    return __evas_gl_glapi->glGetString(name);
+}
+
+void GL::clear(GLbitfield mask) {
+    __evas_gl_glapi->glClear(mask);
+}
+void GL::lineWidth(GLfloat width) {
+    __evas_gl_glapi->glLineWidth(width);
+}
+void GL::viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+    __evas_gl_glapi->glViewport(x, y, width, height);
+}
+
+void GL::enable(GLenum id) {
+    __evas_gl_glapi->glEnable(id);
+}
+void GL::disable(GLenum id) {
+    __evas_gl_glapi->glDisable(id);
+}
+void GL::depthFunc(GLenum func) {
+    __evas_gl_glapi->glDepthFunc(func);
+}
+void GL::depthMask(GLboolean flag) {
+    __evas_gl_glapi->glDepthMask(flag);
+}
+void GL::depthRange(GLfloat n, GLfloat f) {
+    __evas_gl_glapi->glDepthRangef(n, f);
+}
+void GL::clearDepth(GLfloat d) {
+    __evas_gl_glapi->glClearDepthf(d);
+}
+void GL::blendFunc(GLenum sfactor, GLenum dfactor) {
+    __evas_gl_glapi->glBlendFunc(sfactor, dfactor);
+}
+void GL::stencilFunc(GLenum func, GLint ref, GLuint mask) {
+    __evas_gl_glapi->glStencilFunc(func, ref, mask);
+}
+void GL::stencilMask(GLuint mask) {
+    __evas_gl_glapi->glStencilMask(mask);
+}
+void GL::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+    __evas_gl_glapi->glStencilOp(fail, zfail, zpass);
+}
+void GL::clearStencil(GLint s) {
+    __evas_gl_glapi->glClearStencil(s);
+}
+void GL::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+    __evas_gl_glapi->glColorMask(red, green, blue, alpha);
+}
+void GL::cullFace(GLenum mode) {
+    __evas_gl_glapi->glCullFace(mode);
+}
+void GL::frontFace(GLenum mode) {
+    __evas_gl_glapi->glFrontFace(mode);
+}
+void GL::clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+    __evas_gl_glapi->glClearColor(red, green, blue, alpha);
+}
+void GL::getIntegerv(GLenum pname, GLint *params ) {
+    __evas_gl_glapi->glGetIntegerv(pname, params );
+}
+
+// Program
+void GL::useProgram(GLuint program) {
+    __evas_gl_glapi->glUseProgram(program);
+}
+void GL::deleteProgram(GLuint program) {
+    __evas_gl_glapi->glDeleteProgram(program);
+}
+void GL::deleteShader(GLuint shader) {
+    __evas_gl_glapi->glDeleteShader(shader);
+}
+GLuint GL::createShader(GLenum type) {
+    return __evas_gl_glapi->glCreateShader(type);
+}
+GLuint GL::createProgram() {
+    return __evas_gl_glapi->glCreateProgram();
+}
+
+void GL::compileShader(GLuint shader) {
+    __evas_gl_glapi->glCompileShader(shader);
+}
+void GL::attachShader(GLuint program, GLuint shader) {
+    __evas_gl_glapi->glAttachShader(program,shader);
+}
+void GL::linkProgram(GLuint program) {
+    __evas_gl_glapi->glLinkProgram(program);
+}
+
+void GL::shaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) {
+    auto source = const_cast<const GLchar**>(string);
+    __evas_gl_glapi->glShaderSource(shader, count, source, length);
+}
+void GL::getShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    __evas_gl_glapi->glGetShaderInfoLog(shader, bufSize, length, infoLog);
+}
+void GL::getProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+    __evas_gl_glapi->glGetProgramInfoLog(program, bufSize, length, infoLog);
+}
+GLint GL::getUniformLocation(GLuint program, const GLchar *name) {
+    return __evas_gl_glapi->glGetUniformLocation(program, name);
+}
+GLint GL::getAttribLocation(GLuint program, const GLchar *name) {
+    return __evas_gl_glapi->glGetAttribLocation(program, name);
+}
+void GL::getProgramiv(GLuint program, GLenum pname, GLint *params) {
+    __evas_gl_glapi->glGetProgramiv(program,pname,params);
+}
+void GL::getShaderiv(GLuint shader, GLenum pname, GLint *params) {
+    __evas_gl_glapi->glGetShaderiv(shader,pname, params);
+}
+
+// Buffers
+void GL::bindBuffer(GLenum target, GLuint buffer) {
+    __evas_gl_glapi->glBindBuffer(target, buffer);
+}
+void GL::deleteBuffers(GLsizei n, const GLuint *buffers) {
+    __evas_gl_glapi->glDeleteBuffers(n, buffers);
+}
+void GL::genBuffers(GLsizei n, GLuint *buffers) {
+    __evas_gl_glapi->glGenBuffers(n, buffers);
+}
+void GL::bufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
+    __evas_gl_glapi->glBufferData(target, size, data, usage);
+}
+void GL::bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {
+    __evas_gl_glapi->glBufferSubData(target, offset, size, data);
+}
+void GL::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLvoid* pixels) {
+    __evas_gl_glapi->glReadPixels(x, y, width, height, format, type, pixels);
+}
+
+// Texture
+void GL::bindTexture(GLenum target, GLuint texture ) {
+    __evas_gl_glapi->glBindTexture(target, texture );
+}
+void GL::activeTexture(GLenum texture) {
+    __evas_gl_glapi->glActiveTexture(texture);
+}
+void GL::genTextures(GLsizei n, GLuint *textures ) {
+    __evas_gl_glapi->glGenTextures(n, textures );
+}
+void GL::deleteTextures(GLsizei n, const GLuint *textures) {
+    __evas_gl_glapi->glDeleteTextures(n, textures);
+}
+void GL::texParameteri(GLenum target, GLenum pname, GLint param ) {
+    __evas_gl_glapi->glTexParameteri(target, pname, param );
+}
+void GL::texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
+                    GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+    __evas_gl_glapi->glTexImage2D(target, level, internalFormat, width, height, border, format, type, pixels); }
+
+void GL::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                       GLenum format, GLenum type, const GLvoid *pixels) {
+    __evas_gl_glapi->glTexSubImage2D(target, level, xoffset, yoffset, width, height, format, type, pixels); }
+
+void GL::generateMipmap(GLenum target) {
+    __evas_gl_glapi->glGenerateMipmap(target);
+}
+
+void GL::enableVertexAttribArray(GLuint index) {
+    __evas_gl_glapi->glEnableVertexAttribArray(index);
+}
+void GL::disableVertexAttribArray(GLuint index) {
+    __evas_gl_glapi->glDisableVertexAttribArray(index);
+}
+void GL::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
+                             GLsizei stride, const void *pointer) {
+    __evas_gl_glapi->glVertexAttribPointer(index, size, type, normalized, stride, pointer);
+}
+
+void GL::drawArrays(GLenum mode, GLint first, GLsizei count ) {
+    __evas_gl_glapi->glDrawArrays(mode, first, count );
+}
+void GL::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) {
+    __evas_gl_glapi->glDrawElements(mode, count, type, indices );
+}
+
+void GL::uniform1f(GLint location, GLfloat v0) {
+    __evas_gl_glapi->glUniform1f(location, v0);
+}
+void GL::uniform2f(GLint location, GLfloat v0, GLfloat v1) {
+    __evas_gl_glapi->glUniform2f(location, v0, v1);
+}
+void GL::uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
+    __evas_gl_glapi->glUniform3f(location, v0, v1, v2);
+}
+void GL::uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+    __evas_gl_glapi->glUniform4f(location, v0, v1, v2, v3);
+}
+
+void GL::uniform1i(GLint location, GLint v0) {
+    __evas_gl_glapi->glUniform1i(location, v0);
+}
+void GL::uniform2i(GLint location, GLint v0, GLint v1) {
+    __evas_gl_glapi->glUniform2i(location, v0, v1);
+}
+void GL::uniform3i(GLint location, GLint v0, GLint v1, GLint v2) {
+    __evas_gl_glapi->glUniform3i(location, v0, v1, v2);
+}
+void GL::uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
+    __evas_gl_glapi->glUniform4i(location, v0, v1, v2, v3);
+}
+
+void GL::uniform1fv(GLint location, GLsizei count, const GLfloat *value) {
+    __evas_gl_glapi->glUniform1fv(location, count, value);
+}
+void GL::uniform2fv(GLint location, GLsizei count, const GLfloat *value) {
+    __evas_gl_glapi->glUniform2fv(location, count, value);
+}
+void GL::uniform3fv(GLint location, GLsizei count, const GLfloat *value) {
+    __evas_gl_glapi->glUniform3fv(location, count, value);
+}
+void GL::uniform4fv(GLint location, GLsizei count, const GLfloat *value) {
+    __evas_gl_glapi->glUniform4fv(location, count, value);
+}
+void GL::uniform1iv(GLint location, GLsizei count, const GLint *value) {
+    __evas_gl_glapi->glUniform1iv(location, count, value);
+}
+void GL::uniform2iv(GLint location, GLsizei count, const GLint *value) {
+    __evas_gl_glapi->glUniform2iv(location, count, value);
+}
+void GL::uniform3iv(GLint location, GLsizei count, const GLint *value) {
+    __evas_gl_glapi->glUniform3iv(location, count, value);
+}
+void GL::uniform4iv(GLint location, GLsizei count, const GLint *value) {
+    __evas_gl_glapi->glUniform4iv(location, count, value);
+}
+
+void GL::uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    __evas_gl_glapi->glUniformMatrix2fv(location, count, transpose, value);
+}
+void GL::uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    __evas_gl_glapi->glUniformMatrix3fv(location, count, transpose, value);
+}
+void GL::uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+    __evas_gl_glapi->glUniformMatrix4fv(location, count, transpose, value);
+}
+
+// mapbuffer
+void* GL::mapBuffer(GLenum target, GLenum access) {
+    return __evas_gl_glapi->glMapBufferOES(target, access);
+}
+GLboolean GL::unmapBuffer(GLenum target) {
+    return __evas_gl_glapi->glUnmapBufferOES(target);
+}
+
+void GL::finish(void) {
+    __evas_gl_glapi->glFinish();
+}
+
+// VAO
+void GL::bindVertexArray(GLuint array) {
+    __evas_gl_glapi->glBindVertexArrayOES(array);
+}
+void GL::deleteVertexArrays(GLsizei n, const GLuint *arrays) {
+    __evas_gl_glapi->glDeleteVertexArraysOES(n, arrays);
+}
+void GL::genVertexArrays(GLsizei n, GLuint *arrays) {
+    __evas_gl_glapi->glGenVertexArraysOES(n, arrays);
+}
+
+// Framebuffer
+void GL::bindFramebuffer(GLenum target, GLuint framebuffer) {
+    __evas_gl_glapi->glBindFramebuffer(target, framebuffer);
+}
+
+void GL::genFramebuffers(GLsizei n, GLuint *framebuffers) {
+    __evas_gl_glapi->glGenFramebuffers(n, framebuffers);
+}
+
+void GL::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
+                              GLuint texture, GLint level) {
+    __evas_gl_glapi->glFramebufferTexture2D(target, attachment, textarget, texture, level);
+}
+
+void GL::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width,
+                             GLsizei height) {
+    __evas_gl_glapi->glRenderbufferStorage(target, internalformat, width, height);
+}
+
+void GL::framebufferRenderbuffer(GLenum target, GLenum attachment,
+                                 GLenum renderbuffertarget, GLuint renderbuffer) {
+    __evas_gl_glapi->glFramebufferRenderbuffer(target, attachment, renderbuffertarget, renderbuffer);
+}
+
+void GL::genRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+    __evas_gl_glapi->glGenRenderbuffers(n, renderbuffers);
+}
+
+void GL::bindRenderbuffer(GLenum target, GLuint renderbuffer) {
+    __evas_gl_glapi->glBindRenderbuffer(target, renderbuffer);
+}
+
+void GL::deleteFramebuffers(GLsizei n, const GLuint *framebuffers) {
+    __evas_gl_glapi->glDeleteFramebuffers(n, framebuffers);
+}
+
+void GL::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {
+    __evas_gl_glapi->glDeleteRenderbuffers(n, renderbuffers);
+}
+
+GLenum GL::checkFramebufferStatus(GLenum target) {
+    return __evas_gl_glapi->glCheckFramebufferStatus(target);
+}
+
+}
diff --git a/platforms/tizen/src/tizen_gl.h b/platforms/tizen/src/tizen_gl.h
new file mode 100644 (file)
index 0000000..c8ee9c0
--- /dev/null
@@ -0,0 +1,17 @@
+#pragma once
+
+#include "gl.h"
+#include <Evas_GL.h>
+
+#ifdef ELEMENTARY_GLVIEW_GLOBAL_DEFINE
+ELEMENTARY_GLVIEW_GLOBAL_DECLARE()
+#define GL()
+#else
+extern Evas_GL_API *__evas_gl_glapi;
+
+#define ELEMENTARY_GLVIEW_GLOBAL_DEFINE() \
+    Evas_GL_API *__evas_gl_glapi = NULL;
+#define ELEMENTARY_GLVIEW_GLOBAL_USE(glview) \
+   do { __evas_gl_glapi = elm_glview_gl_api_get(glview); } while (0)
+#define GL() __evas_gl_glapi->
+#endif
diff --git a/proxy.py b/proxy.py
new file mode 100644 (file)
index 0000000..7a598fc
--- /dev/null
+++ b/proxy.py
@@ -0,0 +1,70 @@
+# Originally from http://sharebear.co.uk/blog/2009/09/17/very-simple-python-caching-proxy/
+#
+# Usage:
+# A call to http://localhost:8000/example.com/foo.html will cache the file
+# at http://example.com/foo.html on disc and not redownload it again.
+# To clear the cache simply do a `rm *.cached`. To stop the server simply
+# send SIGINT (Ctrl-C). It does not handle any headers or post data.
+#
+# see also: https://pymotw.com/2/BaseHTTPServer/
+
+import BaseHTTPServer
+# import hashlib
+import os
+import urllib2
+
+from BaseHTTPServer import HTTPServer
+from SocketServer import ThreadingMixIn
+import tempfile
+
+class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
+    pass
+
+class CacheHandler(BaseHTTPServer.BaseHTTPRequestHandler):
+    def ok(self):
+        self.send_response(200)
+        self.send_header("Content-Encoding", "gzip")
+        self.end_headers()
+
+    def do_GET(self):
+
+        dirname = ".tiles/" + os.path.dirname(self.path)[1:]
+        filename = os.path.basename(self.path)
+
+        while not os.path.exists(dirname):
+            # might be a race here
+            try:
+                os.makedirs(dirname)
+            except:
+                None
+
+        cache_filename = dirname + "/" + filename
+
+        if os.path.exists(cache_filename):
+            data = open(cache_filename, mode='rb').readlines()
+            self.ok()
+            self.wfile.writelines(data)
+            return
+
+        print "fetching: %s" % (cache_filename)
+        data = urllib2.urlopen("http:/" + self.path, timeout=10).readlines()
+        self.ok()
+        self.wfile.writelines(data)
+
+        f = tempfile.NamedTemporaryFile(dir=os.path.dirname(cache_filename),
+                                        mode='wb',
+                                        delete=False)
+        f.writelines(data)
+        f.close()
+        os.rename(f.name, cache_filename)
+
+def run():
+    if not os.path.exists(".tiles"):
+        os.makedirs(".tiles")
+
+    server_address = ('', 8000)
+    httpd = ThreadedHTTPServer(server_address, CacheHandler)
+    httpd.serve_forever()
+
+if __name__ == '__main__':
+    run()
diff --git a/scenes/fonts/DroidSansFallback.ttf b/scenes/fonts/DroidSansFallback.ttf
new file mode 100755 (executable)
index 0000000..61460b1
Binary files /dev/null and b/scenes/fonts/DroidSansFallback.ttf differ
diff --git a/scenes/fonts/DroidSansJapanese.ttf b/scenes/fonts/DroidSansJapanese.ttf
new file mode 100755 (executable)
index 0000000..ca79221
Binary files /dev/null and b/scenes/fonts/DroidSansJapanese.ttf differ
diff --git a/scenes/fonts/NotoNaskh-Regular.ttf b/scenes/fonts/NotoNaskh-Regular.ttf
new file mode 100644 (file)
index 0000000..eaba984
Binary files /dev/null and b/scenes/fonts/NotoNaskh-Regular.ttf differ
diff --git a/scenes/fonts/NotoSans-Regular.ttf b/scenes/fonts/NotoSans-Regular.ttf
new file mode 100644 (file)
index 0000000..04be6f5
Binary files /dev/null and b/scenes/fonts/NotoSans-Regular.ttf differ
diff --git a/scenes/fonts/NotoSansHebrew-Regular.ttf b/scenes/fonts/NotoSansHebrew-Regular.ttf
new file mode 100644 (file)
index 0000000..49d3158
Binary files /dev/null and b/scenes/fonts/NotoSansHebrew-Regular.ttf differ
diff --git a/scenes/fonts/firasans-medium.ttf b/scenes/fonts/firasans-medium.ttf
new file mode 100644 (file)
index 0000000..e6a6637
Binary files /dev/null and b/scenes/fonts/firasans-medium.ttf differ
diff --git a/scenes/fonts/roboto-regular.ttf b/scenes/fonts/roboto-regular.ttf
new file mode 100755 (executable)
index 0000000..3e6e2e7
Binary files /dev/null and b/scenes/fonts/roboto-regular.ttf differ
diff --git a/scenes/img/arrow-3.png b/scenes/img/arrow-3.png
new file mode 100644 (file)
index 0000000..ac4f18d
Binary files /dev/null and b/scenes/img/arrow-3.png differ
diff --git a/scenes/img/cross.png b/scenes/img/cross.png
new file mode 100644 (file)
index 0000000..8a01939
Binary files /dev/null and b/scenes/img/cross.png differ
diff --git a/scenes/img/cubemap.png b/scenes/img/cubemap.png
new file mode 100644 (file)
index 0000000..463d7c8
Binary files /dev/null and b/scenes/img/cubemap.png differ
diff --git a/scenes/img/grid.jpg b/scenes/img/grid.jpg
new file mode 100644 (file)
index 0000000..bcc6ee1
Binary files /dev/null and b/scenes/img/grid.jpg differ
diff --git a/scenes/img/mapzen-logo.png b/scenes/img/mapzen-logo.png
new file mode 100644 (file)
index 0000000..a6341d7
Binary files /dev/null and b/scenes/img/mapzen-logo.png differ
diff --git a/scenes/img/normals.jpg b/scenes/img/normals.jpg
new file mode 100644 (file)
index 0000000..ae2c8ce
Binary files /dev/null and b/scenes/img/normals.jpg differ
diff --git a/scenes/img/poi_icons_32.png b/scenes/img/poi_icons_32.png
new file mode 100644 (file)
index 0000000..3818d49
Binary files /dev/null and b/scenes/img/poi_icons_32.png differ
diff --git a/scenes/img/sem.jpg b/scenes/img/sem.jpg
new file mode 100644 (file)
index 0000000..b2b23e0
Binary files /dev/null and b/scenes/img/sem.jpg differ
diff --git a/scenes/import.yaml b/scenes/import.yaml
new file mode 100644 (file)
index 0000000..f00d35a
--- /dev/null
@@ -0,0 +1,2 @@
+import:
+    - import/test.yaml
diff --git a/scenes/import/test.yaml b/scenes/import/test.yaml
new file mode 100644 (file)
index 0000000..b337081
--- /dev/null
@@ -0,0 +1,2 @@
+import:
+    - ../scene.yaml
diff --git a/scenes/raster-double.yaml b/scenes/raster-double.yaml
new file mode 100644 (file)
index 0000000..890e569
--- /dev/null
@@ -0,0 +1,42 @@
+global:
+    sdk_mapzen_api_key: ''
+
+sources:
+    terrain-normals:
+        type: Raster
+        url: https://tile.mapzen.com/mapzen/terrain/v1/normal/{z}/{x}/{y}.png
+        url_params:
+            api_key: global.sdk_mapzen_api_key
+    mapzen-osm:
+        type: TopoJSON
+        url: https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.topojson
+        rasters: [basemap, terrain-normals]
+        url_params:
+            api_key: global.sdk_mapzen_api_key
+    basemap:
+        type: Raster
+        #url: http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg
+        url: http://a.tile.openstreetmap.org/{z}/{x}/{y}.png
+        #rasters: [terrain-normals]
+
+styles:
+    normals:
+        base: polygons
+        raster: custom
+        shaders:
+            blocks:
+                color: |
+                    color = sampleRaster(0); // color from first raster (basemap)
+                normal: |
+                    normal = normalize(sampleRaster(1).xyz * 2. - 1.); // normal from second raster (normal tiles)
+
+lights:
+    light2: { type: directional, direction: [1, 1, -.9], diffuse: 0.8, ambient: 0.3 }
+
+layers:
+    earth:
+        data: { source: mapzen-osm }
+        draw:
+            normals:
+                color: white
+                order: 0
diff --git a/scenes/raster-simple.yaml b/scenes/raster-simple.yaml
new file mode 100644 (file)
index 0000000..9fa6f88
--- /dev/null
@@ -0,0 +1,14 @@
+sources:
+    stamen-terrain:
+        type: Raster
+        #url: http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg
+        url: http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png
+        url_subdomains: [a, b, c]
+
+layers:
+    terrain:
+        data: { source: stamen-terrain }
+        draw:
+            raster:
+                color: [0.5, 0.5, 0.5]
+                order: 0 # draw on bottom
diff --git a/scenes/raster-terrain.yaml b/scenes/raster-terrain.yaml
new file mode 100644 (file)
index 0000000..96c8487
--- /dev/null
@@ -0,0 +1,44 @@
+global:
+    sdk_mapzen_api_key: ''
+
+sources:
+    terrain-normals:
+        type: Raster
+        url: https://tile.mapzen.com/mapzen/terrain/v1/normal/{z}/{x}/{y}.png
+        url_params:
+            api_key: global.sdk_mapzen_api_key
+    mapzen-osm:
+        type: TopoJSON
+        url: https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.topojson
+        rasters: [terrain-normals]
+    basemap:
+        type: Raster
+        #url: http://a.tile.stamen.com/terrain-background/{z}/{x}/{y}.jpg
+        url: http://a.tile.openstreetmap.org/{z}/{x}/{y}.png
+        rasters: [terrain-normals]
+
+styles:
+    normals:
+        base: polygons
+        raster: custom
+        shaders:
+            blocks:
+                color: |
+                    color = sampleRaster(0); // color from first raster (basemap)
+                normal: |
+                    normal = normalize(sampleRaster(1).xyz * 2. - 1.); // normal from second raster (normal tiles)
+
+lights:
+    # point1:
+    #     type: point
+    #     position: [0, 0, 200px]
+    #     origin: ground
+    light2: { type: directional, direction: [1, 1, -.9], diffuse: 0.8, ambient: 0.3 }
+
+layers:
+    earth:
+        data: { source: basemap }
+        draw:
+            normals:
+                color: white
+                order: 0
diff --git a/scenes/scene.yaml b/scenes/scene.yaml
new file mode 100644 (file)
index 0000000..0973252
--- /dev/null
@@ -0,0 +1,699 @@
+global:
+    feature_order: function () { return feature.sort_rank; }
+    sdk_mapzen_api_key: ''
+
+fonts:
+    Montserrat:
+        url: https://fonts.gstatic.com/s/montserrat/v7/zhcz-_WihjSQC0oHJ9TCYL3hpw3pgy2gAi-Ip7WPMi0.woff
+    Open Sans:
+        - weight: 400
+          url: https://fonts.gstatic.com/s/opensans/v13/wMws1cEtxWZc6AZZIpiqWALUuEpTyoUstqEm5AMlJo4.woff
+        - weight: 400
+          style: italic
+          url: https://fonts.gstatic.com/s/opensans/v13/O4NhV7_qs9r9seTo7fnsVLO3LdcAZYWl9Si6vvxL-qU.woff
+
+scene:
+    background:
+        color: '#f0ebeb'
+cameras:
+    iso-camera:
+        # Manhattan
+        position: [-74.00976419448854, 40.70532700869127, 16]
+        type: isometric
+        axis: [0, 1]
+        active: false
+    perspective-camera:
+        # Manhattan
+        position: [-74.00976419448854, 40.70532700869127, 16]
+        type: perspective
+        fov: 45
+        max_tilt: [[2, 0], [16, 90]]
+        active: true
+
+lights:
+    light1:
+        type: directional
+        origin: world
+        direction: [1, 1, -1]
+        diffuse: [.3, .3, .3, 1.]
+        ambient: [0.7, 0.7, 0.7, 1.]
+
+textures:
+    pois:
+        url: img/poi_icons_32.png
+        sprites:
+            plane: [0, 0, 32, 32]
+            tree: [0, 185, 32, 32]
+            sunburst: [0, 629, 32, 32]
+            restaurant: [0, 777, 32, 32]
+            cafe: [0, 814, 32, 32]
+            museum: [0, 518, 32, 32]
+            bar: [0, 887, 32, 32]
+            train: [0, 74, 32, 32]
+            bus: [0, 148, 32, 32]
+            hospital: [0, 444, 32, 32]
+            parking: [0, 1073, 32, 32]
+            info: [0, 1110, 32, 32]
+            hotel: [0, 259, 32, 32]
+            bookstore: [0, 333, 32, 32]
+            shield: [0, 1142, 32, 32]
+            arrow: [1, 1175, 22, 22]
+
+styles:
+    heightglow:
+        base: polygons
+        lighting: vertex
+        shaders:
+            blocks:
+                color: "color.rgb += vec3(worldPosition().z / 800.);"
+    heightglowline:
+        base: lines
+        mix: heightglow
+    icons:
+        base: points
+        texture: pois
+    dashed:
+        base: lines
+        dash: [3.0, 0.3]
+    transit-lines:
+        base: lines
+        blend: overlay
+        blend_order: -2
+        shaders:
+            blocks:
+                filter: |
+                    color.rgb *= 1.25; // pump up the colors
+                    color.a = 0.5;     // translucent
+        draw: # default draw parameters
+            color: function() { return feature.colour || 'gray'; }
+            width: 6px
+            outline:
+                color: [.8, .8, .8]
+                width: 1px
+            interactive: true
+
+sources:
+    osm:
+        type: MVT
+        url: https://tile.mapzen.com/mapzen/vector/v1/all/{z}/{x}/{y}.mvt
+        max_zoom: 16
+        url_params:
+            api_key: global.sdk_mapzen_api_key
+
+layers:
+    touch:
+        data: { source: touch }
+        line:
+          filter: { type: line }
+          draw:
+            lines:
+              color: function () { return feature.color || 'black'; }
+              order: 500
+              width: 2px
+        poly:
+            filter: { type: poly }
+            draw:
+              polygons:
+                color: magenta
+                order: 40
+        point:
+            filter: { type: point }
+            draw:
+              icons:
+                sprite: sunburst
+                collide: false
+                transition: { show: { time: 0s }, hide: { time: 0s } }
+
+    earth:
+        data: { source: osm }
+        continents:
+            filter: { kind: continent, $geometry: point }
+            draw:
+                text:
+                    priority: 1
+                    font:
+                        family: Open Sans
+                        size: 12px
+                        fill: [0, 0, 0, .8]
+                        stroke: { color: white, width: 4 }
+                        transform: uppercase
+    landuse:
+        data: { source: osm }
+        filter:
+            - { $zoom: { min: 16 } }
+            - { area: { min: 500px2 } }
+        areas:
+            draw:
+                polygons:
+                    order: global.feature_order
+                    color: honeydew
+
+            parks:
+                filter: { kind: [park, graveyard, cemetery, forest, recreation_ground] }
+                draw:
+                    polygons:
+                        color: '#bddec5'
+            park-detail:
+                filter: { kind: [pitch, wood, natural_wood, grass] }
+                draw:
+                    polygons:
+                        color: '#9dbea5'
+            industry:
+                filter: { kind: [commercial, industrial] }
+                draw:
+                    polygons:
+                        color: '#C0CDCD'
+            civic:
+                filter: { kind: university }
+                draw:
+                    polygons:
+                        color: '#D9CFC3'
+            urban:
+                filter: { kind: urban_area }
+                draw:
+                    polygons:
+                        # color: [0.902, 0.835, 0.753, 1.00]
+                        color: [[7, lightgrey], [9, [.88, .88, .88]]]
+                        # color: lightgrey
+
+    water:
+        data: { source: osm }
+        draw:
+            polygons:
+                order: global.feature_order
+                color: '#9dc3de'
+        oceans:
+            filter: { kind: ocean }
+            visible: true
+            draw:
+                text:
+                    font:
+                        family: Open Sans
+                        size: 14pt
+                        style: italic
+        seas:
+            filter: { kind: sea, $zoom: { min: 7 } }
+            visible: true
+            draw:
+                text:
+                    font:
+                        family: Open Sans
+                        size: 12pt
+                        style: italic
+
+    roads:
+        data: { source: osm }
+        filter: { not: { kind: rail } }
+        draw:
+            lines:
+                color: white
+                # color: function() { return [Math.random(), Math.random(), Math.random()] }
+                width: 12
+                order: global.feature_order
+                outline:
+                    color: [[16, '#999'], [18, '#aaa']]
+                    width: [[15, 0], [16, 2]]
+                    order: 352 # put all outlines below all roads
+
+        rounded:
+            filter: { $zoom: { min: 18 } }
+            draw:
+                lines:
+                    cap: round
+
+        highway:
+            filter: { kind: highway }
+            draw:
+                lines:
+                    color: [[5, '#F89595'], [7, '#D16768']]
+                    width: [[5, 1px], [8, 1.5px], [14, 2px], [15, 12]]
+                    outline:
+                        width: [[14, 0], [15, 2]]
+            link:
+                filter: { is_link: true }
+                draw:
+                    lines:
+                        color: '#aaa'
+                        width: [[13, 0], [14, 12]]
+        major_road:
+            filter: { kind: major_road, $zoom: { min: 10 } }
+            draw:
+                lines:
+                    width: [[10, 0], [13, 2px], [14, 2px], [16, 12]]
+                    outline:
+                        width: [[16, 0], [17, 1]]
+        minor_road:
+            filter: { kind: minor_road }
+            draw:
+                lines:
+                    width: [[13, 0px], [14, 1px], [15, 8]]
+                    outline:
+                        width: [[17, 0], [18, 1]]
+        paths:
+            filter: { kind: path }
+            draw:
+                lines:
+                    style: dashed
+                    color: white
+                    width: [[15, 0px], [18, 3px]]
+                    outline:
+                        width: 0
+
+            # apply outline to roads intersecting parks - see data source transform example in `sources`
+            land:
+                filter: { intersects_park: true }
+                draw:
+                    lines:
+                        outline:
+                            style: lines
+                            color: red
+                            width: 1px
+
+        ferry:
+            filter: { kind: ferry }
+            draw:
+                lines:
+                    style: dashed
+                    color: '#8db3ce'
+                    width: [[14, 1px], [18, 2px]]
+                    outline:
+                        width: 0
+        airports:
+            filter: { kind: aeroway }
+            draw:
+                lines:
+                    color: '#ddd'
+                    outline:
+                        width: 0
+
+            taxiways:
+                filter: { kind_detail: taxiway }
+                draw:
+                    lines:
+                        width: [[13, 0px], [14, 2px], [17, 10px]]
+
+            runways:
+                filter: { kind_detail: runway }
+                draw:
+                    lines:
+                        color: [[13, '#FFE4B5'], [16, white]]
+                        width: [[11, 3px], [12, 5px], [13, 10px], [15, 75]]
+                        cap: square
+                        outline:
+                            color: orange
+                            width: [[11, 0px], [12, 1px], [13, 2px], [15, 12.5]]
+        arrows:
+            # oneway arrows and shields are distinct groups!
+            filter: { oneway: yes, shield_text: false, $zoom: { min: 17 } }
+            draw:
+                icons:
+                    flat: true
+                    sprite: arrow
+                    size: [[17, 18px], [18, 20px], [20, 32px]]
+                    placement: spaced
+                    placement_spacing: [[17, 70px], [20, 175px]]
+                    angle: auto
+
+        shields:
+            filter:
+                network: 'US:I' # US interstates only in this demo
+                shield_text: true
+            draw:
+                icons:
+                    sprite: shield
+                    # sprite: function() { return feature.network }
+                    priority: 2
+                    color: white
+                    size: 24px
+                    placement: midpoint
+                    repeat_group: shields
+                    text:
+                        repeat_distance: 150px
+                        anchor: center
+                        text_source: shield_text
+                        font:
+                            family: sans-serif
+                            size: 11px
+                            fill: white
+
+            # thin-out shields at low-zoom
+            thinning:
+                filter: { $zoom: { max: 11 } }
+                draw:
+                    icons:
+                        repeat_distance: 75px
+
+        labels:
+            filter:
+                name: true
+                not: { kind: [rail, aeroway] }
+            draw:
+                text:
+                    interactive: true
+                    transition: { show: { time: 0s }, hide: { time: 1s } }
+                    font:
+                        family: Open Sans
+                        fill: '#666'
+                        size: 12px
+
+            highway:
+                filter: { kind: highway }
+                draw:
+                    text:
+                        repeat_distance: 200px
+                        repeat_group: road_labels
+                        priority: 2
+                        font:
+                            stroke: { color: white, width: 4 }
+                            transform: capitalize
+
+            major_road:
+                filter: { kind: major_road, $zoom: { min: 13 } }
+                draw:
+                    text:
+                        repeat_distance: 100px
+                        repeat_group: roads
+                        priority: 3
+                        font:
+                            size: 14px
+                            stroke: { color: white, width: 4 }
+
+            minor_road:
+                filter: { kind: minor_road, $zoom: { min: 15 } }
+                draw:
+                    text:
+                        priority: 5
+                        font:
+                            stroke: { color: white, width: 4 }
+
+            ferry:
+                filter: { kind: ferry }
+                draw:
+                    text:
+                        text_wrap: 20
+                        font:
+                            fill: '#8db3ce'
+                            stroke: { color: white, width: 4px }
+                            style: italic
+
+    buildings:
+        data: { source: osm }
+        filter: { $zoom: { min: 14 } }
+
+        draw:
+            polygons:
+                style: heightglow
+                order: global.feature_order
+                color: [.83, .83, .83]
+
+        # turn interactive feature selection on for buildings with names
+        interactive:
+            filter: { name: true }
+            draw: { polygons: { interactive: true } }
+
+        # extrude 3d buildings
+        extruded:
+            filter: { $zoom: { min: 15 } }
+            draw:
+                polygons:
+                    extrude: function () { return feature.height > 20 || $zoom >= 16; }
+                lines:
+                    style: heightglowline
+                    width: 1.0
+                    color: [.75, .75, .73]
+                    order: function() { return feature.sort_key + 1 || 0; }
+                    extrude: true
+
+        high-line:
+            filter: { roof_material: grass }
+            draw:
+                polygons:
+                    style: polygons
+                    color: '#bddec5'
+
+        # point labels for buildings
+        labels:
+            filter:
+                $geometry: point
+                name: true
+                any:
+                    - { $zoom: { min: 17 }, height: { min: 50 } }
+                    - $zoom: { min: 18 }
+            draw:
+                text:
+                    priority: 7
+                    font:
+                        family: Open Sans
+                        size: 8pt
+                        fill: darkred
+                        stroke: { color: white, width: 3 }
+
+    pois:
+        data: { source: osm }
+        draw:
+            icons:
+                interactive: true
+                collide: true
+                transition: { show: { time: 0s }, hide: { time: 1s } }
+                text:
+                    interactive: true
+                    font:
+                        family: Open Sans
+                        style: normal
+                        size: 1.2em
+                        fill: white
+        parks:
+            filter:
+                kind: [park, cemetery, graveyard]
+                any:
+                    - { $zoom: { min: 16 } }
+                    - { area: { min: 500px2 } }
+            draw:
+                icons:
+                    sprite: tree
+                    priority: 2
+                    size: 16px
+                    text:
+                        font:
+                            size: 10pt
+                            style: italic
+                            fill: darkgreen
+                            stroke: { color: white, width: 3 }
+
+        forest:
+            filter:
+                kind: forest
+                any:
+                    - { $zoom: { min: 7 }, tier: 1 }
+                    - { $zoom: { min: 9 }, tier: { max: 3 } }
+            draw:
+                icons:
+                    visible: false
+                text:
+                    priority: 2
+                    font:
+                        size: 9pt
+                        style: italic
+                        fill: darkgreen
+                        stroke: { color: white, width: 3 }
+
+        not_landuse:
+            filter:
+                name: true
+                not:
+                    kind: [peak, viewpoint, bicycle_rental, car_sharing, park, forest, cemetery, graveyard]
+                $zoom: { min: 15 }
+            draw:
+                icons:
+                    size: [[13, 12px], [15, 18px]]
+                    interactive: true
+                    priority: 6
+                    text:
+                        optional: true
+                        visible: false
+
+            # add text label at higher zoom
+            labels:
+                filter:
+                    - { $zoom: { min: 17 } }
+                    - { $zoom: { min: 16 }, kind: station }
+                draw:
+                    icons:
+                        text:
+                            visible: true
+                            font:
+                                size: 12px
+                                fill: black
+
+            # add generic icon at high zoom
+            generic:
+                filter: { $zoom: { min: 18 } }
+                draw: { icons: { sprite: info } }
+
+            # examples of different icons mapped to feature properties
+            icons:
+                restaurant:
+                    filter: { kind: [restaurant] }
+                    draw: { icons: { sprite: restaurant } }
+                cafe:
+                    filter: { kind: [cafe, convenience] }
+                    draw: { icons: { sprite: cafe } }
+                bar:
+                    filter: { kind: [bar, pub] }
+                    draw: { icons: { sprite: bar } }
+                culture:
+                    filter: { kind: [museum, library, church, place_of_worship, bank] }
+                    draw: { icons: { sprite: museum } }
+                station:
+                    filter: { kind: [station] }
+                    draw: { icons: { sprite: train, priority: 2 } }
+                hospital:
+                    filter: { kind: [hospital, pharmacy] }
+                    draw: { icons: { sprite: hospital } }
+                hotel:
+                    filter: { kind: [hotel, hostel] }
+                    draw: { icons: { sprite: hotel } }
+                bus_stop:
+                    filter: { kind: [bus_stop] }
+                    draw: { icons: { sprite: bus } }
+                bookstore:
+                    filter: { kind: [bookstore] }
+                    draw: { icons: { sprite: bookstore } }
+
+    boundaries:
+        data: { source: osm }
+        draw:
+            lines:
+                visible: false
+                order: global.feature_order
+                width: 2px
+                color: wheat
+
+            text:
+                priority: 0
+                text_source:
+                    left: 'name:left'
+                    right: 'name:right'
+                font:
+                    family: Open Sans
+                    size: 12px
+                    fill: [0, 0, 0, .8]
+                    stroke: { color: white, width: 4 }
+                    transform: uppercase
+                    weight: bold
+        country:
+            filter: { kind: country }
+            draw:
+                lines:
+                    visible: true
+                    color: [0.824, 0.651, 0.329, 1.00]
+
+        region:
+            filter: { kind: [region, macroregion] }
+            draw:
+                lines:
+                    visible: true
+
+    places:
+        data: { source: osm }
+
+        # city labels with points
+        city-points:
+            filter:
+                kind: locality
+                kind_detail: city
+                $zoom: { max: 11 }
+            visible: true
+            draw:
+                points:
+                    size: 8px
+                    color: darkred
+                    text:
+                        priority: 1
+                        font:
+                            family: Open Sans
+                            size: 12px
+                            fill: [0, 0, 0, .8]
+                            stroke: { color: white, width: 4 }
+                            transform: uppercase
+                            weight: bold
+                            size: [[8, 11px], [12, 16px]]
+
+        # places w/text-only labels (not accompanying point)
+        text-only:
+            draw:
+                text:
+                    visible: false
+                    priority: 1
+                    font:
+                        family: Open Sans
+                        size: 12px
+                        fill: [0, 0, 0, .8]
+                        stroke: { color: white, width: 4 }
+                        transform: uppercase
+
+            countries:
+                filter:
+                    kind: country
+                    any:
+                        - { population: { min: 100000000 } }
+                        - { $zoom: { min: 5, max: 8 }, population: { min: 1000000 } }
+                        # - population: { min: 10000000 }
+                draw:
+                    text:
+                        visible: true
+                        font:
+                            weight: bold
+                            size: [[6, 14px], [8, 20px]]
+
+            regions:
+                filter:
+                    kind: region
+                    kind_detail: [state, province]
+                    $zoom: { min: 5, max: 9 }
+                draw:
+                    text:
+                        visible: true
+                        font:
+                            # weight: bold
+                            size: [[6, 12px], [8, 16px]]
+
+                # use short name when available at low-zooms
+                short:
+                    filter: { $zoom: { max: 7 } }
+                    draw:
+                        text:
+                            text_source: 'name:short'
+
+            cities:
+                filter:
+                    kind: locality
+                    kind_detail: city
+                    $zoom: { min: 11 } # show city point labels below z11
+                draw:
+                    text:
+                        visible: true
+                        font:
+                            weight: bold
+                            size: [[8, 11px], [12, 16px]]
+
+            neighborhoods:
+                filter:
+                    - { kind: [neighbourhood, macrohood], $zoom: { min: 13 } }
+                    - { kind: microhood, $zoom: { min: 15 } }
+                draw:
+                    text:
+                        visible: true
+                        font:
+                            size: [[13, 11px], [14, 11px], [15, 13px]]
+                            style: italic
+                            fill: rgba(136, 45, 23, 0.9)
+
+    transit:
+        data: { source: osm }
+        filter: { $zoom: { min: 16 } }
+        draw:
+            lines:
+                style: transit-lines
+                order: 400
+
diff --git a/scripts/incbin.sh b/scripts/incbin.sh
new file mode 100755 (executable)
index 0000000..6ceee98
--- /dev/null
@@ -0,0 +1,130 @@
+: incbin - A utility for including binary files in C source.
+:          Given a binary file and a C symbol name, generates
+:          a .h or .c file with that binary data stored as an
+:          array of unsigned chars.
+:
+:          This script has no non-standard dependencies and runs
+:          on both Windows and UNIX.
+:
+:          http://github.com/rmitton/incbin
+:
+: Usage:
+: Windows: incbin.bat myfile.bin output.h symbolname
+: UNIX:    sh incbin.bat myfile.bin output.h symbolname
+:
+:          ; if false ; then #lolwut
+#!/bin/bash
+
+<!--- : Begin batch script ---
+
+@echo off
+cscript //nologo "%~f0?.wsf" %*
+exit /b
+
+<<'EOF'
+--- Begin wsf script --->
+
+<job><script language="VBScript">
+
+Set fso = Wscript.CreateObject("Scripting.FileSystemObject")
+Set stderr = fso.GetStandardStream(2)
+
+On Error Resume Next
+
+inpath = Wscript.Arguments(0)
+outpath = Wscript.Arguments(1)
+symbol = Wscript.Arguments(2)
+If Err.Number <> 0 Then
+       stderr.WriteLine "Usage: incbin input.bin output.h symbolname"
+    WScript.Quit 1
+End If
+
+Set ts = fso.getFile(inpath).OpenAsTextStream()
+If Err.Number <> 0 Then
+       stderr.WriteLine inpath & ": " & Err.Description
+    WScript.Quit 1
+End If
+
+Set outf = fso.CreateTextFile(outpath, True, False)
+If Err.Number <> 0 Then
+       stderr.WriteLine outpath & ": " & Err.Description
+    WScript.Quit 1
+End If
+
+outf.WriteLine("/* Generated by incbin */" & vbCrLf & vbCrLf & "#include <stddef.h>" & vbCrLf)
+outf.WriteLine("const unsigned char " & symbol & "_data[] = {")
+
+offset = 0
+While Not ts.atEndOfStream
+       If offset Mod 16 = 0 Then
+               If offset > 0 Then outf.WriteLine(",")
+               outf.Write("/*")
+               offstr = Hex(offset)
+               While Len(offstr) < 8
+                       offstr = "0" & offstr
+               Wend
+               outf.Write(offstr & "*/ ")
+       Else
+               outf.Write(",")
+       End If
+    byteval = AscB(ts.Read(1))
+    hexstr = Hex(byteval)
+    If byteval < 16 Then hexstr = "0" & hexstr
+    outf.Write("0x" & hexstr)
+    offset = offset + 1
+Wend
+
+outf.WriteLine(vbCrLf & "};" & vbCrLf)
+outf.WriteLine("const size_t " & symbol & "_size = sizeof(" & symbol & "_data);")
+
+ts.Close()
+outf.Close()
+
+</script></job><!---
+
+EOF
+fi
+
+# --- Begin sh script ---
+
+set -e
+
+usage () {
+       echo Usage: incbin input.bin output.h symbolname
+       exit 1
+}
+
+[ -z "$1" ] && usage
+[ -z "$2" ] && usage
+[ -z "$3" ] && usage
+bytes=`od -An -t x1 -v "$1"`
+
+(
+       echo "/* Generated by incbin */"
+       echo
+       echo "#include <stddef.h>"
+       echo
+       echo "const unsigned char $3_data[] = {"
+
+       offset=0 ; count=16
+       for val in $bytes ; do
+               if [ $count -eq 16 ] ; then
+                       if [ $offset -ne 0 ] ; then
+                               echo ,
+                       fi
+                       printf "/*%08x*/ " $offset
+                       count=0
+               else
+                       printf ,
+               fi
+               printf 0x$val
+
+               offset=$(($offset+1)) ; count=$(($count+1))
+       done
+       echo
+       echo "};"
+       echo
+       echo "const size_t $3_size = sizeof($3_data);"
+) > "$2"
+
+# --->
diff --git a/scripts/travis/android-sdk-license b/scripts/travis/android-sdk-license
new file mode 100644 (file)
index 0000000..0bf3284
--- /dev/null
@@ -0,0 +1,2 @@
+
+8933bad161af4178b1185d1a37fbf41ea5269c55
\ No newline at end of file
diff --git a/scripts/travis/before_install.sh b/scripts/travis/before_install.sh
new file mode 100755 (executable)
index 0000000..1cf7de3
--- /dev/null
@@ -0,0 +1,40 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "android" ]]; then
+
+    # Note: the right way to download these packages is through the Android Studio SDK manager,
+    # these steps should be removed when/if ndk-bundle and cmake become available from the
+    # command-line SDK update tool.
+
+    # Download android ndk
+    echo "Downloading ndk..."
+    curl -L https://dl.google.com/android/repository/android-ndk-r13b-linux-x86_64.zip -o ndk.zip
+    echo "Done."
+
+    # Extract android ndk
+    echo "Extracting ndk..."
+    unzip -qq ndk.zip
+    echo "Done."
+
+    # Update PATH
+    echo "Updating PATH..."
+    export ANDROID_NDK_HOME=${PWD}/android-ndk-r13b
+    export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_NDK_HOME}
+    echo $PATH
+    echo "Done."
+
+    # Copy a license file into the SDK (needed to install CMake).
+    mkdir -p ${ANDROID_HOME}/licenses
+    cp ./scripts/travis/android-sdk-license ${ANDROID_HOME}/licenses/
+
+fi
+
+if [[ ${TRAVIS_OS_NAME} == "osx" ]]; then
+
+    # https://github.com/travis-ci/travis-ci/issues/6307
+    rvm get head
+
+fi
diff --git a/scripts/travis/script_build.sh b/scripts/travis/script_build.sh
new file mode 100755 (executable)
index 0000000..fa3113a
--- /dev/null
@@ -0,0 +1,30 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "osx" ]]; then
+    # Build osx project
+    echo "Building osx project"
+    CMAKE_OPTIONS="-DUNIT_TESTS=1 -DBENCHMARK=1" make -j osx
+fi
+
+if [[ ${PLATFORM} == "linux" ]]; then
+    # Build linux project
+    echo "Building linux project"
+    CMAKE_OPTIONS="-DUNIT_TESTS=1 -DBENCHMARK=1" make -j 4 linux
+fi
+
+if [[ ${PLATFORM} == "ios" ]]; then
+    # Build ios project
+    echo "Building ios framework for simulator"
+    make ios-framework-sim
+fi
+
+if [[ ${PLATFORM} == "android" ]]; then
+    # Build android project
+    echo "Building android project"
+    export TERM=dumb
+    make android
+fi
+
diff --git a/scripts/travis/script_build_bench.sh b/scripts/travis/script_build_bench.sh
new file mode 100644 (file)
index 0000000..c029138
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "osx" || ${PLATFORM} == "linux" ]]; then
+    # Build unit tests
+    make -j4 benchmark
+fi
+
diff --git a/scripts/travis/script_build_tests.sh b/scripts/travis/script_build_tests.sh
new file mode 100755 (executable)
index 0000000..382527a
--- /dev/null
@@ -0,0 +1,10 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "osx" || ${PLATFORM} == "linux" ]]; then
+    # Build unit tests
+    make -j4 tests
+fi
+
diff --git a/scripts/travis/script_deploy_android_demo.sh b/scripts/travis/script_deploy_android_demo.sh
new file mode 100755 (executable)
index 0000000..21fdce5
--- /dev/null
@@ -0,0 +1,22 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [ "${PLATFORM}" = "android" ]; then
+    printf "[default]\naccess_key = $S3_ACCESS_KEY\n secret_key = $S3_SECRET_KEY" > ~/.s3cfg
+
+    if [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ]; then
+        url_latest="s3://android.mapzen.com/tangram-latest.apk"
+        echo "Uploading latest build to $url_latest"
+        s3cmd put platforms/android/demo/build/outputs/apk/demo-debug.apk $url_latest
+
+        url_snapshot="s3://android.mapzen.com/tangram-snapshots/master-$TRAVIS_BUILD_NUMBER.apk"
+        echo "Uploading snapshot build to $url_snapshot"
+        s3cmd put platforms/android/demo/build/outputs/apk/demo-debug.apk $url_snapshot
+    elif ! [ "${TRAVIS_BRANCH}" = "master" ]; then
+        url_dev="s3://android.mapzen.com/tangram-development/$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER.apk"
+        echo "Uploading development build to $url_dev"
+        s3cmd put platforms/android/demo/build/outputs/apk/demo-debug.apk $url_dev
+    fi
+fi
diff --git a/scripts/travis/script_deploy_android_snapshot.sh b/scripts/travis/script_deploy_android_snapshot.sh
new file mode 100755 (executable)
index 0000000..f18ea6e
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [ "${PLATFORM}" = "android" ] && [ "${TRAVIS_PULL_REQUEST}" = "false" ] && [ "${TRAVIS_BRANCH}" = "master" ]; then
+
+    # Configure private repository credentials (used to sign release artifacts)
+    echo -e "machine github.com\n  login $GITHUB_USERNAME\n  password $GITHUB_PASSWORD" >> ~/.netrc
+
+    make android-sdk
+
+    cd "$TRAVIS_BUILD_DIR"/platforms/android
+    git clone https://github.com/mapzen/android-config.git
+    ./gradlew uploadArchives -PdoFullRelease -PsonatypeUsername="$SONATYPE_USERNAME" -PsonatypePassword="$SONATYPE_PASSWORD" -Psigning.keyId="$SIGNING_KEY_ID" -Psigning.password="$SIGNING_PASSWORD" -Psigning.secretKeyRingFile="$SIGNING_SECRET_KEY_RING_FILE"
+    cd "$TRAVIS_BUILD_DIR"
+fi
diff --git a/scripts/travis/script_run_bench.sh b/scripts/travis/script_run_bench.sh
new file mode 100755 (executable)
index 0000000..c5c6ed8
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "osx" || ${PLATFORM} == "linux" ]]; then
+    # Run unit tests
+    echo "Running Benchmarks"
+
+    pushd ./build/${PLATFORM}/bin
+    # a tile for testing
+    curl --compressed -L -o tile.mvt https://tile.mapzen.com/mapzen/vector/v1/all/10/301/384.mvt?api_key=vector-tiles-tyHL4AY&
+
+    for file in bench/*.out
+        do
+            echo "Running ${file}"
+            $file
+        done
+    popd
+fi
diff --git a/scripts/travis/script_run_tests.sh b/scripts/travis/script_run_tests.sh
new file mode 100755 (executable)
index 0000000..b706c34
--- /dev/null
@@ -0,0 +1,17 @@
+#!/usr/bin/env bash
+
+set -e
+set -o pipefail
+
+if [[ ${PLATFORM} == "osx" || ${PLATFORM} == "linux" ]]; then
+    # Run unit tests
+    echo "Running Unit Tests"
+    pushd ./build/${PLATFORM}/bin
+
+    for file in unit/*.out
+        do
+            echo "Running ${file}"
+            $file
+        done
+    popd
+fi
diff --git a/tangram-es.manifest b/tangram-es.manifest
new file mode 100644 (file)
index 0000000..f5a44ec
--- /dev/null
@@ -0,0 +1,5 @@
+<manifest>
+        <request>
+                <domain name="_"/>
+        </request>
+</manifest>
diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt
new file mode 100644 (file)
index 0000000..2e94c47
--- /dev/null
@@ -0,0 +1,36 @@
+
+add_library(platform_test
+  ${CMAKE_CURRENT_SOURCE_DIR}/src/catch.cpp)
+
+target_link_libraries(platform_test
+  PUBLIC
+  platform_mock
+  -lpthread)
+
+target_include_directories(platform_test
+    PUBLIC
+    ${CMAKE_CURRENT_SOURCE_DIR}/catch)
+
+file(GLOB TEST_SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/unit/*.cpp)
+
+# create an executable per test
+foreach(_src_file_path ${TEST_SOURCES})
+  string(REPLACE ".cpp" "" test_case ${_src_file_path})
+  string(REGEX MATCH "([^/]*)$" test_name ${test_case})
+
+  set(EXECUTABLE_NAME "${test_name}.out")
+  add_executable(${EXECUTABLE_NAME} ${_src_file_path})
+
+  target_link_libraries(${EXECUTABLE_NAME}
+    ${CORE_LIBRARY}
+    platform_test)
+
+  set_target_properties(${EXECUTABLE_NAME}
+    PROPERTIES
+    RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin/unit"
+    )
+
+endforeach()
+
+# Copy resources into output directory (only needs to be performed for one target)
+add_resources(${EXECUTABLE_NAME} "${PROJECT_SOURCE_DIR}/scenes")
diff --git a/tests/catch/catch.hpp b/tests/catch/catch.hpp
new file mode 100644 (file)
index 0000000..6b8dfb5
--- /dev/null
@@ -0,0 +1,8997 @@
+/*
+ *  CATCH v1.0 build 53 (master branch)
+ *  Generated: 2014-08-20 08:08:19.533804
+ *  ----------------------------------------------------------
+ *  This file has been merged from multiple headers. Please don't edit it directly
+ *  Copyright (c) 2012 Two Blue Cubes Ltd. All rights reserved.
+ *
+ *  Distributed under the Boost Software License, Version 1.0. (See accompanying
+ *  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
+ */
+#ifndef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+#define TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
+#define TWOBLUECUBES_CATCH_HPP_INCLUDED
+
+// #included from: internal/catch_suppress_warnings.h
+
+#define TWOBLUECUBES_CATCH_SUPPRESS_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wglobal-constructors"
+#pragma clang diagnostic ignored "-Wvariadic-macros"
+#pragma clang diagnostic ignored "-Wc99-extensions"
+#pragma clang diagnostic ignored "-Wunused-variable"
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#pragma clang diagnostic ignored "-Wc++98-compat"
+#pragma clang diagnostic ignored "-Wc++98-compat-pedantic"
+#elif defined __GNUC__
+#pragma GCC diagnostic ignored "-Wvariadic-macros"
+#pragma GCC diagnostic ignored "-Wunused-variable"
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wpadded"
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+#  define CATCH_CONFIG_RUNNER
+#endif
+
+#ifdef CATCH_CONFIG_RUNNER
+#  ifndef CLARA_CONFIG_MAIN
+#    define CLARA_CONFIG_MAIN_NOT_DEFINED
+#    define CLARA_CONFIG_MAIN
+#  endif
+#endif
+
+// #included from: internal/catch_notimplemented_exception.h
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_H_INCLUDED
+
+// #included from: catch_common.h
+#define TWOBLUECUBES_CATCH_COMMON_H_INCLUDED
+
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line
+#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line )
+#define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ )
+
+#define INTERNAL_CATCH_STRINGIFY2( expr ) #expr
+#define INTERNAL_CATCH_STRINGIFY( expr ) INTERNAL_CATCH_STRINGIFY2( expr )
+
+#include <sstream>
+#include <stdexcept>
+#include <algorithm>
+
+// #included from: catch_compiler_capabilities.h
+#define TWOBLUECUBES_CATCH_COMPILER_CAPABILITIES_HPP_INCLUDED
+
+// Much of the following code is based on Boost (1.53)
+
+#ifdef __clang__
+
+#  if __has_feature(cxx_nullptr)
+#    define CATCH_CONFIG_CPP11_NULLPTR
+#  endif
+
+#  if __has_feature(cxx_noexcept)
+#    define CATCH_CONFIG_CPP11_NOEXCEPT
+#  endif
+
+#endif // __clang__
+
+////////////////////////////////////////////////////////////////////////////////
+// Borland
+#ifdef __BORLANDC__
+
+#if (__BORLANDC__ > 0x582 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __BORLANDC__
+
+////////////////////////////////////////////////////////////////////////////////
+// EDG
+#ifdef __EDG_VERSION__
+
+#if (__EDG_VERSION__ > 238 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __EDG_VERSION__
+
+////////////////////////////////////////////////////////////////////////////////
+// Digital Mars
+#ifdef __DMC__
+
+#if (__DMC__ > 0x840 )
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // __DMC__
+
+////////////////////////////////////////////////////////////////////////////////
+// GCC
+#ifdef __GNUC__
+
+#if __GNUC__ < 3
+
+#if (__GNUC_MINOR__ >= 96 )
+//#define CATCH_CONFIG_SFINAE
+#endif
+
+#elif __GNUC__ >= 3
+
+// #define CATCH_CONFIG_SFINAE // Taking this out completely for now
+
+#endif // __GNUC__ < 3
+
+#if __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6 && defined(__GXX_EXPERIMENTAL_CXX0X__) )
+
+#define CATCH_CONFIG_CPP11_NULLPTR
+#endif
+
+#endif // __GNUC__
+
+////////////////////////////////////////////////////////////////////////////////
+// Visual C++
+#ifdef _MSC_VER
+
+#if (_MSC_VER >= 1310 ) // (VC++ 7.0+)
+//#define CATCH_CONFIG_SFINAE // Not confirmed
+#endif
+
+#endif // _MSC_VER
+
+// Use variadic macros if the compiler supports them
+#if ( defined _MSC_VER && _MSC_VER > 1400 && !defined __EDGE__) || \
+    ( defined __WAVE__ && __WAVE_HAS_VARIADICS ) || \
+    ( defined __GNUC__ && __GNUC__ >= 3 ) || \
+    ( !defined __cplusplus && __STDC_VERSION__ >= 199901L || __cplusplus >= 201103L )
+
+#ifndef CATCH_CONFIG_NO_VARIADIC_MACROS
+#define CATCH_CONFIG_VARIADIC_MACROS
+#endif
+
+#endif
+
+////////////////////////////////////////////////////////////////////////////////
+// C++ language feature support
+
+// detect language version:
+#if (__cplusplus == 201103L)
+#  define CATCH_CPP11
+#  define CATCH_CPP11_OR_GREATER
+#elif (__cplusplus >= 201103L)
+#  define CATCH_CPP11_OR_GREATER
+#endif
+
+// noexcept support:
+#if defined(CATCH_CONFIG_CPP11_NOEXCEPT) && !defined(CATCH_NOEXCEPT)
+#  define CATCH_NOEXCEPT noexcept
+#  define CATCH_NOEXCEPT_IS(x) noexcept(x)
+#else
+#  define CATCH_NOEXCEPT throw()
+#  define CATCH_NOEXCEPT_IS(x)
+#endif
+
+namespace Catch {
+
+    class NonCopyable {
+        NonCopyable( NonCopyable const& );
+        void operator = ( NonCopyable const& );
+    protected:
+        NonCopyable() {}
+        virtual ~NonCopyable();
+    };
+
+    class SafeBool {
+    public:
+        typedef void (SafeBool::*type)() const;
+
+        static type makeSafe( bool value ) {
+            return value ? &SafeBool::trueValue : 0;
+        }
+    private:
+        void trueValue() const {}
+    };
+
+    template<typename ContainerT>
+    inline void deleteAll( ContainerT& container ) {
+        typename ContainerT::const_iterator it = container.begin();
+        typename ContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete *it;
+    }
+    template<typename AssociativeContainerT>
+    inline void deleteAllValues( AssociativeContainerT& container ) {
+        typename AssociativeContainerT::const_iterator it = container.begin();
+        typename AssociativeContainerT::const_iterator itEnd = container.end();
+        for(; it != itEnd; ++it )
+            delete it->second;
+    }
+
+    bool startsWith( std::string const& s, std::string const& prefix );
+    bool endsWith( std::string const& s, std::string const& suffix );
+    bool contains( std::string const& s, std::string const& infix );
+    void toLowerInPlace( std::string& s );
+    std::string toLower( std::string const& s );
+    std::string trim( std::string const& str );
+
+    struct pluralise {
+        pluralise( std::size_t count, std::string const& label );
+
+        friend std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser );
+
+        std::size_t m_count;
+        std::string m_label;
+    };
+
+    struct SourceLineInfo {
+
+        SourceLineInfo();
+        SourceLineInfo( char const* _file, std::size_t _line );
+        SourceLineInfo( SourceLineInfo const& other );
+#  ifdef CATCH_CPP11_OR_GREATER
+        SourceLineInfo( SourceLineInfo && )                  = default;
+        SourceLineInfo& operator = ( SourceLineInfo const& ) = default;
+        SourceLineInfo& operator = ( SourceLineInfo && )     = default;
+#  endif
+        bool empty() const;
+        bool operator == ( SourceLineInfo const& other ) const;
+
+        std::string file;
+        std::size_t line;
+    };
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info );
+
+    // This is just here to avoid compiler warnings with macro constants and boolean literals
+    inline bool isTrue( bool value ){ return value; }
+    inline bool alwaysTrue() { return true; }
+    inline bool alwaysFalse() { return false; }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo );
+
+    // Use this in variadic streaming macros to allow
+    //    >> +StreamEndStop
+    // as well as
+    //    >> stuff +StreamEndStop
+    struct StreamEndStop {
+        std::string operator+() {
+            return std::string();
+        }
+    };
+    template<typename T>
+    T const& operator + ( T const& value, StreamEndStop ) {
+        return value;
+    }
+}
+
+#define CATCH_INTERNAL_LINEINFO ::Catch::SourceLineInfo( __FILE__, static_cast<std::size_t>( __LINE__ ) )
+#define CATCH_INTERNAL_ERROR( msg ) ::Catch::throwLogicError( msg, CATCH_INTERNAL_LINEINFO );
+
+#include <ostream>
+
+namespace Catch {
+
+    class NotImplementedException : public std::exception
+    {
+    public:
+        NotImplementedException( SourceLineInfo const& lineInfo );
+        NotImplementedException( NotImplementedException const& ) {}
+
+        virtual ~NotImplementedException() CATCH_NOEXCEPT {}
+
+        virtual const char* what() const CATCH_NOEXCEPT;
+
+    private:
+        std::string m_what;
+        SourceLineInfo m_lineInfo;
+    };
+
+} // end namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define CATCH_NOT_IMPLEMENTED throw Catch::NotImplementedException( CATCH_INTERNAL_LINEINFO )
+
+// #included from: internal/catch_context.h
+#define TWOBLUECUBES_CATCH_CONTEXT_H_INCLUDED
+
+// #included from: catch_interfaces_generators.h
+#define TWOBLUECUBES_CATCH_INTERFACES_GENERATORS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct IGeneratorInfo {
+        virtual ~IGeneratorInfo();
+        virtual bool moveNext() = 0;
+        virtual std::size_t getCurrentIndex() const = 0;
+    };
+
+    struct IGeneratorsForTest {
+        virtual ~IGeneratorsForTest();
+
+        virtual IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) = 0;
+        virtual bool moveNext() = 0;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest();
+
+} // end namespace Catch
+
+// #included from: catch_ptr.hpp
+#define TWOBLUECUBES_CATCH_PTR_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    // An intrusive reference counting smart pointer.
+    // T must implement addRef() and release() methods
+    // typically implementing the IShared interface
+    template<typename T>
+    class Ptr {
+    public:
+        Ptr() : m_p( NULL ){}
+        Ptr( T* p ) : m_p( p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        Ptr( Ptr const& other ) : m_p( other.m_p ){
+            if( m_p )
+                m_p->addRef();
+        }
+        ~Ptr(){
+            if( m_p )
+                m_p->release();
+        }
+        void reset() {
+            if( m_p )
+                m_p->release();
+            m_p = NULL;
+        }
+        Ptr& operator = ( T* p ){
+            Ptr temp( p );
+            swap( temp );
+            return *this;
+        }
+        Ptr& operator = ( Ptr const& other ){
+            Ptr temp( other );
+            swap( temp );
+            return *this;
+        }
+        void swap( Ptr& other ) { std::swap( m_p, other.m_p ); }
+        T* get() { return m_p; }
+        const T* get() const{ return m_p; }
+        T& operator*() const { return *m_p; }
+        T* operator->() const { return m_p; }
+        bool operator !() const { return m_p == NULL; }
+        operator SafeBool::type() const { return SafeBool::makeSafe( m_p != NULL ); }
+
+    private:
+        T* m_p;
+    };
+
+    struct IShared : NonCopyable {
+        virtual ~IShared();
+        virtual void addRef() const = 0;
+        virtual void release() const = 0;
+    };
+
+    template<typename T = IShared>
+    struct SharedImpl : T {
+
+        SharedImpl() : m_rc( 0 ){}
+
+        virtual void addRef() const {
+            ++m_rc;
+        }
+        virtual void release() const {
+            if( --m_rc == 0 )
+                delete this;
+        }
+
+        mutable unsigned int m_rc;
+    };
+
+} // end namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#include <memory>
+#include <vector>
+#include <stdlib.h>
+
+namespace Catch {
+
+    class TestCase;
+    class Stream;
+    struct IResultCapture;
+    struct IRunner;
+    struct IGeneratorsForTest;
+    struct IConfig;
+
+    struct IContext
+    {
+        virtual ~IContext();
+
+        virtual IResultCapture* getResultCapture() = 0;
+        virtual IRunner* getRunner() = 0;
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) = 0;
+        virtual bool advanceGeneratorsForCurrentTest() = 0;
+        virtual Ptr<IConfig const> getConfig() const = 0;
+    };
+
+    struct IMutableContext : IContext
+    {
+        virtual ~IMutableContext();
+        virtual void setResultCapture( IResultCapture* resultCapture ) = 0;
+        virtual void setRunner( IRunner* runner ) = 0;
+        virtual void setConfig( Ptr<IConfig const> const& config ) = 0;
+    };
+
+    IContext& getCurrentContext();
+    IMutableContext& getCurrentMutableContext();
+    void cleanUpContext();
+    Stream createStream( std::string const& streamName );
+
+}
+
+// #included from: internal/catch_test_registry.hpp
+#define TWOBLUECUBES_CATCH_TEST_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_interfaces_testcase.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TESTCASE_H_INCLUDED
+
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec;
+
+    struct ITestCase : IShared {
+        virtual void invoke () const = 0;
+    protected:
+        virtual ~ITestCase();
+    };
+
+    class TestCase;
+    struct IConfig;
+
+    struct ITestCaseRegistry {
+        virtual ~ITestCaseRegistry();
+        virtual std::vector<TestCase> const& getAllTests() const = 0;
+        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const = 0;
+
+    };
+}
+
+namespace Catch {
+
+template<typename C>
+class MethodTestCase : public SharedImpl<ITestCase> {
+
+public:
+    MethodTestCase( void (C::*method)() ) : m_method( method ) {}
+
+    virtual void invoke() const {
+        C obj;
+        (obj.*m_method)();
+    }
+
+private:
+    virtual ~MethodTestCase() {}
+
+    void (C::*m_method)();
+};
+
+typedef void(*TestFunction)();
+
+struct NameAndDesc {
+    NameAndDesc( const char* _name = "", const char* _description= "" )
+    : name( _name ), description( _description )
+    {}
+
+    const char* name;
+    const char* description;
+};
+
+struct AutoReg {
+
+    AutoReg(    TestFunction function,
+                SourceLineInfo const& lineInfo,
+                NameAndDesc const& nameAndDesc );
+
+    template<typename C>
+    AutoReg(    void (C::*method)(),
+                char const* className,
+                NameAndDesc const& nameAndDesc,
+                SourceLineInfo const& lineInfo ) {
+        registerTestCase(   new MethodTestCase<C>( method ),
+                            className,
+                            nameAndDesc,
+                            lineInfo );
+    }
+
+    void registerTestCase(  ITestCase* testCase,
+                            char const* className,
+                            NameAndDesc const& nameAndDesc,
+                            SourceLineInfo const& lineInfo );
+
+    ~AutoReg();
+
+private:
+    AutoReg( AutoReg const& );
+    void operator= ( AutoReg const& );
+};
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE( ... ) \
+        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( __VA_ARGS__ ) ); }\
+        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, ... ) \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); }
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, ... )\
+        namespace{ \
+            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( __VA_ARGS__ ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
+
+#else
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TESTCASE( Name, Desc ) \
+        static void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )(); \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ ), CATCH_INTERNAL_LINEINFO, Catch::NameAndDesc( Name, Desc ) ); }\
+        static void INTERNAL_CATCH_UNIQUE_NAME(  ____C_A_T_C_H____T_E_S_T____ )()
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_METHOD_AS_TEST_CASE( QualifiedMethod, Name, Desc ) \
+        namespace{ Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar )( &QualifiedMethod, "&" #QualifiedMethod, Catch::NameAndDesc( Name, Desc ), CATCH_INTERNAL_LINEINFO ); }
+
+    ///////////////////////////////////////////////////////////////////////////////
+    #define INTERNAL_CATCH_TEST_CASE_METHOD( ClassName, TestName, Desc )\
+        namespace{ \
+            struct INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ ) : ClassName{ \
+                void test(); \
+            }; \
+            Catch::AutoReg INTERNAL_CATCH_UNIQUE_NAME( autoRegistrar ) ( &INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test, #ClassName, Catch::NameAndDesc( TestName, Desc ), CATCH_INTERNAL_LINEINFO ); \
+        } \
+        void INTERNAL_CATCH_UNIQUE_NAME( ____C_A_T_C_H____T_E_S_T____ )::test()
+
+#endif
+
+// #included from: internal/catch_capture.hpp
+#define TWOBLUECUBES_CATCH_CAPTURE_HPP_INCLUDED
+
+// #included from: catch_result_builder.h
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_H_INCLUDED
+
+// #included from: catch_result_type.h
+#define TWOBLUECUBES_CATCH_RESULT_TYPE_H_INCLUDED
+
+namespace Catch {
+
+    // ResultWas::OfType enum
+    struct ResultWas { enum OfType {
+        Unknown = -1,
+        Ok = 0,
+        Info = 1,
+        Warning = 2,
+
+        FailureBit = 0x10,
+
+        ExpressionFailed = FailureBit | 1,
+        ExplicitFailure = FailureBit | 2,
+
+        Exception = 0x100 | FailureBit,
+
+        ThrewException = Exception | 1,
+        DidntThrowException = Exception | 2
+
+    }; };
+
+    inline bool isOk( ResultWas::OfType resultType ) {
+        return ( resultType & ResultWas::FailureBit ) == 0;
+    }
+    inline bool isJustInfo( int flags ) {
+        return flags == ResultWas::Info;
+    }
+
+    // ResultDisposition::Flags enum
+    struct ResultDisposition { enum Flags {
+        Normal = 0x00,
+
+        ContinueOnFailure = 0x01,   // Failures fail test, but execution continues
+        FalseTest = 0x02,           // Prefix expression with !
+        SuppressFail = 0x04         // Failures are reported but do not fail the test
+    }; };
+
+    inline ResultDisposition::Flags operator | ( ResultDisposition::Flags lhs, ResultDisposition::Flags rhs ) {
+        return static_cast<ResultDisposition::Flags>( static_cast<int>( lhs ) | static_cast<int>( rhs ) );
+    }
+
+    inline bool shouldContinueOnFailure( int flags )    { return ( flags & ResultDisposition::ContinueOnFailure ) != 0; }
+    inline bool isFalseTest( int flags )                { return ( flags & ResultDisposition::FalseTest ) != 0; }
+    inline bool shouldSuppressFailure( int flags )      { return ( flags & ResultDisposition::SuppressFail ) != 0; }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.h
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct AssertionInfo
+    {
+        AssertionInfo() {}
+        AssertionInfo(  std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        std::string const& _capturedExpression,
+                        ResultDisposition::Flags _resultDisposition );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        std::string capturedExpression;
+        ResultDisposition::Flags resultDisposition;
+    };
+
+    struct AssertionResultData
+    {
+        AssertionResultData() : resultType( ResultWas::Unknown ) {}
+
+        std::string reconstructedExpression;
+        std::string message;
+        ResultWas::OfType resultType;
+    };
+
+    class AssertionResult {
+    public:
+        AssertionResult();
+        AssertionResult( AssertionInfo const& info, AssertionResultData const& data );
+        ~AssertionResult();
+#  ifdef CATCH_CPP11_OR_GREATER
+         AssertionResult( AssertionResult const& )              = default;
+         AssertionResult( AssertionResult && )                  = default;
+         AssertionResult& operator = ( AssertionResult const& ) = default;
+         AssertionResult& operator = ( AssertionResult && )     = default;
+#  endif
+
+        bool isOk() const;
+        bool succeeded() const;
+        ResultWas::OfType getResultType() const;
+        bool hasExpression() const;
+        bool hasMessage() const;
+        std::string getExpression() const;
+        std::string getExpressionInMacro() const;
+        bool hasExpandedExpression() const;
+        std::string getExpandedExpression() const;
+        std::string getMessage() const;
+        SourceLineInfo getSourceInfo() const;
+        std::string getTestMacroName() const;
+
+    protected:
+        AssertionInfo m_info;
+        AssertionResultData m_resultData;
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct TestFailureException{};
+
+    template<typename T> class ExpressionLhs;
+
+    struct STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison;
+
+    struct CopyableStream {
+        CopyableStream() {}
+        CopyableStream( CopyableStream const& other ) {
+            oss << other.oss.str();
+        }
+        CopyableStream& operator=( CopyableStream const& other ) {
+            oss.str("");
+            oss << other.oss.str();
+            return *this;
+        }
+        std::ostringstream oss;
+    };
+
+    class ResultBuilder {
+    public:
+        ResultBuilder(  char const* macroName,
+                        SourceLineInfo const& lineInfo,
+                        char const* capturedExpression,
+                        ResultDisposition::Flags resultDisposition );
+
+        template<typename T>
+        ExpressionLhs<T const&> operator->* ( T const& operand );
+        ExpressionLhs<bool> operator->* ( bool value );
+
+        template<typename T>
+        ResultBuilder& operator << ( T const& value ) {
+            m_stream.oss << value;
+            return *this;
+        }
+
+        template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
+        template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
+
+        ResultBuilder& setResultType( ResultWas::OfType result );
+        ResultBuilder& setResultType( bool result );
+        ResultBuilder& setLhs( std::string const& lhs );
+        ResultBuilder& setRhs( std::string const& rhs );
+        ResultBuilder& setOp( std::string const& op );
+
+        void endExpression();
+
+        std::string reconstructExpression() const;
+        AssertionResult build() const;
+
+        void useActiveException( ResultDisposition::Flags resultDisposition = ResultDisposition::Normal );
+        void captureResult( ResultWas::OfType resultType );
+        void captureExpression();
+        void react();
+        bool shouldDebugBreak() const;
+        bool allowThrows() const;
+
+    private:
+        AssertionInfo m_assertionInfo;
+        AssertionResultData m_data;
+        struct ExprComponents {
+            ExprComponents() : testFalse( false ) {}
+            bool testFalse;
+            std::string lhs, rhs, op;
+        } m_exprComponents;
+        CopyableStream m_stream;
+
+        bool m_shouldDebugBreak;
+        bool m_shouldThrow;
+    };
+
+} // namespace Catch
+
+// Include after due to circular dependency:
+// #included from: catch_expression_lhs.hpp
+#define TWOBLUECUBES_CATCH_EXPRESSION_LHS_HPP_INCLUDED
+
+// #included from: catch_evaluate.hpp
+#define TWOBLUECUBES_CATCH_EVALUATE_HPP_INCLUDED
+
+#ifdef _MSC_VER
+#pragma warning(push)
+#pragma warning(disable:4389) // '==' : signed/unsigned mismatch
+#endif
+
+#include <cstddef>
+
+namespace Catch {
+namespace Internal {
+
+    enum Operator {
+        IsEqualTo,
+        IsNotEqualTo,
+        IsLessThan,
+        IsGreaterThan,
+        IsLessThanOrEqualTo,
+        IsGreaterThanOrEqualTo
+    };
+
+    template<Operator Op> struct OperatorTraits             { static const char* getName(){ return "*error*"; } };
+    template<> struct OperatorTraits<IsEqualTo>             { static const char* getName(){ return "=="; } };
+    template<> struct OperatorTraits<IsNotEqualTo>          { static const char* getName(){ return "!="; } };
+    template<> struct OperatorTraits<IsLessThan>            { static const char* getName(){ return "<"; } };
+    template<> struct OperatorTraits<IsGreaterThan>         { static const char* getName(){ return ">"; } };
+    template<> struct OperatorTraits<IsLessThanOrEqualTo>   { static const char* getName(){ return "<="; } };
+    template<> struct OperatorTraits<IsGreaterThanOrEqualTo>{ static const char* getName(){ return ">="; } };
+
+    template<typename T>
+    inline T& opCast(T const& t) { return const_cast<T&>(t); }
+
+// nullptr_t support based on pull request #154 from Konstantin Baumann
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    inline std::nullptr_t opCast(std::nullptr_t) { return nullptr; }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+    // So the compare overloads can be operator agnostic we convey the operator as a template
+    // enum, which is used to specialise an Evaluator for doing the comparison.
+    template<typename T1, typename T2, Operator Op>
+    class Evaluator{};
+
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs) {
+            return opCast( lhs ) ==  opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsNotEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) != opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) < opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThan> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) > opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsGreaterThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) >= opCast( rhs );
+        }
+    };
+    template<typename T1, typename T2>
+    struct Evaluator<T1, T2, IsLessThanOrEqualTo> {
+        static bool evaluate( T1 const& lhs, T2 const& rhs ) {
+            return opCast( lhs ) <= opCast( rhs );
+        }
+    };
+
+    template<Operator Op, typename T1, typename T2>
+    bool applyEvaluator( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // This level of indirection allows us to specialise for integer types
+    // to avoid signed/ unsigned warnings
+
+    // "base" overload
+    template<Operator Op, typename T1, typename T2>
+    bool compare( T1 const& lhs, T2 const& rhs ) {
+        return Evaluator<T1, T2, Op>::evaluate( lhs, rhs );
+    }
+
+    // unsigned X to int
+    template<Operator Op> bool compare( unsigned int lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, int rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned int>( rhs ) );
+    }
+
+    // unsigned X to long
+    template<Operator Op> bool compare( unsigned int lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned long lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+    template<Operator Op> bool compare( unsigned char lhs, long rhs ) {
+        return applyEvaluator<Op>( lhs, static_cast<unsigned long>( rhs ) );
+    }
+
+    // int to unsigned X
+    template<Operator Op> bool compare( int lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( int lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned int>( lhs ), rhs );
+    }
+
+    // long to unsigned X
+    template<Operator Op> bool compare( long lhs, unsigned int rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned long rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+    template<Operator Op> bool compare( long lhs, unsigned char rhs ) {
+        return applyEvaluator<Op>( static_cast<unsigned long>( lhs ), rhs );
+    }
+
+    // pointer to long (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( long lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, long rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+    // pointer to int (when comparing against NULL)
+    template<Operator Op, typename T> bool compare( int lhs, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( reinterpret_cast<T*>( lhs ), rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, int rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, reinterpret_cast<T*>( rhs ) );
+    }
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+    // pointer to nullptr_t (when comparing against nullptr)
+    template<Operator Op, typename T> bool compare( std::nullptr_t, T* rhs ) {
+        return Evaluator<T*, T*, Op>::evaluate( NULL, rhs );
+    }
+    template<Operator Op, typename T> bool compare( T* lhs, std::nullptr_t ) {
+        return Evaluator<T*, T*, Op>::evaluate( lhs, NULL );
+    }
+#endif // CATCH_CONFIG_CPP11_NULLPTR
+
+} // end of namespace Internal
+} // end of namespace Catch
+
+#ifdef _MSC_VER
+#pragma warning(pop)
+#endif
+
+// #included from: catch_tostring.h
+#define TWOBLUECUBES_CATCH_TOSTRING_H_INCLUDED
+
+// #included from: catch_sfinae.hpp
+#define TWOBLUECUBES_CATCH_SFINAE_HPP_INCLUDED
+
+// Try to detect if the current compiler supports SFINAE
+
+namespace Catch {
+
+    struct TrueType {
+        static const bool value = true;
+        typedef void Enable;
+        char sizer[1];
+    };
+    struct FalseType {
+        static const bool value = false;
+        typedef void Disable;
+        char sizer[2];
+    };
+
+#ifdef CATCH_CONFIG_SFINAE
+
+    template<bool> struct NotABooleanExpression;
+
+    template<bool c> struct If : NotABooleanExpression<c> {};
+    template<> struct If<true> : TrueType {};
+    template<> struct If<false> : FalseType {};
+
+    template<int size> struct SizedIf;
+    template<> struct SizedIf<sizeof(TrueType)> : TrueType {};
+    template<> struct SizedIf<sizeof(FalseType)> : FalseType {};
+
+#endif // CATCH_CONFIG_SFINAE
+
+} // end namespace Catch
+
+#include <sstream>
+#include <iomanip>
+#include <limits>
+#include <vector>
+#include <cstddef>
+
+#ifdef __OBJC__
+// #included from: catch_objc_arc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_ARC_HPP_INCLUDED
+
+#import <Foundation/Foundation.h>
+
+#ifdef __has_feature
+#define CATCH_ARC_ENABLED __has_feature(objc_arc)
+#else
+#define CATCH_ARC_ENABLED 0
+#endif
+
+void arcSafeRelease( NSObject* obj );
+id performOptionalSelector( id obj, SEL sel );
+
+#if !CATCH_ARC_ENABLED
+inline void arcSafeRelease( NSObject* obj ) {
+    [obj release];
+}
+inline id performOptionalSelector( id obj, SEL sel ) {
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED
+#define CATCH_ARC_STRONG
+#else
+inline void arcSafeRelease( NSObject* ){}
+inline id performOptionalSelector( id obj, SEL sel ) {
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
+#endif
+    if( [obj respondsToSelector: sel] )
+        return [obj performSelector: sel];
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+    return nil;
+}
+#define CATCH_UNSAFE_UNRETAINED __unsafe_unretained
+#define CATCH_ARC_STRONG __strong
+#endif
+
+#endif
+
+namespace Catch {
+namespace Detail {
+
+// SFINAE is currently disabled by default for all compilers.
+// If the non SFINAE version of IsStreamInsertable is ambiguous for you
+// and your compiler supports SFINAE, try #defining CATCH_CONFIG_SFINAE
+#ifdef CATCH_CONFIG_SFINAE
+
+    template<typename T>
+    class IsStreamInsertableHelper {
+        template<int N> struct TrueIfSizeable : TrueType {};
+
+        template<typename T2>
+        static TrueIfSizeable<sizeof((*(std::ostream*)0) << *((T2 const*)0))> dummy(T2*);
+        static FalseType dummy(...);
+
+    public:
+        typedef SizedIf<sizeof(dummy((T*)0))> type;
+    };
+
+    template<typename T>
+    struct IsStreamInsertable : IsStreamInsertableHelper<T>::type {};
+
+#else
+
+    struct BorgType {
+        template<typename T> BorgType( T const& );
+    };
+
+    TrueType& testStreamable( std::ostream& );
+    FalseType testStreamable( FalseType );
+
+    FalseType operator<<( std::ostream const&, BorgType const& );
+
+    template<typename T>
+    struct IsStreamInsertable {
+        static std::ostream &s;
+        static T  const&t;
+        enum { value = sizeof( testStreamable(s << t) ) == sizeof( TrueType ) };
+    };
+
+#endif
+
+    template<bool C>
+    struct StringMakerBase {
+        template<typename T>
+        static std::string convert( T const& ) { return "{?}"; }
+    };
+
+    template<>
+    struct StringMakerBase<true> {
+        template<typename T>
+        static std::string convert( T const& _value ) {
+            std::ostringstream oss;
+            oss << _value;
+            return oss.str();
+        }
+    };
+
+    std::string rawMemoryToString( const void *object, std::size_t size );
+
+    template<typename T>
+    inline std::string rawMemoryToString( const T& object ) {
+      return rawMemoryToString( &object, sizeof(object) );
+    }
+
+} // end namespace Detail
+
+template<typename T>
+std::string toString( T const& value );
+
+template<typename T>
+struct StringMaker :
+    Detail::StringMakerBase<Detail::IsStreamInsertable<T>::value> {};
+
+template<typename T>
+struct StringMaker<T*> {
+    template<typename U>
+    static std::string convert( U* p ) {
+        if( !p )
+            return INTERNAL_CATCH_STRINGIFY( NULL );
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+template<typename R, typename C>
+struct StringMaker<R C::*> {
+    static std::string convert( R C::* p ) {
+        if( !p )
+            return INTERNAL_CATCH_STRINGIFY( NULL );
+        else
+            return Detail::rawMemoryToString( p );
+    }
+};
+
+namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last );
+}
+
+template<typename T, typename Allocator>
+struct StringMaker<std::vector<T, Allocator> > {
+    static std::string convert( std::vector<T,Allocator> const& v ) {
+        return Detail::rangeToString( v.begin(), v.end() );
+    }
+};
+
+namespace Detail {
+    template<typename T>
+    std::string makeString( T const& value ) {
+        return StringMaker<T>::convert( value );
+    }
+} // end namespace Detail
+
+/// \brief converts any type to a string
+///
+/// The default template forwards on to ostringstream - except when an
+/// ostringstream overload does not exist - in which case it attempts to detect
+/// that and writes {?}.
+/// Overload (not specialise) this template for custom typs that you don't want
+/// to provide an ostream overload for.
+template<typename T>
+std::string toString( T const& value ) {
+    return StringMaker<T>::convert( value );
+}
+
+// Built in overloads
+
+std::string toString( std::string const& value );
+std::string toString( std::wstring const& value );
+std::string toString( const char* const value );
+std::string toString( char* const value );
+std::string toString( const wchar_t* const value );
+std::string toString( wchar_t* const value );
+std::string toString( int value );
+std::string toString( unsigned long value );
+std::string toString( unsigned int value );
+std::string toString( const double value );
+std::string toString( const float value );
+std::string toString( bool value );
+std::string toString( char value );
+std::string toString( signed char value );
+std::string toString( unsigned char value );
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t );
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring );
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring );
+    std::string toString( NSObject* const& nsObject );
+#endif
+
+    namespace Detail {
+    template<typename InputIterator>
+    std::string rangeToString( InputIterator first, InputIterator last ) {
+        std::ostringstream oss;
+        oss << "{ ";
+        if( first != last ) {
+            oss << toString( *first );
+            for( ++first ; first != last ; ++first ) {
+                oss << ", " << toString( *first );
+            }
+        }
+        oss << " }";
+        return oss.str();
+    }
+}
+
+} // end namespace Catch
+
+namespace Catch {
+
+// Wraps the LHS of an expression and captures the operator and RHS (if any) -
+// wrapping them all in a ResultBuilder object
+template<typename T>
+class ExpressionLhs {
+    ExpressionLhs& operator = ( ExpressionLhs const& );
+#  ifdef CATCH_CPP11_OR_GREATER
+    ExpressionLhs& operator = ( ExpressionLhs && ) = delete;
+#  endif
+
+public:
+    ExpressionLhs( ResultBuilder& rb, T lhs ) : m_rb( rb ), m_lhs( lhs ) {}
+#  ifdef CATCH_CPP11_OR_GREATER
+    ExpressionLhs( ExpressionLhs const& ) = default;
+    ExpressionLhs( ExpressionLhs && )     = default;
+#  endif
+
+    template<typename RhsT>
+    ResultBuilder& operator == ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator != ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator < ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThan>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator > ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThan>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator <= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsLessThanOrEqualTo>( rhs );
+    }
+
+    template<typename RhsT>
+    ResultBuilder& operator >= ( RhsT const& rhs ) {
+        return captureExpression<Internal::IsGreaterThanOrEqualTo>( rhs );
+    }
+
+    ResultBuilder& operator == ( bool rhs ) {
+        return captureExpression<Internal::IsEqualTo>( rhs );
+    }
+
+    ResultBuilder& operator != ( bool rhs ) {
+        return captureExpression<Internal::IsNotEqualTo>( rhs );
+    }
+
+    void endExpression() {
+        bool value = m_lhs ? true : false;
+        m_rb
+            .setLhs( Catch::toString( value ) )
+            .setResultType( value )
+            .endExpression();
+    }
+
+    // Only simple binary expressions are allowed on the LHS.
+    // If more complex compositions are required then place the sub expression in parentheses
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator + ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator - ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator / ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator * ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator && ( RhsT const& );
+    template<typename RhsT> STATIC_ASSERT_Expression_Too_Complex_Please_Rewrite_As_Binary_Comparison& operator || ( RhsT const& );
+
+private:
+    template<Internal::Operator Op, typename RhsT>
+    ResultBuilder& captureExpression( RhsT const& rhs ) {
+        return m_rb
+            .setResultType( Internal::compare<Op>( m_lhs, rhs ) )
+            .setLhs( Catch::toString( m_lhs ) )
+            .setRhs( Catch::toString( rhs ) )
+            .setOp( Internal::OperatorTraits<Op>::getName() );
+    }
+
+private:
+    ResultBuilder& m_rb;
+    T m_lhs;
+};
+
+} // end namespace Catch
+
+
+namespace Catch {
+
+    template<typename T>
+    inline ExpressionLhs<T const&> ResultBuilder::operator->* ( T const& operand ) {
+        return ExpressionLhs<T const&>( *this, operand );
+    }
+
+    inline ExpressionLhs<bool> ResultBuilder::operator->* ( bool value ) {
+        return ExpressionLhs<bool>( *this, value );
+    }
+
+} // namespace Catch
+
+// #included from: catch_message.h
+#define TWOBLUECUBES_CATCH_MESSAGE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct MessageInfo {
+        MessageInfo(    std::string const& _macroName,
+                        SourceLineInfo const& _lineInfo,
+                        ResultWas::OfType _type );
+
+        std::string macroName;
+        SourceLineInfo lineInfo;
+        ResultWas::OfType type;
+        std::string message;
+        unsigned int sequence;
+
+        bool operator == ( MessageInfo const& other ) const {
+            return sequence == other.sequence;
+        }
+        bool operator < ( MessageInfo const& other ) const {
+            return sequence < other.sequence;
+        }
+    private:
+        static unsigned int globalCount;
+    };
+
+    struct MessageBuilder {
+        MessageBuilder( std::string const& macroName,
+                        SourceLineInfo const& lineInfo,
+                        ResultWas::OfType type )
+        : m_info( macroName, lineInfo, type )
+        {}
+
+        template<typename T>
+        MessageBuilder& operator << ( T const& value ) {
+            m_stream << value;
+            return *this;
+        }
+
+        MessageInfo m_info;
+        std::ostringstream m_stream;
+    };
+
+    class ScopedMessage {
+    public:
+        ScopedMessage( MessageBuilder const& builder );
+        ScopedMessage( ScopedMessage const& other );
+        ~ScopedMessage();
+
+        MessageInfo m_info;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_capture.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CAPTURE_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    class AssertionResult;
+    struct AssertionInfo;
+    struct SectionInfo;
+    struct MessageInfo;
+    class ScopedMessageBuilder;
+    struct Counts;
+
+    struct IResultCapture {
+
+        virtual ~IResultCapture();
+
+        virtual void assertionEnded( AssertionResult const& result ) = 0;
+        virtual bool sectionStarted(    SectionInfo const& sectionInfo,
+                                        Counts& assertions ) = 0;
+        virtual void sectionEnded( SectionInfo const& name, Counts const& assertions, double _durationInSeconds ) = 0;
+        virtual void pushScopedMessage( MessageInfo const& message ) = 0;
+        virtual void popScopedMessage( MessageInfo const& message ) = 0;
+
+        virtual std::string getCurrentTestName() const = 0;
+        virtual const AssertionResult* getLastResult() const = 0;
+    };
+
+    IResultCapture& getResultCapture();
+}
+
+// #included from: catch_debugger.h
+#define TWOBLUECUBES_CATCH_DEBUGGER_H_INCLUDED
+
+// #included from: catch_platform.h
+#define TWOBLUECUBES_CATCH_PLATFORM_H_INCLUDED
+
+#if defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_MAC
+#elif  defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
+#define CATCH_PLATFORM_IPHONE
+#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER)
+#define CATCH_PLATFORM_WINDOWS
+#endif
+
+#include <string>
+
+namespace Catch{
+
+    bool isDebuggerActive();
+    void writeToDebugConsole( std::string const& text );
+}
+
+#ifdef CATCH_PLATFORM_MAC
+
+    // The following code snippet based on:
+    // http://cocoawithlove.com/2008/03/break-into-debugger.html
+    #ifdef DEBUG
+        #if defined(__ppc64__) || defined(__ppc__)
+            #define CATCH_BREAK_INTO_DEBUGGER() \
+                if( Catch::isDebuggerActive() ) { \
+                    __asm__("li r0, 20\nsc\nnop\nli r0, 37\nli r4, 2\nsc\nnop\n" \
+                    : : : "memory","r0","r3","r4" ); \
+                }
+        #else
+            #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) {__asm__("int $3\n" : : );}
+        #endif
+    #endif
+
+#elif defined(_MSC_VER)
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { __debugbreak(); }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) void __stdcall DebugBreak();
+    #define CATCH_BREAK_INTO_DEBUGGER() if( Catch::isDebuggerActive() ) { DebugBreak(); }
+#endif
+
+#ifndef CATCH_BREAK_INTO_DEBUGGER
+#define CATCH_BREAK_INTO_DEBUGGER() Catch::alwaysTrue();
+#endif
+
+// #included from: catch_interfaces_runner.h
+#define TWOBLUECUBES_CATCH_INTERFACES_RUNNER_H_INCLUDED
+
+namespace Catch {
+    class TestCase;
+
+    struct IRunner {
+        virtual ~IRunner();
+        virtual bool aborting() const = 0;
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// In the event of a failure works out if the debugger needs to be invoked
+// and/or an exception thrown and takes appropriate action.
+// This needs to be done as a macro so the debugger will stop in the user
+// source code rather than in Catch library code
+#define INTERNAL_CATCH_REACT( resultBuilder ) \
+    if( resultBuilder.shouldDebugBreak() ) CATCH_BREAK_INTO_DEBUGGER(); \
+    resultBuilder.react();
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            ( __catchResult->*expr ).endExpression(); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( Catch::ResultDisposition::Normal ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::isTrue( false && (expr) ) ) // expr here is never evaluated at runtime but it forces the compiler to give it a look
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_IF( expr, resultDisposition, macroName ) \
+    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+    if( Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_ELSE( expr, resultDisposition, macroName ) \
+    INTERNAL_CATCH_TEST( expr, resultDisposition, macroName ); \
+    if( !Catch::getResultCapture().getLastResult()->succeeded() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_NO_THROW( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        try { \
+            expr; \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        } \
+        catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS( expr, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                expr; \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( ... ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_THROWS_AS( expr, exceptionType, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #expr, resultDisposition ); \
+        if( __catchResult.allowThrows() ) \
+            try { \
+                expr; \
+                __catchResult.captureResult( Catch::ResultWas::DidntThrowException ); \
+            } \
+            catch( exceptionType ) { \
+                __catchResult.captureResult( Catch::ResultWas::Ok ); \
+            } \
+            catch( ... ) { \
+                __catchResult.useActiveException( resultDisposition ); \
+            } \
+        else \
+            __catchResult.captureResult( Catch::ResultWas::Ok ); \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+///////////////////////////////////////////////////////////////////////////////
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, ... ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << __VA_ARGS__ + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#else
+    #define INTERNAL_CATCH_MSG( messageType, resultDisposition, macroName, log ) \
+        do { \
+            Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, "", resultDisposition ); \
+            __catchResult << log + ::Catch::StreamEndStop(); \
+            __catchResult.captureResult( messageType ); \
+            INTERNAL_CATCH_REACT( __catchResult ) \
+        } while( Catch::alwaysFalse() )
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_INFO( log, macroName ) \
+    Catch::ScopedMessage INTERNAL_CATCH_UNIQUE_NAME( scopedMessage ) = Catch::MessageBuilder( macroName, CATCH_INTERNAL_LINEINFO, Catch::ResultWas::Info ) << log;
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CHECK_THAT( arg, matcher, resultDisposition, macroName ) \
+    do { \
+        Catch::ResultBuilder __catchResult( macroName, CATCH_INTERNAL_LINEINFO, #arg " " #matcher, resultDisposition ); \
+        try { \
+            std::string matcherAsString = ::Catch::Matchers::matcher.toString(); \
+            __catchResult \
+                .setLhs( Catch::toString( arg ) ) \
+                .setRhs( matcherAsString == "{?}" ? #matcher : matcherAsString ) \
+                .setOp( "matches" ) \
+                .setResultType( ::Catch::Matchers::matcher.match( arg ) ); \
+            __catchResult.captureExpression(); \
+        } catch( ... ) { \
+            __catchResult.useActiveException( resultDisposition | Catch::ResultDisposition::ContinueOnFailure ); \
+        } \
+        INTERNAL_CATCH_REACT( __catchResult ) \
+    } while( Catch::alwaysFalse() )
+
+// #included from: internal/catch_section.h
+#define TWOBLUECUBES_CATCH_SECTION_H_INCLUDED
+
+// #included from: catch_section_info.h
+#define TWOBLUECUBES_CATCH_SECTION_INFO_H_INCLUDED
+
+namespace Catch {
+
+    struct SectionInfo {
+        SectionInfo
+            (   SourceLineInfo const& _lineInfo,
+                std::string const& _name,
+                std::string const& _description = std::string() );
+
+        std::string name;
+        std::string description;
+        SourceLineInfo lineInfo;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_totals.hpp
+#define TWOBLUECUBES_CATCH_TOTALS_HPP_INCLUDED
+
+#include <cstddef>
+
+namespace Catch {
+
+    struct Counts {
+        Counts() : passed( 0 ), failed( 0 ), failedButOk( 0 ) {}
+
+        Counts operator - ( Counts const& other ) const {
+            Counts diff;
+            diff.passed = passed - other.passed;
+            diff.failed = failed - other.failed;
+            diff.failedButOk = failedButOk - other.failedButOk;
+            return diff;
+        }
+        Counts& operator += ( Counts const& other ) {
+            passed += other.passed;
+            failed += other.failed;
+            failedButOk += other.failedButOk;
+            return *this;
+        }
+
+        std::size_t total() const {
+            return passed + failed + failedButOk;
+        }
+        bool allPassed() const {
+            return failed == 0 && failedButOk == 0;
+        }
+
+        std::size_t passed;
+        std::size_t failed;
+        std::size_t failedButOk;
+    };
+
+    struct Totals {
+
+        Totals operator - ( Totals const& other ) const {
+            Totals diff;
+            diff.assertions = assertions - other.assertions;
+            diff.testCases = testCases - other.testCases;
+            return diff;
+        }
+
+        Totals delta( Totals const& prevTotals ) const {
+            Totals diff = *this - prevTotals;
+            if( diff.assertions.failed > 0 )
+                ++diff.testCases.failed;
+            else if( diff.assertions.failedButOk > 0 )
+                ++diff.testCases.failedButOk;
+            else
+                ++diff.testCases.passed;
+            return diff;
+        }
+
+        Totals& operator += ( Totals const& other ) {
+            assertions += other.assertions;
+            testCases += other.testCases;
+            return *this;
+        }
+
+        Counts assertions;
+        Counts testCases;
+    };
+}
+
+// #included from: catch_timer.h
+#define TWOBLUECUBES_CATCH_TIMER_H_INCLUDED
+
+#ifdef CATCH_PLATFORM_WINDOWS
+typedef unsigned long long uint64_t;
+#else
+#include <stdint.h>
+#endif
+
+namespace Catch {
+
+    class Timer {
+    public:
+        Timer() : m_ticks( 0 ) {}
+        void start();
+        unsigned int getElapsedNanoseconds() const;
+        unsigned int getElapsedMilliseconds() const;
+        double getElapsedSeconds() const;
+
+    private:
+        uint64_t m_ticks;
+    };
+
+} // namespace Catch
+
+#include <string>
+
+namespace Catch {
+
+    class Section {
+    public:
+        Section( SectionInfo const& info );
+        ~Section();
+
+        // This indicates whether the section should be executed or not
+        operator bool() const;
+
+    private:
+#ifdef CATCH_CPP11_OR_GREATER
+        Section( Section const& )              = delete;
+        Section( Section && )                  = delete;
+        Section& operator = ( Section const& ) = delete;
+        Section& operator = ( Section && )     = delete;
+#else
+        Section( Section const& info );
+        Section& operator = ( Section const& );
+#endif
+        SectionInfo m_info;
+
+        std::string m_name;
+        Counts m_assertions;
+        bool m_sectionIncluded;
+        Timer m_timer;
+    };
+
+} // end namespace Catch
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define INTERNAL_CATCH_SECTION( ... ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, __VA_ARGS__ ) )
+#else
+    #define INTERNAL_CATCH_SECTION( name, desc ) \
+        if( Catch::Section const& INTERNAL_CATCH_UNIQUE_NAME( catch_internal_Section ) = Catch::SectionInfo( CATCH_INTERNAL_LINEINFO, name, desc ) )
+#endif
+
+// #included from: internal/catch_generators.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_HPP_INCLUDED
+
+#include <iterator>
+#include <vector>
+#include <string>
+#include <stdlib.h>
+
+namespace Catch {
+
+template<typename T>
+struct IGenerator {
+    virtual ~IGenerator() {}
+    virtual T getValue( std::size_t index ) const = 0;
+    virtual std::size_t size () const = 0;
+};
+
+template<typename T>
+class BetweenGenerator : public IGenerator<T> {
+public:
+    BetweenGenerator( T from, T to ) : m_from( from ), m_to( to ){}
+
+    virtual T getValue( std::size_t index ) const {
+        return m_from+static_cast<int>( index );
+    }
+
+    virtual std::size_t size() const {
+        return static_cast<std::size_t>( 1+m_to-m_from );
+    }
+
+private:
+
+    T m_from;
+    T m_to;
+};
+
+template<typename T>
+class ValuesGenerator : public IGenerator<T> {
+public:
+    ValuesGenerator(){}
+
+    void add( T value ) {
+        m_values.push_back( value );
+    }
+
+    virtual T getValue( std::size_t index ) const {
+        return m_values[index];
+    }
+
+    virtual std::size_t size() const {
+        return m_values.size();
+    }
+
+private:
+    std::vector<T> m_values;
+};
+
+template<typename T>
+class CompositeGenerator {
+public:
+    CompositeGenerator() : m_totalSize( 0 ) {}
+
+    // *** Move semantics, similar to auto_ptr ***
+    CompositeGenerator( CompositeGenerator& other )
+    :   m_fileInfo( other.m_fileInfo ),
+        m_totalSize( 0 )
+    {
+        move( other );
+    }
+
+    CompositeGenerator& setFileInfo( const char* fileInfo ) {
+        m_fileInfo = fileInfo;
+        return *this;
+    }
+
+    ~CompositeGenerator() {
+        deleteAll( m_composed );
+    }
+
+    operator T () const {
+        size_t overallIndex = getCurrentContext().getGeneratorIndex( m_fileInfo, m_totalSize );
+
+        typename std::vector<const IGenerator<T>*>::const_iterator it = m_composed.begin();
+        typename std::vector<const IGenerator<T>*>::const_iterator itEnd = m_composed.end();
+        for( size_t index = 0; it != itEnd; ++it )
+        {
+            const IGenerator<T>* generator = *it;
+            if( overallIndex >= index && overallIndex < index + generator->size() )
+            {
+                return generator->getValue( overallIndex-index );
+            }
+            index += generator->size();
+        }
+        CATCH_INTERNAL_ERROR( "Indexed past end of generated range" );
+        return T(); // Suppress spurious "not all control paths return a value" warning in Visual Studio - if you know how to fix this please do so
+    }
+
+    void add( const IGenerator<T>* generator ) {
+        m_totalSize += generator->size();
+        m_composed.push_back( generator );
+    }
+
+    CompositeGenerator& then( CompositeGenerator& other ) {
+        move( other );
+        return *this;
+    }
+
+    CompositeGenerator& then( T value ) {
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( value );
+        add( valuesGen );
+        return *this;
+    }
+
+private:
+
+    void move( CompositeGenerator& other ) {
+        std::copy( other.m_composed.begin(), other.m_composed.end(), std::back_inserter( m_composed ) );
+        m_totalSize += other.m_totalSize;
+        other.m_composed.clear();
+    }
+
+    std::vector<const IGenerator<T>*> m_composed;
+    std::string m_fileInfo;
+    size_t m_totalSize;
+};
+
+namespace Generators
+{
+    template<typename T>
+    CompositeGenerator<T> between( T from, T to ) {
+        CompositeGenerator<T> generators;
+        generators.add( new BetweenGenerator<T>( from, to ) );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3 ){
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+    template<typename T>
+    CompositeGenerator<T> values( T val1, T val2, T val3, T val4 ) {
+        CompositeGenerator<T> generators;
+        ValuesGenerator<T>* valuesGen = new ValuesGenerator<T>();
+        valuesGen->add( val1 );
+        valuesGen->add( val2 );
+        valuesGen->add( val3 );
+        valuesGen->add( val4 );
+        generators.add( valuesGen );
+        return generators;
+    }
+
+} // end namespace Generators
+
+using namespace Generators;
+
+} // end namespace Catch
+
+#define INTERNAL_CATCH_LINESTR2( line ) #line
+#define INTERNAL_CATCH_LINESTR( line ) INTERNAL_CATCH_LINESTR2( line )
+
+#define INTERNAL_CATCH_GENERATE( expr ) expr.setFileInfo( __FILE__ "(" INTERNAL_CATCH_LINESTR( __LINE__ ) ")" )
+
+// #included from: internal/catch_interfaces_exception.h
+#define TWOBLUECUBES_CATCH_INTERFACES_EXCEPTION_H_INCLUDED
+
+#include <string>
+// #included from: catch_interfaces_registry_hub.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REGISTRY_HUB_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    class TestCase;
+    struct ITestCaseRegistry;
+    struct IExceptionTranslatorRegistry;
+    struct IExceptionTranslator;
+    struct IReporterRegistry;
+    struct IReporterFactory;
+
+    struct IRegistryHub {
+        virtual ~IRegistryHub();
+
+        virtual IReporterRegistry const& getReporterRegistry() const = 0;
+        virtual ITestCaseRegistry const& getTestCaseRegistry() const = 0;
+        virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() = 0;
+    };
+
+    struct IMutableRegistryHub {
+        virtual ~IMutableRegistryHub();
+        virtual void registerReporter( std::string const& name, IReporterFactory* factory ) = 0;
+        virtual void registerTest( TestCase const& testInfo ) = 0;
+        virtual void registerTranslator( const IExceptionTranslator* translator ) = 0;
+    };
+
+    IRegistryHub& getRegistryHub();
+    IMutableRegistryHub& getMutableRegistryHub();
+    void cleanUp();
+    std::string translateActiveException();
+
+}
+
+
+namespace Catch {
+
+    typedef std::string(*exceptionTranslateFunction)();
+
+    struct IExceptionTranslator {
+        virtual ~IExceptionTranslator();
+        virtual std::string translate() const = 0;
+    };
+
+    struct IExceptionTranslatorRegistry {
+        virtual ~IExceptionTranslatorRegistry();
+
+        virtual std::string translateActiveException() const = 0;
+    };
+
+    class ExceptionTranslatorRegistrar {
+        template<typename T>
+        class ExceptionTranslator : public IExceptionTranslator {
+        public:
+
+            ExceptionTranslator( std::string(*translateFunction)( T& ) )
+            : m_translateFunction( translateFunction )
+            {}
+
+            virtual std::string translate() const {
+                try {
+                    throw;
+                }
+                catch( T& ex ) {
+                    return m_translateFunction( ex );
+                }
+            }
+
+        protected:
+            std::string(*m_translateFunction)( T& );
+        };
+
+    public:
+        template<typename T>
+        ExceptionTranslatorRegistrar( std::string(*translateFunction)( T& ) ) {
+            getMutableRegistryHub().registerTranslator
+                ( new ExceptionTranslator<T>( translateFunction ) );
+        }
+    };
+}
+
+///////////////////////////////////////////////////////////////////////////////
+#define INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature ) \
+    static std::string INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator )( signature ); \
+    namespace{ Catch::ExceptionTranslatorRegistrar INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionRegistrar )( &INTERNAL_CATCH_UNIQUE_NAME( catch_internal_ExceptionTranslator ) ); }\
+    static std::string INTERNAL_CATCH_UNIQUE_NAME(  catch_internal_ExceptionTranslator )( signature )
+
+// #included from: internal/catch_approx.hpp
+#define TWOBLUECUBES_CATCH_APPROX_HPP_INCLUDED
+
+#include <cmath>
+#include <limits>
+
+namespace Catch {
+namespace Detail {
+
+    class Approx {
+    public:
+        explicit Approx ( double value )
+        :   m_epsilon( std::numeric_limits<float>::epsilon()*100 ),
+            m_scale( 1.0 ),
+            m_value( value )
+        {}
+
+        Approx( Approx const& other )
+        :   m_epsilon( other.m_epsilon ),
+            m_scale( other.m_scale ),
+            m_value( other.m_value )
+        {}
+
+        static Approx custom() {
+            return Approx( 0 );
+        }
+
+        Approx operator()( double value ) {
+            Approx approx( value );
+            approx.epsilon( m_epsilon );
+            approx.scale( m_scale );
+            return approx;
+        }
+
+        friend bool operator == ( double lhs, Approx const& rhs ) {
+            // Thanks to Richard Harris for his help refining this formula
+            return fabs( lhs - rhs.m_value ) < rhs.m_epsilon * (rhs.m_scale + (std::max)( fabs(lhs), fabs(rhs.m_value) ) );
+        }
+
+        friend bool operator == ( Approx const& lhs, double rhs ) {
+            return operator==( rhs, lhs );
+        }
+
+        friend bool operator != ( double lhs, Approx const& rhs ) {
+            return !operator==( lhs, rhs );
+        }
+
+        friend bool operator != ( Approx const& lhs, double rhs ) {
+            return !operator==( rhs, lhs );
+        }
+
+        Approx& epsilon( double newEpsilon ) {
+            m_epsilon = newEpsilon;
+            return *this;
+        }
+
+        Approx& scale( double newScale ) {
+            m_scale = newScale;
+            return *this;
+        }
+
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << "Approx( " << Catch::toString( m_value ) << " )";
+            return oss.str();
+        }
+
+    private:
+        double m_epsilon;
+        double m_scale;
+        double m_value;
+    };
+}
+
+template<>
+inline std::string toString<Detail::Approx>( Detail::Approx const& value ) {
+    return value.toString();
+}
+
+} // end namespace Catch
+
+// #included from: internal/catch_matchers.hpp
+#define TWOBLUECUBES_CATCH_MATCHERS_HPP_INCLUDED
+
+namespace Catch {
+namespace Matchers {
+    namespace Impl {
+
+    template<typename ExpressionT>
+    struct Matcher : SharedImpl<IShared>
+    {
+        typedef ExpressionT ExpressionType;
+
+        virtual ~Matcher() {}
+        virtual Ptr<Matcher> clone() const = 0;
+        virtual bool match( ExpressionT const& expr ) const = 0;
+        virtual std::string toString() const = 0;
+    };
+
+    template<typename DerivedT, typename ExpressionT>
+    struct MatcherImpl : Matcher<ExpressionT> {
+
+        virtual Ptr<Matcher<ExpressionT> > clone() const {
+            return Ptr<Matcher<ExpressionT> >( new DerivedT( static_cast<DerivedT const&>( *this ) ) );
+        }
+    };
+
+    namespace Generic {
+
+        template<typename ExpressionT>
+        class AllOf : public MatcherImpl<AllOf<ExpressionT>, ExpressionT> {
+        public:
+
+            AllOf() {}
+            AllOf( AllOf const& other ) : m_matchers( other.m_matchers ) {}
+
+            AllOf& add( Matcher<ExpressionT> const& matcher ) {
+                m_matchers.push_back( matcher.clone() );
+                return *this;
+            }
+            virtual bool match( ExpressionT const& expr ) const
+            {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i )
+                    if( !m_matchers[i]->match( expr ) )
+                        return false;
+                return true;
+            }
+            virtual std::string toString() const {
+                std::ostringstream oss;
+                oss << "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        oss << " and ";
+                    oss << m_matchers[i]->toString();
+                }
+                oss << " )";
+                return oss.str();
+            }
+
+        private:
+            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
+        };
+
+        template<typename ExpressionT>
+        class AnyOf : public MatcherImpl<AnyOf<ExpressionT>, ExpressionT> {
+        public:
+
+            AnyOf() {}
+            AnyOf( AnyOf const& other ) : m_matchers( other.m_matchers ) {}
+
+            AnyOf& add( Matcher<ExpressionT> const& matcher ) {
+                m_matchers.push_back( matcher.clone() );
+                return *this;
+            }
+            virtual bool match( ExpressionT const& expr ) const
+            {
+                for( std::size_t i = 0; i < m_matchers.size(); ++i )
+                    if( m_matchers[i]->match( expr ) )
+                        return true;
+                return false;
+            }
+            virtual std::string toString() const {
+                std::ostringstream oss;
+                oss << "( ";
+                for( std::size_t i = 0; i < m_matchers.size(); ++i ) {
+                    if( i != 0 )
+                        oss << " or ";
+                    oss << m_matchers[i]->toString();
+                }
+                oss << " )";
+                return oss.str();
+            }
+
+        private:
+            std::vector<Ptr<Matcher<ExpressionT> > > m_matchers;
+        };
+
+    }
+
+    namespace StdString {
+
+        inline std::string makeString( std::string const& str ) { return str; }
+        inline std::string makeString( const char* str ) { return str ? std::string( str ) : std::string(); }
+
+        struct Equals : MatcherImpl<Equals, std::string> {
+            Equals( std::string const& str ) : m_str( str ){}
+            Equals( Equals const& other ) : m_str( other.m_str ){}
+
+            virtual ~Equals();
+
+            virtual bool match( std::string const& expr ) const {
+                return m_str == expr;
+            }
+            virtual std::string toString() const {
+                return "equals: \"" + m_str + "\"";
+            }
+
+            std::string m_str;
+        };
+
+        struct Contains : MatcherImpl<Contains, std::string> {
+            Contains( std::string const& substr ) : m_substr( substr ){}
+            Contains( Contains const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~Contains();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) != std::string::npos;
+            }
+            virtual std::string toString() const {
+                return "contains: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+
+        struct StartsWith : MatcherImpl<StartsWith, std::string> {
+            StartsWith( std::string const& substr ) : m_substr( substr ){}
+            StartsWith( StartsWith const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~StartsWith();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) == 0;
+            }
+            virtual std::string toString() const {
+                return "starts with: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+
+        struct EndsWith : MatcherImpl<EndsWith, std::string> {
+            EndsWith( std::string const& substr ) : m_substr( substr ){}
+            EndsWith( EndsWith const& other ) : m_substr( other.m_substr ){}
+
+            virtual ~EndsWith();
+
+            virtual bool match( std::string const& expr ) const {
+                return expr.find( m_substr ) == expr.size() - m_substr.size();
+            }
+            virtual std::string toString() const {
+                return "ends with: \"" + m_substr + "\"";
+            }
+
+            std::string m_substr;
+        };
+    } // namespace StdString
+    } // namespace Impl
+
+    // The following functions create the actual matcher objects.
+    // This allows the types to be inferred
+    template<typename ExpressionT>
+    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2 ) {
+        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AllOf<ExpressionT> AllOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2,
+                                                    Impl::Matcher<ExpressionT> const& m3 ) {
+        return Impl::Generic::AllOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2 ) {
+        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 );
+    }
+    template<typename ExpressionT>
+    inline Impl::Generic::AnyOf<ExpressionT> AnyOf( Impl::Matcher<ExpressionT> const& m1,
+                                                    Impl::Matcher<ExpressionT> const& m2,
+                                                    Impl::Matcher<ExpressionT> const& m3 ) {
+        return Impl::Generic::AnyOf<ExpressionT>().add( m1 ).add( m2 ).add( m3 );
+    }
+
+    inline Impl::StdString::Equals      Equals( std::string const& str ) {
+        return Impl::StdString::Equals( str );
+    }
+    inline Impl::StdString::Equals      Equals( const char* str ) {
+        return Impl::StdString::Equals( Impl::StdString::makeString( str ) );
+    }
+    inline Impl::StdString::Contains    Contains( std::string const& substr ) {
+        return Impl::StdString::Contains( substr );
+    }
+    inline Impl::StdString::Contains    Contains( const char* substr ) {
+        return Impl::StdString::Contains( Impl::StdString::makeString( substr ) );
+    }
+    inline Impl::StdString::StartsWith  StartsWith( std::string const& substr ) {
+        return Impl::StdString::StartsWith( substr );
+    }
+    inline Impl::StdString::StartsWith  StartsWith( const char* substr ) {
+        return Impl::StdString::StartsWith( Impl::StdString::makeString( substr ) );
+    }
+    inline Impl::StdString::EndsWith    EndsWith( std::string const& substr ) {
+        return Impl::StdString::EndsWith( substr );
+    }
+    inline Impl::StdString::EndsWith    EndsWith( const char* substr ) {
+        return Impl::StdString::EndsWith( Impl::StdString::makeString( substr ) );
+    }
+
+} // namespace Matchers
+
+using namespace Matchers;
+
+} // namespace Catch
+
+// #included from: internal/catch_interfaces_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_INTERFACES_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+// #included from: catch_tag_alias.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_H_INCLUDED
+
+#include <string>
+
+namespace Catch {
+
+    struct TagAlias {
+        TagAlias( std::string _tag, SourceLineInfo _lineInfo ) : tag( _tag ), lineInfo( _lineInfo ) {}
+
+        std::string tag;
+        SourceLineInfo lineInfo;
+    };
+
+    struct RegistrarForTagAliases {
+        RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+    };
+
+} // end namespace Catch
+
+#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); }
+// #included from: catch_option.hpp
+#define TWOBLUECUBES_CATCH_OPTION_HPP_INCLUDED
+
+namespace Catch {
+
+    // An optional type
+    template<typename T>
+    class Option {
+    public:
+        Option() : nullableValue( NULL ) {}
+        Option( T const& _value )
+        : nullableValue( new( storage ) T( _value ) )
+        {}
+        Option( Option const& _other )
+        : nullableValue( _other ? new( storage ) T( *_other ) : NULL )
+        {}
+
+        ~Option() {
+            reset();
+        }
+
+        Option& operator= ( Option const& _other ) {
+            if( &_other != this ) {
+                reset();
+                if( _other )
+                    nullableValue = new( storage ) T( *_other );
+            }
+            return *this;
+        }
+        Option& operator = ( T const& _value ) {
+            reset();
+            nullableValue = new( storage ) T( _value );
+            return *this;
+        }
+
+        void reset() {
+            if( nullableValue )
+                nullableValue->~T();
+            nullableValue = NULL;
+        }
+
+        T& operator*() { return *nullableValue; }
+        T const& operator*() const { return *nullableValue; }
+        T* operator->() { return nullableValue; }
+        const T* operator->() const { return nullableValue; }
+
+        T valueOr( T const& defaultValue ) const {
+            return nullableValue ? *nullableValue : defaultValue;
+        }
+
+        bool some() const { return nullableValue != NULL; }
+        bool none() const { return nullableValue == NULL; }
+
+        bool operator !() const { return nullableValue == NULL; }
+        operator SafeBool::type() const {
+            return SafeBool::makeSafe( some() );
+        }
+
+    private:
+        T* nullableValue;
+        char storage[sizeof(T)];
+    };
+
+} // end namespace Catch
+
+namespace Catch {
+
+    struct ITagAliasRegistry {
+        virtual ~ITagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const = 0;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const = 0;
+
+        static ITagAliasRegistry const& get();
+    };
+
+} // end namespace Catch
+
+// These files are included here so the single_include script doesn't put them
+// in the conditionally compiled sections
+// #included from: internal/catch_test_case_info.h
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_H_INCLUDED
+
+#include <string>
+#include <set>
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    struct ITestCase;
+
+    struct TestCaseInfo {
+        enum SpecialProperties{
+            None = 0,
+            IsHidden = 1 << 1,
+            ShouldFail = 1 << 2,
+            MayFail = 1 << 3,
+            Throws = 1 << 4
+        };
+
+        TestCaseInfo(   std::string const& _name,
+                        std::string const& _className,
+                        std::string const& _description,
+                        std::set<std::string> const& _tags,
+                        SourceLineInfo const& _lineInfo );
+
+        TestCaseInfo( TestCaseInfo const& other );
+
+        bool isHidden() const;
+        bool throws() const;
+        bool okToFail() const;
+        bool expectedToFail() const;
+
+        std::string name;
+        std::string className;
+        std::string description;
+        std::set<std::string> tags;
+        std::set<std::string> lcaseTags;
+        std::string tagsAsString;
+        SourceLineInfo lineInfo;
+        SpecialProperties properties;
+    };
+
+    class TestCase : public TestCaseInfo {
+    public:
+
+        TestCase( ITestCase* testCase, TestCaseInfo const& info );
+        TestCase( TestCase const& other );
+
+        TestCase withName( std::string const& _newName ) const;
+
+        void invoke() const;
+
+        TestCaseInfo const& getTestCaseInfo() const;
+
+        void swap( TestCase& other );
+        bool operator == ( TestCase const& other ) const;
+        bool operator < ( TestCase const& other ) const;
+        TestCase& operator = ( TestCase const& other );
+
+    private:
+        Ptr<ITestCase> test;
+    };
+
+    TestCase makeTestCase(  ITestCase* testCase,
+                            std::string const& className,
+                            std::string const& name,
+                            std::string const& description,
+                            SourceLineInfo const& lineInfo );
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+
+#ifdef __OBJC__
+// #included from: internal/catch_objc.hpp
+#define TWOBLUECUBES_CATCH_OBJC_HPP_INCLUDED
+
+#import <objc/runtime.h>
+
+#include <string>
+
+// NB. Any general catch headers included here must be included
+// in catch.hpp first to make sure they are included by the single
+// header for non obj-usage
+
+///////////////////////////////////////////////////////////////////////////////
+// This protocol is really only here for (self) documenting purposes, since
+// all its methods are optional.
+@protocol OcFixture
+
+@optional
+
+-(void) setUp;
+-(void) tearDown;
+
+@end
+
+namespace Catch {
+
+    class OcMethod : public SharedImpl<ITestCase> {
+
+    public:
+        OcMethod( Class cls, SEL sel ) : m_cls( cls ), m_sel( sel ) {}
+
+        virtual void invoke() const {
+            id obj = [[m_cls alloc] init];
+
+            performOptionalSelector( obj, @selector(setUp)  );
+            performOptionalSelector( obj, m_sel );
+            performOptionalSelector( obj, @selector(tearDown)  );
+
+            arcSafeRelease( obj );
+        }
+    private:
+        virtual ~OcMethod() {}
+
+        Class m_cls;
+        SEL m_sel;
+    };
+
+    namespace Detail{
+
+        inline std::string getAnnotation(   Class cls,
+                                            std::string const& annotationName,
+                                            std::string const& testCaseName ) {
+            NSString* selStr = [[NSString alloc] initWithFormat:@"Catch_%s_%s", annotationName.c_str(), testCaseName.c_str()];
+            SEL sel = NSSelectorFromString( selStr );
+            arcSafeRelease( selStr );
+            id value = performOptionalSelector( cls, sel );
+            if( value )
+                return [(NSString*)value UTF8String];
+            return "";
+        }
+    }
+
+    inline size_t registerTestMethods() {
+        size_t noTestMethods = 0;
+        int noClasses = objc_getClassList( NULL, 0 );
+
+        Class* classes = (CATCH_UNSAFE_UNRETAINED Class *)malloc( sizeof(Class) * noClasses);
+        objc_getClassList( classes, noClasses );
+
+        for( int c = 0; c < noClasses; c++ ) {
+            Class cls = classes[c];
+            {
+                u_int count;
+                Method* methods = class_copyMethodList( cls, &count );
+                for( u_int m = 0; m < count ; m++ ) {
+                    SEL selector = method_getName(methods[m]);
+                    std::string methodName = sel_getName(selector);
+                    if( startsWith( methodName, "Catch_TestCase_" ) ) {
+                        std::string testCaseName = methodName.substr( 15 );
+                        std::string name = Detail::getAnnotation( cls, "Name", testCaseName );
+                        std::string desc = Detail::getAnnotation( cls, "Description", testCaseName );
+                        const char* className = class_getName( cls );
+
+                        getMutableRegistryHub().registerTest( makeTestCase( new OcMethod( cls, selector ), className, name.c_str(), desc.c_str(), SourceLineInfo() ) );
+                        noTestMethods++;
+                    }
+                }
+                free(methods);
+            }
+        }
+        return noTestMethods;
+    }
+
+    namespace Matchers {
+        namespace Impl {
+        namespace NSStringMatchers {
+
+            template<typename MatcherT>
+            struct StringHolder : MatcherImpl<MatcherT, NSString*>{
+                StringHolder( NSString* substr ) : m_substr( [substr copy] ){}
+                StringHolder( StringHolder const& other ) : m_substr( [other.m_substr copy] ){}
+                StringHolder() {
+                    arcSafeRelease( m_substr );
+                }
+
+                NSString* m_substr;
+            };
+
+            struct Equals : StringHolder<Equals> {
+                Equals( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str isEqualToString:m_substr];
+                }
+
+                virtual std::string toString() const {
+                    return "equals string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct Contains : StringHolder<Contains> {
+                Contains( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location != NSNotFound;
+                }
+
+                virtual std::string toString() const {
+                    return "contains string: " + Catch::toString( m_substr );
+                }
+            };
+
+            struct StartsWith : StringHolder<StartsWith> {
+                StartsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == 0;
+                }
+
+                virtual std::string toString() const {
+                    return "starts with: " + Catch::toString( m_substr );
+                }
+            };
+            struct EndsWith : StringHolder<EndsWith> {
+                EndsWith( NSString* substr ) : StringHolder( substr ){}
+
+                virtual bool match( ExpressionType const& str ) const {
+                    return  (str != nil || m_substr == nil ) &&
+                            [str rangeOfString:m_substr].location == [str length] - [m_substr length];
+                }
+
+                virtual std::string toString() const {
+                    return "ends with: " + Catch::toString( m_substr );
+                }
+            };
+
+        } // namespace NSStringMatchers
+        } // namespace Impl
+
+        inline Impl::NSStringMatchers::Equals
+            Equals( NSString* substr ){ return Impl::NSStringMatchers::Equals( substr ); }
+
+        inline Impl::NSStringMatchers::Contains
+            Contains( NSString* substr ){ return Impl::NSStringMatchers::Contains( substr ); }
+
+        inline Impl::NSStringMatchers::StartsWith
+            StartsWith( NSString* substr ){ return Impl::NSStringMatchers::StartsWith( substr ); }
+
+        inline Impl::NSStringMatchers::EndsWith
+            EndsWith( NSString* substr ){ return Impl::NSStringMatchers::EndsWith( substr ); }
+
+    } // namespace Matchers
+
+    using namespace Matchers;
+
+} // namespace Catch
+
+///////////////////////////////////////////////////////////////////////////////
+#define OC_TEST_CASE( name, desc )\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Name_test ) \
+{\
+return @ name; \
+}\
++(NSString*) INTERNAL_CATCH_UNIQUE_NAME( Catch_Description_test ) \
+{ \
+return @ desc; \
+} \
+-(void) INTERNAL_CATCH_UNIQUE_NAME( Catch_TestCase_test )
+
+#endif
+
+#ifdef CATCH_CONFIG_RUNNER
+// #included from: internal/catch_impl.hpp
+#define TWOBLUECUBES_CATCH_IMPL_HPP_INCLUDED
+
+// Collect all the implementation files together here
+// These are the equivalent of what would usually be cpp files
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wweak-vtables"
+#endif
+
+// #included from: catch_runner.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_HPP_INCLUDED
+
+// #included from: internal/catch_commandline.hpp
+#define TWOBLUECUBES_CATCH_COMMANDLINE_HPP_INCLUDED
+
+// #included from: catch_config.hpp
+#define TWOBLUECUBES_CATCH_CONFIG_HPP_INCLUDED
+
+// #included from: catch_test_spec_parser.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_PARSER_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+// #included from: catch_test_spec.hpp
+#define TWOBLUECUBES_CATCH_TEST_SPEC_HPP_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class TestSpec {
+        struct Pattern : SharedImpl<> {
+            virtual ~Pattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const = 0;
+        };
+        class NamePattern : public Pattern {
+            enum WildcardPosition {
+                NoWildcard = 0,
+                WildcardAtStart = 1,
+                WildcardAtEnd = 2,
+                WildcardAtBothEnds = WildcardAtStart | WildcardAtEnd
+            };
+
+        public:
+            NamePattern( std::string const& name ) : m_name( toLower( name ) ), m_wildcard( NoWildcard ) {
+                if( startsWith( m_name, "*" ) ) {
+                    m_name = m_name.substr( 1 );
+                    m_wildcard = WildcardAtStart;
+                }
+                if( endsWith( m_name, "*" ) ) {
+                    m_name = m_name.substr( 0, m_name.size()-1 );
+                    m_wildcard = static_cast<WildcardPosition>( m_wildcard | WildcardAtEnd );
+                }
+            }
+            virtual ~NamePattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                switch( m_wildcard ) {
+                    case NoWildcard:
+                        return m_name == toLower( testCase.name );
+                    case WildcardAtStart:
+                        return endsWith( toLower( testCase.name ), m_name );
+                    case WildcardAtEnd:
+                        return startsWith( toLower( testCase.name ), m_name );
+                    case WildcardAtBothEnds:
+                        return contains( toLower( testCase.name ), m_name );
+                }
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunreachable-code"
+#endif
+                throw std::logic_error( "Unknown enum" );
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+            }
+        private:
+            std::string m_name;
+            WildcardPosition m_wildcard;
+        };
+        class TagPattern : public Pattern {
+        public:
+            TagPattern( std::string const& tag ) : m_tag( toLower( tag ) ) {}
+            virtual ~TagPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const {
+                return testCase.lcaseTags.find( m_tag ) != testCase.lcaseTags.end();
+            }
+        private:
+            std::string m_tag;
+        };
+        class ExcludedPattern : public Pattern {
+        public:
+            ExcludedPattern( Ptr<Pattern> const& underlyingPattern ) : m_underlyingPattern( underlyingPattern ) {}
+            virtual ~ExcludedPattern();
+            virtual bool matches( TestCaseInfo const& testCase ) const { return !m_underlyingPattern->matches( testCase ); }
+        private:
+            Ptr<Pattern> m_underlyingPattern;
+        };
+
+        struct Filter {
+            std::vector<Ptr<Pattern> > m_patterns;
+
+            bool matches( TestCaseInfo const& testCase ) const {
+                // All patterns in a filter must match for the filter to be a match
+                for( std::vector<Ptr<Pattern> >::const_iterator it = m_patterns.begin(), itEnd = m_patterns.end(); it != itEnd; ++it )
+                    if( !(*it)->matches( testCase ) )
+                        return false;
+                    return true;
+            }
+        };
+
+    public:
+        bool hasFilters() const {
+            return !m_filters.empty();
+        }
+        bool matches( TestCaseInfo const& testCase ) const {
+            // A TestSpec matches if any filter matches
+            for( std::vector<Filter>::const_iterator it = m_filters.begin(), itEnd = m_filters.end(); it != itEnd; ++it )
+                if( it->matches( testCase ) )
+                    return true;
+            return false;
+        }
+
+    private:
+        std::vector<Filter> m_filters;
+
+        friend class TestSpecParser;
+    };
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+namespace Catch {
+
+    class TestSpecParser {
+        enum Mode{ None, Name, QuotedName, Tag };
+        Mode m_mode;
+        bool m_exclusion;
+        std::size_t m_start, m_pos;
+        std::string m_arg;
+        TestSpec::Filter m_currentFilter;
+        TestSpec m_testSpec;
+        ITagAliasRegistry const* m_tagAliases;
+
+    public:
+        TestSpecParser( ITagAliasRegistry const& tagAliases ) : m_tagAliases( &tagAliases ) {}
+
+        TestSpecParser& parse( std::string const& arg ) {
+            m_mode = None;
+            m_exclusion = false;
+            m_start = std::string::npos;
+            m_arg = m_tagAliases->expandAliases( arg );
+            for( m_pos = 0; m_pos < m_arg.size(); ++m_pos )
+                visitChar( m_arg[m_pos] );
+            if( m_mode == Name )
+                addPattern<TestSpec::NamePattern>();
+            return *this;
+        }
+        TestSpec testSpec() {
+            addFilter();
+            return m_testSpec;
+        }
+    private:
+        void visitChar( char c ) {
+            if( m_mode == None ) {
+                switch( c ) {
+                case ' ': return;
+                case '~': m_exclusion = true; return;
+                case '[': return startNewMode( Tag, ++m_pos );
+                case '"': return startNewMode( QuotedName, ++m_pos );
+                default: startNewMode( Name, m_pos ); break;
+                }
+            }
+            if( m_mode == Name ) {
+                if( c == ',' ) {
+                    addPattern<TestSpec::NamePattern>();
+                    addFilter();
+                }
+                else if( c == '[' ) {
+                    if( subString() == "exclude:" )
+                        m_exclusion = true;
+                    else
+                        addPattern<TestSpec::NamePattern>();
+                    startNewMode( Tag, ++m_pos );
+                }
+            }
+            else if( m_mode == QuotedName && c == '"' )
+                addPattern<TestSpec::NamePattern>();
+            else if( m_mode == Tag && c == ']' )
+                addPattern<TestSpec::TagPattern>();
+        }
+        void startNewMode( Mode mode, std::size_t start ) {
+            m_mode = mode;
+            m_start = start;
+        }
+        std::string subString() const { return m_arg.substr( m_start, m_pos - m_start ); }
+        template<typename T>
+        void addPattern() {
+            std::string token = subString();
+            if( startsWith( token, "exclude:" ) ) {
+                m_exclusion = true;
+                token = token.substr( 8 );
+            }
+            if( !token.empty() ) {
+                Ptr<TestSpec::Pattern> pattern = new T( token );
+                if( m_exclusion )
+                    pattern = new TestSpec::ExcludedPattern( pattern );
+                m_currentFilter.m_patterns.push_back( pattern );
+            }
+            m_exclusion = false;
+            m_mode = None;
+        }
+        void addFilter() {
+            if( !m_currentFilter.m_patterns.empty() ) {
+                m_testSpec.m_filters.push_back( m_currentFilter );
+                m_currentFilter = TestSpec::Filter();
+            }
+        }
+    };
+    inline TestSpec parseTestSpec( std::string const& arg ) {
+        return TestSpecParser( ITagAliasRegistry::get() ).parse( arg ).testSpec();
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+// #included from: catch_interfaces_config.h
+#define TWOBLUECUBES_CATCH_INTERFACES_CONFIG_H_INCLUDED
+
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    struct Verbosity { enum Level {
+        NoOutput = 0,
+        Quiet,
+        Normal
+    }; };
+
+    struct WarnAbout { enum What {
+        Nothing = 0x00,
+        NoAssertions = 0x01
+    }; };
+
+    struct ShowDurations { enum OrNot {
+        DefaultForReporter,
+        Always,
+        Never
+    }; };
+
+    class TestSpec;
+
+    struct IConfig : IShared {
+
+        virtual ~IConfig();
+
+        virtual bool allowThrows() const = 0;
+        virtual std::ostream& stream() const = 0;
+        virtual std::string name() const = 0;
+        virtual bool includeSuccessfulResults() const = 0;
+        virtual bool shouldDebugBreak() const = 0;
+        virtual bool warnAboutMissingAssertions() const = 0;
+        virtual int abortAfter() const = 0;
+        virtual bool showInvisibles() const = 0;
+        virtual ShowDurations::OrNot showDurations() const = 0;
+        virtual TestSpec const& testSpec() const = 0;
+    };
+}
+
+// #included from: catch_stream.h
+#define TWOBLUECUBES_CATCH_STREAM_H_INCLUDED
+
+#include <streambuf>
+
+#ifdef __clang__
+#pragma clang diagnostic ignored "-Wpadded"
+#endif
+
+namespace Catch {
+
+    class Stream {
+    public:
+        Stream();
+        Stream( std::streambuf* _streamBuf, bool _isOwned );
+        void release();
+
+        std::streambuf* streamBuf;
+
+    private:
+        bool isOwned;
+    };
+}
+
+#include <memory>
+#include <vector>
+#include <string>
+#include <iostream>
+
+#ifndef CATCH_CONFIG_CONSOLE_WIDTH
+#define CATCH_CONFIG_CONSOLE_WIDTH 80
+#endif
+
+namespace Catch {
+
+    struct ConfigData {
+
+        ConfigData()
+        :   listTests( false ),
+            listTags( false ),
+            listReporters( false ),
+            listTestNamesOnly( false ),
+            showSuccessfulTests( false ),
+            shouldDebugBreak( false ),
+            noThrow( false ),
+            showHelp( false ),
+            showInvisibles( false ),
+            abortAfter( -1 ),
+            verbosity( Verbosity::Normal ),
+            warnings( WarnAbout::Nothing ),
+            showDurations( ShowDurations::DefaultForReporter )
+        {}
+
+        bool listTests;
+        bool listTags;
+        bool listReporters;
+        bool listTestNamesOnly;
+
+        bool showSuccessfulTests;
+        bool shouldDebugBreak;
+        bool noThrow;
+        bool showHelp;
+        bool showInvisibles;
+
+        int abortAfter;
+
+        Verbosity::Level verbosity;
+        WarnAbout::What warnings;
+        ShowDurations::OrNot showDurations;
+
+        std::string reporterName;
+        std::string outputFilename;
+        std::string name;
+        std::string processName;
+
+        std::vector<std::string> testsOrTags;
+    };
+
+    class Config : public SharedImpl<IConfig> {
+    private:
+        Config( Config const& other );
+        Config& operator = ( Config const& other );
+        virtual void dummy();
+    public:
+
+        Config()
+        :   m_os( std::cout.rdbuf() )
+        {}
+
+        Config( ConfigData const& data )
+        :   m_data( data ),
+            m_os( std::cout.rdbuf() )
+        {
+            if( !data.testsOrTags.empty() ) {
+                TestSpecParser parser( ITagAliasRegistry::get() );
+                for( std::size_t i = 0; i < data.testsOrTags.size(); ++i )
+                    parser.parse( data.testsOrTags[i] );
+                m_testSpec = parser.testSpec();
+            }
+        }
+
+        virtual ~Config() {
+            m_os.rdbuf( std::cout.rdbuf() );
+            m_stream.release();
+        }
+
+        void setFilename( std::string const& filename ) {
+            m_data.outputFilename = filename;
+        }
+
+        std::string const& getFilename() const {
+            return m_data.outputFilename ;
+        }
+
+        bool listTests() const { return m_data.listTests; }
+        bool listTestNamesOnly() const { return m_data.listTestNamesOnly; }
+        bool listTags() const { return m_data.listTags; }
+        bool listReporters() const { return m_data.listReporters; }
+
+        std::string getProcessName() const { return m_data.processName; }
+
+        bool shouldDebugBreak() const { return m_data.shouldDebugBreak; }
+
+        void setStreamBuf( std::streambuf* buf ) {
+            m_os.rdbuf( buf ? buf : std::cout.rdbuf() );
+        }
+
+        void useStream( std::string const& streamName ) {
+            Stream stream = createStream( streamName );
+            setStreamBuf( stream.streamBuf );
+            m_stream.release();
+            m_stream = stream;
+        }
+
+        std::string getReporterName() const { return m_data.reporterName; }
+
+        int abortAfter() const { return m_data.abortAfter; }
+
+        TestSpec const& testSpec() const { return m_testSpec; }
+
+        bool showHelp() const { return m_data.showHelp; }
+        bool showInvisibles() const { return m_data.showInvisibles; }
+
+        // IConfig interface
+        virtual bool allowThrows() const        { return !m_data.noThrow; }
+        virtual std::ostream& stream() const    { return m_os; }
+        virtual std::string name() const        { return m_data.name.empty() ? m_data.processName : m_data.name; }
+        virtual bool includeSuccessfulResults() const   { return m_data.showSuccessfulTests; }
+        virtual bool warnAboutMissingAssertions() const { return m_data.warnings & WarnAbout::NoAssertions; }
+        virtual ShowDurations::OrNot showDurations() const { return m_data.showDurations; }
+
+    private:
+        ConfigData m_data;
+
+        Stream m_stream;
+        mutable std::ostream m_os;
+        TestSpec m_testSpec;
+    };
+
+} // end namespace Catch
+
+// #included from: catch_clara.h
+#define TWOBLUECUBES_CATCH_CLARA_H_INCLUDED
+
+// Use Catch's value for console width (store Clara's off to the side, if present)
+#ifdef CLARA_CONFIG_CONSOLE_WIDTH
+#define CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH CLARA_CONFIG_CONSOLE_WIDTH
+#undef CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+// Declare Clara inside the Catch namespace
+#define STITCH_CLARA_OPEN_NAMESPACE namespace Catch {
+// #included from: ../external/clara.h
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TWOBLUECUBES_CLARA_H_INCLUDED) || defined(STITCH_CLARA_OPEN_NAMESPACE)
+
+#ifndef STITCH_CLARA_OPEN_NAMESPACE
+#define TWOBLUECUBES_CLARA_H_INCLUDED
+#define STITCH_CLARA_OPEN_NAMESPACE
+#define STITCH_CLARA_CLOSE_NAMESPACE
+#else
+#define STITCH_CLARA_CLOSE_NAMESPACE }
+#endif
+
+#define STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE STITCH_CLARA_OPEN_NAMESPACE
+
+// ----------- #included from tbc_text_format.h -----------
+
+// Only use header guard if we are not using an outer namespace
+#if !defined(TBC_TEXT_FORMAT_H_INCLUDED) || defined(STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE)
+#ifndef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+#define TBC_TEXT_FORMAT_H_INCLUDED
+#endif
+
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef STITCH_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TBC_TEXT_FORMAT_H_INCLUDED
+
+// ----------- end of #include from tbc_text_format.h -----------
+// ........... back in /Users/philnash/Dev/OSS/Clara/srcs/clara.h
+
+#undef STITCH_TBC_TEXT_FORMAT_OPEN_NAMESPACE
+
+#include <map>
+#include <algorithm>
+#include <stdexcept>
+#include <memory>
+
+// Use optional outer namespace
+#ifdef STITCH_CLARA_OPEN_NAMESPACE
+STITCH_CLARA_OPEN_NAMESPACE
+#endif
+
+namespace Clara {
+
+    struct UnpositionalTag {};
+
+    extern UnpositionalTag _;
+
+#ifdef CLARA_CONFIG_MAIN
+    UnpositionalTag _;
+#endif
+
+    namespace Detail {
+
+#ifdef CLARA_CONSOLE_WIDTH
+    const unsigned int consoleWidth = CLARA_CONFIG_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+        using namespace Tbc;
+
+        inline bool startsWith( std::string const& str, std::string const& prefix ) {
+            return str.size() >= prefix.size() && str.substr( 0, prefix.size() ) == prefix;
+        }
+
+        template<typename T> struct RemoveConstRef{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const&>{ typedef T type; };
+        template<typename T> struct RemoveConstRef<T const>{ typedef T type; };
+
+        template<typename T>    struct IsBool       { static const bool value = false; };
+        template<>              struct IsBool<bool> { static const bool value = true; };
+
+        template<typename T>
+        void convertInto( std::string const& _source, T& _dest ) {
+            std::stringstream ss;
+            ss << _source;
+            ss >> _dest;
+            if( ss.fail() )
+                throw std::runtime_error( "Unable to convert " + _source + " to destination type" );
+        }
+        inline void convertInto( std::string const& _source, std::string& _dest ) {
+            _dest = _source;
+        }
+        inline void convertInto( std::string const& _source, bool& _dest ) {
+            std::string sourceLC = _source;
+            std::transform( sourceLC.begin(), sourceLC.end(), sourceLC.begin(), ::tolower );
+            if( sourceLC == "y" || sourceLC == "1" || sourceLC == "true" || sourceLC == "yes" || sourceLC == "on" )
+                _dest = true;
+            else if( sourceLC == "n" || sourceLC == "0" || sourceLC == "false" || sourceLC == "no" || sourceLC == "off" )
+                _dest = false;
+            else
+                throw std::runtime_error( "Expected a boolean value but did not recognise:\n  '" + _source + "'" );
+        }
+        inline void convertInto( bool _source, bool& _dest ) {
+            _dest = _source;
+        }
+        template<typename T>
+        inline void convertInto( bool, T& ) {
+            throw std::runtime_error( "Invalid conversion" );
+        }
+
+        template<typename ConfigT>
+        struct IArgFunction {
+            virtual ~IArgFunction() {}
+#  ifdef CATCH_CPP11_OR_GREATER
+            IArgFunction()                      = default;
+            IArgFunction( IArgFunction const& ) = default;
+#  endif
+            virtual void set( ConfigT& config, std::string const& value ) const = 0;
+            virtual void setFlag( ConfigT& config ) const = 0;
+            virtual bool takesArg() const = 0;
+            virtual IArgFunction* clone() const = 0;
+        };
+
+        template<typename ConfigT>
+        class BoundArgFunction {
+        public:
+            BoundArgFunction() : functionObj( NULL ) {}
+            BoundArgFunction( IArgFunction<ConfigT>* _functionObj ) : functionObj( _functionObj ) {}
+            BoundArgFunction( BoundArgFunction const& other ) : functionObj( other.functionObj ? other.functionObj->clone() : NULL ) {}
+            BoundArgFunction& operator = ( BoundArgFunction const& other ) {
+                IArgFunction<ConfigT>* newFunctionObj = other.functionObj ? other.functionObj->clone() : NULL;
+                delete functionObj;
+                functionObj = newFunctionObj;
+                return *this;
+            }
+            ~BoundArgFunction() { delete functionObj; }
+
+            void set( ConfigT& config, std::string const& value ) const {
+                functionObj->set( config, value );
+            }
+            void setFlag( ConfigT& config ) const {
+                functionObj->setFlag( config );
+            }
+            bool takesArg() const { return functionObj->takesArg(); }
+
+            bool isSet() const {
+                return functionObj != NULL;
+            }
+        private:
+            IArgFunction<ConfigT>* functionObj;
+        };
+
+        template<typename C>
+        struct NullBinder : IArgFunction<C>{
+            virtual void set( C&, std::string const& ) const {}
+            virtual void setFlag( C& ) const {}
+            virtual bool takesArg() const { return true; }
+            virtual IArgFunction<C>* clone() const { return new NullBinder( *this ); }
+        };
+
+        template<typename C, typename M>
+        struct BoundDataMember : IArgFunction<C>{
+            BoundDataMember( M C::* _member ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                convertInto( stringValue, p.*member );
+            }
+            virtual void setFlag( C& p ) const {
+                convertInto( true, p.*member );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundDataMember( *this ); }
+            M C::* member;
+        };
+        template<typename C, typename M>
+        struct BoundUnaryMethod : IArgFunction<C>{
+            BoundUnaryMethod( void (C::*_member)( M ) ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( stringValue, value );
+                (p.*member)( value );
+            }
+            virtual void setFlag( C& p ) const {
+                typename RemoveConstRef<M>::type value;
+                convertInto( true, value );
+                (p.*member)( value );
+            }
+            virtual bool takesArg() const { return !IsBool<M>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryMethod( *this ); }
+            void (C::*member)( M );
+        };
+        template<typename C>
+        struct BoundNullaryMethod : IArgFunction<C>{
+            BoundNullaryMethod( void (C::*_member)() ) : member( _member ) {}
+            virtual void set( C& p, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    (p.*member)();
+            }
+            virtual void setFlag( C& p ) const {
+                (p.*member)();
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundNullaryMethod( *this ); }
+            void (C::*member)();
+        };
+
+        template<typename C>
+        struct BoundUnaryFunction : IArgFunction<C>{
+            BoundUnaryFunction( void (*_function)( C& ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                bool value;
+                convertInto( stringValue, value );
+                if( value )
+                    function( obj );
+            }
+            virtual void setFlag( C& p ) const {
+                function( p );
+            }
+            virtual bool takesArg() const { return false; }
+            virtual IArgFunction<C>* clone() const { return new BoundUnaryFunction( *this ); }
+            void (*function)( C& );
+        };
+
+        template<typename C, typename T>
+        struct BoundBinaryFunction : IArgFunction<C>{
+            BoundBinaryFunction( void (*_function)( C&, T ) ) : function( _function ) {}
+            virtual void set( C& obj, std::string const& stringValue ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( stringValue, value );
+                function( obj, value );
+            }
+            virtual void setFlag( C& obj ) const {
+                typename RemoveConstRef<T>::type value;
+                convertInto( true, value );
+                function( obj, value );
+            }
+            virtual bool takesArg() const { return !IsBool<T>::value; }
+            virtual IArgFunction<C>* clone() const { return new BoundBinaryFunction( *this ); }
+            void (*function)( C&, T );
+        };
+
+    } // namespace Detail
+
+    struct Parser {
+        Parser() : separators( " \t=:" ) {}
+
+        struct Token {
+            enum Type { Positional, ShortOpt, LongOpt };
+            Token( Type _type, std::string const& _data ) : type( _type ), data( _data ) {}
+            Type type;
+            std::string data;
+        };
+
+        void parseIntoTokens( int argc, char const * const * argv, std::vector<Parser::Token>& tokens ) const {
+            const std::string doubleDash = "--";
+            for( int i = 1; i < argc && argv[i] != doubleDash; ++i )
+                parseIntoTokens( argv[i] , tokens);
+        }
+        void parseIntoTokens( std::string arg, std::vector<Parser::Token>& tokens ) const {
+            while( !arg.empty() ) {
+                Parser::Token token( Parser::Token::Positional, arg );
+                arg = "";
+                if( token.data[0] == '-' ) {
+                    if( token.data.size() > 1 && token.data[1] == '-' ) {
+                        token = Parser::Token( Parser::Token::LongOpt, token.data.substr( 2 ) );
+                    }
+                    else {
+                        token = Parser::Token( Parser::Token::ShortOpt, token.data.substr( 1 ) );
+                        if( token.data.size() > 1 && separators.find( token.data[1] ) == std::string::npos ) {
+                            arg = "-" + token.data.substr( 1 );
+                            token.data = token.data.substr( 0, 1 );
+                        }
+                    }
+                }
+                if( token.type != Parser::Token::Positional ) {
+                    std::size_t pos = token.data.find_first_of( separators );
+                    if( pos != std::string::npos ) {
+                        arg = token.data.substr( pos+1 );
+                        token.data = token.data.substr( 0, pos );
+                    }
+                }
+                tokens.push_back( token );
+            }
+        }
+        std::string separators;
+    };
+
+    template<typename ConfigT>
+    struct CommonArgProperties {
+        CommonArgProperties() {}
+        CommonArgProperties( Detail::BoundArgFunction<ConfigT> const& _boundField ) : boundField( _boundField ) {}
+
+        Detail::BoundArgFunction<ConfigT> boundField;
+        std::string description;
+        std::string detail;
+        std::string placeholder; // Only value if boundField takes an arg
+
+        bool takesArg() const {
+            return !placeholder.empty();
+        }
+        void validate() const {
+            if( !boundField.isSet() )
+                throw std::logic_error( "option not bound" );
+        }
+    };
+    struct OptionArgProperties {
+        std::vector<std::string> shortNames;
+        std::string longName;
+
+        bool hasShortName( std::string const& shortName ) const {
+            return std::find( shortNames.begin(), shortNames.end(), shortName ) != shortNames.end();
+        }
+        bool hasLongName( std::string const& _longName ) const {
+            return _longName == longName;
+        }
+    };
+    struct PositionalArgProperties {
+        PositionalArgProperties() : position( -1 ) {}
+        int position; // -1 means non-positional (floating)
+
+        bool isFixedPositional() const {
+            return position != -1;
+        }
+    };
+
+    template<typename ConfigT>
+    class CommandLine {
+
+        struct Arg : CommonArgProperties<ConfigT>, OptionArgProperties, PositionalArgProperties {
+            Arg() {}
+            Arg( Detail::BoundArgFunction<ConfigT> const& _boundField ) : CommonArgProperties<ConfigT>( _boundField ) {}
+
+            using CommonArgProperties<ConfigT>::placeholder; // !TBD
+
+            std::string dbgName() const {
+                if( !longName.empty() )
+                    return "--" + longName;
+                if( !shortNames.empty() )
+                    return "-" + shortNames[0];
+                return "positional args";
+            }
+            std::string commands() const {
+                std::ostringstream oss;
+                bool first = true;
+                std::vector<std::string>::const_iterator it = shortNames.begin(), itEnd = shortNames.end();
+                for(; it != itEnd; ++it ) {
+                    if( first )
+                        first = false;
+                    else
+                        oss << ", ";
+                    oss << "-" << *it;
+                }
+                if( !longName.empty() ) {
+                    if( !first )
+                        oss << ", ";
+                    oss << "--" << longName;
+                }
+                if( !placeholder.empty() )
+                    oss << " <" << placeholder << ">";
+                return oss.str();
+            }
+        };
+
+        // NOTE: std::auto_ptr is deprecated in c++11/c++0x
+#if defined(__cplusplus) && __cplusplus > 199711L
+        typedef std::unique_ptr<Arg> ArgAutoPtr;
+#else
+        typedef std::auto_ptr<Arg> ArgAutoPtr;
+#endif
+
+        friend void addOptName( Arg& arg, std::string const& optName )
+        {
+            if( optName.empty() )
+                return;
+            if( Detail::startsWith( optName, "--" ) ) {
+                if( !arg.longName.empty() )
+                    throw std::logic_error( "Only one long opt may be specified. '"
+                        + arg.longName
+                        + "' already specified, now attempting to add '"
+                        + optName + "'" );
+                arg.longName = optName.substr( 2 );
+            }
+            else if( Detail::startsWith( optName, "-" ) )
+                arg.shortNames.push_back( optName.substr( 1 ) );
+            else
+                throw std::logic_error( "option must begin with - or --. Option was: '" + optName + "'" );
+        }
+        friend void setPositionalArg( Arg& arg, int position )
+        {
+            arg.position = position;
+        }
+
+        class ArgBuilder {
+        public:
+            ArgBuilder( Arg* arg ) : m_arg( arg ) {}
+
+            // Bind a non-boolean data member (requires placeholder string)
+            template<typename C, typename M>
+            void bind( M C::* field, std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,M>( field );
+                m_arg->placeholder = placeholder;
+            }
+            // Bind a boolean data member (no placeholder required)
+            template<typename C>
+            void bind( bool C::* field ) {
+                m_arg->boundField = new Detail::BoundDataMember<C,bool>( field );
+            }
+
+            // Bind a method taking a single, non-boolean argument (requires a placeholder string)
+            template<typename C, typename M>
+            void bind( void (C::* unaryMethod)( M ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,M>( unaryMethod );
+                m_arg->placeholder = placeholder;
+            }
+
+            // Bind a method taking a single, boolean argument (no placeholder string required)
+            template<typename C>
+            void bind( void (C::* unaryMethod)( bool ) ) {
+                m_arg->boundField = new Detail::BoundUnaryMethod<C,bool>( unaryMethod );
+            }
+
+            // Bind a method that takes no arguments (will be called if opt is present)
+            template<typename C>
+            void bind( void (C::* nullaryMethod)() ) {
+                m_arg->boundField = new Detail::BoundNullaryMethod<C>( nullaryMethod );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (no placeholder string required)
+            template<typename C>
+            void bind( void (* unaryFunction)( C& ) ) {
+                m_arg->boundField = new Detail::BoundUnaryFunction<C>( unaryFunction );
+            }
+
+            // Bind a free function taking a single argument - the object to operate on (requires a placeholder string)
+            template<typename C, typename T>
+            void bind( void (* binaryFunction)( C&, T ), std::string const& placeholder ) {
+                m_arg->boundField = new Detail::BoundBinaryFunction<C, T>( binaryFunction );
+                m_arg->placeholder = placeholder;
+            }
+
+            ArgBuilder& describe( std::string const& description ) {
+                m_arg->description = description;
+                return *this;
+            }
+            ArgBuilder& detail( std::string const& detail ) {
+                m_arg->detail = detail;
+                return *this;
+            }
+
+        protected:
+            Arg* m_arg;
+        };
+
+        class OptBuilder : public ArgBuilder {
+        public:
+            OptBuilder( Arg* arg ) : ArgBuilder( arg ) {}
+            OptBuilder( OptBuilder& other ) : ArgBuilder( other ) {}
+
+            OptBuilder& operator[]( std::string const& optName ) {
+                addOptName( *ArgBuilder::m_arg, optName );
+                return *this;
+            }
+        };
+
+    public:
+
+        CommandLine()
+        :   m_boundProcessName( new Detail::NullBinder<ConfigT>() ),
+            m_highestSpecifiedArgPosition( 0 ),
+            m_throwOnUnrecognisedTokens( false )
+        {}
+        CommandLine( CommandLine const& other )
+        :   m_boundProcessName( other.m_boundProcessName ),
+            m_options ( other.m_options ),
+            m_positionalArgs( other.m_positionalArgs ),
+            m_highestSpecifiedArgPosition( other.m_highestSpecifiedArgPosition ),
+            m_throwOnUnrecognisedTokens( other.m_throwOnUnrecognisedTokens )
+        {
+            if( other.m_floatingArg.get() )
+                m_floatingArg = ArgAutoPtr( new Arg( *other.m_floatingArg ) );
+        }
+
+        CommandLine& setThrowOnUnrecognisedTokens( bool shouldThrow = true ) {
+            m_throwOnUnrecognisedTokens = shouldThrow;
+            return *this;
+        }
+
+        OptBuilder operator[]( std::string const& optName ) {
+            m_options.push_back( Arg() );
+            addOptName( m_options.back(), optName );
+            OptBuilder builder( &m_options.back() );
+            return builder;
+        }
+
+        ArgBuilder operator[]( int position ) {
+            m_positionalArgs.insert( std::make_pair( position, Arg() ) );
+            if( position > m_highestSpecifiedArgPosition )
+                m_highestSpecifiedArgPosition = position;
+            setPositionalArg( m_positionalArgs[position], position );
+            ArgBuilder builder( &m_positionalArgs[position] );
+            return builder;
+        }
+
+        // Invoke this with the _ instance
+        ArgBuilder operator[]( UnpositionalTag ) {
+            if( m_floatingArg.get() )
+                throw std::logic_error( "Only one unpositional argument can be added" );
+            m_floatingArg = ArgAutoPtr( new Arg() );
+            ArgBuilder builder( m_floatingArg.get() );
+            return builder;
+        }
+
+        template<typename C, typename M>
+        void bindProcessName( M C::* field ) {
+            m_boundProcessName = new Detail::BoundDataMember<C,M>( field );
+        }
+        template<typename C, typename M>
+        void bindProcessName( void (C::*_unaryMethod)( M ) ) {
+            m_boundProcessName = new Detail::BoundUnaryMethod<C,M>( _unaryMethod );
+        }
+
+        void optUsage( std::ostream& os, std::size_t indent = 0, std::size_t width = Detail::consoleWidth ) const {
+            typename std::vector<Arg>::const_iterator itBegin = m_options.begin(), itEnd = m_options.end(), it;
+            std::size_t maxWidth = 0;
+            for( it = itBegin; it != itEnd; ++it )
+                maxWidth = (std::max)( maxWidth, it->commands().size() );
+
+            for( it = itBegin; it != itEnd; ++it ) {
+                Detail::Text usage( it->commands(), Detail::TextAttributes()
+                                                        .setWidth( maxWidth+indent )
+                                                        .setIndent( indent ) );
+                Detail::Text desc( it->description, Detail::TextAttributes()
+                                                        .setWidth( width - maxWidth - 3 ) );
+
+                for( std::size_t i = 0; i < (std::max)( usage.size(), desc.size() ); ++i ) {
+                    std::string usageCol = i < usage.size() ? usage[i] : "";
+                    os << usageCol;
+
+                    if( i < desc.size() && !desc[i].empty() )
+                        os  << std::string( indent + 2 + maxWidth - usageCol.size(), ' ' )
+                            << desc[i];
+                    os << "\n";
+                }
+            }
+        }
+        std::string optUsage() const {
+            std::ostringstream oss;
+            optUsage( oss );
+            return oss.str();
+        }
+
+        void argSynopsis( std::ostream& os ) const {
+            for( int i = 1; i <= m_highestSpecifiedArgPosition; ++i ) {
+                if( i > 1 )
+                    os << " ";
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( i );
+                if( it != m_positionalArgs.end() )
+                    os << "<" << it->second.placeholder << ">";
+                else if( m_floatingArg.get() )
+                    os << "<" << m_floatingArg->placeholder << ">";
+                else
+                    throw std::logic_error( "non consecutive positional arguments with no floating args" );
+            }
+            // !TBD No indication of mandatory args
+            if( m_floatingArg.get() ) {
+                if( m_highestSpecifiedArgPosition > 1 )
+                    os << " ";
+                os << "[<" << m_floatingArg->placeholder << "> ...]";
+            }
+        }
+        std::string argSynopsis() const {
+            std::ostringstream oss;
+            argSynopsis( oss );
+            return oss.str();
+        }
+
+        void usage( std::ostream& os, std::string const& procName ) const {
+            validate();
+            os << "usage:\n  " << procName << " ";
+            argSynopsis( os );
+            if( !m_options.empty() ) {
+                os << " [options]\n\nwhere options are: \n";
+                optUsage( os, 2 );
+            }
+            os << "\n";
+        }
+        std::string usage( std::string const& procName ) const {
+            std::ostringstream oss;
+            usage( oss, procName );
+            return oss.str();
+        }
+
+        ConfigT parse( int argc, char const * const * argv ) const {
+            ConfigT config;
+            parseInto( argc, argv, config );
+            return config;
+        }
+
+        std::vector<Parser::Token> parseInto( int argc, char const * const * argv, ConfigT& config ) const {
+            std::string processName = argv[0];
+            std::size_t lastSlash = processName.find_last_of( "/\\" );
+            if( lastSlash != std::string::npos )
+                processName = processName.substr( lastSlash+1 );
+            m_boundProcessName.set( config, processName );
+            std::vector<Parser::Token> tokens;
+            Parser parser;
+            parser.parseIntoTokens( argc, argv, tokens );
+            return populate( tokens, config );
+        }
+
+        std::vector<Parser::Token> populate( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            validate();
+            std::vector<Parser::Token> unusedTokens = populateOptions( tokens, config );
+            unusedTokens = populateFixedArgs( unusedTokens, config );
+            unusedTokens = populateFloatingArgs( unusedTokens, config );
+            return unusedTokens;
+        }
+
+        std::vector<Parser::Token> populateOptions( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            std::vector<std::string> errors;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::vector<Arg>::const_iterator it = m_options.begin(), itEnd = m_options.end();
+                for(; it != itEnd; ++it ) {
+                    Arg const& arg = *it;
+
+                    try {
+                        if( ( token.type == Parser::Token::ShortOpt && arg.hasShortName( token.data ) ) ||
+                            ( token.type == Parser::Token::LongOpt && arg.hasLongName( token.data ) ) ) {
+                            if( arg.takesArg() ) {
+                                if( i == tokens.size()-1 || tokens[i+1].type != Parser::Token::Positional )
+                                    errors.push_back( "Expected argument to option: " + token.data );
+                                else
+                                    arg.boundField.set( config, tokens[++i].data );
+                            }
+                            else {
+                                arg.boundField.setFlag( config );
+                            }
+                            break;
+                        }
+                    }
+                    catch( std::exception& ex ) {
+                        errors.push_back( std::string( ex.what() ) + "\n- while parsing: (" + arg.commands() + ")" );
+                    }
+                }
+                if( it == itEnd ) {
+                    if( token.type == Parser::Token::Positional || !m_throwOnUnrecognisedTokens )
+                        unusedTokens.push_back( token );
+                    else if( m_throwOnUnrecognisedTokens )
+                        errors.push_back( "unrecognised option: " + token.data );
+                }
+            }
+            if( !errors.empty() ) {
+                std::ostringstream oss;
+                for( std::vector<std::string>::const_iterator it = errors.begin(), itEnd = errors.end();
+                        it != itEnd;
+                        ++it ) {
+                    if( it != errors.begin() )
+                        oss << "\n";
+                    oss << *it;
+                }
+                throw std::runtime_error( oss.str() );
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFixedArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            std::vector<Parser::Token> unusedTokens;
+            int position = 1;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                typename std::map<int, Arg>::const_iterator it = m_positionalArgs.find( position );
+                if( it != m_positionalArgs.end() )
+                    it->second.boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+                if( token.type == Parser::Token::Positional )
+                    position++;
+            }
+            return unusedTokens;
+        }
+        std::vector<Parser::Token> populateFloatingArgs( std::vector<Parser::Token> const& tokens, ConfigT& config ) const {
+            if( !m_floatingArg.get() )
+                return tokens;
+            std::vector<Parser::Token> unusedTokens;
+            for( std::size_t i = 0; i < tokens.size(); ++i ) {
+                Parser::Token const& token = tokens[i];
+                if( token.type == Parser::Token::Positional )
+                    m_floatingArg->boundField.set( config, token.data );
+                else
+                    unusedTokens.push_back( token );
+            }
+            return unusedTokens;
+        }
+
+        void validate() const
+        {
+            if( m_options.empty() && m_positionalArgs.empty() && !m_floatingArg.get() )
+                throw std::logic_error( "No options or arguments specified" );
+
+            for( typename std::vector<Arg>::const_iterator  it = m_options.begin(),
+                                                            itEnd = m_options.end();
+                    it != itEnd; ++it )
+                it->validate();
+        }
+
+    private:
+        Detail::BoundArgFunction<ConfigT> m_boundProcessName;
+        std::vector<Arg> m_options;
+        std::map<int, Arg> m_positionalArgs;
+        ArgAutoPtr m_floatingArg;
+        int m_highestSpecifiedArgPosition;
+        bool m_throwOnUnrecognisedTokens;
+    };
+
+} // end namespace Clara
+
+STITCH_CLARA_CLOSE_NAMESPACE
+#undef STITCH_CLARA_OPEN_NAMESPACE
+#undef STITCH_CLARA_CLOSE_NAMESPACE
+
+#endif // TWOBLUECUBES_CLARA_H_INCLUDED
+#undef STITCH_CLARA_OPEN_NAMESPACE
+
+// Restore Clara's value for console width, if present
+#ifdef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#define CLARA_CONFIG_CONSOLE_WIDTH CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#undef CATCH_TEMP_CLARA_CONFIG_CONSOLE_WIDTH
+#endif
+
+#include <fstream>
+
+namespace Catch {
+
+    inline void abortAfterFirst( ConfigData& config ) { config.abortAfter = 1; }
+    inline void abortAfterX( ConfigData& config, int x ) {
+        if( x < 1 )
+            throw std::runtime_error( "Value after -x or --abortAfter must be greater than zero" );
+        config.abortAfter = x;
+    }
+    inline void addTestOrTags( ConfigData& config, std::string const& _testSpec ) { config.testsOrTags.push_back( _testSpec ); }
+
+    inline void addWarning( ConfigData& config, std::string const& _warning ) {
+        if( _warning == "NoAssertions" )
+            config.warnings = static_cast<WarnAbout::What>( config.warnings | WarnAbout::NoAssertions );
+        else
+            throw std::runtime_error( "Unrecognised warning: '" + _warning + "'" );
+
+    }
+    inline void setVerbosity( ConfigData& config, int level ) {
+        // !TBD: accept strings?
+        config.verbosity = static_cast<Verbosity::Level>( level );
+    }
+    inline void setShowDurations( ConfigData& config, bool _showDurations ) {
+        config.showDurations = _showDurations
+            ? ShowDurations::Always
+            : ShowDurations::Never;
+    }
+    inline void loadTestNamesFromFile( ConfigData& config, std::string const& _filename ) {
+        std::ifstream f( _filename.c_str() );
+        if( !f.is_open() )
+            throw std::domain_error( "Unable to load input file: " + _filename );
+
+        std::string line;
+        while( std::getline( f, line ) ) {
+            line = trim(line);
+            if( !line.empty() && !startsWith( line, "#" ) )
+                addTestOrTags( config, "\"" + line + "\"," );
+        }
+    }
+
+    inline Clara::CommandLine<ConfigData> makeCommandLineParser() {
+
+        using namespace Clara;
+        CommandLine<ConfigData> cli;
+
+        cli.bindProcessName( &ConfigData::processName );
+
+        cli["-?"]["-h"]["--help"]
+            .describe( "display usage information" )
+            .bind( &ConfigData::showHelp );
+
+        cli["-l"]["--list-tests"]
+            .describe( "list all/matching test cases" )
+            .bind( &ConfigData::listTests );
+
+        cli["-t"]["--list-tags"]
+            .describe( "list all/matching tags" )
+            .bind( &ConfigData::listTags );
+
+        cli["-s"]["--success"]
+            .describe( "include successful tests in output" )
+            .bind( &ConfigData::showSuccessfulTests );
+
+        cli["-b"]["--break"]
+            .describe( "break into debugger on failure" )
+            .bind( &ConfigData::shouldDebugBreak );
+
+        cli["-e"]["--nothrow"]
+            .describe( "skip exception tests" )
+            .bind( &ConfigData::noThrow );
+
+        cli["-i"]["--invisibles"]
+            .describe( "show invisibles (tabs, newlines)" )
+            .bind( &ConfigData::showInvisibles );
+
+        cli["-o"]["--out"]
+            .describe( "output filename" )
+            .bind( &ConfigData::outputFilename, "filename" );
+
+        cli["-r"]["--reporter"]
+//            .placeholder( "name[:filename]" )
+            .describe( "reporter to use (defaults to console)" )
+            .bind( &ConfigData::reporterName, "name" );
+
+        cli["-n"]["--name"]
+            .describe( "suite name" )
+            .bind( &ConfigData::name, "name" );
+
+        cli["-a"]["--abort"]
+            .describe( "abort at first failure" )
+            .bind( &abortAfterFirst );
+
+        cli["-x"]["--abortx"]
+            .describe( "abort after x failures" )
+            .bind( &abortAfterX, "no. failures" );
+
+        cli["-w"]["--warn"]
+            .describe( "enable warnings" )
+            .bind( &addWarning, "warning name" );
+
+// - needs updating if reinstated
+//        cli.into( &setVerbosity )
+//            .describe( "level of verbosity (0=no output)" )
+//            .shortOpt( "v")
+//            .longOpt( "verbosity" )
+//            .placeholder( "level" );
+
+        cli[_]
+            .describe( "which test or tests to use" )
+            .bind( &addTestOrTags, "test name, pattern or tags" );
+
+        cli["-d"]["--durations"]
+            .describe( "show test durations" )
+            .bind( &setShowDurations, "yes/no" );
+
+        cli["-f"]["--input-file"]
+            .describe( "load test names to run from a file" )
+            .bind( &loadTestNamesFromFile, "filename" );
+
+        // Less common commands which don't have a short form
+        cli["--list-test-names-only"]
+            .describe( "list all/matching test cases names only" )
+            .bind( &ConfigData::listTestNamesOnly );
+
+        cli["--list-reporters"]
+            .describe( "list all reporters" )
+            .bind( &ConfigData::listReporters );
+
+        return cli;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_list.hpp
+#define TWOBLUECUBES_CATCH_LIST_HPP_INCLUDED
+
+// #included from: catch_text.h
+#define TWOBLUECUBES_CATCH_TEXT_H_INCLUDED
+
+#define TBC_TEXT_FORMAT_CONSOLE_WIDTH CATCH_CONFIG_CONSOLE_WIDTH
+
+#define CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE Catch
+// #included from: ../external/tbc_text_format.h
+// Only use header guard if we are not using an outer namespace
+#ifndef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+# ifdef TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+#  ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#   define TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#  endif
+# else
+#  define TWOBLUECUBES_TEXT_FORMAT_H_INCLUDED
+# endif
+#endif
+#ifndef TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#include <string>
+#include <vector>
+#include <sstream>
+
+// Use optional outer namespace
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+namespace CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE {
+#endif
+
+namespace Tbc {
+
+#ifdef TBC_TEXT_FORMAT_CONSOLE_WIDTH
+    const unsigned int consoleWidth = TBC_TEXT_FORMAT_CONSOLE_WIDTH;
+#else
+    const unsigned int consoleWidth = 80;
+#endif
+
+    struct TextAttributes {
+        TextAttributes()
+        :   initialIndent( std::string::npos ),
+            indent( 0 ),
+            width( consoleWidth-1 ),
+            tabChar( '\t' )
+        {}
+
+        TextAttributes& setInitialIndent( std::size_t _value )  { initialIndent = _value; return *this; }
+        TextAttributes& setIndent( std::size_t _value )         { indent = _value; return *this; }
+        TextAttributes& setWidth( std::size_t _value )          { width = _value; return *this; }
+        TextAttributes& setTabChar( char _value )               { tabChar = _value; return *this; }
+
+        std::size_t initialIndent;  // indent of first line, or npos
+        std::size_t indent;         // indent of subsequent lines, or all if initialIndent is npos
+        std::size_t width;          // maximum width of text, including indent. Longer text will wrap
+        char tabChar;               // If this char is seen the indent is changed to current pos
+    };
+
+    class Text {
+    public:
+        Text( std::string const& _str, TextAttributes const& _attr = TextAttributes() )
+        : attr( _attr )
+        {
+            std::string wrappableChars = " [({.,/|\\-";
+            std::size_t indent = _attr.initialIndent != std::string::npos
+                ? _attr.initialIndent
+                : _attr.indent;
+            std::string remainder = _str;
+
+            while( !remainder.empty() ) {
+                if( lines.size() >= 1000 ) {
+                    lines.push_back( "... message truncated due to excessive size" );
+                    return;
+                }
+                std::size_t tabPos = std::string::npos;
+                std::size_t width = (std::min)( remainder.size(), _attr.width - indent );
+                std::size_t pos = remainder.find_first_of( '\n' );
+                if( pos <= width ) {
+                    width = pos;
+                }
+                pos = remainder.find_last_of( _attr.tabChar, width );
+                if( pos != std::string::npos ) {
+                    tabPos = pos;
+                    if( remainder[width] == '\n' )
+                        width--;
+                    remainder = remainder.substr( 0, tabPos ) + remainder.substr( tabPos+1 );
+                }
+
+                if( width == remainder.size() ) {
+                    spliceLine( indent, remainder, width );
+                }
+                else if( remainder[width] == '\n' ) {
+                    spliceLine( indent, remainder, width );
+                    if( width <= 1 || remainder.size() != 1 )
+                        remainder = remainder.substr( 1 );
+                    indent = _attr.indent;
+                }
+                else {
+                    pos = remainder.find_last_of( wrappableChars, width );
+                    if( pos != std::string::npos && pos > 0 ) {
+                        spliceLine( indent, remainder, pos );
+                        if( remainder[0] == ' ' )
+                            remainder = remainder.substr( 1 );
+                    }
+                    else {
+                        spliceLine( indent, remainder, width-1 );
+                        lines.back() += "-";
+                    }
+                    if( lines.size() == 1 )
+                        indent = _attr.indent;
+                    if( tabPos != std::string::npos )
+                        indent += tabPos;
+                }
+            }
+        }
+
+        void spliceLine( std::size_t _indent, std::string& _remainder, std::size_t _pos ) {
+            lines.push_back( std::string( _indent, ' ' ) + _remainder.substr( 0, _pos ) );
+            _remainder = _remainder.substr( _pos );
+        }
+
+        typedef std::vector<std::string>::const_iterator const_iterator;
+
+        const_iterator begin() const { return lines.begin(); }
+        const_iterator end() const { return lines.end(); }
+        std::string const& last() const { return lines.back(); }
+        std::size_t size() const { return lines.size(); }
+        std::string const& operator[]( std::size_t _index ) const { return lines[_index]; }
+        std::string toString() const {
+            std::ostringstream oss;
+            oss << *this;
+            return oss.str();
+        }
+
+        inline friend std::ostream& operator << ( std::ostream& _stream, Text const& _text ) {
+            for( Text::const_iterator it = _text.begin(), itEnd = _text.end();
+                it != itEnd; ++it ) {
+                if( it != _text.begin() )
+                    _stream << "\n";
+                _stream << *it;
+            }
+            return _stream;
+        }
+
+    private:
+        std::string str;
+        TextAttributes attr;
+        std::vector<std::string> lines;
+    };
+
+} // end namespace Tbc
+
+#ifdef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+} // end outer namespace
+#endif
+
+#endif // TWOBLUECUBES_TEXT_FORMAT_H_ALREADY_INCLUDED
+#undef CLICHE_TBC_TEXT_FORMAT_OUTER_NAMESPACE
+
+namespace Catch {
+    using Tbc::Text;
+    using Tbc::TextAttributes;
+}
+
+// #included from: catch_console_colour.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_HPP_INCLUDED
+
+namespace Catch {
+
+    namespace Detail {
+        struct IColourImpl;
+    }
+
+    struct Colour {
+        enum Code {
+            None = 0,
+
+            White,
+            Red,
+            Green,
+            Blue,
+            Cyan,
+            Yellow,
+            Grey,
+
+            Bright = 0x10,
+
+            BrightRed = Bright | Red,
+            BrightGreen = Bright | Green,
+            LightGrey = Bright | Grey,
+            BrightWhite = Bright | White,
+
+            // By intention
+            FileName = LightGrey,
+            Warning = Yellow,
+            ResultError = BrightRed,
+            ResultSuccess = BrightGreen,
+            ResultExpectedFailure = Warning,
+
+            Error = BrightRed,
+            Success = Green,
+
+            OriginalExpression = Cyan,
+            ReconstructedExpression = Yellow,
+
+            SecondaryText = LightGrey,
+            Headers = White
+        };
+
+        // Use constructed object for RAII guard
+        Colour( Code _colourCode );
+        Colour( Colour const& other );
+        ~Colour();
+
+        // Use static method for one-shot changes
+        static void use( Code _colourCode );
+
+    private:
+        static Detail::IColourImpl* impl();
+        bool m_moved;
+    };
+
+    inline std::ostream& operator << ( std::ostream& os, Colour const& ) { return os; }
+
+} // end namespace Catch
+
+// #included from: catch_interfaces_reporter.h
+#define TWOBLUECUBES_CATCH_INTERFACES_REPORTER_H_INCLUDED
+
+#include <string>
+#include <ostream>
+#include <map>
+#include <assert.h>
+
+namespace Catch
+{
+    struct ReporterConfig {
+        explicit ReporterConfig( Ptr<IConfig> const& _fullConfig )
+        :   m_stream( &_fullConfig->stream() ), m_fullConfig( _fullConfig ) {}
+
+        ReporterConfig( Ptr<IConfig> const& _fullConfig, std::ostream& _stream )
+        :   m_stream( &_stream ), m_fullConfig( _fullConfig ) {}
+
+        std::ostream& stream() const    { return *m_stream; }
+        Ptr<IConfig> fullConfig() const { return m_fullConfig; }
+
+    private:
+        std::ostream* m_stream;
+        Ptr<IConfig> m_fullConfig;
+    };
+
+    struct ReporterPreferences {
+        ReporterPreferences()
+        : shouldRedirectStdOut( false )
+        {}
+
+        bool shouldRedirectStdOut;
+    };
+
+    template<typename T>
+    struct LazyStat : Option<T> {
+        LazyStat() : used( false ) {}
+        LazyStat& operator=( T const& _value ) {
+            Option<T>::operator=( _value );
+            used = false;
+            return *this;
+        }
+        void reset() {
+            Option<T>::reset();
+            used = false;
+        }
+        bool used;
+    };
+
+    struct TestRunInfo {
+        TestRunInfo( std::string const& _name ) : name( _name ) {}
+        std::string name;
+    };
+    struct GroupInfo {
+        GroupInfo(  std::string const& _name,
+                    std::size_t _groupIndex,
+                    std::size_t _groupsCount )
+        :   name( _name ),
+            groupIndex( _groupIndex ),
+            groupsCounts( _groupsCount )
+        {}
+
+        std::string name;
+        std::size_t groupIndex;
+        std::size_t groupsCounts;
+    };
+
+    struct AssertionStats {
+        AssertionStats( AssertionResult const& _assertionResult,
+                        std::vector<MessageInfo> const& _infoMessages,
+                        Totals const& _totals )
+        :   assertionResult( _assertionResult ),
+            infoMessages( _infoMessages ),
+            totals( _totals )
+        {
+            if( assertionResult.hasMessage() ) {
+                // Copy message into messages list.
+                // !TBD This should have been done earlier, somewhere
+                MessageBuilder builder( assertionResult.getTestMacroName(), assertionResult.getSourceInfo(), assertionResult.getResultType() );
+                builder << assertionResult.getMessage();
+                builder.m_info.message = builder.m_stream.str();
+
+                infoMessages.push_back( builder.m_info );
+            }
+        }
+        virtual ~AssertionStats();
+
+#  ifdef CATCH_CPP11_OR_GREATER
+        AssertionStats( AssertionStats const& )              = default;
+        AssertionStats( AssertionStats && )                  = default;
+        AssertionStats& operator = ( AssertionStats const& ) = default;
+        AssertionStats& operator = ( AssertionStats && )     = default;
+#  endif
+
+        AssertionResult assertionResult;
+        std::vector<MessageInfo> infoMessages;
+        Totals totals;
+    };
+
+    struct SectionStats {
+        SectionStats(   SectionInfo const& _sectionInfo,
+                        Counts const& _assertions,
+                        double _durationInSeconds,
+                        bool _missingAssertions )
+        :   sectionInfo( _sectionInfo ),
+            assertions( _assertions ),
+            durationInSeconds( _durationInSeconds ),
+            missingAssertions( _missingAssertions )
+        {}
+        virtual ~SectionStats();
+#  ifdef CATCH_CPP11_OR_GREATER
+        SectionStats( SectionStats const& )              = default;
+        SectionStats( SectionStats && )                  = default;
+        SectionStats& operator = ( SectionStats const& ) = default;
+        SectionStats& operator = ( SectionStats && )     = default;
+#  endif
+
+        SectionInfo sectionInfo;
+        Counts assertions;
+        double durationInSeconds;
+        bool missingAssertions;
+    };
+
+    struct TestCaseStats {
+        TestCaseStats(  TestCaseInfo const& _testInfo,
+                        Totals const& _totals,
+                        std::string const& _stdOut,
+                        std::string const& _stdErr,
+                        bool _aborting )
+        : testInfo( _testInfo ),
+            totals( _totals ),
+            stdOut( _stdOut ),
+            stdErr( _stdErr ),
+            aborting( _aborting )
+        {}
+        virtual ~TestCaseStats();
+
+#  ifdef CATCH_CPP11_OR_GREATER
+        TestCaseStats( TestCaseStats const& )              = default;
+        TestCaseStats( TestCaseStats && )                  = default;
+        TestCaseStats& operator = ( TestCaseStats const& ) = default;
+        TestCaseStats& operator = ( TestCaseStats && )     = default;
+#  endif
+
+        TestCaseInfo testInfo;
+        Totals totals;
+        std::string stdOut;
+        std::string stdErr;
+        bool aborting;
+    };
+
+    struct TestGroupStats {
+        TestGroupStats( GroupInfo const& _groupInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   groupInfo( _groupInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        TestGroupStats( GroupInfo const& _groupInfo )
+        :   groupInfo( _groupInfo ),
+            aborting( false )
+        {}
+        virtual ~TestGroupStats();
+
+#  ifdef CATCH_CPP11_OR_GREATER
+        TestGroupStats( TestGroupStats const& )              = default;
+        TestGroupStats( TestGroupStats && )                  = default;
+        TestGroupStats& operator = ( TestGroupStats const& ) = default;
+        TestGroupStats& operator = ( TestGroupStats && )     = default;
+#  endif
+
+        GroupInfo groupInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct TestRunStats {
+        TestRunStats(   TestRunInfo const& _runInfo,
+                        Totals const& _totals,
+                        bool _aborting )
+        :   runInfo( _runInfo ),
+            totals( _totals ),
+            aborting( _aborting )
+        {}
+        virtual ~TestRunStats();
+
+#  ifndef CATCH_CPP11_OR_GREATER
+        TestRunStats( TestRunStats const& _other )
+        :   runInfo( _other.runInfo ),
+            totals( _other.totals ),
+            aborting( _other.aborting )
+        {}
+#  else
+        TestRunStats( TestRunStats const& )              = default;
+        TestRunStats( TestRunStats && )                  = default;
+        TestRunStats& operator = ( TestRunStats const& ) = default;
+        TestRunStats& operator = ( TestRunStats && )     = default;
+#  endif
+
+        TestRunInfo runInfo;
+        Totals totals;
+        bool aborting;
+    };
+
+    struct IStreamingReporter : IShared {
+        virtual ~IStreamingReporter();
+
+        // Implementing class must also provide the following static method:
+        // static std::string getDescription();
+
+        virtual ReporterPreferences getPreferences() const = 0;
+
+        virtual void noMatchingTestCases( std::string const& spec ) = 0;
+
+        virtual void testRunStarting( TestRunInfo const& testRunInfo ) = 0;
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) = 0;
+
+        virtual void testCaseStarting( TestCaseInfo const& testInfo ) = 0;
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) = 0;
+
+        virtual void assertionStarting( AssertionInfo const& assertionInfo ) = 0;
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) = 0;
+        virtual void sectionEnded( SectionStats const& sectionStats ) = 0;
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) = 0;
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) = 0;
+        virtual void testRunEnded( TestRunStats const& testRunStats ) = 0;
+    };
+
+    struct IReporterFactory {
+        virtual ~IReporterFactory();
+        virtual IStreamingReporter* create( ReporterConfig const& config ) const = 0;
+        virtual std::string getDescription() const = 0;
+    };
+
+    struct IReporterRegistry {
+        typedef std::map<std::string, IReporterFactory*> FactoryMap;
+
+        virtual ~IReporterRegistry();
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const = 0;
+        virtual FactoryMap const& getFactories() const = 0;
+    };
+
+}
+
+#include <limits>
+#include <algorithm>
+
+namespace Catch {
+
+    inline std::size_t listTests( Config const& config ) {
+
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            std::cout << "Matching test cases:\n";
+        else {
+            std::cout << "All available test cases:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::size_t matchedTests = 0;
+        TextAttributes nameAttr, tagsAttr;
+        nameAttr.setInitialIndent( 2 ).setIndent( 4 );
+        tagsAttr.setIndent( 6 );
+
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            Colour::Code colour = testCaseInfo.isHidden()
+                ? Colour::SecondaryText
+                : Colour::None;
+            Colour colourGuard( colour );
+
+            std::cout << Text( testCaseInfo.name, nameAttr ) << std::endl;
+            if( !testCaseInfo.tags.empty() )
+                std::cout << Text( testCaseInfo.tagsAsString, tagsAttr ) << std::endl;
+        }
+
+        if( !config.testSpec().hasFilters() )
+            std::cout << pluralise( matchedTests, "test case" ) << "\n" << std::endl;
+        else
+            std::cout << pluralise( matchedTests, "matching test case" ) << "\n" << std::endl;
+        return matchedTests;
+    }
+
+    inline std::size_t listTestsNamesOnly( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( !config.testSpec().hasFilters() )
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        std::size_t matchedTests = 0;
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            matchedTests++;
+            TestCaseInfo const& testCaseInfo = it->getTestCaseInfo();
+            std::cout << testCaseInfo.name << std::endl;
+        }
+        return matchedTests;
+    }
+
+    struct TagInfo {
+        TagInfo() : count ( 0 ) {}
+        void add( std::string const& spelling ) {
+            ++count;
+            spellings.insert( spelling );
+        }
+        std::string all() const {
+            std::string out;
+            for( std::set<std::string>::const_iterator it = spellings.begin(), itEnd = spellings.end();
+                        it != itEnd;
+                        ++it )
+                out += "[" + *it + "]";
+            return out;
+        }
+        std::set<std::string> spellings;
+        std::size_t count;
+    };
+
+    inline std::size_t listTags( Config const& config ) {
+        TestSpec testSpec = config.testSpec();
+        if( config.testSpec().hasFilters() )
+            std::cout << "Tags for matching test cases:\n";
+        else {
+            std::cout << "All available tags:\n";
+            testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "*" ).testSpec();
+        }
+
+        std::map<std::string, TagInfo> tagCounts;
+
+        std::vector<TestCase> matchedTestCases;
+        getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, config, matchedTestCases );
+        for( std::vector<TestCase>::const_iterator it = matchedTestCases.begin(), itEnd = matchedTestCases.end();
+                it != itEnd;
+                ++it ) {
+            for( std::set<std::string>::const_iterator  tagIt = it->getTestCaseInfo().tags.begin(),
+                                                        tagItEnd = it->getTestCaseInfo().tags.end();
+                    tagIt != tagItEnd;
+                    ++tagIt ) {
+                std::string tagName = *tagIt;
+                std::string lcaseTagName = toLower( tagName );
+                std::map<std::string, TagInfo>::iterator countIt = tagCounts.find( lcaseTagName );
+                if( countIt == tagCounts.end() )
+                    countIt = tagCounts.insert( std::make_pair( lcaseTagName, TagInfo() ) ).first;
+                countIt->second.add( tagName );
+            }
+        }
+
+        for( std::map<std::string, TagInfo>::const_iterator countIt = tagCounts.begin(),
+                                                            countItEnd = tagCounts.end();
+                countIt != countItEnd;
+                ++countIt ) {
+            std::ostringstream oss;
+            oss << "  " << std::setw(2) << countIt->second.count << "  ";
+            Text wrapper( countIt->second.all(), TextAttributes()
+                                                    .setInitialIndent( 0 )
+                                                    .setIndent( oss.str().size() )
+                                                    .setWidth( CATCH_CONFIG_CONSOLE_WIDTH-10 ) );
+            std::cout << oss.str() << wrapper << "\n";
+        }
+        std::cout << pluralise( tagCounts.size(), "tag" ) << "\n" << std::endl;
+        return tagCounts.size();
+    }
+
+    inline std::size_t listReporters( Config const& /*config*/ ) {
+        std::cout << "Available reports:\n";
+        IReporterRegistry::FactoryMap const& factories = getRegistryHub().getReporterRegistry().getFactories();
+        IReporterRegistry::FactoryMap::const_iterator itBegin = factories.begin(), itEnd = factories.end(), it;
+        std::size_t maxNameLen = 0;
+        for(it = itBegin; it != itEnd; ++it )
+            maxNameLen = (std::max)( maxNameLen, it->first.size() );
+
+        for(it = itBegin; it != itEnd; ++it ) {
+            Text wrapper( it->second->getDescription(), TextAttributes()
+                                                        .setInitialIndent( 0 )
+                                                        .setIndent( 7+maxNameLen )
+                                                        .setWidth( CATCH_CONFIG_CONSOLE_WIDTH - maxNameLen-8 ) );
+            std::cout << "  "
+                    << it->first
+                    << ":"
+                    << std::string( maxNameLen - it->first.size() + 2, ' ' )
+                    << wrapper << "\n";
+        }
+        std::cout << std::endl;
+        return factories.size();
+    }
+
+    inline Option<std::size_t> list( Config const& config ) {
+        Option<std::size_t> listedCount;
+        if( config.listTests() )
+            listedCount = listedCount.valueOr(0) + listTests( config );
+        if( config.listTestNamesOnly() )
+            listedCount = listedCount.valueOr(0) + listTestsNamesOnly( config );
+        if( config.listTags() )
+            listedCount = listedCount.valueOr(0) + listTags( config );
+        if( config.listReporters() )
+            listedCount = listedCount.valueOr(0) + listReporters( config );
+        return listedCount;
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_runner_impl.hpp
+#define TWOBLUECUBES_CATCH_RUNNER_IMPL_HPP_INCLUDED
+
+// #included from: catch_test_case_tracker.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_TRACKER_HPP_INCLUDED
+
+#include <map>
+#include <string>
+#include <assert.h>
+
+namespace Catch {
+namespace SectionTracking {
+
+    class TrackedSection {
+
+        typedef std::map<std::string, TrackedSection> TrackedSections;
+
+    public:
+        enum RunState {
+            NotStarted,
+            Executing,
+            ExecutingChildren,
+            Completed
+        };
+
+        TrackedSection( std::string const& name, TrackedSection* parent )
+        :   m_name( name ), m_runState( NotStarted ), m_parent( parent )
+        {}
+
+        RunState runState() const { return m_runState; }
+
+        TrackedSection* findChild( std::string const& childName ) {
+            TrackedSections::iterator it = m_children.find( childName );
+            return it != m_children.end()
+                ? &it->second
+                : NULL;
+        }
+        TrackedSection* acquireChild( std::string const& childName ) {
+            if( TrackedSection* child = findChild( childName ) )
+                return child;
+            m_children.insert( std::make_pair( childName, TrackedSection( childName, this ) ) );
+            return findChild( childName );
+        }
+        void enter() {
+            if( m_runState == NotStarted )
+                m_runState = Executing;
+        }
+        void leave() {
+            for( TrackedSections::const_iterator it = m_children.begin(), itEnd = m_children.end();
+                    it != itEnd;
+                    ++it )
+                if( it->second.runState() != Completed ) {
+                    m_runState = ExecutingChildren;
+                    return;
+                }
+            m_runState = Completed;
+        }
+        TrackedSection* getParent() {
+            return m_parent;
+        }
+        bool hasChildren() const {
+            return !m_children.empty();
+        }
+
+    private:
+        std::string m_name;
+        RunState m_runState;
+        TrackedSections m_children;
+        TrackedSection* m_parent;
+
+    };
+
+    class TestCaseTracker {
+    public:
+        TestCaseTracker( std::string const& testCaseName )
+        :   m_testCase( testCaseName, NULL ),
+            m_currentSection( &m_testCase ),
+            m_completedASectionThisRun( false )
+        {}
+
+        bool enterSection( std::string const& name ) {
+            TrackedSection* child = m_currentSection->acquireChild( name );
+            if( m_completedASectionThisRun || child->runState() == TrackedSection::Completed )
+                return false;
+
+            m_currentSection = child;
+            m_currentSection->enter();
+            return true;
+        }
+        void leaveSection() {
+            m_currentSection->leave();
+            m_currentSection = m_currentSection->getParent();
+            assert( m_currentSection != NULL );
+            m_completedASectionThisRun = true;
+        }
+
+        bool currentSectionHasChildren() const {
+            return m_currentSection->hasChildren();
+        }
+        bool isCompleted() const {
+            return m_testCase.runState() == TrackedSection::Completed;
+        }
+
+        class Guard {
+        public:
+            Guard( TestCaseTracker& tracker ) : m_tracker( tracker ) {
+                m_tracker.enterTestCase();
+            }
+            ~Guard() {
+                m_tracker.leaveTestCase();
+            }
+        private:
+            Guard( Guard const& );
+            void operator = ( Guard const& );
+            TestCaseTracker& m_tracker;
+        };
+
+    private:
+        void enterTestCase() {
+            m_currentSection = &m_testCase;
+            m_completedASectionThisRun = false;
+            m_testCase.enter();
+        }
+        void leaveTestCase() {
+            m_testCase.leave();
+        }
+
+        TrackedSection m_testCase;
+        TrackedSection* m_currentSection;
+        bool m_completedASectionThisRun;
+    };
+
+} // namespace SectionTracking
+
+using SectionTracking::TestCaseTracker;
+
+} // namespace Catch
+
+#include <set>
+#include <string>
+
+namespace Catch {
+
+    class StreamRedirect {
+
+    public:
+        StreamRedirect( std::ostream& stream, std::string& targetString )
+        :   m_stream( stream ),
+            m_prevBuf( stream.rdbuf() ),
+            m_targetString( targetString )
+        {
+            stream.rdbuf( m_oss.rdbuf() );
+        }
+
+        ~StreamRedirect() {
+            m_targetString += m_oss.str();
+            m_stream.rdbuf( m_prevBuf );
+        }
+
+    private:
+        std::ostream& m_stream;
+        std::streambuf* m_prevBuf;
+        std::ostringstream m_oss;
+        std::string& m_targetString;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class RunContext : public IResultCapture, public IRunner {
+
+        RunContext( RunContext const& );
+        void operator =( RunContext const& );
+
+    public:
+
+        explicit RunContext( Ptr<IConfig const> const& config, Ptr<IStreamingReporter> const& reporter )
+        :   m_runInfo( config->name() ),
+            m_context( getCurrentMutableContext() ),
+            m_activeTestCase( NULL ),
+            m_config( config ),
+            m_reporter( reporter ),
+            m_prevRunner( m_context.getRunner() ),
+            m_prevResultCapture( m_context.getResultCapture() ),
+            m_prevConfig( m_context.getConfig() )
+        {
+            m_context.setRunner( this );
+            m_context.setConfig( m_config );
+            m_context.setResultCapture( this );
+            m_reporter->testRunStarting( m_runInfo );
+        }
+
+        virtual ~RunContext() {
+            m_reporter->testRunEnded( TestRunStats( m_runInfo, m_totals, aborting() ) );
+            m_context.setRunner( m_prevRunner );
+            m_context.setConfig( NULL );
+            m_context.setResultCapture( m_prevResultCapture );
+            m_context.setConfig( m_prevConfig );
+        }
+
+        void testGroupStarting( std::string const& testSpec, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupStarting( GroupInfo( testSpec, groupIndex, groupsCount ) );
+        }
+        void testGroupEnded( std::string const& testSpec, Totals const& totals, std::size_t groupIndex, std::size_t groupsCount ) {
+            m_reporter->testGroupEnded( TestGroupStats( GroupInfo( testSpec, groupIndex, groupsCount ), totals, aborting() ) );
+        }
+
+        Totals runTest( TestCase const& testCase ) {
+            Totals prevTotals = m_totals;
+
+            std::string redirectedCout;
+            std::string redirectedCerr;
+
+            TestCaseInfo testInfo = testCase.getTestCaseInfo();
+
+            m_reporter->testCaseStarting( testInfo );
+
+            m_activeTestCase = &testCase;
+            m_testCaseTracker = TestCaseTracker( testInfo.name );
+
+            do {
+                do {
+                    runCurrentTest( redirectedCout, redirectedCerr );
+                }
+                while( !m_testCaseTracker->isCompleted() && !aborting() );
+            }
+            while( getCurrentContext().advanceGeneratorsForCurrentTest() && !aborting() );
+
+            Totals deltaTotals = m_totals.delta( prevTotals );
+            m_totals.testCases += deltaTotals.testCases;
+            m_reporter->testCaseEnded( TestCaseStats(   testInfo,
+                                                        deltaTotals,
+                                                        redirectedCout,
+                                                        redirectedCerr,
+                                                        aborting() ) );
+
+            m_activeTestCase = NULL;
+            m_testCaseTracker.reset();
+
+            return deltaTotals;
+        }
+
+        Ptr<IConfig const> config() const {
+            return m_config;
+        }
+
+    private: // IResultCapture
+
+        virtual void assertionEnded( AssertionResult const& result ) {
+            if( result.getResultType() == ResultWas::Ok ) {
+                m_totals.assertions.passed++;
+            }
+            else if( !result.isOk() ) {
+                m_totals.assertions.failed++;
+            }
+
+            if( m_reporter->assertionEnded( AssertionStats( result, m_messages, m_totals ) ) )
+                m_messages.clear();
+
+            // Reset working state
+            m_lastAssertionInfo = AssertionInfo( "", m_lastAssertionInfo.lineInfo, "{Unknown expression after the reported line}" , m_lastAssertionInfo.resultDisposition );
+            m_lastResult = result;
+        }
+
+        virtual bool sectionStarted (
+            SectionInfo const& sectionInfo,
+            Counts& assertions
+        )
+        {
+            std::ostringstream oss;
+            oss << sectionInfo.name << "@" << sectionInfo.lineInfo;
+
+            if( !m_testCaseTracker->enterSection( oss.str() ) )
+                return false;
+
+            m_lastAssertionInfo.lineInfo = sectionInfo.lineInfo;
+
+            m_reporter->sectionStarting( sectionInfo );
+
+            assertions = m_totals.assertions;
+
+            return true;
+        }
+        bool testForMissingAssertions( Counts& assertions ) {
+            if( assertions.total() != 0 ||
+                    !m_config->warnAboutMissingAssertions() ||
+                    m_testCaseTracker->currentSectionHasChildren() )
+                return false;
+            m_totals.assertions.failed++;
+            assertions.failed++;
+            return true;
+        }
+
+        virtual void sectionEnded( SectionInfo const& info, Counts const& prevAssertions, double _durationInSeconds ) {
+            if( std::uncaught_exception() ) {
+                m_unfinishedSections.push_back( UnfinishedSections( info, prevAssertions, _durationInSeconds ) );
+                return;
+            }
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            m_testCaseTracker->leaveSection();
+
+            m_reporter->sectionEnded( SectionStats( info, assertions, _durationInSeconds, missingAssertions ) );
+            m_messages.clear();
+        }
+
+        virtual void pushScopedMessage( MessageInfo const& message ) {
+            m_messages.push_back( message );
+        }
+
+        virtual void popScopedMessage( MessageInfo const& message ) {
+            m_messages.erase( std::remove( m_messages.begin(), m_messages.end(), message ), m_messages.end() );
+        }
+
+        virtual std::string getCurrentTestName() const {
+            return m_activeTestCase
+                ? m_activeTestCase->getTestCaseInfo().name
+                : "";
+        }
+
+        virtual const AssertionResult* getLastResult() const {
+            return &m_lastResult;
+        }
+
+    public:
+        // !TBD We need to do this another way!
+        bool aborting() const {
+            return m_totals.assertions.failed == static_cast<std::size_t>( m_config->abortAfter() );
+        }
+
+    private:
+
+        void runCurrentTest( std::string& redirectedCout, std::string& redirectedCerr ) {
+            TestCaseInfo const& testCaseInfo = m_activeTestCase->getTestCaseInfo();
+            SectionInfo testCaseSection( testCaseInfo.lineInfo, testCaseInfo.name, testCaseInfo.description );
+            m_reporter->sectionStarting( testCaseSection );
+            Counts prevAssertions = m_totals.assertions;
+            double duration = 0;
+            try {
+                m_lastAssertionInfo = AssertionInfo( "TEST_CASE", testCaseInfo.lineInfo, "", ResultDisposition::Normal );
+                TestCaseTracker::Guard guard( *m_testCaseTracker );
+
+                Timer timer;
+                timer.start();
+                if( m_reporter->getPreferences().shouldRedirectStdOut ) {
+                    StreamRedirect coutRedir( std::cout, redirectedCout );
+                    StreamRedirect cerrRedir( std::cerr, redirectedCerr );
+                    m_activeTestCase->invoke();
+                }
+                else {
+                    m_activeTestCase->invoke();
+                }
+                duration = timer.getElapsedSeconds();
+            }
+            catch( TestFailureException& ) {
+                // This just means the test was aborted due to failure
+            }
+            catch(...) {
+                ResultBuilder exResult( m_lastAssertionInfo.macroName.c_str(),
+                                        m_lastAssertionInfo.lineInfo,
+                                        m_lastAssertionInfo.capturedExpression.c_str(),
+                                        m_lastAssertionInfo.resultDisposition );
+                exResult.useActiveException();
+            }
+            // If sections ended prematurely due to an exception we stored their
+            // infos here so we can tear them down outside the unwind process.
+            for( std::vector<UnfinishedSections>::const_reverse_iterator it = m_unfinishedSections.rbegin(),
+                        itEnd = m_unfinishedSections.rend();
+                    it != itEnd;
+                    ++it )
+                sectionEnded( it->info, it->prevAssertions, it->durationInSeconds );
+            m_unfinishedSections.clear();
+            m_messages.clear();
+
+            Counts assertions = m_totals.assertions - prevAssertions;
+            bool missingAssertions = testForMissingAssertions( assertions );
+
+            if( testCaseInfo.okToFail() ) {
+                std::swap( assertions.failedButOk, assertions.failed );
+                m_totals.assertions.failed -= assertions.failedButOk;
+                m_totals.assertions.failedButOk += assertions.failedButOk;
+            }
+
+            SectionStats testCaseSectionStats( testCaseSection, assertions, duration, missingAssertions );
+            m_reporter->sectionEnded( testCaseSectionStats );
+        }
+
+    private:
+        struct UnfinishedSections {
+            UnfinishedSections( SectionInfo const& _info, Counts const& _prevAssertions, double _durationInSeconds )
+            : info( _info ), prevAssertions( _prevAssertions ), durationInSeconds( _durationInSeconds )
+            {}
+
+            SectionInfo info;
+            Counts prevAssertions;
+            double durationInSeconds;
+        };
+
+        TestRunInfo m_runInfo;
+        IMutableContext& m_context;
+        TestCase const* m_activeTestCase;
+        Option<TestCaseTracker> m_testCaseTracker;
+        AssertionResult m_lastResult;
+
+        Ptr<IConfig const> m_config;
+        Totals m_totals;
+        Ptr<IStreamingReporter> m_reporter;
+        std::vector<MessageInfo> m_messages;
+        IRunner* m_prevRunner;
+        IResultCapture* m_prevResultCapture;
+        Ptr<IConfig const> m_prevConfig;
+        AssertionInfo m_lastAssertionInfo;
+        std::vector<UnfinishedSections> m_unfinishedSections;
+    };
+
+    IResultCapture& getResultCapture() {
+        if( IResultCapture* capture = getCurrentContext().getResultCapture() )
+            return *capture;
+        else
+            throw std::logic_error( "No result capture instance" );
+    }
+
+} // end namespace Catch
+
+// #included from: internal/catch_version.h
+#define TWOBLUECUBES_CATCH_VERSION_H_INCLUDED
+
+namespace Catch {
+
+    // Versioning information
+    struct Version {
+        Version(    unsigned int _majorVersion,
+                    unsigned int _minorVersion,
+                    unsigned int _buildNumber,
+                    char const* const _branchName )
+        :   majorVersion( _majorVersion ),
+            minorVersion( _minorVersion ),
+            buildNumber( _buildNumber ),
+            branchName( _branchName )
+        {}
+
+        unsigned int const majorVersion;
+        unsigned int const minorVersion;
+        unsigned int const buildNumber;
+        char const* const branchName;
+
+    private:
+        void operator=( Version const& );
+    };
+
+    extern Version libraryVersion;
+}
+
+#include <fstream>
+#include <stdlib.h>
+#include <limits>
+
+namespace Catch {
+
+    class Runner {
+
+    public:
+        Runner( Ptr<Config> const& config )
+        :   m_config( config )
+        {
+            openStream();
+            makeReporter();
+        }
+
+        Totals runTests() {
+
+            RunContext context( m_config.get(), m_reporter );
+
+            Totals totals;
+
+            context.testGroupStarting( "", 1, 1 ); // deprecated?
+
+            TestSpec testSpec = m_config->testSpec();
+            if( !testSpec.hasFilters() )
+                testSpec = TestSpecParser( ITagAliasRegistry::get() ).parse( "~[.]" ).testSpec(); // All not hidden tests
+
+            std::vector<TestCase> testCases;
+            getRegistryHub().getTestCaseRegistry().getFilteredTests( testSpec, *m_config, testCases );
+
+            int testsRunForGroup = 0;
+            for( std::vector<TestCase>::const_iterator it = testCases.begin(), itEnd = testCases.end();
+                    it != itEnd;
+                    ++it ) {
+                testsRunForGroup++;
+                if( m_testsAlreadyRun.find( *it ) == m_testsAlreadyRun.end() ) {
+
+                    if( context.aborting() )
+                        break;
+
+                    totals += context.runTest( *it );
+                    m_testsAlreadyRun.insert( *it );
+                }
+            }
+            context.testGroupEnded( "", totals, 1, 1 );
+            return totals;
+        }
+
+    private:
+        void openStream() {
+            // Open output file, if specified
+            if( !m_config->getFilename().empty() ) {
+                m_ofs.open( m_config->getFilename().c_str() );
+                if( m_ofs.fail() ) {
+                    std::ostringstream oss;
+                    oss << "Unable to open file: '" << m_config->getFilename() << "'";
+                    throw std::domain_error( oss.str() );
+                }
+                m_config->setStreamBuf( m_ofs.rdbuf() );
+            }
+        }
+        void makeReporter() {
+            std::string reporterName = m_config->getReporterName().empty()
+                ? "console"
+                : m_config->getReporterName();
+
+            m_reporter = getRegistryHub().getReporterRegistry().create( reporterName, m_config.get() );
+            if( !m_reporter ) {
+                std::ostringstream oss;
+                oss << "No reporter registered with name: '" << reporterName << "'";
+                throw std::domain_error( oss.str() );
+            }
+        }
+
+    private:
+        Ptr<Config> m_config;
+        std::ofstream m_ofs;
+        Ptr<IStreamingReporter> m_reporter;
+        std::set<TestCase> m_testsAlreadyRun;
+    };
+
+    class Session {
+        static bool alreadyInstantiated;
+
+    public:
+
+        struct OnUnusedOptions { enum DoWhat { Ignore, Fail }; };
+
+        Session()
+        : m_cli( makeCommandLineParser() ) {
+            if( alreadyInstantiated ) {
+                std::string msg = "Only one instance of Catch::Session can ever be used";
+                std::cerr << msg << std::endl;
+                throw std::logic_error( msg );
+            }
+            alreadyInstantiated = true;
+        }
+        ~Session() {
+            Catch::cleanUp();
+        }
+
+        void showHelp( std::string const& processName ) {
+            std::cout << "\nCatch v"    << libraryVersion.majorVersion << "."
+                                        << libraryVersion.minorVersion << " build "
+                                        << libraryVersion.buildNumber;
+            if( libraryVersion.branchName != std::string( "master" ) )
+                std::cout << " (" << libraryVersion.branchName << " branch)";
+            std::cout << "\n";
+
+            m_cli.usage( std::cout, processName );
+            std::cout << "For more detail usage please see the project docs\n" << std::endl;
+        }
+
+        int applyCommandLine( int argc, char* const argv[], OnUnusedOptions::DoWhat unusedOptionBehaviour = OnUnusedOptions::Fail ) {
+            try {
+                m_cli.setThrowOnUnrecognisedTokens( unusedOptionBehaviour == OnUnusedOptions::Fail );
+                m_unusedTokens = m_cli.parseInto( argc, argv, m_configData );
+                if( m_configData.showHelp )
+                    showHelp( m_configData.processName );
+                m_config.reset();
+            }
+            catch( std::exception& ex ) {
+                {
+                    Colour colourGuard( Colour::Red );
+                    std::cerr   << "\nError(s) in input:\n"
+                                << Text( ex.what(), TextAttributes().setIndent(2) )
+                                << "\n\n";
+                }
+                m_cli.usage( std::cout, m_configData.processName );
+                return (std::numeric_limits<int>::max)();
+            }
+            return 0;
+        }
+
+        void useConfigData( ConfigData const& _configData ) {
+            m_configData = _configData;
+            m_config.reset();
+        }
+
+        int run( int argc, char* const argv[] ) {
+
+            int returnCode = applyCommandLine( argc, argv );
+            if( returnCode == 0 )
+                returnCode = run();
+            return returnCode;
+        }
+
+        int run() {
+            if( m_configData.showHelp )
+                return 0;
+
+            try
+            {
+                config(); // Force config to be constructed
+                Runner runner( m_config );
+
+                // Handle list request
+                if( Option<std::size_t> listed = list( config() ) )
+                    return static_cast<int>( *listed );
+
+                return static_cast<int>( runner.runTests().assertions.failed );
+            }
+            catch( std::exception& ex ) {
+                std::cerr << ex.what() << std::endl;
+                return (std::numeric_limits<int>::max)();
+            }
+        }
+
+        Clara::CommandLine<ConfigData> const& cli() const {
+            return m_cli;
+        }
+        std::vector<Clara::Parser::Token> const& unusedTokens() const {
+            return m_unusedTokens;
+        }
+        ConfigData& configData() {
+            return m_configData;
+        }
+        Config& config() {
+            if( !m_config )
+                m_config = new Config( m_configData );
+            return *m_config;
+        }
+
+    private:
+        Clara::CommandLine<ConfigData> m_cli;
+        std::vector<Clara::Parser::Token> m_unusedTokens;
+        ConfigData m_configData;
+        Ptr<Config> m_config;
+    };
+
+    bool Session::alreadyInstantiated = false;
+
+} // end namespace Catch
+
+// #included from: catch_registry_hub.hpp
+#define TWOBLUECUBES_CATCH_REGISTRY_HUB_HPP_INCLUDED
+
+// #included from: catch_test_case_registry_impl.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_REGISTRY_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <set>
+#include <sstream>
+#include <iostream>
+
+namespace Catch {
+
+    class TestRegistry : public ITestCaseRegistry {
+    public:
+        TestRegistry() : m_unnamedCount( 0 ) {}
+        virtual ~TestRegistry();
+
+        virtual void registerTest( TestCase const& testCase ) {
+            std::string name = testCase.getTestCaseInfo().name;
+            if( name == "" ) {
+                std::ostringstream oss;
+                oss << "Anonymous test case " << ++m_unnamedCount;
+                return registerTest( testCase.withName( oss.str() ) );
+            }
+
+            if( m_functions.find( testCase ) == m_functions.end() ) {
+                m_functions.insert( testCase );
+                m_functionsInOrder.push_back( testCase );
+                if( !testCase.isHidden() )
+                    m_nonHiddenFunctions.push_back( testCase );
+            }
+            else {
+                TestCase const& prev = *m_functions.find( testCase );
+                {
+                    Colour colourGuard( Colour::Red );
+                    std::cerr   << "error: TEST_CASE( \"" << name << "\" ) already defined.\n"
+                                << "\tFirst seen at " << prev.getTestCaseInfo().lineInfo << "\n"
+                                << "\tRedefined at " << testCase.getTestCaseInfo().lineInfo << std::endl;
+                }
+                exit(1);
+            }
+        }
+
+        virtual std::vector<TestCase> const& getAllTests() const {
+            return m_functionsInOrder;
+        }
+
+        virtual std::vector<TestCase> const& getAllNonHiddenTests() const {
+            return m_nonHiddenFunctions;
+        }
+
+        virtual void getFilteredTests( TestSpec const& testSpec, IConfig const& config, std::vector<TestCase>& matchingTestCases ) const {
+            for( std::vector<TestCase>::const_iterator  it = m_functionsInOrder.begin(),
+                                                        itEnd = m_functionsInOrder.end();
+                    it != itEnd;
+                    ++it ) {
+                if( testSpec.matches( *it ) && ( config.allowThrows() || !it->throws() ) )
+                    matchingTestCases.push_back( *it );
+            }
+        }
+
+    private:
+
+        std::set<TestCase> m_functions;
+        std::vector<TestCase> m_functionsInOrder;
+        std::vector<TestCase> m_nonHiddenFunctions;
+        size_t m_unnamedCount;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class FreeFunctionTestCase : public SharedImpl<ITestCase> {
+    public:
+
+        FreeFunctionTestCase( TestFunction fun ) : m_fun( fun ) {}
+
+        virtual void invoke() const {
+            m_fun();
+        }
+
+    private:
+        virtual ~FreeFunctionTestCase();
+
+        TestFunction m_fun;
+    };
+
+    inline std::string extractClassName( std::string const& classOrQualifiedMethodName ) {
+        std::string className = classOrQualifiedMethodName;
+        if( startsWith( className, "&" ) )
+        {
+            std::size_t lastColons = className.rfind( "::" );
+            std::size_t penultimateColons = className.rfind( "::", lastColons-1 );
+            if( penultimateColons == std::string::npos )
+                penultimateColons = 1;
+            className = className.substr( penultimateColons, lastColons-penultimateColons );
+        }
+        return className;
+    }
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    AutoReg::AutoReg(   TestFunction function,
+                        SourceLineInfo const& lineInfo,
+                        NameAndDesc const& nameAndDesc ) {
+        registerTestCase( new FreeFunctionTestCase( function ), "", nameAndDesc, lineInfo );
+    }
+
+    AutoReg::~AutoReg() {}
+
+    void AutoReg::registerTestCase( ITestCase* testCase,
+                                    char const* classOrQualifiedMethodName,
+                                    NameAndDesc const& nameAndDesc,
+                                    SourceLineInfo const& lineInfo ) {
+
+        getMutableRegistryHub().registerTest
+            ( makeTestCase( testCase,
+                            extractClassName( classOrQualifiedMethodName ),
+                            nameAndDesc.name,
+                            nameAndDesc.description,
+                            lineInfo ) );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_reporter_registry.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRY_HPP_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class ReporterRegistry : public IReporterRegistry {
+
+    public:
+
+        virtual ~ReporterRegistry() {
+            deleteAllValues( m_factories );
+        }
+
+        virtual IStreamingReporter* create( std::string const& name, Ptr<IConfig> const& config ) const {
+            FactoryMap::const_iterator it =  m_factories.find( name );
+            if( it == m_factories.end() )
+                return NULL;
+            return it->second->create( ReporterConfig( config ) );
+        }
+
+        void registerReporter( std::string const& name, IReporterFactory* factory ) {
+            m_factories.insert( std::make_pair( name, factory ) );
+        }
+
+        FactoryMap const& getFactories() const {
+            return m_factories;
+        }
+
+    private:
+        FactoryMap m_factories;
+    };
+}
+
+// #included from: catch_exception_translator_registry.hpp
+#define TWOBLUECUBES_CATCH_EXCEPTION_TRANSLATOR_REGISTRY_HPP_INCLUDED
+
+#ifdef __OBJC__
+#import "Foundation/Foundation.h"
+#endif
+
+namespace Catch {
+
+    class ExceptionTranslatorRegistry : public IExceptionTranslatorRegistry {
+    public:
+        ~ExceptionTranslatorRegistry() {
+            deleteAll( m_translators );
+        }
+
+        virtual void registerTranslator( const IExceptionTranslator* translator ) {
+            m_translators.push_back( translator );
+        }
+
+        virtual std::string translateActiveException() const {
+            try {
+#ifdef __OBJC__
+                // In Objective-C try objective-c exceptions first
+                @try {
+                    throw;
+                }
+                @catch (NSException *exception) {
+                    return toString( [exception description] );
+                }
+#else
+                throw;
+#endif
+            }
+            catch( TestFailureException& ) {
+                throw;
+            }
+            catch( std::exception& ex ) {
+                return ex.what();
+            }
+            catch( std::string& msg ) {
+                return msg;
+            }
+            catch( const char* msg ) {
+                return msg;
+            }
+            catch(...) {
+                return tryTranslators( m_translators.begin() );
+            }
+        }
+
+        std::string tryTranslators( std::vector<const IExceptionTranslator*>::const_iterator it ) const {
+            if( it == m_translators.end() )
+                return "Unknown exception";
+
+            try {
+                return (*it)->translate();
+            }
+            catch(...) {
+                return tryTranslators( it+1 );
+            }
+        }
+
+    private:
+        std::vector<const IExceptionTranslator*> m_translators;
+    };
+}
+
+namespace Catch {
+
+    namespace {
+
+        class RegistryHub : public IRegistryHub, public IMutableRegistryHub {
+
+            RegistryHub( RegistryHub const& );
+            void operator=( RegistryHub const& );
+
+        public: // IRegistryHub
+            RegistryHub() {
+            }
+            virtual IReporterRegistry const& getReporterRegistry() const {
+                return m_reporterRegistry;
+            }
+            virtual ITestCaseRegistry const& getTestCaseRegistry() const {
+                return m_testCaseRegistry;
+            }
+            virtual IExceptionTranslatorRegistry& getExceptionTranslatorRegistry() {
+                return m_exceptionTranslatorRegistry;
+            }
+
+        public: // IMutableRegistryHub
+            virtual void registerReporter( std::string const& name, IReporterFactory* factory ) {
+                m_reporterRegistry.registerReporter( name, factory );
+            }
+            virtual void registerTest( TestCase const& testInfo ) {
+                m_testCaseRegistry.registerTest( testInfo );
+            }
+            virtual void registerTranslator( const IExceptionTranslator* translator ) {
+                m_exceptionTranslatorRegistry.registerTranslator( translator );
+            }
+
+        private:
+            TestRegistry m_testCaseRegistry;
+            ReporterRegistry m_reporterRegistry;
+            ExceptionTranslatorRegistry m_exceptionTranslatorRegistry;
+        };
+
+        // Single, global, instance
+        inline RegistryHub*& getTheRegistryHub() {
+            static RegistryHub* theRegistryHub = NULL;
+            if( !theRegistryHub )
+                theRegistryHub = new RegistryHub();
+            return theRegistryHub;
+        }
+    }
+
+    IRegistryHub& getRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    IMutableRegistryHub& getMutableRegistryHub() {
+        return *getTheRegistryHub();
+    }
+    void cleanUp() {
+        delete getTheRegistryHub();
+        getTheRegistryHub() = NULL;
+        cleanUpContext();
+    }
+    std::string translateActiveException() {
+        return getRegistryHub().getExceptionTranslatorRegistry().translateActiveException();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_notimplemented_exception.hpp
+#define TWOBLUECUBES_CATCH_NOTIMPLEMENTED_EXCEPTION_HPP_INCLUDED
+
+#include <ostream>
+
+namespace Catch {
+
+    NotImplementedException::NotImplementedException( SourceLineInfo const& lineInfo )
+    :   m_lineInfo( lineInfo ) {
+        std::ostringstream oss;
+        oss << lineInfo << ": function ";
+        oss << "not implemented";
+        m_what = oss.str();
+    }
+
+    const char* NotImplementedException::what() const CATCH_NOEXCEPT {
+        return m_what.c_str();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_context_impl.hpp
+#define TWOBLUECUBES_CATCH_CONTEXT_IMPL_HPP_INCLUDED
+
+// #included from: catch_stream.hpp
+#define TWOBLUECUBES_CATCH_STREAM_HPP_INCLUDED
+
+// #included from: catch_streambuf.h
+#define TWOBLUECUBES_CATCH_STREAMBUF_H_INCLUDED
+
+#include <streambuf>
+
+namespace Catch {
+
+    class StreamBufBase : public std::streambuf {
+    public:
+        virtual ~StreamBufBase() CATCH_NOEXCEPT;
+    };
+}
+
+#include <stdexcept>
+#include <cstdio>
+
+namespace Catch {
+
+    template<typename WriterF, size_t bufferSize=256>
+    class StreamBufImpl : public StreamBufBase {
+        char data[bufferSize];
+        WriterF m_writer;
+
+    public:
+        StreamBufImpl() {
+            setp( data, data + sizeof(data) );
+        }
+
+        ~StreamBufImpl() CATCH_NOEXCEPT {
+            sync();
+        }
+
+    private:
+        int overflow( int c ) {
+            sync();
+
+            if( c != EOF ) {
+                if( pbase() == epptr() )
+                    m_writer( std::string( 1, static_cast<char>( c ) ) );
+                else
+                    sputc( static_cast<char>( c ) );
+            }
+            return 0;
+        }
+
+        int sync() {
+            if( pbase() != pptr() ) {
+                m_writer( std::string( pbase(), static_cast<std::string::size_type>( pptr() - pbase() ) ) );
+                setp( pbase(), epptr() );
+            }
+            return 0;
+        }
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    struct OutputDebugWriter {
+
+        void operator()( std::string const&str ) {
+            writeToDebugConsole( str );
+        }
+    };
+
+    Stream::Stream()
+    : streamBuf( NULL ), isOwned( false )
+    {}
+
+    Stream::Stream( std::streambuf* _streamBuf, bool _isOwned )
+    : streamBuf( _streamBuf ), isOwned( _isOwned )
+    {}
+
+    void Stream::release() {
+        if( isOwned ) {
+            delete streamBuf;
+            streamBuf = NULL;
+            isOwned = false;
+        }
+    }
+}
+
+namespace Catch {
+
+    class Context : public IMutableContext {
+
+        Context() : m_config( NULL ), m_runner( NULL ), m_resultCapture( NULL ) {}
+        Context( Context const& );
+        void operator=( Context const& );
+
+    public: // IContext
+        virtual IResultCapture* getResultCapture() {
+            return m_resultCapture;
+        }
+        virtual IRunner* getRunner() {
+            return m_runner;
+        }
+        virtual size_t getGeneratorIndex( std::string const& fileInfo, size_t totalSize ) {
+            return getGeneratorsForCurrentTest()
+            .getGeneratorInfo( fileInfo, totalSize )
+            .getCurrentIndex();
+        }
+        virtual bool advanceGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            return generators && generators->moveNext();
+        }
+
+        virtual Ptr<IConfig const> getConfig() const {
+            return m_config;
+        }
+
+    public: // IMutableContext
+        virtual void setResultCapture( IResultCapture* resultCapture ) {
+            m_resultCapture = resultCapture;
+        }
+        virtual void setRunner( IRunner* runner ) {
+            m_runner = runner;
+        }
+        virtual void setConfig( Ptr<IConfig const> const& config ) {
+            m_config = config;
+        }
+
+        friend IMutableContext& getCurrentMutableContext();
+
+    private:
+        IGeneratorsForTest* findGeneratorsForCurrentTest() {
+            std::string testName = getResultCapture()->getCurrentTestName();
+
+            std::map<std::string, IGeneratorsForTest*>::const_iterator it =
+            m_generatorsByTestName.find( testName );
+            return it != m_generatorsByTestName.end()
+                ? it->second
+                : NULL;
+        }
+
+        IGeneratorsForTest& getGeneratorsForCurrentTest() {
+            IGeneratorsForTest* generators = findGeneratorsForCurrentTest();
+            if( !generators ) {
+                std::string testName = getResultCapture()->getCurrentTestName();
+                generators = createGeneratorsForTest();
+                m_generatorsByTestName.insert( std::make_pair( testName, generators ) );
+            }
+            return *generators;
+        }
+
+    private:
+        Ptr<IConfig const> m_config;
+        IRunner* m_runner;
+        IResultCapture* m_resultCapture;
+        std::map<std::string, IGeneratorsForTest*> m_generatorsByTestName;
+    };
+
+    namespace {
+        Context* currentContext = NULL;
+    }
+    IMutableContext& getCurrentMutableContext() {
+        if( !currentContext )
+            currentContext = new Context();
+        return *currentContext;
+    }
+    IContext& getCurrentContext() {
+        return getCurrentMutableContext();
+    }
+
+    Stream createStream( std::string const& streamName ) {
+        if( streamName == "stdout" ) return Stream( std::cout.rdbuf(), false );
+        if( streamName == "stderr" ) return Stream( std::cerr.rdbuf(), false );
+        if( streamName == "debug" ) return Stream( new StreamBufImpl<OutputDebugWriter>, true );
+
+        throw std::domain_error( "Unknown stream: " + streamName );
+    }
+
+    void cleanUpContext() {
+        delete currentContext;
+        currentContext = NULL;
+    }
+}
+
+// #included from: catch_console_colour_impl.hpp
+#define TWOBLUECUBES_CATCH_CONSOLE_COLOUR_IMPL_HPP_INCLUDED
+
+namespace Catch { namespace Detail {
+    struct IColourImpl {
+        virtual ~IColourImpl() {}
+        virtual void use( Colour::Code _colourCode ) = 0;
+    };
+}}
+
+#if defined ( CATCH_PLATFORM_WINDOWS ) /////////////////////////////////////////
+
+#ifndef NOMINMAX
+#define NOMINMAX
+#endif
+
+#ifdef __AFXDLL
+#include <AfxWin.h>
+#else
+#include <windows.h>
+#endif
+
+namespace Catch {
+namespace {
+
+    class Win32ColourImpl : public Detail::IColourImpl {
+    public:
+        Win32ColourImpl() : stdoutHandle( GetStdHandle(STD_OUTPUT_HANDLE) )
+        {
+            CONSOLE_SCREEN_BUFFER_INFO csbiInfo;
+            GetConsoleScreenBufferInfo( stdoutHandle, &csbiInfo );
+            originalAttributes = csbiInfo.wAttributes;
+        }
+
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:      return setTextAttribute( originalAttributes );
+                case Colour::White:     return setTextAttribute( FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+                case Colour::Red:       return setTextAttribute( FOREGROUND_RED );
+                case Colour::Green:     return setTextAttribute( FOREGROUND_GREEN );
+                case Colour::Blue:      return setTextAttribute( FOREGROUND_BLUE );
+                case Colour::Cyan:      return setTextAttribute( FOREGROUND_BLUE | FOREGROUND_GREEN );
+                case Colour::Yellow:    return setTextAttribute( FOREGROUND_RED | FOREGROUND_GREEN );
+                case Colour::Grey:      return setTextAttribute( 0 );
+
+                case Colour::LightGrey:     return setTextAttribute( FOREGROUND_INTENSITY );
+                case Colour::BrightRed:     return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_RED );
+                case Colour::BrightGreen:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN );
+                case Colour::BrightWhite:   return setTextAttribute( FOREGROUND_INTENSITY | FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+
+    private:
+        void setTextAttribute( WORD _textAttribute ) {
+            SetConsoleTextAttribute( stdoutHandle, _textAttribute );
+        }
+        HANDLE stdoutHandle;
+        WORD originalAttributes;
+    };
+
+    inline bool shouldUseColourForPlatform() {
+        return true;
+    }
+
+    static Detail::IColourImpl* platformColourInstance() {
+        static Win32ColourImpl s_instance;
+        return &s_instance;
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#else // Not Windows - assumed to be POSIX compatible //////////////////////////
+
+#include <unistd.h>
+
+namespace Catch {
+namespace {
+
+    // use POSIX/ ANSI console terminal codes
+    // Thanks to Adam Strzelecki for original contribution
+    // (http://github.com/nanoant)
+    // https://github.com/philsquared/Catch/pull/131
+    class PosixColourImpl : public Detail::IColourImpl {
+    public:
+        virtual void use( Colour::Code _colourCode ) {
+            switch( _colourCode ) {
+                case Colour::None:
+                case Colour::White:     return setColour( "[0m" );
+                case Colour::Red:       return setColour( "[0;31m" );
+                case Colour::Green:     return setColour( "[0;32m" );
+                case Colour::Blue:      return setColour( "[0:34m" );
+                case Colour::Cyan:      return setColour( "[0;36m" );
+                case Colour::Yellow:    return setColour( "[0;33m" );
+                case Colour::Grey:      return setColour( "[1;30m" );
+
+                case Colour::LightGrey:     return setColour( "[0;37m" );
+                case Colour::BrightRed:     return setColour( "[1;31m" );
+                case Colour::BrightGreen:   return setColour( "[1;32m" );
+                case Colour::BrightWhite:   return setColour( "[1;37m" );
+
+                case Colour::Bright: throw std::logic_error( "not a colour" );
+            }
+        }
+    private:
+        void setColour( const char* _escapeCode ) {
+            std::cout << '\033' << _escapeCode;
+        }
+    };
+
+    inline bool shouldUseColourForPlatform() {
+        return isatty(STDOUT_FILENO);
+    }
+
+    static Detail::IColourImpl* platformColourInstance() {
+        static PosixColourImpl s_instance;
+        return &s_instance;
+    }
+
+} // end anon namespace
+} // end namespace Catch
+
+#endif // not Windows
+
+namespace Catch {
+
+    namespace {
+        struct NoColourImpl : Detail::IColourImpl {
+            void use( Colour::Code ) {}
+
+            static IColourImpl* instance() {
+                static NoColourImpl s_instance;
+                return &s_instance;
+            }
+        };
+        static bool shouldUseColour() {
+            return shouldUseColourForPlatform() && !isDebuggerActive();
+        }
+    }
+
+    Colour::Colour( Code _colourCode ) : m_moved( false ) { use( _colourCode ); }
+    Colour::Colour( Colour const& _other ) : m_moved( false ) { const_cast<Colour&>( _other ).m_moved = true; }
+    Colour::~Colour(){ if( !m_moved ) use( None ); }
+    void Colour::use( Code _colourCode ) {
+        impl()->use( _colourCode );
+    }
+
+    Detail::IColourImpl* Colour::impl() {
+        return shouldUseColour()
+            ? platformColourInstance()
+            : NoColourImpl::instance();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_generators_impl.hpp
+#define TWOBLUECUBES_CATCH_GENERATORS_IMPL_HPP_INCLUDED
+
+#include <vector>
+#include <string>
+#include <map>
+
+namespace Catch {
+
+    struct GeneratorInfo : IGeneratorInfo {
+
+        GeneratorInfo( std::size_t size )
+        :   m_size( size ),
+            m_currentIndex( 0 )
+        {}
+
+        bool moveNext() {
+            if( ++m_currentIndex == m_size ) {
+                m_currentIndex = 0;
+                return false;
+            }
+            return true;
+        }
+
+        std::size_t getCurrentIndex() const {
+            return m_currentIndex;
+        }
+
+        std::size_t m_size;
+        std::size_t m_currentIndex;
+    };
+
+    ///////////////////////////////////////////////////////////////////////////
+
+    class GeneratorsForTest : public IGeneratorsForTest {
+
+    public:
+        ~GeneratorsForTest() {
+            deleteAll( m_generatorsInOrder );
+        }
+
+        IGeneratorInfo& getGeneratorInfo( std::string const& fileInfo, std::size_t size ) {
+            std::map<std::string, IGeneratorInfo*>::const_iterator it = m_generatorsByName.find( fileInfo );
+            if( it == m_generatorsByName.end() ) {
+                IGeneratorInfo* info = new GeneratorInfo( size );
+                m_generatorsByName.insert( std::make_pair( fileInfo, info ) );
+                m_generatorsInOrder.push_back( info );
+                return *info;
+            }
+            return *it->second;
+        }
+
+        bool moveNext() {
+            std::vector<IGeneratorInfo*>::const_iterator it = m_generatorsInOrder.begin();
+            std::vector<IGeneratorInfo*>::const_iterator itEnd = m_generatorsInOrder.end();
+            for(; it != itEnd; ++it ) {
+                if( (*it)->moveNext() )
+                    return true;
+            }
+            return false;
+        }
+
+    private:
+        std::map<std::string, IGeneratorInfo*> m_generatorsByName;
+        std::vector<IGeneratorInfo*> m_generatorsInOrder;
+    };
+
+    IGeneratorsForTest* createGeneratorsForTest()
+    {
+        return new GeneratorsForTest();
+    }
+
+} // end namespace Catch
+
+// #included from: catch_assertionresult.hpp
+#define TWOBLUECUBES_CATCH_ASSERTIONRESULT_HPP_INCLUDED
+
+namespace Catch {
+
+    AssertionInfo::AssertionInfo(   std::string const& _macroName,
+                                    SourceLineInfo const& _lineInfo,
+                                    std::string const& _capturedExpression,
+                                    ResultDisposition::Flags _resultDisposition )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        capturedExpression( _capturedExpression ),
+        resultDisposition( _resultDisposition )
+    {}
+
+    AssertionResult::AssertionResult() {}
+
+    AssertionResult::AssertionResult( AssertionInfo const& info, AssertionResultData const& data )
+    :   m_info( info ),
+        m_resultData( data )
+    {}
+
+    AssertionResult::~AssertionResult() {}
+
+    // Result was a success
+    bool AssertionResult::succeeded() const {
+        return Catch::isOk( m_resultData.resultType );
+    }
+
+    // Result was a success, or failure is suppressed
+    bool AssertionResult::isOk() const {
+        return Catch::isOk( m_resultData.resultType ) || shouldSuppressFailure( m_info.resultDisposition );
+    }
+
+    ResultWas::OfType AssertionResult::getResultType() const {
+        return m_resultData.resultType;
+    }
+
+    bool AssertionResult::hasExpression() const {
+        return !m_info.capturedExpression.empty();
+    }
+
+    bool AssertionResult::hasMessage() const {
+        return !m_resultData.message.empty();
+    }
+
+    std::string AssertionResult::getExpression() const {
+        if( isFalseTest( m_info.resultDisposition ) )
+            return "!" + m_info.capturedExpression;
+        else
+            return m_info.capturedExpression;
+    }
+    std::string AssertionResult::getExpressionInMacro() const {
+        if( m_info.macroName.empty() )
+            return m_info.capturedExpression;
+        else
+            return m_info.macroName + "( " + m_info.capturedExpression + " )";
+    }
+
+    bool AssertionResult::hasExpandedExpression() const {
+        return hasExpression() && getExpandedExpression() != getExpression();
+    }
+
+    std::string AssertionResult::getExpandedExpression() const {
+        return m_resultData.reconstructedExpression;
+    }
+
+    std::string AssertionResult::getMessage() const {
+        return m_resultData.message;
+    }
+    SourceLineInfo AssertionResult::getSourceInfo() const {
+        return m_info.lineInfo;
+    }
+
+    std::string AssertionResult::getTestMacroName() const {
+        return m_info.macroName;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_test_case_info.hpp
+#define TWOBLUECUBES_CATCH_TEST_CASE_INFO_HPP_INCLUDED
+
+namespace Catch {
+
+    inline TestCaseInfo::SpecialProperties parseSpecialTag( std::string const& tag ) {
+        if( tag == "." ||
+            tag == "hide" ||
+            tag == "!hide" )
+            return TestCaseInfo::IsHidden;
+        else if( tag == "!throws" )
+            return TestCaseInfo::Throws;
+        else if( tag == "!shouldfail" )
+            return TestCaseInfo::ShouldFail;
+        else if( tag == "!mayfail" )
+            return TestCaseInfo::MayFail;
+        else
+            return TestCaseInfo::None;
+    }
+    inline bool isReservedTag( std::string const& tag ) {
+        return parseSpecialTag( tag ) == TestCaseInfo::None && tag.size() > 0 && !isalnum( tag[0] );
+    }
+    inline void enforceNotReservedTag( std::string const& tag, SourceLineInfo const& _lineInfo ) {
+        if( isReservedTag( tag ) ) {
+            {
+                Colour colourGuard( Colour::Red );
+                std::cerr
+                    << "Tag name [" << tag << "] not allowed.\n"
+                    << "Tag names starting with non alpha-numeric characters are reserved\n";
+            }
+            {
+                Colour colourGuard( Colour::FileName );
+                std::cerr << _lineInfo << std::endl;
+            }
+            exit(1);
+        }
+    }
+
+    TestCase makeTestCase(  ITestCase* _testCase,
+                            std::string const& _className,
+                            std::string const& _name,
+                            std::string const& _descOrTags,
+                            SourceLineInfo const& _lineInfo )
+    {
+        bool isHidden( startsWith( _name, "./" ) ); // Legacy support
+
+        // Parse out tags
+        std::set<std::string> tags;
+        std::string desc, tag;
+        bool inTag = false;
+        for( std::size_t i = 0; i < _descOrTags.size(); ++i ) {
+            char c = _descOrTags[i];
+            if( !inTag ) {
+                if( c == '[' )
+                    inTag = true;
+                else
+                    desc += c;
+            }
+            else {
+                if( c == ']' ) {
+                    enforceNotReservedTag( tag, _lineInfo );
+
+                    inTag = false;
+                    if( tag == "hide" || tag == "." )
+                        isHidden = true;
+                    else
+                        tags.insert( tag );
+                    tag.clear();
+                }
+                else
+                    tag += c;
+            }
+        }
+        if( isHidden ) {
+            tags.insert( "hide" );
+            tags.insert( "." );
+        }
+
+        TestCaseInfo info( _name, _className, desc, tags, _lineInfo );
+        return TestCase( _testCase, info );
+    }
+
+    TestCaseInfo::TestCaseInfo( std::string const& _name,
+                                std::string const& _className,
+                                std::string const& _description,
+                                std::set<std::string> const& _tags,
+                                SourceLineInfo const& _lineInfo )
+    :   name( _name ),
+        className( _className ),
+        description( _description ),
+        tags( _tags ),
+        lineInfo( _lineInfo ),
+        properties( None )
+    {
+        std::ostringstream oss;
+        for( std::set<std::string>::const_iterator it = _tags.begin(), itEnd = _tags.end(); it != itEnd; ++it ) {
+            oss << "[" << *it << "]";
+            std::string lcaseTag = toLower( *it );
+            properties = static_cast<SpecialProperties>( properties | parseSpecialTag( lcaseTag ) );
+            lcaseTags.insert( lcaseTag );
+        }
+        tagsAsString = oss.str();
+    }
+
+    TestCaseInfo::TestCaseInfo( TestCaseInfo const& other )
+    :   name( other.name ),
+        className( other.className ),
+        description( other.description ),
+        tags( other.tags ),
+        lcaseTags( other.lcaseTags ),
+        tagsAsString( other.tagsAsString ),
+        lineInfo( other.lineInfo ),
+        properties( other.properties )
+    {}
+
+    bool TestCaseInfo::isHidden() const {
+        return ( properties & IsHidden ) != 0;
+    }
+    bool TestCaseInfo::throws() const {
+        return ( properties & Throws ) != 0;
+    }
+    bool TestCaseInfo::okToFail() const {
+        return ( properties & (ShouldFail | MayFail ) ) != 0;
+    }
+    bool TestCaseInfo::expectedToFail() const {
+        return ( properties & (ShouldFail ) ) != 0;
+    }
+
+    TestCase::TestCase( ITestCase* testCase, TestCaseInfo const& info ) : TestCaseInfo( info ), test( testCase ) {}
+
+    TestCase::TestCase( TestCase const& other )
+    :   TestCaseInfo( other ),
+        test( other.test )
+    {}
+
+    TestCase TestCase::withName( std::string const& _newName ) const {
+        TestCase other( *this );
+        other.name = _newName;
+        return other;
+    }
+
+    void TestCase::swap( TestCase& other ) {
+        test.swap( other.test );
+        name.swap( other.name );
+        className.swap( other.className );
+        description.swap( other.description );
+        tags.swap( other.tags );
+        lcaseTags.swap( other.lcaseTags );
+        tagsAsString.swap( other.tagsAsString );
+        std::swap( TestCaseInfo::properties, static_cast<TestCaseInfo&>( other ).properties );
+        std::swap( lineInfo, other.lineInfo );
+    }
+
+    void TestCase::invoke() const {
+        test->invoke();
+    }
+
+    bool TestCase::operator == ( TestCase const& other ) const {
+        return  test.get() == other.test.get() &&
+                name == other.name &&
+                className == other.className;
+    }
+
+    bool TestCase::operator < ( TestCase const& other ) const {
+        return name < other.name;
+    }
+    TestCase& TestCase::operator = ( TestCase const& other ) {
+        TestCase temp( other );
+        swap( temp );
+        return *this;
+    }
+
+    TestCaseInfo const& TestCase::getTestCaseInfo() const
+    {
+        return *this;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_version.hpp
+#define TWOBLUECUBES_CATCH_VERSION_HPP_INCLUDED
+
+namespace Catch {
+
+    // These numbers are maintained by a script
+    Version libraryVersion( 1, 0, 53, "master" );
+}
+
+// #included from: catch_message.hpp
+#define TWOBLUECUBES_CATCH_MESSAGE_HPP_INCLUDED
+
+namespace Catch {
+
+    MessageInfo::MessageInfo(   std::string const& _macroName,
+                                SourceLineInfo const& _lineInfo,
+                                ResultWas::OfType _type )
+    :   macroName( _macroName ),
+        lineInfo( _lineInfo ),
+        type( _type ),
+        sequence( ++globalCount )
+    {}
+
+    // This may need protecting if threading support is added
+    unsigned int MessageInfo::globalCount = 0;
+
+    ////////////////////////////////////////////////////////////////////////////
+
+    ScopedMessage::ScopedMessage( MessageBuilder const& builder )
+    : m_info( builder.m_info )
+    {
+        m_info.message = builder.m_stream.str();
+        getResultCapture().pushScopedMessage( m_info );
+    }
+    ScopedMessage::ScopedMessage( ScopedMessage const& other )
+    : m_info( other.m_info )
+    {}
+
+    ScopedMessage::~ScopedMessage() {
+        getResultCapture().popScopedMessage( m_info );
+    }
+
+} // end namespace Catch
+
+// #included from: catch_legacy_reporter_adapter.hpp
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_HPP_INCLUDED
+
+// #included from: catch_legacy_reporter_adapter.h
+#define TWOBLUECUBES_CATCH_LEGACY_REPORTER_ADAPTER_H_INCLUDED
+
+namespace Catch
+{
+    // Deprecated
+    struct IReporter : IShared {
+        virtual ~IReporter();
+
+        virtual bool shouldRedirectStdout() const = 0;
+
+        virtual void StartTesting() = 0;
+        virtual void EndTesting( Totals const& totals ) = 0;
+        virtual void StartGroup( std::string const& groupName ) = 0;
+        virtual void EndGroup( std::string const& groupName, Totals const& totals ) = 0;
+        virtual void StartTestCase( TestCaseInfo const& testInfo ) = 0;
+        virtual void EndTestCase( TestCaseInfo const& testInfo, Totals const& totals, std::string const& stdOut, std::string const& stdErr ) = 0;
+        virtual void StartSection( std::string const& sectionName, std::string const& description ) = 0;
+        virtual void EndSection( std::string const& sectionName, Counts const& assertions ) = 0;
+        virtual void NoAssertionsInSection( std::string const& sectionName ) = 0;
+        virtual void NoAssertionsInTestCase( std::string const& testName ) = 0;
+        virtual void Aborted() = 0;
+        virtual void Result( AssertionResult const& result ) = 0;
+    };
+
+    class LegacyReporterAdapter : public SharedImpl<IStreamingReporter>
+    {
+    public:
+        LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter );
+        virtual ~LegacyReporterAdapter();
+
+        virtual ReporterPreferences getPreferences() const;
+        virtual void noMatchingTestCases( std::string const& );
+        virtual void testRunStarting( TestRunInfo const& );
+        virtual void testGroupStarting( GroupInfo const& groupInfo );
+        virtual void testCaseStarting( TestCaseInfo const& testInfo );
+        virtual void sectionStarting( SectionInfo const& sectionInfo );
+        virtual void assertionStarting( AssertionInfo const& );
+        virtual bool assertionEnded( AssertionStats const& assertionStats );
+        virtual void sectionEnded( SectionStats const& sectionStats );
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats );
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats );
+        virtual void testRunEnded( TestRunStats const& testRunStats );
+
+    private:
+        Ptr<IReporter> m_legacyReporter;
+    };
+}
+
+namespace Catch
+{
+    LegacyReporterAdapter::LegacyReporterAdapter( Ptr<IReporter> const& legacyReporter )
+    :   m_legacyReporter( legacyReporter )
+    {}
+    LegacyReporterAdapter::~LegacyReporterAdapter() {}
+
+    ReporterPreferences LegacyReporterAdapter::getPreferences() const {
+        ReporterPreferences prefs;
+        prefs.shouldRedirectStdOut = m_legacyReporter->shouldRedirectStdout();
+        return prefs;
+    }
+
+    void LegacyReporterAdapter::noMatchingTestCases( std::string const& ) {}
+    void LegacyReporterAdapter::testRunStarting( TestRunInfo const& ) {
+        m_legacyReporter->StartTesting();
+    }
+    void LegacyReporterAdapter::testGroupStarting( GroupInfo const& groupInfo ) {
+        m_legacyReporter->StartGroup( groupInfo.name );
+    }
+    void LegacyReporterAdapter::testCaseStarting( TestCaseInfo const& testInfo ) {
+        m_legacyReporter->StartTestCase( testInfo );
+    }
+    void LegacyReporterAdapter::sectionStarting( SectionInfo const& sectionInfo ) {
+        m_legacyReporter->StartSection( sectionInfo.name, sectionInfo.description );
+    }
+    void LegacyReporterAdapter::assertionStarting( AssertionInfo const& ) {
+        // Not on legacy interface
+    }
+
+    bool LegacyReporterAdapter::assertionEnded( AssertionStats const& assertionStats ) {
+        if( assertionStats.assertionResult.getResultType() != ResultWas::Ok ) {
+            for( std::vector<MessageInfo>::const_iterator it = assertionStats.infoMessages.begin(), itEnd = assertionStats.infoMessages.end();
+                    it != itEnd;
+                    ++it ) {
+                if( it->type == ResultWas::Info ) {
+                    ResultBuilder rb( it->macroName.c_str(), it->lineInfo, "", ResultDisposition::Normal );
+                    rb << it->message;
+                    rb.setResultType( ResultWas::Info );
+                    AssertionResult result = rb.build();
+                    m_legacyReporter->Result( result );
+                }
+            }
+        }
+        m_legacyReporter->Result( assertionStats.assertionResult );
+        return true;
+    }
+    void LegacyReporterAdapter::sectionEnded( SectionStats const& sectionStats ) {
+        if( sectionStats.missingAssertions )
+            m_legacyReporter->NoAssertionsInSection( sectionStats.sectionInfo.name );
+        m_legacyReporter->EndSection( sectionStats.sectionInfo.name, sectionStats.assertions );
+    }
+    void LegacyReporterAdapter::testCaseEnded( TestCaseStats const& testCaseStats ) {
+        m_legacyReporter->EndTestCase
+            (   testCaseStats.testInfo,
+                testCaseStats.totals,
+                testCaseStats.stdOut,
+                testCaseStats.stdErr );
+    }
+    void LegacyReporterAdapter::testGroupEnded( TestGroupStats const& testGroupStats ) {
+        if( testGroupStats.aborting )
+            m_legacyReporter->Aborted();
+        m_legacyReporter->EndGroup( testGroupStats.groupInfo.name, testGroupStats.totals );
+    }
+    void LegacyReporterAdapter::testRunEnded( TestRunStats const& testRunStats ) {
+        m_legacyReporter->EndTesting( testRunStats.totals );
+    }
+}
+
+// #included from: catch_timer.hpp
+
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wc++11-long-long"
+#endif
+
+#ifdef CATCH_PLATFORM_WINDOWS
+#include <windows.h>
+#else
+#include <sys/time.h>
+#endif
+
+namespace Catch {
+
+    namespace {
+#ifdef CATCH_PLATFORM_WINDOWS
+        uint64_t getCurrentTicks() {
+            static uint64_t hz=0, hzo=0;
+            if (!hz) {
+                QueryPerformanceFrequency((LARGE_INTEGER*)&hz);
+                QueryPerformanceCounter((LARGE_INTEGER*)&hzo);
+            }
+            uint64_t t;
+            QueryPerformanceCounter((LARGE_INTEGER*)&t);
+            return ((t-hzo)*1000000)/hz;
+        }
+#else
+        uint64_t getCurrentTicks() {
+            timeval t;
+            gettimeofday(&t,NULL);
+            return static_cast<uint64_t>( t.tv_sec ) * 1000000ull + static_cast<uint64_t>( t.tv_usec );
+        }
+#endif
+    }
+
+    void Timer::start() {
+        m_ticks = getCurrentTicks();
+    }
+    unsigned int Timer::getElapsedNanoseconds() const {
+        return static_cast<unsigned int>(getCurrentTicks() - m_ticks);
+    }
+    unsigned int Timer::getElapsedMilliseconds() const {
+        return static_cast<unsigned int>((getCurrentTicks() - m_ticks)/1000);
+    }
+    double Timer::getElapsedSeconds() const {
+        return (getCurrentTicks() - m_ticks)/1000000.0;
+    }
+
+} // namespace Catch
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+// #included from: catch_common.hpp
+#define TWOBLUECUBES_CATCH_COMMON_HPP_INCLUDED
+
+namespace Catch {
+
+    bool startsWith( std::string const& s, std::string const& prefix ) {
+        return s.size() >= prefix.size() && s.substr( 0, prefix.size() ) == prefix;
+    }
+    bool endsWith( std::string const& s, std::string const& suffix ) {
+        return s.size() >= suffix.size() && s.substr( s.size()-suffix.size(), suffix.size() ) == suffix;
+    }
+    bool contains( std::string const& s, std::string const& infix ) {
+        return s.find( infix ) != std::string::npos;
+    }
+    void toLowerInPlace( std::string& s ) {
+        std::transform( s.begin(), s.end(), s.begin(), ::tolower );
+    }
+    std::string toLower( std::string const& s ) {
+        std::string lc = s;
+        toLowerInPlace( lc );
+        return lc;
+    }
+    std::string trim( std::string const& str ) {
+        static char const* whitespaceChars = "\n\r\t ";
+        std::string::size_type start = str.find_first_not_of( whitespaceChars );
+        std::string::size_type end = str.find_last_not_of( whitespaceChars );
+
+        return start != std::string::npos ? str.substr( start, 1+end-start ) : "";
+    }
+
+    pluralise::pluralise( std::size_t count, std::string const& label )
+    :   m_count( count ),
+        m_label( label )
+    {}
+
+    std::ostream& operator << ( std::ostream& os, pluralise const& pluraliser ) {
+        os << pluraliser.m_count << " " << pluraliser.m_label;
+        if( pluraliser.m_count != 1 )
+            os << "s";
+        return os;
+    }
+
+    SourceLineInfo::SourceLineInfo() : line( 0 ){}
+    SourceLineInfo::SourceLineInfo( char const* _file, std::size_t _line )
+    :   file( _file ),
+        line( _line )
+    {}
+    SourceLineInfo::SourceLineInfo( SourceLineInfo const& other )
+    :   file( other.file ),
+        line( other.line )
+    {}
+    bool SourceLineInfo::empty() const {
+        return file.empty();
+    }
+    bool SourceLineInfo::operator == ( SourceLineInfo const& other ) const {
+        return line == other.line && file == other.file;
+    }
+
+    std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ) {
+#ifndef __GNUG__
+        os << info.file << "(" << info.line << ")";
+#else
+        os << info.file << ":" << info.line;
+#endif
+        return os;
+    }
+
+    void throwLogicError( std::string const& message, SourceLineInfo const& locationInfo ) {
+        std::ostringstream oss;
+        oss << locationInfo << ": Internal Catch error: '" << message << "'";
+        if( alwaysTrue() )
+            throw std::logic_error( oss.str() );
+    }
+}
+
+// #included from: catch_section.hpp
+#define TWOBLUECUBES_CATCH_SECTION_HPP_INCLUDED
+
+namespace Catch {
+
+    SectionInfo::SectionInfo
+        (   SourceLineInfo const& _lineInfo,
+            std::string const& _name,
+            std::string const& _description )
+    :   name( _name ),
+        description( _description ),
+        lineInfo( _lineInfo )
+    {}
+
+    Section::Section( SectionInfo const& info )
+    :   m_info( info ),
+        m_sectionIncluded( getResultCapture().sectionStarted( m_info, m_assertions ) )
+    {
+        m_timer.start();
+    }
+
+    Section::~Section() {
+        if( m_sectionIncluded )
+            getResultCapture().sectionEnded( m_info, m_assertions, m_timer.getElapsedSeconds() );
+    }
+
+    // This indicates whether the section should be executed or not
+    Section::operator bool() const {
+        return m_sectionIncluded;
+    }
+
+} // end namespace Catch
+
+// #included from: catch_debugger.hpp
+#define TWOBLUECUBES_CATCH_DEBUGGER_HPP_INCLUDED
+
+#include <iostream>
+
+#ifdef CATCH_PLATFORM_MAC
+
+    #include <assert.h>
+    #include <stdbool.h>
+    #include <sys/types.h>
+    #include <unistd.h>
+    #include <sys/sysctl.h>
+
+    namespace Catch{
+
+        // The following function is taken directly from the following technical note:
+        // http://developer.apple.com/library/mac/#qa/qa2004/qa1361.html
+
+        // Returns true if the current process is being debugged (either
+        // running under the debugger or has a debugger attached post facto).
+        bool isDebuggerActive(){
+
+            int                 mib[4];
+            struct kinfo_proc   info;
+            size_t              size;
+
+            // Initialize the flags so that, if sysctl fails for some bizarre
+            // reason, we get a predictable result.
+
+            info.kp_proc.p_flag = 0;
+
+            // Initialize mib, which tells sysctl the info we want, in this case
+            // we're looking for information about a specific process ID.
+
+            mib[0] = CTL_KERN;
+            mib[1] = KERN_PROC;
+            mib[2] = KERN_PROC_PID;
+            mib[3] = getpid();
+
+            // Call sysctl.
+
+            size = sizeof(info);
+            if( sysctl(mib, sizeof(mib) / sizeof(*mib), &info, &size, NULL, 0) != 0 ) {
+                std::cerr << "\n** Call to sysctl failed - unable to determine if debugger is active **\n" << std::endl;
+                return false;
+            }
+
+            // We're being debugged if the P_TRACED flag is set.
+
+            return ( (info.kp_proc.p_flag & P_TRACED) != 0 );
+        }
+    } // namespace Catch
+
+#elif defined(_MSC_VER)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#elif defined(__MINGW32__)
+    extern "C" __declspec(dllimport) int __stdcall IsDebuggerPresent();
+    namespace Catch {
+        bool isDebuggerActive() {
+            return IsDebuggerPresent() != 0;
+        }
+    }
+#else
+    namespace Catch {
+       inline bool isDebuggerActive() { return false; }
+    }
+#endif // Platform
+
+#ifdef CATCH_PLATFORM_WINDOWS
+    extern "C" __declspec(dllimport) void __stdcall OutputDebugStringA( const char* );
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            ::OutputDebugStringA( text.c_str() );
+        }
+    }
+#else
+    namespace Catch {
+        void writeToDebugConsole( std::string const& text ) {
+            // !TBD: Need a version for Mac/ XCode and other IDEs
+            std::cout << text;
+        }
+    }
+#endif // Platform
+
+// #included from: catch_tostring.hpp
+#define TWOBLUECUBES_CATCH_TOSTRING_HPP_INCLUDED
+
+namespace Catch {
+
+namespace Detail {
+
+    namespace {
+        struct Endianness {
+            enum Arch { Big, Little };
+
+            static Arch which() {
+                union _{
+                    int asInt;
+                    char asChar[sizeof (int)];
+                } u;
+
+                u.asInt = 1;
+                return ( u.asChar[sizeof(int)-1] == 1 ) ? Big : Little;
+            }
+        };
+    }
+
+    std::string rawMemoryToString( const void *object, std::size_t size )
+    {
+        // Reverse order for little endian architectures
+        int i = 0, end = static_cast<int>( size ), inc = 1;
+        if( Endianness::which() == Endianness::Little ) {
+            i = end-1;
+            end = inc = -1;
+        }
+
+        unsigned char const *bytes = static_cast<unsigned char const *>(object);
+        std::ostringstream os;
+        os << "0x" << std::setfill('0') << std::hex;
+        for( ; i != end; i += inc )
+             os << std::setw(2) << static_cast<unsigned>(bytes[i]);
+       return os.str();
+    }
+}
+
+std::string toString( std::string const& value ) {
+    std::string s = value;
+    if( getCurrentContext().getConfig()->showInvisibles() ) {
+        for(size_t i = 0; i < s.size(); ++i ) {
+            std::string subs;
+            switch( s[i] ) {
+            case '\n': subs = "\\n"; break;
+            case '\t': subs = "\\t"; break;
+            default: break;
+            }
+            if( !subs.empty() ) {
+                s = s.substr( 0, i ) + subs + s.substr( i+1 );
+                ++i;
+            }
+        }
+    }
+    return "\"" + s + "\"";
+}
+std::string toString( std::wstring const& value ) {
+
+    std::string s;
+    s.reserve( value.size() );
+    for(size_t i = 0; i < value.size(); ++i )
+        s += value[i] <= 0xff ? static_cast<char>( value[i] ) : '?';
+    return toString( s );
+}
+
+std::string toString( const char* const value ) {
+    return value ? Catch::toString( std::string( value ) ) : std::string( "{null string}" );
+}
+
+std::string toString( char* const value ) {
+    return Catch::toString( static_cast<const char*>( value ) );
+}
+
+std::string toString( const wchar_t* const value )
+{
+       return value ? Catch::toString( std::wstring(value) ) : std::string( "{null string}" );
+}
+
+std::string toString( wchar_t* const value )
+{
+       return Catch::toString( static_cast<const wchar_t*>( value ) );
+}
+
+std::string toString( int value ) {
+    std::ostringstream oss;
+    oss << value;
+    return oss.str();
+}
+
+std::string toString( unsigned long value ) {
+    std::ostringstream oss;
+    if( value > 8192 )
+        oss << "0x" << std::hex << value;
+    else
+        oss << value;
+    return oss.str();
+}
+
+std::string toString( unsigned int value ) {
+    return toString( static_cast<unsigned long>( value ) );
+}
+
+template<typename T>
+std::string fpToString( T value, int precision ) {
+    std::ostringstream oss;
+    oss << std::setprecision( precision )
+        << std::fixed
+        << value;
+    std::string d = oss.str();
+    std::size_t i = d.find_last_not_of( '0' );
+    if( i != std::string::npos && i != d.size()-1 ) {
+        if( d[i] == '.' )
+            i++;
+        d = d.substr( 0, i+1 );
+    }
+    return d;
+}
+
+std::string toString( const double value ) {
+    return fpToString( value, 10 );
+}
+std::string toString( const float value ) {
+    return fpToString( value, 5 ) + "f";
+}
+
+std::string toString( bool value ) {
+    return value ? "true" : "false";
+}
+
+std::string toString( char value ) {
+    return value < ' '
+        ? toString( static_cast<unsigned int>( value ) )
+        : Detail::makeString( value );
+}
+
+std::string toString( signed char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+std::string toString( unsigned char value ) {
+    return toString( static_cast<char>( value ) );
+}
+
+#ifdef CATCH_CONFIG_CPP11_NULLPTR
+std::string toString( std::nullptr_t ) {
+    return "nullptr";
+}
+#endif
+
+#ifdef __OBJC__
+    std::string toString( NSString const * const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSString * CATCH_ARC_STRONG const& nsstring ) {
+        if( !nsstring )
+            return "nil";
+        return "@" + toString([nsstring UTF8String]);
+    }
+    std::string toString( NSObject* const& nsObject ) {
+        return toString( [nsObject description] );
+    }
+#endif
+
+} // end namespace Catch
+
+// #included from: catch_result_builder.hpp
+#define TWOBLUECUBES_CATCH_RESULT_BUILDER_HPP_INCLUDED
+
+namespace Catch {
+
+    ResultBuilder::ResultBuilder(   char const* macroName,
+                                    SourceLineInfo const& lineInfo,
+                                    char const* capturedExpression,
+                                    ResultDisposition::Flags resultDisposition )
+    :   m_assertionInfo( macroName, lineInfo, capturedExpression, resultDisposition ),
+        m_shouldDebugBreak( false ),
+        m_shouldThrow( false )
+    {}
+
+    ResultBuilder& ResultBuilder::setResultType( ResultWas::OfType result ) {
+        m_data.resultType = result;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setResultType( bool result ) {
+        m_data.resultType = result ? ResultWas::Ok : ResultWas::ExpressionFailed;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setLhs( std::string const& lhs ) {
+        m_exprComponents.lhs = lhs;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setRhs( std::string const& rhs ) {
+        m_exprComponents.rhs = rhs;
+        return *this;
+    }
+    ResultBuilder& ResultBuilder::setOp( std::string const& op ) {
+        m_exprComponents.op = op;
+        return *this;
+    }
+
+    void ResultBuilder::endExpression() {
+        m_exprComponents.testFalse = isFalseTest( m_assertionInfo.resultDisposition );
+        captureExpression();
+    }
+
+    void ResultBuilder::useActiveException( ResultDisposition::Flags resultDisposition ) {
+        m_assertionInfo.resultDisposition = resultDisposition;
+        m_stream.oss << Catch::translateActiveException();
+        captureResult( ResultWas::ThrewException );
+    }
+
+    void ResultBuilder::captureResult( ResultWas::OfType resultType ) {
+        setResultType( resultType );
+        captureExpression();
+    }
+
+    void ResultBuilder::captureExpression() {
+        AssertionResult result = build();
+        getResultCapture().assertionEnded( result );
+
+        if( !result.isOk() ) {
+            if( getCurrentContext().getConfig()->shouldDebugBreak() )
+                m_shouldDebugBreak = true;
+            if( getCurrentContext().getRunner()->aborting() || m_assertionInfo.resultDisposition == ResultDisposition::Normal )
+                m_shouldThrow = true;
+        }
+    }
+    void ResultBuilder::react() {
+        if( m_shouldThrow )
+            throw Catch::TestFailureException();
+    }
+
+    bool ResultBuilder::shouldDebugBreak() const { return m_shouldDebugBreak; }
+    bool ResultBuilder::allowThrows() const { return getCurrentContext().getConfig()->allowThrows(); }
+
+    AssertionResult ResultBuilder::build() const
+    {
+        assert( m_data.resultType != ResultWas::Unknown );
+
+        AssertionResultData data = m_data;
+
+        // Flip bool results if testFalse is set
+        if( m_exprComponents.testFalse ) {
+            if( data.resultType == ResultWas::Ok )
+                data.resultType = ResultWas::ExpressionFailed;
+            else if( data.resultType == ResultWas::ExpressionFailed )
+                data.resultType = ResultWas::Ok;
+        }
+
+        data.message = m_stream.oss.str();
+        data.reconstructedExpression = reconstructExpression();
+        if( m_exprComponents.testFalse ) {
+            if( m_exprComponents.op == "" )
+                data.reconstructedExpression = "!" + data.reconstructedExpression;
+            else
+                data.reconstructedExpression = "!(" + data.reconstructedExpression + ")";
+        }
+        return AssertionResult( m_assertionInfo, data );
+    }
+    std::string ResultBuilder::reconstructExpression() const {
+        if( m_exprComponents.op == "" )
+            return m_exprComponents.lhs.empty() ? m_assertionInfo.capturedExpression : m_exprComponents.op + m_exprComponents.lhs;
+        else if( m_exprComponents.op == "matches" )
+            return m_exprComponents.lhs + " " + m_exprComponents.rhs;
+        else if( m_exprComponents.op != "!" ) {
+            if( m_exprComponents.lhs.size() + m_exprComponents.rhs.size() < 40 &&
+                m_exprComponents.lhs.find("\n") == std::string::npos &&
+                m_exprComponents.rhs.find("\n") == std::string::npos )
+                return m_exprComponents.lhs + " " + m_exprComponents.op + " " + m_exprComponents.rhs;
+            else
+                return m_exprComponents.lhs + "\n" + m_exprComponents.op + "\n" + m_exprComponents.rhs;
+        }
+        else
+            return "{can't expand - use " + m_assertionInfo.macroName + "_FALSE( " + m_assertionInfo.capturedExpression.substr(1) + " ) instead of " + m_assertionInfo.macroName + "( " + m_assertionInfo.capturedExpression + " ) for better diagnostics}";
+    }
+
+} // end namespace Catch
+
+// #included from: catch_tag_alias_registry.hpp
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_HPP_INCLUDED
+
+// #included from: catch_tag_alias_registry.h
+#define TWOBLUECUBES_CATCH_TAG_ALIAS_REGISTRY_H_INCLUDED
+
+#include <map>
+
+namespace Catch {
+
+    class TagAliasRegistry : public ITagAliasRegistry {
+    public:
+        virtual ~TagAliasRegistry();
+        virtual Option<TagAlias> find( std::string const& alias ) const;
+        virtual std::string expandAliases( std::string const& unexpandedTestSpec ) const;
+        void add( char const* alias, char const* tag, SourceLineInfo const& lineInfo );
+        static TagAliasRegistry& get();
+
+    private:
+        std::map<std::string, TagAlias> m_registry;
+    };
+
+} // end namespace Catch
+
+#include <map>
+#include <iostream>
+
+namespace Catch {
+
+    TagAliasRegistry::~TagAliasRegistry() {}
+
+    Option<TagAlias> TagAliasRegistry::find( std::string const& alias ) const {
+        std::map<std::string, TagAlias>::const_iterator it = m_registry.find( alias );
+        if( it != m_registry.end() )
+            return it->second;
+        else
+            return Option<TagAlias>();
+    }
+
+    std::string TagAliasRegistry::expandAliases( std::string const& unexpandedTestSpec ) const {
+        std::string expandedTestSpec = unexpandedTestSpec;
+        for( std::map<std::string, TagAlias>::const_iterator it = m_registry.begin(), itEnd = m_registry.end();
+                it != itEnd;
+                ++it ) {
+            std::size_t pos = expandedTestSpec.find( it->first );
+            if( pos != std::string::npos ) {
+                expandedTestSpec =  expandedTestSpec.substr( 0, pos ) +
+                                    it->second.tag +
+                                    expandedTestSpec.substr( pos + it->first.size() );
+            }
+        }
+        return expandedTestSpec;
+    }
+
+    void TagAliasRegistry::add( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+
+        if( !startsWith( alias, "[@" ) || !endsWith( alias, "]" ) ) {
+            std::ostringstream oss;
+            oss << "error: tag alias, \"" << alias << "\" is not of the form [@alias name].\n" << lineInfo;
+            throw std::domain_error( oss.str().c_str() );
+        }
+        if( !m_registry.insert( std::make_pair( alias, TagAlias( tag, lineInfo ) ) ).second ) {
+            std::ostringstream oss;
+            oss << "error: tag alias, \"" << alias << "\" already registered.\n"
+                << "\tFirst seen at " << find(alias)->lineInfo << "\n"
+                << "\tRedefined at " << lineInfo;
+            throw std::domain_error( oss.str().c_str() );
+        }
+    }
+
+    TagAliasRegistry& TagAliasRegistry::get() {
+        static TagAliasRegistry instance;
+        return instance;
+
+    }
+
+    ITagAliasRegistry::~ITagAliasRegistry() {}
+    ITagAliasRegistry const& ITagAliasRegistry::get() { return TagAliasRegistry::get(); }
+
+    RegistrarForTagAliases::RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ) {
+        try {
+            TagAliasRegistry::get().add( alias, tag, lineInfo );
+        }
+        catch( std::exception& ex ) {
+            Colour colourGuard( Colour::Red );
+            std::cerr << ex.what() << std::endl;
+            exit(1);
+        }
+    }
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_xml.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_XML_HPP_INCLUDED
+
+// #included from: catch_reporter_bases.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_BASES_HPP_INCLUDED
+
+namespace Catch {
+
+    struct StreamingReporterBase : SharedImpl<IStreamingReporter> {
+
+        StreamingReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+
+        virtual ~StreamingReporterBase();
+
+        virtual void noMatchingTestCases( std::string const& ) {}
+
+        virtual void testRunStarting( TestRunInfo const& _testRunInfo ) {
+            currentTestRunInfo = _testRunInfo;
+        }
+        virtual void testGroupStarting( GroupInfo const& _groupInfo ) {
+            currentGroupInfo = _groupInfo;
+        }
+
+        virtual void testCaseStarting( TestCaseInfo const& _testInfo ) {
+            currentTestCaseInfo = _testInfo;
+        }
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
+            m_sectionStack.push_back( _sectionInfo );
+        }
+
+        virtual void sectionEnded( SectionStats const& /* _sectionStats */ ) {
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& /* _testCaseStats */ ) {
+            currentTestCaseInfo.reset();
+            assert( m_sectionStack.empty() );
+        }
+        virtual void testGroupEnded( TestGroupStats const& /* _testGroupStats */ ) {
+            currentGroupInfo.reset();
+        }
+        virtual void testRunEnded( TestRunStats const& /* _testRunStats */ ) {
+            currentTestCaseInfo.reset();
+            currentGroupInfo.reset();
+            currentTestRunInfo.reset();
+        }
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+
+        LazyStat<TestRunInfo> currentTestRunInfo;
+        LazyStat<GroupInfo> currentGroupInfo;
+        LazyStat<TestCaseInfo> currentTestCaseInfo;
+
+        std::vector<SectionInfo> m_sectionStack;
+    };
+
+    struct CumulativeReporterBase : SharedImpl<IStreamingReporter> {
+        template<typename T, typename ChildNodeT>
+        struct Node : SharedImpl<> {
+            explicit Node( T const& _value ) : value( _value ) {}
+            virtual ~Node() {}
+
+            typedef std::vector<Ptr<ChildNodeT> > ChildNodes;
+            T value;
+            ChildNodes children;
+        };
+        struct SectionNode : SharedImpl<> {
+            explicit SectionNode( SectionStats const& _stats ) : stats( _stats ) {}
+            virtual ~SectionNode();
+
+            bool operator == ( SectionNode const& other ) const {
+                return stats.sectionInfo.lineInfo == other.stats.sectionInfo.lineInfo;
+            }
+            bool operator == ( Ptr<SectionNode> const& other ) const {
+                return operator==( *other );
+            }
+
+            SectionStats stats;
+            typedef std::vector<Ptr<SectionNode> > ChildSections;
+            typedef std::vector<AssertionStats> Assertions;
+            ChildSections childSections;
+            Assertions assertions;
+            std::string stdOut;
+            std::string stdErr;
+        };
+
+        struct BySectionInfo {
+            BySectionInfo( SectionInfo const& other ) : m_other( other ) {}
+                       BySectionInfo( BySectionInfo const& other ) : m_other( other.m_other ) {}
+            bool operator() ( Ptr<SectionNode> const& node ) const {
+                return node->stats.sectionInfo.lineInfo == m_other.lineInfo;
+            }
+        private:
+                       void operator=( BySectionInfo const& );
+            SectionInfo const& m_other;
+        };
+
+        typedef Node<TestCaseStats, SectionNode> TestCaseNode;
+        typedef Node<TestGroupStats, TestCaseNode> TestGroupNode;
+        typedef Node<TestRunStats, TestGroupNode> TestRunNode;
+
+        CumulativeReporterBase( ReporterConfig const& _config )
+        :   m_config( _config.fullConfig() ),
+            stream( _config.stream() )
+        {}
+        ~CumulativeReporterBase();
+
+        virtual void testRunStarting( TestRunInfo const& ) {}
+        virtual void testGroupStarting( GroupInfo const& ) {}
+
+        virtual void testCaseStarting( TestCaseInfo const& ) {}
+
+        virtual void sectionStarting( SectionInfo const& sectionInfo ) {
+            SectionStats incompleteStats( sectionInfo, Counts(), 0, false );
+            Ptr<SectionNode> node;
+            if( m_sectionStack.empty() ) {
+                if( !m_rootSection )
+                    m_rootSection = new SectionNode( incompleteStats );
+                node = m_rootSection;
+            }
+            else {
+                SectionNode& parentNode = *m_sectionStack.back();
+                SectionNode::ChildSections::const_iterator it =
+                    std::find_if(   parentNode.childSections.begin(),
+                                    parentNode.childSections.end(),
+                                    BySectionInfo( sectionInfo ) );
+                if( it == parentNode.childSections.end() ) {
+                    node = new SectionNode( incompleteStats );
+                    parentNode.childSections.push_back( node );
+                }
+                else
+                    node = *it;
+            }
+            m_sectionStack.push_back( node );
+            m_deepestSection = node;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {}
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& sectionNode = *m_sectionStack.back();
+            sectionNode.assertions.push_back( assertionStats );
+            return true;
+        }
+        virtual void sectionEnded( SectionStats const& sectionStats ) {
+            assert( !m_sectionStack.empty() );
+            SectionNode& node = *m_sectionStack.back();
+            node.stats = sectionStats;
+            m_sectionStack.pop_back();
+        }
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            Ptr<TestCaseNode> node = new TestCaseNode( testCaseStats );
+            assert( m_sectionStack.size() == 0 );
+            node->children.push_back( m_rootSection );
+            m_testCases.push_back( node );
+            m_rootSection.reset();
+
+            assert( m_deepestSection );
+            m_deepestSection->stdOut = testCaseStats.stdOut;
+            m_deepestSection->stdErr = testCaseStats.stdErr;
+        }
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            Ptr<TestGroupNode> node = new TestGroupNode( testGroupStats );
+            node->children.swap( m_testCases );
+            m_testGroups.push_back( node );
+        }
+        virtual void testRunEnded( TestRunStats const& testRunStats ) {
+            Ptr<TestRunNode> node = new TestRunNode( testRunStats );
+            node->children.swap( m_testGroups );
+            m_testRuns.push_back( node );
+            testRunEndedCumulative();
+        }
+        virtual void testRunEndedCumulative() = 0;
+
+        Ptr<IConfig> m_config;
+        std::ostream& stream;
+        std::vector<AssertionStats> m_assertions;
+        std::vector<std::vector<Ptr<SectionNode> > > m_sections;
+        std::vector<Ptr<TestCaseNode> > m_testCases;
+        std::vector<Ptr<TestGroupNode> > m_testGroups;
+
+        std::vector<Ptr<TestRunNode> > m_testRuns;
+
+        Ptr<SectionNode> m_rootSection;
+        Ptr<SectionNode> m_deepestSection;
+        std::vector<Ptr<SectionNode> > m_sectionStack;
+
+    };
+
+} // end namespace Catch
+
+// #included from: ../internal/catch_reporter_registrars.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_REGISTRARS_HPP_INCLUDED
+
+namespace Catch {
+
+    template<typename T>
+    class LegacyReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new LegacyReporterAdapter( new T( config ) );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        LegacyReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+
+    template<typename T>
+    class ReporterRegistrar {
+
+        class ReporterFactory : public IReporterFactory {
+
+            // *** Please Note ***:
+            // - If you end up here looking at a compiler error because it's trying to register
+            // your custom reporter class be aware that the native reporter interface has changed
+            // to IStreamingReporter. The "legacy" interface, IReporter, is still supported via
+            // an adapter. Just use REGISTER_LEGACY_REPORTER to take advantage of the adapter.
+            // However please consider updating to the new interface as the old one is now
+            // deprecated and will probably be removed quite soon!
+            // Please contact me via github if you have any questions at all about this.
+            // In fact, ideally, please contact me anyway to let me know you've hit this - as I have
+            // no idea who is actually using custom reporters at all (possibly no-one!).
+            // The new interface is designed to minimise exposure to interface changes in the future.
+            virtual IStreamingReporter* create( ReporterConfig const& config ) const {
+                return new T( config );
+            }
+
+            virtual std::string getDescription() const {
+                return T::getDescription();
+            }
+        };
+
+    public:
+
+        ReporterRegistrar( std::string const& name ) {
+            getMutableRegistryHub().registerReporter( name, new ReporterFactory() );
+        }
+    };
+}
+
+#define INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) \
+    namespace{ Catch::LegacyReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+#define INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType ) \
+    namespace{ Catch::ReporterRegistrar<reporterType> catch_internal_RegistrarFor##reporterType( name ); }
+
+// #included from: ../internal/catch_xmlwriter.hpp
+#define TWOBLUECUBES_CATCH_XMLWRITER_HPP_INCLUDED
+
+#include <sstream>
+#include <iostream>
+#include <string>
+#include <vector>
+
+namespace Catch {
+
+    class XmlWriter {
+    public:
+
+        class ScopedElement {
+        public:
+            ScopedElement( XmlWriter* writer )
+            :   m_writer( writer )
+            {}
+
+            ScopedElement( ScopedElement const& other )
+            :   m_writer( other.m_writer ){
+                other.m_writer = NULL;
+            }
+
+            ~ScopedElement() {
+                if( m_writer )
+                    m_writer->endElement();
+            }
+
+            ScopedElement& writeText( std::string const& text, bool indent = true ) {
+                m_writer->writeText( text, indent );
+                return *this;
+            }
+
+            template<typename T>
+            ScopedElement& writeAttribute( std::string const& name, T const& attribute ) {
+                m_writer->writeAttribute( name, attribute );
+                return *this;
+            }
+
+        private:
+            mutable XmlWriter* m_writer;
+        };
+
+        XmlWriter()
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( &std::cout )
+        {}
+
+        XmlWriter( std::ostream& os )
+        :   m_tagIsOpen( false ),
+            m_needsNewline( false ),
+            m_os( &os )
+        {}
+
+        ~XmlWriter() {
+            while( !m_tags.empty() )
+                endElement();
+        }
+
+//#  ifndef CATCH_CPP11_OR_GREATER
+//        XmlWriter& operator = ( XmlWriter const& other ) {
+//            XmlWriter temp( other );
+//            swap( temp );
+//            return *this;
+//        }
+//#  else
+//        XmlWriter( XmlWriter const& )              = default;
+//        XmlWriter( XmlWriter && )                  = default;
+//        XmlWriter& operator = ( XmlWriter const& ) = default;
+//        XmlWriter& operator = ( XmlWriter && )     = default;
+//#  endif
+//
+//        void swap( XmlWriter& other ) {
+//            std::swap( m_tagIsOpen, other.m_tagIsOpen );
+//            std::swap( m_needsNewline, other.m_needsNewline );
+//            std::swap( m_tags, other.m_tags );
+//            std::swap( m_indent, other.m_indent );
+//            std::swap( m_os, other.m_os );
+//        }
+
+        XmlWriter& startElement( std::string const& name ) {
+            ensureTagClosed();
+            newlineIfNecessary();
+            stream() << m_indent << "<" << name;
+            m_tags.push_back( name );
+            m_indent += "  ";
+            m_tagIsOpen = true;
+            return *this;
+        }
+
+        ScopedElement scopedElement( std::string const& name ) {
+            ScopedElement scoped( this );
+            startElement( name );
+            return scoped;
+        }
+
+        XmlWriter& endElement() {
+            newlineIfNecessary();
+            m_indent = m_indent.substr( 0, m_indent.size()-2 );
+            if( m_tagIsOpen ) {
+                stream() << "/>\n";
+                m_tagIsOpen = false;
+            }
+            else {
+                stream() << m_indent << "</" << m_tags.back() << ">\n";
+            }
+            m_tags.pop_back();
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, std::string const& attribute ) {
+            if( !name.empty() && !attribute.empty() ) {
+                stream() << " " << name << "=\"";
+                writeEncodedText( attribute );
+                stream() << "\"";
+            }
+            return *this;
+        }
+
+        XmlWriter& writeAttribute( std::string const& name, bool attribute ) {
+            stream() << " " << name << "=\"" << ( attribute ? "true" : "false" ) << "\"";
+            return *this;
+        }
+
+        template<typename T>
+        XmlWriter& writeAttribute( std::string const& name, T const& attribute ) {
+            if( !name.empty() )
+                stream() << " " << name << "=\"" << attribute << "\"";
+            return *this;
+        }
+
+        XmlWriter& writeText( std::string const& text, bool indent = true ) {
+            if( !text.empty() ){
+                bool tagWasOpen = m_tagIsOpen;
+                ensureTagClosed();
+                if( tagWasOpen && indent )
+                    stream() << m_indent;
+                writeEncodedText( text );
+                m_needsNewline = true;
+            }
+            return *this;
+        }
+
+        XmlWriter& writeComment( std::string const& text ) {
+            ensureTagClosed();
+            stream() << m_indent << "<!--" << text << "-->";
+            m_needsNewline = true;
+            return *this;
+        }
+
+        XmlWriter& writeBlankLine() {
+            ensureTagClosed();
+            stream() << "\n";
+            return *this;
+        }
+
+        void setStream( std::ostream& os ) {
+            m_os = &os;
+        }
+
+    private:
+        XmlWriter( XmlWriter const& );
+        void operator=( XmlWriter const& );
+
+        std::ostream& stream() {
+            return *m_os;
+        }
+
+        void ensureTagClosed() {
+            if( m_tagIsOpen ) {
+                stream() << ">\n";
+                m_tagIsOpen = false;
+            }
+        }
+
+        void newlineIfNecessary() {
+            if( m_needsNewline ) {
+                stream() << "\n";
+                m_needsNewline = false;
+            }
+        }
+
+        void writeEncodedText( std::string const& text ) {
+            static const char* charsToEncode = "<&\"";
+            std::string mtext = text;
+            std::string::size_type pos = mtext.find_first_of( charsToEncode );
+            while( pos != std::string::npos ) {
+                stream() << mtext.substr( 0, pos );
+
+                switch( mtext[pos] ) {
+                    case '<':
+                        stream() << "&lt;";
+                        break;
+                    case '&':
+                        stream() << "&amp;";
+                        break;
+                    case '\"':
+                        stream() << "&quot;";
+                        break;
+                }
+                mtext = mtext.substr( pos+1 );
+                pos = mtext.find_first_of( charsToEncode );
+            }
+            stream() << mtext;
+        }
+
+        bool m_tagIsOpen;
+        bool m_needsNewline;
+        std::vector<std::string> m_tags;
+        std::string m_indent;
+        std::ostream* m_os;
+    };
+
+}
+namespace Catch {
+    class XmlReporter : public SharedImpl<IReporter> {
+    public:
+        XmlReporter( ReporterConfig const& config ) : m_config( config ), m_sectionDepth( 0 ) {}
+
+        static std::string getDescription() {
+            return "Reports test results as an XML document";
+        }
+        virtual ~XmlReporter();
+
+    private: // IReporter
+
+        virtual bool shouldRedirectStdout() const {
+            return true;
+        }
+
+        virtual void StartTesting() {
+            m_xml.setStream( m_config.stream() );
+            m_xml.startElement( "Catch" );
+            if( !m_config.fullConfig()->name().empty() )
+                m_xml.writeAttribute( "name", m_config.fullConfig()->name() );
+        }
+
+        virtual void EndTesting( const Totals& totals ) {
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", totals.assertions.passed )
+                .writeAttribute( "failures", totals.assertions.failed )
+                .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void StartGroup( const std::string& groupName ) {
+            m_xml.startElement( "Group" )
+                .writeAttribute( "name", groupName );
+        }
+
+        virtual void EndGroup( const std::string&, const Totals& totals ) {
+            m_xml.scopedElement( "OverallResults" )
+                .writeAttribute( "successes", totals.assertions.passed )
+                .writeAttribute( "failures", totals.assertions.failed )
+                .writeAttribute( "expectedFailures", totals.assertions.failedButOk );
+            m_xml.endElement();
+        }
+
+        virtual void StartSection( const std::string& sectionName, const std::string& description ) {
+            if( m_sectionDepth++ > 0 ) {
+                m_xml.startElement( "Section" )
+                    .writeAttribute( "name", trim( sectionName ) )
+                    .writeAttribute( "description", description );
+            }
+        }
+        virtual void NoAssertionsInSection( const std::string& ) {}
+        virtual void NoAssertionsInTestCase( const std::string& ) {}
+
+        virtual void EndSection( const std::string& /*sectionName*/, const Counts& assertions ) {
+            if( --m_sectionDepth > 0 ) {
+                m_xml.scopedElement( "OverallResults" )
+                    .writeAttribute( "successes", assertions.passed )
+                    .writeAttribute( "failures", assertions.failed )
+                    .writeAttribute( "expectedFailures", assertions.failedButOk );
+                m_xml.endElement();
+            }
+        }
+
+        virtual void StartTestCase( const Catch::TestCaseInfo& testInfo ) {
+            m_xml.startElement( "TestCase" ).writeAttribute( "name", trim( testInfo.name ) );
+            m_currentTestSuccess = true;
+        }
+
+        virtual void Result( const Catch::AssertionResult& assertionResult ) {
+            if( !m_config.fullConfig()->includeSuccessfulResults() && assertionResult.getResultType() == ResultWas::Ok )
+                return;
+
+            if( assertionResult.hasExpression() ) {
+                m_xml.startElement( "Expression" )
+                    .writeAttribute( "success", assertionResult.succeeded() )
+                    .writeAttribute( "filename", assertionResult.getSourceInfo().file )
+                    .writeAttribute( "line", assertionResult.getSourceInfo().line );
+
+                m_xml.scopedElement( "Original" )
+                    .writeText( assertionResult.getExpression() );
+                m_xml.scopedElement( "Expanded" )
+                    .writeText( assertionResult.getExpandedExpression() );
+                m_currentTestSuccess &= assertionResult.succeeded();
+            }
+
+            switch( assertionResult.getResultType() ) {
+                case ResultWas::ThrewException:
+                    m_xml.scopedElement( "Exception" )
+                        .writeAttribute( "filename", assertionResult.getSourceInfo().file )
+                        .writeAttribute( "line", assertionResult.getSourceInfo().line )
+                        .writeText( assertionResult.getMessage() );
+                    m_currentTestSuccess = false;
+                    break;
+                case ResultWas::Info:
+                    m_xml.scopedElement( "Info" )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                case ResultWas::Warning:
+                    m_xml.scopedElement( "Warning" )
+                        .writeText( assertionResult.getMessage() );
+                    break;
+                case ResultWas::ExplicitFailure:
+                    m_xml.scopedElement( "Failure" )
+                        .writeText( assertionResult.getMessage() );
+                    m_currentTestSuccess = false;
+                    break;
+                case ResultWas::Unknown:
+                case ResultWas::Ok:
+                case ResultWas::FailureBit:
+                case ResultWas::ExpressionFailed:
+                case ResultWas::Exception:
+                case ResultWas::DidntThrowException:
+                    break;
+            }
+            if( assertionResult.hasExpression() )
+                m_xml.endElement();
+        }
+
+        virtual void Aborted() {
+            // !TBD
+        }
+
+        virtual void EndTestCase( const Catch::TestCaseInfo&, const Totals&, const std::string&, const std::string& ) {
+            m_xml.scopedElement( "OverallResult" ).writeAttribute( "success", m_currentTestSuccess );
+            m_xml.endElement();
+        }
+
+    private:
+        ReporterConfig m_config;
+        bool m_currentTestSuccess;
+        XmlWriter m_xml;
+        int m_sectionDepth;
+    };
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_junit.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_JUNIT_HPP_INCLUDED
+
+#include <assert.h>
+
+namespace Catch {
+
+    class JunitReporter : public CumulativeReporterBase {
+    public:
+        JunitReporter( ReporterConfig const& _config )
+        :   CumulativeReporterBase( _config ),
+            xml( _config.stream() )
+        {}
+
+        ~JunitReporter();
+
+        static std::string getDescription() {
+            return "Reports test results in an XML format that looks like Ant's junitreport target";
+        }
+
+        virtual void noMatchingTestCases( std::string const& /*spec*/ ) {}
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = true;
+            return prefs;
+        }
+
+        virtual void testRunStarting( TestRunInfo const& runInfo ) {
+            CumulativeReporterBase::testRunStarting( runInfo );
+            xml.startElement( "testsuites" );
+        }
+
+        virtual void testGroupStarting( GroupInfo const& groupInfo ) {
+            suiteTimer.start();
+            stdOutForSuite.str("");
+            stdErrForSuite.str("");
+            unexpectedExceptions = 0;
+            CumulativeReporterBase::testGroupStarting( groupInfo );
+        }
+
+        virtual bool assertionEnded( AssertionStats const& assertionStats ) {
+            if( assertionStats.assertionResult.getResultType() == ResultWas::ThrewException )
+                unexpectedExceptions++;
+            return CumulativeReporterBase::assertionEnded( assertionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& testCaseStats ) {
+            stdOutForSuite << testCaseStats.stdOut;
+            stdErrForSuite << testCaseStats.stdErr;
+            CumulativeReporterBase::testCaseEnded( testCaseStats );
+        }
+
+        virtual void testGroupEnded( TestGroupStats const& testGroupStats ) {
+            double suiteTime = suiteTimer.getElapsedSeconds();
+            CumulativeReporterBase::testGroupEnded( testGroupStats );
+            writeGroup( *m_testGroups.back(), suiteTime );
+        }
+
+        virtual void testRunEndedCumulative() {
+            xml.endElement();
+        }
+
+        void writeGroup( TestGroupNode const& groupNode, double suiteTime ) {
+            XmlWriter::ScopedElement e = xml.scopedElement( "testsuite" );
+            TestGroupStats const& stats = groupNode.value;
+            xml.writeAttribute( "name", stats.groupInfo.name );
+            xml.writeAttribute( "errors", unexpectedExceptions );
+            xml.writeAttribute( "failures", stats.totals.assertions.failed-unexpectedExceptions );
+            xml.writeAttribute( "tests", stats.totals.assertions.total() );
+            xml.writeAttribute( "hostname", "tbd" ); // !TBD
+            if( m_config->showDurations() == ShowDurations::Never )
+                xml.writeAttribute( "time", "" );
+            else
+                xml.writeAttribute( "time", suiteTime );
+            xml.writeAttribute( "timestamp", "tbd" ); // !TBD
+
+            // Write test cases
+            for( TestGroupNode::ChildNodes::const_iterator
+                    it = groupNode.children.begin(), itEnd = groupNode.children.end();
+                    it != itEnd;
+                    ++it )
+                writeTestCase( **it );
+
+            xml.scopedElement( "system-out" ).writeText( trim( stdOutForSuite.str() ), false );
+            xml.scopedElement( "system-err" ).writeText( trim( stdErrForSuite.str() ), false );
+        }
+
+        void writeTestCase( TestCaseNode const& testCaseNode ) {
+            TestCaseStats const& stats = testCaseNode.value;
+
+            // All test cases have exactly one section - which represents the
+            // test case itself. That section may have 0-n nested sections
+            assert( testCaseNode.children.size() == 1 );
+            SectionNode const& rootSection = *testCaseNode.children.front();
+
+            std::string className = stats.testInfo.className;
+
+            if( className.empty() ) {
+                if( rootSection.childSections.empty() )
+                    className = "global";
+            }
+            writeSection( className, "", rootSection );
+        }
+
+        void writeSection(  std::string const& className,
+                            std::string const& rootName,
+                            SectionNode const& sectionNode ) {
+            std::string name = trim( sectionNode.stats.sectionInfo.name );
+            if( !rootName.empty() )
+                name = rootName + "/" + name;
+
+            if( !sectionNode.assertions.empty() ||
+                !sectionNode.stdOut.empty() ||
+                !sectionNode.stdErr.empty() ) {
+                XmlWriter::ScopedElement e = xml.scopedElement( "testcase" );
+                if( className.empty() ) {
+                    xml.writeAttribute( "classname", name );
+                    xml.writeAttribute( "name", "root" );
+                }
+                else {
+                    xml.writeAttribute( "classname", className );
+                    xml.writeAttribute( "name", name );
+                }
+                xml.writeAttribute( "time", toString( sectionNode.stats.durationInSeconds ) );
+
+                writeAssertions( sectionNode );
+
+                if( !sectionNode.stdOut.empty() )
+                    xml.scopedElement( "system-out" ).writeText( trim( sectionNode.stdOut ), false );
+                if( !sectionNode.stdErr.empty() )
+                    xml.scopedElement( "system-err" ).writeText( trim( sectionNode.stdErr ), false );
+            }
+            for( SectionNode::ChildSections::const_iterator
+                    it = sectionNode.childSections.begin(),
+                    itEnd = sectionNode.childSections.end();
+                    it != itEnd;
+                    ++it )
+                if( className.empty() )
+                    writeSection( name, "", **it );
+                else
+                    writeSection( className, name, **it );
+        }
+
+        void writeAssertions( SectionNode const& sectionNode ) {
+            for( SectionNode::Assertions::const_iterator
+                    it = sectionNode.assertions.begin(), itEnd = sectionNode.assertions.end();
+                    it != itEnd;
+                    ++it )
+                writeAssertion( *it );
+        }
+        void writeAssertion( AssertionStats const& stats ) {
+            AssertionResult const& result = stats.assertionResult;
+            if( !result.isOk() ) {
+                std::string elementName;
+                switch( result.getResultType() ) {
+                    case ResultWas::ThrewException:
+                        elementName = "error";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        elementName = "failure";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        elementName = "failure";
+                        break;
+
+                    // We should never see these here:
+                    case ResultWas::Info:
+                    case ResultWas::Warning:
+                    case ResultWas::Ok:
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        elementName = "internalError";
+                        break;
+                }
+
+                XmlWriter::ScopedElement e = xml.scopedElement( elementName );
+
+                xml.writeAttribute( "message", result.getExpandedExpression() );
+                xml.writeAttribute( "type", result.getTestMacroName() );
+
+                std::ostringstream oss;
+                if( !result.getMessage().empty() )
+                    oss << result.getMessage() << "\n";
+                for( std::vector<MessageInfo>::const_iterator
+                        it = stats.infoMessages.begin(),
+                        itEnd = stats.infoMessages.end();
+                            it != itEnd;
+                            ++it )
+                    if( it->type == ResultWas::Info )
+                        oss << it->message << "\n";
+
+                oss << "at " << result.getSourceInfo();
+                xml.writeText( oss.str(), false );
+            }
+        }
+
+        XmlWriter xml;
+        Timer suiteTimer;
+        std::ostringstream stdOutForSuite;
+        std::ostringstream stdErrForSuite;
+        unsigned int unexpectedExceptions;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "junit", JunitReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_console.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_CONSOLE_HPP_INCLUDED
+
+#include <cstring>
+
+namespace Catch {
+
+    struct ConsoleReporter : StreamingReporterBase {
+        ConsoleReporter( ReporterConfig const& _config )
+        :   StreamingReporterBase( _config ),
+            m_headerPrinted( false )
+        {}
+
+        virtual ~ConsoleReporter();
+        static std::string getDescription() {
+            return "Reports test results as plain lines of text";
+        }
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << "'" << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            lazyPrint();
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void sectionStarting( SectionInfo const& _sectionInfo ) {
+            m_headerPrinted = false;
+            StreamingReporterBase::sectionStarting( _sectionInfo );
+        }
+        virtual void sectionEnded( SectionStats const& _sectionStats ) {
+            if( _sectionStats.missingAssertions ) {
+                lazyPrint();
+                Colour colour( Colour::ResultError );
+                if( m_sectionStack.size() > 1 )
+                    stream << "\nNo assertions in section";
+                else
+                    stream << "\nNo assertions in test case";
+                stream << " '" << _sectionStats.sectionInfo.name << "'\n" << std::endl;
+            }
+            if( m_headerPrinted ) {
+                if( m_config->showDurations() == ShowDurations::Always )
+                    stream << "Completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+                m_headerPrinted = false;
+            }
+            else {
+                if( m_config->showDurations() == ShowDurations::Always )
+                    stream << _sectionStats.sectionInfo.name << " completed in " << _sectionStats.durationInSeconds << "s" << std::endl;
+            }
+            StreamingReporterBase::sectionEnded( _sectionStats );
+        }
+
+        virtual void testCaseEnded( TestCaseStats const& _testCaseStats ) {
+            StreamingReporterBase::testCaseEnded( _testCaseStats );
+            m_headerPrinted = false;
+        }
+        virtual void testGroupEnded( TestGroupStats const& _testGroupStats ) {
+            if( currentGroupInfo.used ) {
+                printSummaryDivider();
+                stream << "Summary for group '" << _testGroupStats.groupInfo.name << "':\n";
+                printTotals( _testGroupStats.totals );
+                stream << "\n" << std::endl;
+            }
+            StreamingReporterBase::testGroupEnded( _testGroupStats );
+        }
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotalsDivider( _testRunStats.totals );
+            printTotals( _testRunStats.totals );
+            stream << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            :   stream( _stream ),
+                stats( _stats ),
+                result( _stats.assertionResult ),
+                colour( Colour::None ),
+                message( result.getMessage() ),
+                messages( _stats.infoMessages ),
+                printInfoMessages( _printInfoMessages )
+            {
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        colour = Colour::Success;
+                        passOrFail = "PASSED";
+                        //if( result.hasMessage() )
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() ) {
+                            colour = Colour::Success;
+                            passOrFail = "FAILED - but was ok";
+                        }
+                        else {
+                            colour = Colour::Error;
+                            passOrFail = "FAILED";
+                        }
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "with messages";
+                        break;
+                    case ResultWas::ThrewException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "due to unexpected exception with message";
+                        break;
+                    case ResultWas::DidntThrowException:
+                        colour = Colour::Error;
+                        passOrFail = "FAILED";
+                        messageLabel = "because no exception was thrown where one was expected";
+                        break;
+                    case ResultWas::Info:
+                        messageLabel = "info";
+                        break;
+                    case ResultWas::Warning:
+                        messageLabel = "warning";
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        passOrFail = "FAILED";
+                        colour = Colour::Error;
+                        if( _stats.infoMessages.size() == 1 )
+                            messageLabel = "explicitly with message";
+                        if( _stats.infoMessages.size() > 1 )
+                            messageLabel = "explicitly with messages";
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        passOrFail = "** internal error **";
+                        colour = Colour::Error;
+                        break;
+                }
+            }
+
+            void print() const {
+                printSourceInfo();
+                if( stats.totals.assertions.total() > 0 ) {
+                    if( result.isOk() )
+                        stream << "\n";
+                    printResultType();
+                    printOriginalExpression();
+                    printReconstructedExpression();
+                }
+                else {
+                    stream << "\n";
+                }
+                printMessage();
+            }
+
+        private:
+            void printResultType() const {
+                if( !passOrFail.empty() ) {
+                    Colour colourGuard( colour );
+                    stream << passOrFail << ":\n";
+                }
+            }
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    Colour colourGuard( Colour::OriginalExpression );
+                    stream  << "  ";
+                    stream << result.getExpressionInMacro();
+                    stream << "\n";
+                }
+            }
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    stream << "with expansion:\n";
+                    Colour colourGuard( Colour::ReconstructedExpression );
+                    stream << Text( result.getExpandedExpression(), TextAttributes().setIndent(2) ) << "\n";
+                }
+            }
+            void printMessage() const {
+                if( !messageLabel.empty() )
+                    stream << messageLabel << ":" << "\n";
+                for( std::vector<MessageInfo>::const_iterator it = messages.begin(), itEnd = messages.end();
+                        it != itEnd;
+                        ++it ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || it->type != ResultWas::Info )
+                        stream << Text( it->message, TextAttributes().setIndent(2) ) << "\n";
+                }
+            }
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ": ";
+            }
+
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            Colour::Code colour;
+            std::string passOrFail;
+            std::string messageLabel;
+            std::string message;
+            std::vector<MessageInfo> messages;
+            bool printInfoMessages;
+        };
+
+        void lazyPrint() {
+
+            if( !currentTestRunInfo.used )
+                lazyPrintRunInfo();
+            if( !currentGroupInfo.used )
+                lazyPrintGroupInfo();
+
+            if( !m_headerPrinted ) {
+                printTestCaseAndSectionHeader();
+                m_headerPrinted = true;
+            }
+        }
+        void lazyPrintRunInfo() {
+            stream  << "\n" << getLineOfChars<'~'>() << "\n";
+            Colour colour( Colour::SecondaryText );
+            stream  << currentTestRunInfo->name
+                    << " is a Catch v"  << libraryVersion.majorVersion << "."
+                    << libraryVersion.minorVersion << " b"
+                    << libraryVersion.buildNumber;
+            if( libraryVersion.branchName != std::string( "master" ) )
+                stream << " (" << libraryVersion.branchName << ")";
+            stream  << " host application.\n"
+                    << "Run with -? for options\n\n";
+
+            currentTestRunInfo.used = true;
+        }
+        void lazyPrintGroupInfo() {
+            if( !currentGroupInfo->name.empty() && currentGroupInfo->groupsCounts > 1 ) {
+                printClosedHeader( "Group: " + currentGroupInfo->name );
+                currentGroupInfo.used = true;
+            }
+        }
+        void printTestCaseAndSectionHeader() {
+            assert( !m_sectionStack.empty() );
+            printOpenHeader( currentTestCaseInfo->name );
+
+            if( m_sectionStack.size() > 1 ) {
+                Colour colourGuard( Colour::Headers );
+
+                std::vector<SectionInfo>::const_iterator
+                    it = m_sectionStack.begin()+1, // Skip first section (test case)
+                    itEnd = m_sectionStack.end();
+                for( ; it != itEnd; ++it )
+                    printHeaderString( it->name, 2 );
+            }
+
+            SourceLineInfo lineInfo = m_sectionStack.front().lineInfo;
+
+            if( !lineInfo.empty() ){
+                stream << getLineOfChars<'-'>() << "\n";
+                Colour colourGuard( Colour::FileName );
+                stream << lineInfo << "\n";
+            }
+            stream << getLineOfChars<'.'>() << "\n" << std::endl;
+        }
+
+        void printClosedHeader( std::string const& _name ) {
+            printOpenHeader( _name );
+            stream << getLineOfChars<'.'>() << "\n";
+        }
+        void printOpenHeader( std::string const& _name ) {
+            stream  << getLineOfChars<'-'>() << "\n";
+            {
+                Colour colourGuard( Colour::Headers );
+                printHeaderString( _name );
+            }
+        }
+
+        // if string has a : in first line will set indent to follow it on
+        // subsequent lines
+        void printHeaderString( std::string const& _string, std::size_t indent = 0 ) {
+            std::size_t i = _string.find( ": " );
+            if( i != std::string::npos )
+                i+=2;
+            else
+                i = 0;
+            stream << Text( _string, TextAttributes()
+                                        .setIndent( indent+i)
+                                        .setInitialIndent( indent ) ) << "\n";
+        }
+
+        struct SummaryColumn {
+
+            SummaryColumn( std::string const& _label, Colour::Code _colour )
+            :   label( _label ),
+                colour( _colour )
+            {}
+            SummaryColumn addRow( std::size_t count ) {
+                std::ostringstream oss;
+                oss << count;
+                std::string row = oss.str();
+                for( std::vector<std::string>::iterator it = rows.begin(); it != rows.end(); ++it ) {
+                    while( it->size() < row.size() )
+                        *it = " " + *it;
+                    while( it->size() > row.size() )
+                        row = " " + row;
+                }
+                rows.push_back( row );
+                return *this;
+            }
+
+            std::string label;
+            Colour::Code colour;
+            std::vector<std::string> rows;
+
+        };
+
+        void printTotals( Totals const& totals ) {
+            if( totals.testCases.total() == 0 ) {
+                stream << Colour( Colour::Warning ) << "No tests ran\n";
+            }
+            else if( totals.assertions.total() > 0 && totals.assertions.allPassed() ) {
+                stream << Colour( Colour::ResultSuccess ) << "All tests passed";
+                stream << " ("
+                        << pluralise( totals.assertions.passed, "assertion" ) << " in "
+                        << pluralise( totals.testCases.passed, "test case" ) << ")"
+                        << "\n";
+            }
+            else {
+
+                std::vector<SummaryColumn> columns;
+                columns.push_back( SummaryColumn( "", Colour::None )
+                                        .addRow( totals.testCases.total() )
+                                        .addRow( totals.assertions.total() ) );
+                columns.push_back( SummaryColumn( "passed", Colour::Success )
+                                        .addRow( totals.testCases.passed )
+                                        .addRow( totals.assertions.passed ) );
+                columns.push_back( SummaryColumn( "failed", Colour::ResultError )
+                                        .addRow( totals.testCases.failed )
+                                        .addRow( totals.assertions.failed ) );
+                columns.push_back( SummaryColumn( "failed as expected", Colour::ResultExpectedFailure )
+                                        .addRow( totals.testCases.failedButOk )
+                                        .addRow( totals.assertions.failedButOk ) );
+
+                printSummaryRow( "test cases", columns, 0 );
+                printSummaryRow( "assertions", columns, 1 );
+            }
+        }
+        void printSummaryRow( std::string const& label, std::vector<SummaryColumn> const& cols, std::size_t row ) {
+            for( std::vector<SummaryColumn>::const_iterator it = cols.begin(); it != cols.end(); ++it ) {
+                std::string value = it->rows[row];
+                if( it->label.empty() ) {
+                    stream << label << ": ";
+                    if( value != "0" )
+                        stream << value;
+                    else
+                        stream << Colour( Colour::Warning ) << "- none -";
+                }
+                else if( value != "0" ) {
+                    stream  << Colour( Colour::LightGrey ) << " | ";
+                    stream  << Colour( it->colour )
+                            << value << " " << it->label;
+                }
+            }
+            stream << "\n";
+        }
+
+        static std::size_t makeRatio( std::size_t number, std::size_t total ) {
+            std::size_t ratio = total > 0 ? CATCH_CONFIG_CONSOLE_WIDTH * number/ total : 0;
+            return ( ratio == 0 && number > 0 ) ? 1 : ratio;
+        }
+        static std::size_t& findMax( std::size_t& i, std::size_t& j, std::size_t& k ) {
+            if( i > j && i > k )
+                return i;
+            else if( j > k )
+                return j;
+            else
+                return k;
+        }
+
+        void printTotalsDivider( Totals const& totals ) {
+            if( totals.testCases.total() > 0 ) {
+                std::size_t failedRatio = makeRatio( totals.testCases.failed, totals.testCases.total() );
+                std::size_t failedButOkRatio = makeRatio( totals.testCases.failedButOk, totals.testCases.total() );
+                std::size_t passedRatio = makeRatio( totals.testCases.passed, totals.testCases.total() );
+                while( failedRatio + failedButOkRatio + passedRatio < CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )++;
+                while( failedRatio + failedButOkRatio + passedRatio > CATCH_CONFIG_CONSOLE_WIDTH-1 )
+                    findMax( failedRatio, failedButOkRatio, passedRatio )--;
+
+                stream << Colour( Colour::Error ) << std::string( failedRatio, '=' );
+                stream << Colour( Colour::ResultExpectedFailure ) << std::string( failedButOkRatio, '=' );
+                if( totals.testCases.allPassed() )
+                    stream << Colour( Colour::ResultSuccess ) << std::string( passedRatio, '=' );
+                else
+                    stream << Colour( Colour::Success ) << std::string( passedRatio, '=' );
+            }
+            else {
+                stream << Colour( Colour::Warning ) << std::string( CATCH_CONFIG_CONSOLE_WIDTH-1, '=' );
+            }
+            stream << "\n";
+        }
+        void printSummaryDivider() {
+            stream << getLineOfChars<'-'>() << "\n";
+        }
+        template<char C>
+        static char const* getLineOfChars() {
+            static char line[CATCH_CONFIG_CONSOLE_WIDTH] = {0};
+            if( !*line ) {
+                memset( line, C, CATCH_CONFIG_CONSOLE_WIDTH-1 );
+                line[CATCH_CONFIG_CONSOLE_WIDTH-1] = 0;
+            }
+            return line;
+        }
+
+    private:
+        bool m_headerPrinted;
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "console", ConsoleReporter )
+
+} // end namespace Catch
+
+// #included from: ../reporters/catch_reporter_compact.hpp
+#define TWOBLUECUBES_CATCH_REPORTER_COMPACT_HPP_INCLUDED
+
+namespace Catch {
+
+    struct CompactReporter : StreamingReporterBase {
+
+        CompactReporter( ReporterConfig const& _config )
+        : StreamingReporterBase( _config )
+        {}
+
+        virtual ~CompactReporter();
+
+        static std::string getDescription() {
+            return "Reports test results on a single line, suitable for IDEs";
+        }
+
+        virtual ReporterPreferences getPreferences() const {
+            ReporterPreferences prefs;
+            prefs.shouldRedirectStdOut = false;
+            return prefs;
+        }
+
+        virtual void noMatchingTestCases( std::string const& spec ) {
+            stream << "No test cases matched '" << spec << "'" << std::endl;
+        }
+
+        virtual void assertionStarting( AssertionInfo const& ) {
+        }
+
+        virtual bool assertionEnded( AssertionStats const& _assertionStats ) {
+            AssertionResult const& result = _assertionStats.assertionResult;
+
+            bool printInfoMessages = true;
+
+            // Drop out if result was successful and we're not printing those
+            if( !m_config->includeSuccessfulResults() && result.isOk() ) {
+                if( result.getResultType() != ResultWas::Warning )
+                    return false;
+                printInfoMessages = false;
+            }
+
+            AssertionPrinter printer( stream, _assertionStats, printInfoMessages );
+            printer.print();
+
+            stream << std::endl;
+            return true;
+        }
+
+        virtual void testRunEnded( TestRunStats const& _testRunStats ) {
+            printTotals( _testRunStats.totals );
+            stream << "\n" << std::endl;
+            StreamingReporterBase::testRunEnded( _testRunStats );
+        }
+
+    private:
+        class AssertionPrinter {
+            void operator= ( AssertionPrinter const& );
+        public:
+            AssertionPrinter( std::ostream& _stream, AssertionStats const& _stats, bool _printInfoMessages )
+            : stream( _stream )
+            , stats( _stats )
+            , result( _stats.assertionResult )
+            , messages( _stats.infoMessages )
+            , itMessage( _stats.infoMessages.begin() )
+            , printInfoMessages( _printInfoMessages )
+            {}
+
+            void print() {
+                printSourceInfo();
+
+                itMessage = messages.begin();
+
+                switch( result.getResultType() ) {
+                    case ResultWas::Ok:
+                        printResultType( Colour::ResultSuccess, passedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        if ( ! result.hasExpression() )
+                            printRemainingMessages( Colour::None );
+                        else
+                            printRemainingMessages();
+                        break;
+                    case ResultWas::ExpressionFailed:
+                        if( result.isOk() )
+                            printResultType( Colour::ResultSuccess, failedString() + std::string( " - but was ok" ) );
+                        else
+                            printResultType( Colour::Error, failedString() );
+                        printOriginalExpression();
+                        printReconstructedExpression();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ThrewException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "unexpected exception with message:" );
+                        printMessage();
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::DidntThrowException:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "expected exception, got none" );
+                        printExpressionWas();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Info:
+                        printResultType( Colour::None, "info" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::Warning:
+                        printResultType( Colour::None, "warning" );
+                        printMessage();
+                        printRemainingMessages();
+                        break;
+                    case ResultWas::ExplicitFailure:
+                        printResultType( Colour::Error, failedString() );
+                        printIssue( "explicitly" );
+                        printRemainingMessages( Colour::None );
+                        break;
+                    // These cases are here to prevent compiler warnings
+                    case ResultWas::Unknown:
+                    case ResultWas::FailureBit:
+                    case ResultWas::Exception:
+                        printResultType( Colour::Error, "** internal error **" );
+                        break;
+                }
+            }
+
+        private:
+            // Colour::LightGrey
+
+            static Colour::Code dimColour() { return Colour::FileName; }
+
+#ifdef CATCH_PLATFORM_MAC
+            static const char* failedString() { return "FAILED"; }
+            static const char* passedString() { return "PASSED"; }
+#else
+            static const char* failedString() { return "failed"; }
+            static const char* passedString() { return "passed"; }
+#endif
+
+            void printSourceInfo() const {
+                Colour colourGuard( Colour::FileName );
+                stream << result.getSourceInfo() << ":";
+            }
+
+            void printResultType( Colour::Code colour, std::string passOrFail ) const {
+                if( !passOrFail.empty() ) {
+                    {
+                        Colour colourGuard( colour );
+                        stream << " " << passOrFail;
+                    }
+                    stream << ":";
+                }
+            }
+
+            void printIssue( std::string issue ) const {
+                stream << " " << issue;
+            }
+
+            void printExpressionWas() {
+                if( result.hasExpression() ) {
+                    stream << ";";
+                    {
+                        Colour colour( dimColour() );
+                        stream << " expression was:";
+                    }
+                    printOriginalExpression();
+                }
+            }
+
+            void printOriginalExpression() const {
+                if( result.hasExpression() ) {
+                    stream << " " << result.getExpression();
+                }
+            }
+
+            void printReconstructedExpression() const {
+                if( result.hasExpandedExpression() ) {
+                    {
+                        Colour colour( dimColour() );
+                        stream << " for: ";
+                    }
+                    stream << result.getExpandedExpression();
+                }
+            }
+
+            void printMessage() {
+                if ( itMessage != messages.end() ) {
+                    stream << " '" << itMessage->message << "'";
+                    ++itMessage;
+                }
+            }
+
+            void printRemainingMessages( Colour::Code colour = dimColour() ) {
+                if ( itMessage == messages.end() )
+                    return;
+
+                // using messages.end() directly yields compilation error:
+                std::vector<MessageInfo>::const_iterator itEnd = messages.end();
+                const std::size_t N = static_cast<std::size_t>( std::distance( itMessage, itEnd ) );
+
+                {
+                    Colour colourGuard( colour );
+                    stream << " with " << pluralise( N, "message" ) << ":";
+                }
+
+                for(; itMessage != itEnd; ) {
+                    // If this assertion is a warning ignore any INFO messages
+                    if( printInfoMessages || itMessage->type != ResultWas::Info ) {
+                        stream << " '" << itMessage->message << "'";
+                        if ( ++itMessage != itEnd ) {
+                            Colour colourGuard( dimColour() );
+                            stream << " and";
+                        }
+                    }
+                }
+            }
+
+        private:
+            std::ostream& stream;
+            AssertionStats const& stats;
+            AssertionResult const& result;
+            std::vector<MessageInfo> messages;
+            std::vector<MessageInfo>::const_iterator itMessage;
+            bool printInfoMessages;
+        };
+
+        // Colour, message variants:
+        // - white: No tests ran.
+        // -   red: Failed [both/all] N test cases, failed [both/all] M assertions.
+        // - white: Passed [both/all] N test cases (no assertions).
+        // -   red: Failed N tests cases, failed M assertions.
+        // - green: Passed [both/all] N tests cases with M assertions.
+
+        std::string bothOrAll( std::size_t count ) const {
+            return count == 1 ? "" : count == 2 ? "both " : "all " ;
+        }
+
+        void printTotals( const Totals& totals ) const {
+            if( totals.testCases.total() == 0 ) {
+                stream << "No tests ran.";
+            }
+            else if( totals.testCases.failed == totals.testCases.total() ) {
+                Colour colour( Colour::ResultError );
+                const std::string qualify_assertions_failed =
+                    totals.assertions.failed == totals.assertions.total() ?
+                        bothOrAll( totals.assertions.failed ) : "";
+                stream <<
+                    "Failed " << bothOrAll( totals.testCases.failed )
+                              << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << qualify_assertions_failed <<
+                                 pluralise( totals.assertions.failed, "assertion" ) << ".";
+            }
+            else if( totals.assertions.total() == 0 ) {
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.total() )
+                              << pluralise( totals.testCases.total(), "test case" )
+                              << " (no assertions).";
+            }
+            else if( totals.assertions.failed ) {
+                Colour colour( Colour::ResultError );
+                stream <<
+                    "Failed " << pluralise( totals.testCases.failed, "test case"  ) << ", "
+                    "failed " << pluralise( totals.assertions.failed, "assertion" ) << ".";
+            }
+            else {
+                Colour colour( Colour::ResultSuccess );
+                stream <<
+                    "Passed " << bothOrAll( totals.testCases.passed )
+                              << pluralise( totals.testCases.passed, "test case"  ) <<
+                    " with "  << pluralise( totals.assertions.passed, "assertion" ) << ".";
+            }
+        }
+    };
+
+    INTERNAL_CATCH_REGISTER_REPORTER( "compact", CompactReporter )
+
+} // end namespace Catch
+
+namespace Catch {
+    NonCopyable::~NonCopyable() {}
+    IShared::~IShared() {}
+    StreamBufBase::~StreamBufBase() CATCH_NOEXCEPT {}
+    IContext::~IContext() {}
+    IResultCapture::~IResultCapture() {}
+    ITestCase::~ITestCase() {}
+    ITestCaseRegistry::~ITestCaseRegistry() {}
+    IRegistryHub::~IRegistryHub() {}
+    IMutableRegistryHub::~IMutableRegistryHub() {}
+    IExceptionTranslator::~IExceptionTranslator() {}
+    IExceptionTranslatorRegistry::~IExceptionTranslatorRegistry() {}
+    IReporter::~IReporter() {}
+    IReporterFactory::~IReporterFactory() {}
+    IReporterRegistry::~IReporterRegistry() {}
+    IStreamingReporter::~IStreamingReporter() {}
+    AssertionStats::~AssertionStats() {}
+    SectionStats::~SectionStats() {}
+    TestCaseStats::~TestCaseStats() {}
+    TestGroupStats::~TestGroupStats() {}
+    TestRunStats::~TestRunStats() {}
+    CumulativeReporterBase::SectionNode::~SectionNode() {}
+    CumulativeReporterBase::~CumulativeReporterBase() {}
+
+    StreamingReporterBase::~StreamingReporterBase() {}
+    ConsoleReporter::~ConsoleReporter() {}
+    CompactReporter::~CompactReporter() {}
+    IRunner::~IRunner() {}
+    IMutableContext::~IMutableContext() {}
+    IConfig::~IConfig() {}
+    XmlReporter::~XmlReporter() {}
+    JunitReporter::~JunitReporter() {}
+    TestRegistry::~TestRegistry() {}
+    FreeFunctionTestCase::~FreeFunctionTestCase() {}
+    IGeneratorInfo::~IGeneratorInfo() {}
+    IGeneratorsForTest::~IGeneratorsForTest() {}
+    TestSpec::Pattern::~Pattern() {}
+    TestSpec::NamePattern::~NamePattern() {}
+    TestSpec::TagPattern::~TagPattern() {}
+    TestSpec::ExcludedPattern::~ExcludedPattern() {}
+
+    Matchers::Impl::StdString::Equals::~Equals() {}
+    Matchers::Impl::StdString::Contains::~Contains() {}
+    Matchers::Impl::StdString::StartsWith::~StartsWith() {}
+    Matchers::Impl::StdString::EndsWith::~EndsWith() {}
+
+    void Config::dummy() {}
+
+    INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( "xml", XmlReporter )
+}
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif
+
+#endif
+
+#ifdef CATCH_CONFIG_MAIN
+// #included from: internal/catch_default_main.hpp
+#define TWOBLUECUBES_CATCH_DEFAULT_MAIN_HPP_INCLUDED
+
+#ifndef __OBJC__
+
+// Standard C/C++ main entry point
+int main (int argc, char * const argv[]) {
+    return Catch::Session().run( argc, argv );
+}
+
+#else // __OBJC__
+
+// Objective-C entry point
+int main (int argc, char * const argv[]) {
+#if !CATCH_ARC_ENABLED
+    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
+#endif
+
+    Catch::registerTestMethods();
+    int result = Catch::Session().run( argc, (char* const*)argv );
+
+#if !CATCH_ARC_ENABLED
+    [pool drain];
+#endif
+
+    return result;
+}
+
+#endif // __OBJC__
+
+#endif
+
+#ifdef CLARA_CONFIG_MAIN_NOT_DEFINED
+#  undef CLARA_CONFIG_MAIN
+#endif
+
+//////
+
+// If this config identifier is defined then all CATCH macros are prefixed with CATCH_
+#ifdef CATCH_CONFIG_PREFIX_ALL
+
+#define CATCH_REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE" )
+#define CATCH_REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "CATCH_REQUIRE_FALSE" )
+
+#define CATCH_REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS" )
+#define CATCH_REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THROWS_AS" )
+#define CATCH_REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_NOTHROW" )
+
+#define CATCH_CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK" )
+#define CATCH_CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CATCH_CHECK_FALSE" )
+#define CATCH_CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_IF" )
+#define CATCH_CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECKED_ELSE" )
+#define CATCH_CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CATCH_CHECK_NOFAIL" )
+
+#define CATCH_CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS" )
+#define CATCH_CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THROWS_AS" )
+#define CATCH_CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_NOTHROW" )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CATCH_CHECK_THAT" )
+#define CATCH_REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "CATCH_REQUIRE_THAT" )
+
+#define CATCH_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "CATCH_WARN", msg )
+#define CATCH_SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "CATCH_INFO" )
+#define CATCH_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+#define CATCH_SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CATCH_CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define CATCH_TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define CATCH_TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define CATCH_METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define CATCH_SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define CATCH_FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", __VA_ARGS__ )
+    #define CATCH_SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", __VA_ARGS__ )
+#else
+    #define CATCH_TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define CATCH_TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define CATCH_METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define CATCH_SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define CATCH_FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "CATCH_FAIL", msg )
+    #define CATCH_SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "CATCH_SUCCEED", msg )
+#endif
+#define CATCH_ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define CATCH_REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define CATCH_REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define CATCH_GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define CATCH_SCENARIO( ... ) CATCH_TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define CATCH_SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define CATCH_SCENARIO( name, tags ) CATCH_TEST_CASE( "Scenario: " name, tags )
+#define CATCH_SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define CATCH_GIVEN( desc )    CATCH_SECTION( "Given: " desc, "" )
+#define CATCH_WHEN( desc )     CATCH_SECTION( " When: " desc, "" )
+#define CATCH_AND_WHEN( desc ) CATCH_SECTION( "  And: " desc, "" )
+#define CATCH_THEN( desc )     CATCH_SECTION( " Then: " desc, "" )
+#define CATCH_AND_THEN( desc ) CATCH_SECTION( "  And: " desc, "" )
+
+// If CATCH_CONFIG_PREFIX_ALL is not defined then the CATCH_ prefix is not required
+#else
+
+#define REQUIRE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal, "REQUIRE" )
+#define REQUIRE_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::Normal | Catch::ResultDisposition::FalseTest, "REQUIRE_FALSE" )
+
+#define REQUIRE_THROWS( expr ) INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::Normal, "REQUIRE_THROWS" )
+#define REQUIRE_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::Normal, "REQUIRE_THROWS_AS" )
+#define REQUIRE_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::Normal, "REQUIRE_NOTHROW" )
+
+#define CHECK( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK" )
+#define CHECK_FALSE( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::FalseTest, "CHECK_FALSE" )
+#define CHECKED_IF( expr ) INTERNAL_CATCH_IF( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_IF" )
+#define CHECKED_ELSE( expr ) INTERNAL_CATCH_ELSE( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECKED_ELSE" )
+#define CHECK_NOFAIL( expr ) INTERNAL_CATCH_TEST( expr, Catch::ResultDisposition::ContinueOnFailure | Catch::ResultDisposition::SuppressFail, "CHECK_NOFAIL" )
+
+#define CHECK_THROWS( expr )  INTERNAL_CATCH_THROWS( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS" )
+#define CHECK_THROWS_AS( expr, exceptionType ) INTERNAL_CATCH_THROWS_AS( expr, exceptionType, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THROWS_AS" )
+#define CHECK_NOTHROW( expr ) INTERNAL_CATCH_NO_THROW( expr, Catch::ResultDisposition::ContinueOnFailure, "CHECK_NOTHROW" )
+
+#define CHECK_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::ContinueOnFailure, "CHECK_THAT" )
+#define REQUIRE_THAT( arg, matcher ) INTERNAL_CHECK_THAT( arg, matcher, Catch::ResultDisposition::Normal, "REQUIRE_THAT" )
+
+#define INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define WARN( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Warning, Catch::ResultDisposition::ContinueOnFailure, "WARN", msg )
+#define SCOPED_INFO( msg ) INTERNAL_CATCH_INFO( msg, "INFO" )
+#define CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+#define SCOPED_CAPTURE( msg ) INTERNAL_CATCH_INFO( #msg " := " << msg, "CAPTURE" )
+
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+    #define TEST_CASE( ... ) INTERNAL_CATCH_TESTCASE( __VA_ARGS__ )
+    #define TEST_CASE_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, __VA_ARGS__ )
+    #define METHOD_AS_TEST_CASE( method, ... ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, __VA_ARGS__ )
+    #define SECTION( ... ) INTERNAL_CATCH_SECTION( __VA_ARGS__ )
+    #define FAIL( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", __VA_ARGS__ )
+    #define SUCCEED( ... ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", __VA_ARGS__ )
+#else
+    #define TEST_CASE( name, description ) INTERNAL_CATCH_TESTCASE( name, description )
+    #define TEST_CASE_METHOD( className, name, description ) INTERNAL_CATCH_TEST_CASE_METHOD( className, name, description )
+    #define METHOD_AS_TEST_CASE( method, name, description ) INTERNAL_CATCH_METHOD_AS_TEST_CASE( method, name, description )
+    #define SECTION( name, description ) INTERNAL_CATCH_SECTION( name, description )
+    #define FAIL( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::ExplicitFailure, Catch::ResultDisposition::Normal, "FAIL", msg )
+    #define SUCCEED( msg ) INTERNAL_CATCH_MSG( Catch::ResultWas::Ok, Catch::ResultDisposition::ContinueOnFailure, "SUCCEED", msg )
+#endif
+#define ANON_TEST_CASE() INTERNAL_CATCH_TESTCASE( "", "" )
+
+#define REGISTER_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_REPORTER( name, reporterType )
+#define REGISTER_LEGACY_REPORTER( name, reporterType ) INTERNAL_CATCH_REGISTER_LEGACY_REPORTER( name, reporterType )
+
+#define GENERATE( expr) INTERNAL_CATCH_GENERATE( expr )
+
+#endif
+
+#define CATCH_TRANSLATE_EXCEPTION( signature ) INTERNAL_CATCH_TRANSLATE_EXCEPTION( signature )
+
+// "BDD-style" convenience wrappers
+#ifdef CATCH_CONFIG_VARIADIC_MACROS
+#define SCENARIO( ... ) TEST_CASE( "Scenario: " __VA_ARGS__ )
+#define SCENARIO_METHOD( className, ... ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " __VA_ARGS__ )
+#else
+#define SCENARIO( name, tags ) TEST_CASE( "Scenario: " name, tags )
+#define SCENARIO_METHOD( className, name, tags ) INTERNAL_CATCH_TEST_CASE_METHOD( className, "Scenario: " name, tags )
+#endif
+#define GIVEN( desc )    SECTION( "   Given: " desc, "" )
+#define WHEN( desc )     SECTION( "    When: " desc, "" )
+#define AND_WHEN( desc ) SECTION( "And when: " desc, "" )
+#define THEN( desc )     SECTION( "    Then: " desc, "" )
+#define AND_THEN( desc ) SECTION( "     And: " desc, "" )
+
+using Catch::Detail::Approx;
+
+// #included from: internal/catch_reenable_warnings.h
+
+#define TWOBLUECUBES_CATCH_REENABLE_WARNINGS_H_INCLUDED
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#elif defined __GNUC__
+#pragma GCC diagnostic pop
+#endif
+
+#endif // TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED
+
diff --git a/tests/src/catch.cpp b/tests/src/catch.cpp
new file mode 100644 (file)
index 0000000..0c7c351
--- /dev/null
@@ -0,0 +1,2 @@
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
diff --git a/tests/src/gl_mock.cpp b/tests/src/gl_mock.cpp
new file mode 100644 (file)
index 0000000..bd1668e
--- /dev/null
@@ -0,0 +1,226 @@
+#include "gl.h"
+
+namespace Tangram {
+
+GLenum GL::getError() {
+    return 0;
+}
+
+const GLubyte* GL::getString(GLenum name) {
+    return nullptr;
+}
+
+void GL::clear(GLbitfield mask) {
+}
+void GL::lineWidth(GLfloat width) {
+}
+void GL::viewport(GLint x, GLint y, GLsizei width, GLsizei height) {
+}
+
+void GL::enable(GLenum id) {
+}
+void GL::disable(GLenum id) {
+}
+void GL::depthFunc(GLenum func) {
+}
+void GL::depthMask(GLboolean flag) {
+}
+void GL::depthRange(GLfloat n, GLfloat f) {
+}
+void GL::clearDepth(GLfloat d) {
+}
+void GL::blendFunc(GLenum sfactor, GLenum dfactor) {
+}
+void GL::stencilFunc(GLenum func, GLint ref, GLuint mask) {
+}
+void GL::stencilMask(GLuint mask) {
+}
+void GL::stencilOp(GLenum fail, GLenum zfail, GLenum zpass) {
+}
+void GL::clearStencil(GLint s) {
+}
+void GL::colorMask(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha) {
+}
+void GL::cullFace(GLenum mode) {
+}
+void GL::frontFace(GLenum mode) {
+}
+void GL::clearColor(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha) {
+}
+void GL::getIntegerv(GLenum pname, GLint *params ) {
+}
+
+// Program
+void GL::useProgram(GLuint program) {
+}
+void GL::deleteProgram(GLuint program) {
+}
+void GL::deleteShader(GLuint shader) {
+}
+GLuint GL::createShader(GLenum type) {
+    return 0;
+}
+GLuint GL::createProgram() {
+    return 0;
+}
+
+void GL::compileShader(GLuint shader) {
+}
+void GL::attachShader(GLuint program, GLuint shader) {
+}
+void GL::linkProgram(GLuint program) {
+}
+
+void GL::shaderSource(GLuint shader, GLsizei count, const GLchar **string, const GLint *length) {
+}
+void GL::getShaderInfoLog(GLuint shader, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+}
+void GL::getProgramInfoLog(GLuint program, GLsizei bufSize, GLsizei *length, GLchar *infoLog) {
+}
+GLint GL::getUniformLocation(GLuint program, const GLchar *name) {
+    return 0;
+}
+GLint GL::getAttribLocation(GLuint program, const GLchar *name) {
+    return 0;
+}
+void GL::getProgramiv(GLuint program, GLenum pname, GLint *params) {
+}
+void GL::getShaderiv(GLuint shader, GLenum pname, GLint *params) {
+}
+
+// Buffers
+void GL::bindBuffer(GLenum target, GLuint buffer) {
+}
+void GL::deleteBuffers(GLsizei n, const GLuint *buffers) {
+}
+void GL::genBuffers(GLsizei n, GLuint *buffers) {
+}
+void GL::bufferData(GLenum target, GLsizeiptr size, const void *data, GLenum usage) {
+}
+void GL::bufferSubData(GLenum target, GLintptr offset, GLsizeiptr size, const void *data) {
+}
+void GL::readPixels(GLint x, GLint y, GLsizei width, GLsizei height,
+                    GLenum format, GLenum type, GLvoid* pixels) {
+}
+
+// Texture
+void GL::bindTexture(GLenum target, GLuint texture ) {
+}
+void GL::activeTexture(GLenum texture) {
+}
+void GL::genTextures(GLsizei n, GLuint *textures ) {
+}
+void GL::deleteTextures(GLsizei n, const GLuint *textures) {
+}
+void GL::texParameteri(GLenum target, GLenum pname, GLint param ) {
+}
+void GL::texImage2D(GLenum target, GLint level, GLint internalFormat, GLsizei width, GLsizei height,
+                    GLint border, GLenum format, GLenum type, const GLvoid *pixels) {
+}
+void GL::texSubImage2D(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height,
+                       GLenum format, GLenum type, const GLvoid *pixels) {
+}
+void GL::generateMipmap(GLenum target) {
+}
+
+void GL::enableVertexAttribArray(GLuint index) {
+}
+void GL::disableVertexAttribArray(GLuint index) {
+}
+void GL::vertexAttribPointer(GLuint index, GLint size, GLenum type, GLboolean normalized,
+                             GLsizei stride, const void *pointer) {
+}
+
+void GL::drawArrays(GLenum mode, GLint first, GLsizei count ) {
+}
+void GL::drawElements(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices ) {
+}
+
+void GL::uniform1f(GLint location, GLfloat v0) {
+}
+void GL::uniform2f(GLint location, GLfloat v0, GLfloat v1) {
+}
+void GL::uniform3f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2) {
+}
+void GL::uniform4f(GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3) {
+}
+
+void GL::uniform1i(GLint location, GLint v0) {
+}
+void GL::uniform2i(GLint location, GLint v0, GLint v1) {
+}
+void GL::uniform3i(GLint location, GLint v0, GLint v1, GLint v2) {
+}
+void GL::uniform4i(GLint location, GLint v0, GLint v1, GLint v2, GLint v3) {
+}
+
+void GL::uniform1fv(GLint location, GLsizei count, const GLfloat *value) {
+}
+void GL::uniform2fv(GLint location, GLsizei count, const GLfloat *value) {
+}
+void GL::uniform3fv(GLint location, GLsizei count, const GLfloat *value) {
+}
+void GL::uniform4fv(GLint location, GLsizei count, const GLfloat *value) {
+}
+void GL::uniform1iv(GLint location, GLsizei count, const GLint *value) {
+}
+void GL::uniform2iv(GLint location, GLsizei count, const GLint *value) {
+}
+void GL::uniform3iv(GLint location, GLsizei count, const GLint *value) {
+}
+void GL::uniform4iv(GLint location, GLsizei count, const GLint *value) {
+}
+
+void GL::uniformMatrix2fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+}
+void GL::uniformMatrix3fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+}
+void GL::uniformMatrix4fv(GLint location, GLsizei count, GLboolean transpose, const GLfloat *value) {
+}
+
+// mapbuffer
+void* GL::mapBuffer(GLenum target, GLenum access) {
+    return nullptr;
+}
+GLboolean GL::unmapBuffer(GLenum target) {
+    return true;
+}
+
+void GL::finish(void) {
+}
+
+// VAO
+void GL::bindVertexArray(GLuint array) {
+}
+void GL::deleteVertexArrays(GLsizei n, const GLuint *arrays) {
+}
+void GL::genVertexArrays(GLsizei n, GLuint *arrays) {
+}
+
+// Framebuffer
+void GL::bindFramebuffer(GLenum target, GLuint framebuffer) {
+}
+void GL::genFramebuffers(GLsizei n, GLuint *framebuffers) {
+}
+void GL::framebufferTexture2D(GLenum target, GLenum attachment, GLenum textarget,
+                              GLuint texture, GLint level) {
+}
+void GL::renderbufferStorage(GLenum target, GLenum internalformat, GLsizei width,
+                             GLsizei height) {
+}
+void GL::framebufferRenderbuffer(GLenum target, GLenum attachment,
+                                 GLenum renderbuffertarget, GLuint renderbuffer) {
+}
+void GL::genRenderbuffers(GLsizei n, GLuint *renderbuffers) {
+}
+void GL::bindRenderbuffer(GLenum target, GLuint renderbuffer) {
+}
+void GL::deleteFramebuffers(GLsizei n, const GLuint *framebuffers) {
+}
+void GL::deleteRenderbuffers(GLsizei n, const GLuint *renderbuffers) {
+}
+GLenum GL::checkFramebufferStatus(GLenum target) {
+    return 0;
+}
+
+}
diff --git a/tests/src/platform_mock.cpp b/tests/src/platform_mock.cpp
new file mode 100644 (file)
index 0000000..9177144
--- /dev/null
@@ -0,0 +1,52 @@
+#include "platform_mock.h"
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <iostream>
+#include <fstream>
+#include <string>
+
+#include <libgen.h>
+
+#define DEFAULT "fonts/NotoSans-Regular.ttf"
+#define FONT_AR "fonts/NotoNaskh-Regular.ttf"
+#define FONT_HE "fonts/NotoSansHebrew-Regular.ttf"
+#define FONT_JA "fonts/DroidSansJapanese.ttf"
+#define FALLBACK "fonts/DroidSansFallback.ttf"
+
+#include "log.h"
+
+namespace Tangram {
+
+void logMsg(const char* fmt, ...) {
+    va_list args;
+    va_start(args, fmt);
+    vfprintf(stderr, fmt, args);
+    va_end(args);
+}
+
+void MockPlatform::requestRender() const {}
+
+std::vector<FontSourceHandle> MockPlatform::systemFontFallbacksHandle() const {
+    std::vector<FontSourceHandle> handles;
+
+    handles.emplace_back(DEFAULT);
+    handles.emplace_back(FONT_AR);
+    handles.emplace_back(FONT_HE);
+    handles.emplace_back(FONT_JA);
+    handles.emplace_back(FALLBACK);
+
+    return handles;
+}
+
+bool MockPlatform::startUrlRequest(const std::string& _url, UrlCallback _callback) {
+    return true;
+}
+
+void MockPlatform::cancelUrlRequest(const std::string& _url) {}
+
+void setCurrentThreadPriority(int priority) {}
+
+void initGLExtensions() {}
+
+} // namespace Tangram
diff --git a/tests/src/platform_mock.h b/tests/src/platform_mock.h
new file mode 100644 (file)
index 0000000..a32b7b0
--- /dev/null
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "platform.h"
+
+namespace Tangram {
+
+class MockPlatform : public Platform {
+
+public:
+
+    void requestRender() const override;
+    std::vector<FontSourceHandle> systemFontFallbacksHandle() const override;
+    bool startUrlRequest(const std::string& _url, UrlCallback _callback) override;
+    void cancelUrlRequest(const std::string& _url) override;
+
+};
+
+} // namespace Tangram
diff --git a/tests/unit/curlTests.cpp b/tests/unit/curlTests.cpp
new file mode 100644 (file)
index 0000000..917f4c6
--- /dev/null
@@ -0,0 +1,46 @@
+#include "catch.hpp"
+
+#include <iostream>
+
+/*#include "dataSource.h"
+#include "mapTile.h"
+#include "glm/glm.hpp"
+#include "tileID.h"*/
+
+
+TEST_CASE( "URL Name Check for MapzenVectorTileJson", "[CURL][DataSource][MapzenVectorTileJson]" ) {
+    /*MapzenVectorTileJson dataSource;
+    TileID tileCoord = TileID(0,0,0);
+    std::string url;
+    *dataSource.constructURL(tileCoord, url);
+    REQUIRE( url == "http://tile.mapzen.com/mapzen/vector/v1/all/0/0/0.json");
+    TileID tileCoord2 = TileID(19293,24641,16);
+    *dataSource.constructURL(tileCoord2, url);
+    REQUIRE( url == "http://tile.mapzen.com/mapzen/vector/v1/all/16/19293/24641.json");
+    TileID tileCoord3 = TileID(19293,24641,14);
+    *dataSource.constructURL(tileCoord3, url);
+    REQUIRE( url == "http://tile.mapzen.com/mapzen/vector/v1/all/14/19293/24641.json");*/
+}
+
+TEST_CASE( "Extract tile coordinates from URL check for MapzenVectorTileJson", "[CURL][DataSource][MapzenVectorTileJson]" ) {
+    /*MapzenVectorTileJson dataSource;
+    REQUIRE( dataSource.extractIDFromUrl("http://tile.mapzen.com/mapzen/vector/v1/all/16/19293/24641.json") == TileID(19293, 24641, 16) );
+    REQUIRE( dataSource.extractIDFromUrl("http://tile.mapzen.com/mapzen/vector/v1/all/0/0/0.json") == TileID(0,0,0) );
+    REQUIRE( dataSource.extractIDFromUrl("http://tile.mapzen.com/mapzen/vector/v1/all/14/19293/24641.json") == TileID(19293, 24641, 14) );*/
+}
+
+TEST_CASE( "MapzenVectorTileJson::LoadTile check", "[CURL][DataSource][MapzenVectorTileJson]" ) {
+    /*MapzenVectorTileJson dataSource;
+    std::vector<TileID> tileCoords;
+    tileCoords.push_back(TileID(19293,24641,16));
+    tileCoords.push_back(TileID(19293,24641,14));
+    tileCoords.push_back(TileID(0,0,0));
+    dataSource.loadTile(tileCoords);
+    //check if all the test tileCoordinates are loaded
+    REQUIRE(dataSource.JsonRootSize() == 3);
+    //check if all the test tiles have data in the jsonRoots data structure
+    REQUIRE(dataSource.CheckDataExists(TileID(19293, 24641, 14)) == true);
+    REQUIRE(dataSource.CheckDataExists(TileID(19293, 24641, 16)) == true);
+    REQUIRE(dataSource.CheckDataExists(TileID(0, 0, 0)) == true);
+    REQUIRE(dataSource.CheckDataExists(TileID(0, 1, 0)) == false);*/
+}
diff --git a/tests/unit/drawRuleTests.cpp b/tests/unit/drawRuleTests.cpp
new file mode 100644 (file)
index 0000000..d3f3855
--- /dev/null
@@ -0,0 +1,207 @@
+#include "catch.hpp"
+
+#include "scene/drawRule.h"
+#include "scene/sceneLayer.h"
+#include "platform.h"
+
+#include <cstdio>
+#include <algorithm>
+
+using namespace Tangram;
+
+// Functions to initialize DrawRule instances
+const int dg1 = 0;
+const int dg2 = 1;
+
+DrawRuleData instance_a() {
+
+    std::vector<StyleParam> params = {
+        { StyleParamKey::order, "value_0a" },
+        { StyleParamKey::join, "value_4a" },
+        { StyleParamKey::color, "value_1a" }
+    };
+
+    return { "dg1", dg1, std::move(params) };
+
+}
+
+DrawRuleData instance_b() {
+
+    std::vector<StyleParam> params = {
+        { StyleParamKey::order, "value_0b" },
+        { StyleParamKey::width, "value_2b" },
+        { StyleParamKey::color, "value_1b" },
+        { StyleParamKey::cap, "value_3b" },
+        { StyleParamKey::style, "value_4b" }
+    };
+
+    return { "dg1", dg1, std::move(params) };
+
+}
+
+DrawRuleData instance_c() {
+
+    std::vector<StyleParam> params = {};
+
+    // changed from dg2 - styles will not be merged otherwise
+    return { "dg1", dg1, params };
+
+}
+
+TEST_CASE("DrawRule correctly merges with another DrawRule", "[DrawRule]") {
+
+    const SceneLayer layer_a = { "a", Filter(), { instance_a() }, {}, true };
+    const SceneLayer layer_b = { "b", Filter(), { instance_b() }, {}, true };
+    const SceneLayer layer_c = { "c", Filter(), { instance_c() }, {}, true };
+
+    // For parameters contained in multiple rules, the parameter from the last rule
+    // (by lexicographical order) should result.
+    {
+        DrawRuleMergeSet ruleSet;
+        ruleSet.mergeRules(layer_a);
+
+        REQUIRE(ruleSet.matchedRules().size() == 1);
+        auto& merged_ab = ruleSet.matchedRules()[0];
+
+        for (size_t i = 0; i < StyleParamKeySize; i++) {
+            if (!merged_ab.active[i]) {
+                continue;
+            }
+            auto* param = merged_ab.params[i].param;
+            if (!param) {
+                logMsg("param : none %d\n", i);
+                continue;
+            }
+            logMsg("param : %s\n", param->toString().c_str());
+        }
+
+        ruleSet.mergeRules(layer_b);
+
+        REQUIRE(ruleSet.matchedRules().size() == 1);
+
+        // printf("rule_a:\n %s", rule_a.toString().c_str());
+        // printf("rule_c:\n %s", rule_c.toString().c_str());
+        // printf("merged_ac:\n %s", merged_ac.toString().c_str());
+        for (size_t i = 0; i < StyleParamKeySize; i++) {
+            if (!merged_ab.active[i]) {
+                continue;
+            }
+            auto* param = merged_ab.params[i].param;
+            if (!param) {
+                logMsg("param : none %d\n", i);
+                continue;
+            }
+            logMsg("param : %s\n", param->toString().c_str());
+        }
+        REQUIRE(merged_ab.findParameter(StyleParamKey::cap).key == StyleParamKey::cap);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::cap).value.get<std::string>() == "value_3b");
+        REQUIRE(merged_ab.findParameter(StyleParamKey::color).key == StyleParamKey::color);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::color).value.get<std::string>() == "value_1b");
+        REQUIRE(merged_ab.findParameter(StyleParamKey::join).key == StyleParamKey::join);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::join).value.get<std::string>() == "value_4a");
+        REQUIRE(merged_ab.findParameter(StyleParamKey::order).key == StyleParamKey::order);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::order).value.get<std::string>() == "value_0b");
+        REQUIRE(merged_ab.findParameter(StyleParamKey::style).key == StyleParamKey::style);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::style).value.get<std::string>() == "value_4b");
+        REQUIRE(merged_ab.findParameter(StyleParamKey::width).key == StyleParamKey::width);
+        REQUIRE(merged_ab.findParameter(StyleParamKey::width).value.get<std::string>() == "value_2b");
+
+        // explicit style wins
+        REQUIRE(merged_ab.getStyleName() == "value_4b");
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        ruleSet.mergeRules(layer_b);
+        ruleSet.mergeRules(layer_a);
+
+        REQUIRE(ruleSet.matchedRules().size() == 1);
+
+        auto& merged_ba = ruleSet.matchedRules()[0];
+
+        REQUIRE(merged_ba.findParameter(StyleParamKey::cap).key == StyleParamKey::cap);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::cap).value.get<std::string>() == "value_3b");
+        REQUIRE(merged_ba.findParameter(StyleParamKey::color).key == StyleParamKey::color);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::color).value.get<std::string>() == "value_1b");
+        REQUIRE(merged_ba.findParameter(StyleParamKey::join).key == StyleParamKey::join);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::join).value.get<std::string>() == "value_4a");
+        REQUIRE(merged_ba.findParameter(StyleParamKey::order).key == StyleParamKey::order);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::order).value.get<std::string>() == "value_0b");
+        REQUIRE(merged_ba.findParameter(StyleParamKey::style).key == StyleParamKey::style);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::style).value.get<std::string>() == "value_4b");
+        REQUIRE(merged_ba.findParameter(StyleParamKey::width).key == StyleParamKey::width);
+        REQUIRE(merged_ba.findParameter(StyleParamKey::width).value.get<std::string>() == "value_2b");
+
+        // explicit style wins
+        REQUIRE(merged_ba.getStyleName() == "value_4b");
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        ruleSet.mergeRules(layer_c);
+        ruleSet.mergeRules(layer_b);
+
+        REQUIRE(ruleSet.matchedRules().size() == 1);
+
+        auto& merged_bc = ruleSet.matchedRules()[0];
+
+        // for (size_t i = 0; i < StyleParamKeySize; i++) {
+        //     auto* param = merged_bc.params[i];
+        //     if (!param) { continue; }
+        //     REQUIRE(param->key == rule_b[0].parameters[i].key);
+        //     REQUIRE(param->value.get<std::string>() ==
+        //             rule_b[0].parameters[i].value.get<std::string>());
+        // }
+
+        // explicit style wins
+        REQUIRE(merged_bc.getStyleName() == "value_4b");
+    }
+
+}
+
+TEST_CASE("DrawRule locates and outputs a parameter that it contains", "[DrawRule]") {
+
+    std::string str;
+
+    const SceneLayer layer_a = { "a", Filter(), { instance_a() }, {}, true };
+    const SceneLayer layer_b = { "b", Filter(), { instance_b() }, {}, true };
+
+    DrawRuleMergeSet a;
+    a.mergeRules(layer_a);
+    auto& rule_a = a.matchedRules()[0];
+
+    REQUIRE(rule_a.get(StyleParamKey::order, str)); REQUIRE(str == "value_0a");
+    REQUIRE(rule_a.get(StyleParamKey::color, str)); REQUIRE(str == "value_1a");
+    REQUIRE(rule_a.get(StyleParamKey::join, str)); REQUIRE(str == "value_4a");
+
+    DrawRuleMergeSet b;
+    b.mergeRules(layer_b);
+    auto& rule_b = b.matchedRules()[0];
+
+    REQUIRE(rule_b.get(StyleParamKey::color, str)); REQUIRE(str == "value_1b");
+    REQUIRE(rule_b.get(StyleParamKey::width, str)); REQUIRE(str == "value_2b");
+    REQUIRE(rule_b.get(StyleParamKey::cap, str)); REQUIRE(str == "value_3b");
+    REQUIRE(rule_b.get(StyleParamKey::order, str)); REQUIRE(str == "value_0b");
+}
+
+TEST_CASE("DrawRule correctly reports that it doesn't contain a parameter", "[DrawRule]") {
+    std::string str;
+
+    const SceneLayer layer_a = { "a", Filter(), { instance_a() }, {}, true };
+    DrawRuleMergeSet a;
+    a.mergeRules(layer_a);
+    REQUIRE(!a.matchedRules()[0].get(StyleParamKey::width, str)); REQUIRE(str == "");
+
+
+    const SceneLayer layer_b = { "b", Filter(), { instance_b() }, {}, true };
+    DrawRuleMergeSet b;
+    b.mergeRules(layer_b);
+    REQUIRE(!b.matchedRules()[0].get(StyleParamKey::join, str)); REQUIRE(str == "");
+
+    const SceneLayer layer_c = { "c", Filter(), { instance_c() }, {}, true };
+    DrawRuleMergeSet c;
+    c.mergeRules(layer_c);
+    REQUIRE(!c.matchedRules()[0].get(StyleParamKey::order, str)); REQUIRE(str == "");
+
+
+}
diff --git a/tests/unit/dukTests.cpp b/tests/unit/dukTests.cpp
new file mode 100644 (file)
index 0000000..4a10599
--- /dev/null
@@ -0,0 +1,392 @@
+#include "catch.hpp"
+
+#include "yaml-cpp/yaml.h"
+#include "scene/filters.h"
+#include "scene/sceneLoader.h"
+#include "scene/scene.h"
+#include "scene/styleContext.h"
+#include "util/builders.h"
+#include "platform_mock.h"
+
+using namespace Tangram;
+
+TEST_CASE( "", "[Duktape][init]") {
+    StyleContext();
+}
+
+TEST_CASE( "Test evalFilterFn with feature", "[Duktape][evalFilterFn]") {
+    Feature feature;
+    feature.props.set("a", "A");
+    feature.props.set("b", "B");
+    feature.props.set("n", 42);
+
+    StyleContext ctx;
+    ctx.setFeature(feature);
+
+    REQUIRE(ctx.setFunctions({R"(function() { return feature.a === 'A' })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return feature.b === 'B' })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return feature.n === 42 })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return feature.n === 43 })"}));
+    REQUIRE(ctx.evalFilter(0) == false);
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return feature.n === '42' })"}));
+    REQUIRE(ctx.evalFilter(0) == false);
+}
+
+TEST_CASE( "Test evalFilterFn with feature and keywords", "[Duktape][evalFilterFn]") {
+    Feature feature;
+    feature.props.set("scalerank", 2);
+
+    StyleContext ctx;
+    ctx.setFeature(feature);
+    ctx.setKeyword("$zoom", 5);
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return (feature.scalerank * .5) <= ($zoom - 4); })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    ctx.setKeyword("$zoom", 4);
+    REQUIRE(ctx.evalFilter(0) == false);
+
+}
+
+TEST_CASE( "Test evalFilterFn with feature and keyword geometry", "[Duktape][evalFilterFn]") {
+    Feature points;
+    points.geometryType = GeometryType::points;
+
+    Feature lines;
+    lines.geometryType = GeometryType::lines;
+
+    Feature polygons;
+    polygons.geometryType = GeometryType::polygons;
+
+    StyleContext ctx;
+
+    // Test $geometry keyword
+    REQUIRE(ctx.setFunctions({
+                R"(function() { return $geometry === 'point'; })",
+                R"(function() { return $geometry === 'line'; })",
+                R"(function() { return $geometry === 'polygon'; })"}));
+
+    ctx.setFeature(points);
+    REQUIRE(ctx.evalFilter(0) == true);
+    REQUIRE(ctx.evalFilter(1) == false);
+    REQUIRE(ctx.evalFilter(2) == false);
+
+    ctx.setFeature(lines);
+    REQUIRE(ctx.evalFilter(0) == false);
+    REQUIRE(ctx.evalFilter(1) == true);
+    REQUIRE(ctx.evalFilter(2) == false);
+
+    ctx.setFeature(polygons);
+    REQUIRE(ctx.evalFilter(0) == false);
+    REQUIRE(ctx.evalFilter(1) == false);
+    REQUIRE(ctx.evalFilter(2) == true);
+
+}
+
+TEST_CASE( "Test evalFilterFn with different features", "[Duktape][evalFilterFn]") {
+    StyleContext ctx;
+
+    REQUIRE(ctx.setFunctions({ R"(function() { return feature.scalerank === 2; })"}));
+
+    Feature feat1;
+    feat1.props.set("scalerank", 2);
+
+    ctx.setFeature(feat1);
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    Feature feat2;
+    ctx.setFeature(feat2);
+    REQUIRE(ctx.evalFilter(0) == false);
+
+    ctx.setFeature(feat1);
+    REQUIRE(ctx.evalFilter(0) == true);
+}
+
+TEST_CASE( "Test numeric keyword", "[Duktape][setKeyword]") {
+    StyleContext ctx;
+    ctx.setKeyword("$zoom", 10);
+    REQUIRE(ctx.setFunctions({ R"(function() { return $zoom === 10 })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    ctx.setKeyword("$zoom", 0);
+    REQUIRE(ctx.evalFilter(0) == false);
+}
+
+TEST_CASE( "Test string keyword", "[Duktape][setKeyword]") {
+    StyleContext ctx;
+    ctx.setKeyword("$geometry", GeometryType::points);
+    REQUIRE(ctx.setFunctions({ R"(function() { return $geometry === point })"}));
+    REQUIRE(ctx.evalFilter(0) == true);
+
+    ctx.setKeyword("$geometry", "none");
+    REQUIRE(ctx.evalFilter(0) == false);
+
+}
+
+TEST_CASE( "Test evalStyleFn - StyleParamKey::order", "[Duktape][evalStyleFn]") {
+    Feature feat;
+    feat.props.set("sort_key", 2);
+
+    StyleContext ctx;
+    ctx.setFeature(feat);
+    REQUIRE(ctx.setFunctions({ R"(function () { return feature.sort_key + 5 })"}));
+
+    StyleParam::Value value;
+
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::order, value) == true);
+    REQUIRE(value.is<uint32_t>() == true);
+    REQUIRE(value.get<uint32_t>() == 7);
+}
+
+TEST_CASE( "Test evalStyleFn - StyleParamKey::color", "[Duktape][evalStyleFn]") {
+
+    StyleContext ctx;
+    StyleParam::Value value;
+
+    REQUIRE(ctx.setFunctions({ R"(function () { return '#f0f'; })"}));
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::color, value) == true);
+    REQUIRE(value.is<uint32_t>() == true);
+    REQUIRE(value.get<uint32_t>() == 0xffff00ff);
+
+    REQUIRE(ctx.setFunctions({ R"(function () { return 0xff00ffff; })"}));
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::color, value) == true);
+    REQUIRE(value.is<uint32_t>() == true);
+    REQUIRE(value.get<uint32_t>() == 0xff00ffff);
+
+    REQUIRE(ctx.setFunctions({ R"(function () { return [1.0, 1.0, 0.0, 1.0] })"}));
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::color, value) == true);
+    REQUIRE(value.is<uint32_t>() == true);
+    REQUIRE(value.get<uint32_t>() == 0xffffff00);
+
+    REQUIRE(ctx.setFunctions({ R"(function () { return [0.0, 1.0, 0.0] })"}));
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::color, value) == true);
+    REQUIRE(value.is<uint32_t>() == true);
+    REQUIRE(value.get<uint32_t>() == 0xff00ff00);
+
+}
+
+TEST_CASE( "Test evalStyleFn - StyleParamKey::width", "[Duktape][evalStyleFn]") {
+    Feature feat;
+    feat.props.set("width", 2.0);
+
+    StyleContext ctx;
+    ctx.setFeature(feat);
+    REQUIRE(ctx.setFunctions({ R"(function () { return feature.width * 2.3; })"}));
+
+    StyleParam::Value value;
+
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::width, value) == true);
+    REQUIRE(value.is<StyleParam::Width>() == true);
+    REQUIRE(value.get<StyleParam::Width>().value == 4.6f);
+}
+
+TEST_CASE( "Test evalStyleFn - StyleParamKey::extrude", "[Duktape][evalStyleFn]") {
+    Feature feat;
+    feat.props.set("width", 2.0);
+
+    StyleContext ctx;
+    ctx.setFeature(feat);
+    REQUIRE(ctx.setFunctions({
+                R"(function () { return true; })",
+                R"(function () { return false; })",
+                R"(function () { return [1.1, 2.2]; })"}));
+
+    StyleParam::Value value;
+
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::extrude, value) == true);
+    REQUIRE(value.is<glm::vec2>() == true);
+    StyleParam::Value e1(glm::vec2(NAN, NAN));
+    REQUIRE(std::isnan(value.get<glm::vec2>()[0]) == true);
+
+    REQUIRE(ctx.evalStyle(1, StyleParamKey::extrude, value) == true);
+    REQUIRE(value.is<glm::vec2>() == true);
+    StyleParam::Value e2(glm::vec2(0.0f, 0.0f));
+    REQUIRE(value == e2);
+
+    REQUIRE(ctx.evalStyle(2, StyleParamKey::extrude, value) == true);
+    REQUIRE(value.is<glm::vec2>() == true);
+    StyleParam::Value e3(glm::vec2(1.1f, 2.2f));
+    REQUIRE(value == e3);
+
+}
+
+TEST_CASE( "Test evalStyleFn - StyleParamKey::text_source", "[Duktape][evalStyleFn]") {
+    Feature feat;
+    feat.props.set("name", "my name is my name");
+
+    StyleContext ctx;
+    ctx.setFeature(feat);
+    REQUIRE(ctx.setFunctions({
+                R"(function () { return 'hello!'; })",
+                R"(function () { return feature.name; })"}));
+
+    StyleParam::Value value;
+
+    REQUIRE(ctx.evalStyle(0, StyleParamKey::text_source, value) == true);
+    REQUIRE(value.is<std::string>());
+    REQUIRE(value.get<std::string>() == "hello!");
+
+    REQUIRE(ctx.evalStyle(1, StyleParamKey::text_source, value) == true);
+    REQUIRE(value.is<std::string>());
+    REQUIRE(value.get<std::string>() == "my name is my name");
+}
+
+TEST_CASE( "Test evalFilter - Init filter function from yaml", "[Duktape][evalFilter]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    Scene scene(platform);
+    YAML::Node n0 = YAML::Load(R"(filter: function() { return feature.sort_key === 2; })");
+    YAML::Node n1 = YAML::Load(R"(filter: function() { return feature.name === 'test'; })");
+
+    Filter filter0 = SceneLoader::generateFilter(n0["filter"], scene);
+    Filter filter1 = SceneLoader::generateFilter(n1["filter"], scene);
+
+    REQUIRE(scene.functions().size() == 2);
+
+    REQUIRE(filter0.data.is<Filter::Function>());
+    REQUIRE(filter1.data.is<Filter::Function>());
+
+    StyleContext ctx;
+    ctx.initFunctions(scene);
+
+    Feature feat1;
+    feat1.props.set("sort_key", 2);
+    feat1.props.set("name", "test");
+    ctx.setFeature(feat1);
+
+    // NB: feature parameter is ignored for Function evaluation
+    REQUIRE(filter0.eval(feat1, ctx) == true);
+    REQUIRE(filter1.eval(feat1, ctx) == true);
+
+    // This is what happens in the above 'eval' internally
+    REQUIRE(ctx.evalFilter(filter0.data.get<Filter::Function>().id) == true);
+    REQUIRE(ctx.evalFilter(filter1.data.get<Filter::Function>().id) == true);
+
+    // ... Also check that setFeature updates the ctx
+    Feature feat2;
+    feat2.props.set("name", "nope");
+    ctx.setFeature(feat2);
+
+    REQUIRE(filter0.eval(feat2, ctx) == false);
+    REQUIRE(filter1.eval(feat2, ctx) == false);
+
+    REQUIRE(ctx.evalFilter(filter0.data.get<Filter::Function>().id) == false);
+    REQUIRE(ctx.evalFilter(filter1.data.get<Filter::Function>().id) == false);
+
+}
+
+TEST_CASE("Test evalStyle - Init StyleParam function from yaml", "[Duktape][evalStyle]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+    YAML::Node n0 = YAML::Load(R"(
+            draw:
+                color: function() { return '#ffff00ff'; }
+                width: function() { return 2; }
+                cap: function() { return 'round'; }
+            )");
+
+    std::vector<StyleParam> styles;
+
+    SceneLoader::parseStyleParams(n0["draw"], scene, "", styles);
+
+    REQUIRE(scene->functions().size() == 3);
+
+    // for (auto& str : scene.functions()) {
+    //     logMsg("F: '%s'\n", str.c_str());
+    // }
+
+    StyleContext ctx;
+    ctx.initFunctions(*scene);
+
+    for (auto& style : styles) {
+        //logMsg("S: %d - '%s' %d\n", style.key, style.toString().c_str(), style.function);
+
+        if (style.key == StyleParamKey::color) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<uint32_t>() == true);
+            REQUIRE(value.get<uint32_t>() == 0xffff00ff);
+
+        } else if (style.key == StyleParamKey::width) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<StyleParam::Width>() == true);
+            REQUIRE(value.get<StyleParam::Width>().value == 2);
+
+        } else if (style.key == StyleParamKey::cap) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<uint32_t>() == true);
+            REQUIRE(static_cast<CapTypes>(value.get<uint32_t>()) == CapTypes::round);
+        } else {
+            REQUIRE(true == false);
+        }
+    }
+}
+
+TEST_CASE( "Test evalFunction explicit", "[Duktape][evalFunction]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+    YAML::Node n0 = YAML::Load(R"(
+            global:
+                width: 2
+                mapNode:
+                    color: function(c) { return c; }
+                    caps:
+                        cap: round
+                    test: function
+            draw:
+                color: function() { return global.mapNode.color("blue"); }
+                width: function() { return global.width; }
+                cap: function() { return global.mapNode.caps.cap; }
+                text_source: function() { return global.mapNode.test; }
+            )");
+
+    std::vector<StyleParam> styles;
+
+    scene->config() = n0;
+
+    SceneLoader::parseStyleParams(n0["draw"], scene, "", styles);
+
+    REQUIRE(scene->functions().size() == 4);
+
+    StyleContext ctx;
+    ctx.initFunctions(*scene);
+
+    for (auto& style : styles) {
+        if (style.key == StyleParamKey::color) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<uint32_t>() == true);
+            REQUIRE(value.get<uint32_t>() == 0xffff0000);
+
+        } else if (style.key == StyleParamKey::width) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<StyleParam::Width>() == true);
+            REQUIRE(value.get<StyleParam::Width>().value == 2);
+
+        } else if (style.key == StyleParamKey::cap) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<uint32_t>() == true);
+            REQUIRE(static_cast<CapTypes>(value.get<uint32_t>()) == CapTypes::round);
+
+        } else if(style.key == StyleParamKey::text_source) {
+            StyleParam::Value value;
+            REQUIRE(ctx.evalStyle(style.function, style.key, value) == true);
+            REQUIRE(value.is<std::string>() == true);
+            REQUIRE(value.get<std::string>() == "function");
+
+        } else {
+            REQUIRE(true == false);
+        }
+    }
+
+}
diff --git a/tests/unit/fileTests.cpp b/tests/unit/fileTests.cpp
new file mode 100644 (file)
index 0000000..9636b24
--- /dev/null
@@ -0,0 +1,22 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <sys/stat.h>
+#include "tangram.h"
+#include "platform.h"
+
+TEST_CASE( "Compare byte size of allocated resource to os file size", "[Core][bytesFromResource]" ) {
+#if 0
+    unsigned int size;
+    unsigned char* data = bytesFromFile("shaders/polygon.fs", PathType::internal, &size);
+
+    // ask os for size
+    struct stat st;
+    stat("shaders/polygon.fs", &st);
+    unsigned int sys_size = st.st_size;
+
+    REQUIRE(sys_size == size);
+
+    free(data);
+#endif
+}
diff --git a/tests/unit/labelTests.cpp b/tests/unit/labelTests.cpp
new file mode 100644 (file)
index 0000000..a41bcc2
--- /dev/null
@@ -0,0 +1,215 @@
+#include "catch.hpp"
+#include "tangram.h"
+#include "labels/label.h"
+#include "view/view.h"
+#include "style/textStyle.h"
+#include "labels/screenTransform.h"
+#include "labels/textLabel.h"
+#include "labels/textLabels.h"
+#include "glm/mat4x4.hpp"
+#include "glm/gtc/matrix_transform.hpp"
+
+#define EPSILON 0.00001
+
+using namespace Tangram;
+
+glm::vec2 screenSize(500.f, 500.f);
+TextStyle dummyStyle("textStyle", nullptr);
+TextLabels dummy(dummyStyle);
+Label::AABB bounds(0.f, 0.f, 500.f, 500.f);
+
+struct TestTransform {
+    ScreenTransform::Buffer buffer;
+    Range range;
+    ScreenTransform transform;
+    TestTransform() : transform(buffer, range) {}
+};
+
+TextLabel makeLabel(glm::vec2 _transform, Label::Type _type) {
+    Label::Options options;
+    options.offset = {0.0f, 0.0f};
+    options.anchors.anchor[0] = LabelProperty::Anchor::center;
+    options.anchors.count = 1;
+    options.showTransition.time = 0.2;
+    options.hideTransition.time = 0.2;
+
+    TextRange textRanges;
+
+    return TextLabel({{glm::vec3(_transform, 0)}}, _type, options,
+            {}, {0, 0}, dummy, textRanges,
+            TextLabelProperty::Align::none);
+}
+
+View makeView() {
+    View view(256, 256);
+
+    view.setPosition(0, 0);
+    view.setZoom(0);
+    view.update(false);
+
+    return view;
+}
+
+TEST_CASE( "Ensure the transition from wait -> sleep when occlusion happens", "[Core][Label]" ) {
+    View view = makeView();
+    TestTransform t1, t2;
+
+    TextLabel l(makeLabel({screenSize/2.f}, Label::Type::point));
+
+    REQUIRE(l.state() == Label::State::none);
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t1.transform);
+
+    REQUIRE(l.state() != Label::State::sleep);
+    REQUIRE(l.state() == Label::State::none);
+    REQUIRE(l.canOcclude());
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t2.transform);
+    l.occlude(true);
+    l.evalState(0);
+
+    REQUIRE(l.state() == Label::State::sleep);
+}
+
+TEST_CASE( "Ensure the transition from wait -> visible when no occlusion happens", "[Core][Label]" ) {
+    View view = makeView();
+    TestTransform t1, t2;
+
+    TextLabel l(makeLabel({screenSize/2.f}, Label::Type::point));
+
+    REQUIRE(l.state() == Label::State::none);
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t1.transform);
+    l.occlude(false);
+    l.evalState(0);
+
+    REQUIRE(l.state() == Label::State::fading_in);
+    REQUIRE(l.canOcclude());
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t2.transform);
+    l.evalState(1.f);
+
+    REQUIRE(l.state() == Label::State::visible);
+    REQUIRE(l.canOcclude());
+}
+
+TEST_CASE( "Ensure the end state after occlusion is leep state", "[Core][Label]" ) {
+    View view = makeView();
+    TestTransform t1, t2;
+
+    TextLabel l(makeLabel({screenSize/2.f}, Label::Type::point));
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t1.transform);
+    l.occlude(false);
+    l.evalState(0);
+
+    REQUIRE(l.state() == Label::State::fading_in);
+    REQUIRE(l.canOcclude());
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t2.transform);
+    l.occlude(true);
+    l.evalState(1.f);
+
+    REQUIRE(l.state() == Label::State::sleep);
+    REQUIRE(l.canOcclude());
+}
+
+TEST_CASE( "Ensure the sleep transition for out of screen labels", "[Core][Label]" ) {
+    View view = makeView();
+    TestTransform t1, t2;
+
+    TextLabel l(makeLabel({screenSize*4.f}, Label::Type::point));
+
+    REQUIRE(l.state() == Label::State::none);
+
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t1.transform);
+
+    REQUIRE(l.state() == Label::State::sleep);
+    REQUIRE(l.canOcclude());
+
+    l.update(glm::ortho(0.f, screenSize.x * 4.f, screenSize.y * 4.f, 0.f, -1.f, 1.f), view.state(), &bounds, t2.transform);
+    l.evalState(0);
+    REQUIRE(l.state() != Label::State::none);
+
+    REQUIRE(l.state() == Label::State::fading_in);
+    REQUIRE(l.canOcclude());
+}
+
+TEST_CASE( "Ensure debug labels are always visible and cannot occlude", "[Core][Label]" ) {
+    View view = makeView();
+
+    TextLabel l(makeLabel({screenSize/2.f}, Label::Type::debug));
+
+    REQUIRE(l.state() == Label::State::visible);
+    REQUIRE(!l.canOcclude());
+
+    TestTransform t1;
+    l.update(glm::ortho(0.f, screenSize.x, screenSize.y, 0.f, -1.f, 1.f), view.state(), &bounds, t1.transform);
+    l.evalState(1.f);
+
+    REQUIRE(l.state() == Label::State::visible);
+    REQUIRE(!l.canOcclude());
+}
+
+TEST_CASE( "Linear interpolation", "[Core][Label][Fade]" ) {
+    FadeEffect fadeOut(false, FadeEffect::Interpolation::linear, 1.0);
+
+    REQUIRE(fadeOut.update(0.0) == 1.0);
+    REQUIRE(fadeOut.update(0.5) == 0.5);
+    REQUIRE(fadeOut.update(0.5) == 0.0);
+
+    fadeOut.update(0.01);
+
+    REQUIRE(fadeOut.isFinished());
+
+    FadeEffect fadeIn(true, FadeEffect::Interpolation::linear, 1.0);
+
+    REQUIRE(fadeIn.update(0.0) == 0.0);
+    REQUIRE(fadeIn.update(0.5) == 0.5);
+    REQUIRE(fadeIn.update(0.5) == 1.0);
+
+    fadeIn.update(0.01);
+
+    REQUIRE(fadeIn.isFinished());
+}
+
+TEST_CASE( "Pow interpolation", "[Core][Label][Fade]" ) {
+    FadeEffect fadeOut(false, FadeEffect::Interpolation::pow, 1.0);
+
+    REQUIRE(fadeOut.update(0.0) == 1.0);
+    REQUIRE(fadeOut.update(0.5) == 0.75);
+    REQUIRE(fadeOut.update(0.5) == 0.0);
+
+    fadeOut.update(0.01);
+
+    REQUIRE(fadeOut.isFinished());
+
+    FadeEffect fadeIn(true, FadeEffect::Interpolation::pow, 1.0);
+
+    REQUIRE(fadeIn.update(0.0) == 0.0);
+    REQUIRE(fadeIn.update(0.5) == 0.25);
+    REQUIRE(fadeIn.update(0.5) == 1.0);
+
+    fadeIn.update(0.01);
+
+    REQUIRE(fadeIn.isFinished());
+}
+
+TEST_CASE( "Sine interpolation", "[Core][Label][Fade]" ) {
+    FadeEffect fadeOut(false, FadeEffect::Interpolation::sine, 1.0);
+
+    REQUIRE(std::fabs(fadeOut.update(0.0) - 1.0) < EPSILON);
+    REQUIRE(std::fabs(fadeOut.update(1.0) - 0.0) < EPSILON);
+
+    fadeOut.update(0.01);
+
+    REQUIRE(fadeOut.isFinished());
+
+    FadeEffect fadeIn(true, FadeEffect::Interpolation::sine, 1.0);
+
+    REQUIRE(std::fabs(fadeIn.update(0.0) - 0.0) < EPSILON);
+    REQUIRE(std::fabs(fadeIn.update(1.0) - 1.0) < EPSILON);
+
+    fadeIn.update(0.01);
+
+    REQUIRE(fadeIn.isFinished());
+}
diff --git a/tests/unit/labelsTests.cpp b/tests/unit/labelsTests.cpp
new file mode 100644 (file)
index 0000000..79e4129
--- /dev/null
@@ -0,0 +1,219 @@
+#include "catch.hpp"
+#include "tangram.h"
+#include "platform.h"
+#include "scene/scene.h"
+#include "style/style.h"
+#include "style/textStyle.h"
+#include "labels/labels.h"
+#include "labels/textLabel.h"
+#include "labels/textLabels.h"
+#include "gl/dynamicQuadMesh.h"
+
+#include "view/view.h"
+#include "tile/tile.h"
+
+#include <memory>
+
+namespace Tangram {
+
+TextStyle dummyStyle("textStyle", nullptr);
+TextLabels dummy(dummyStyle);
+Label::AABB* bounds = nullptr;
+
+std::unique_ptr<TextLabel> makeLabel(glm::vec2 _transform, Label::Type _type, std::string id) {
+    Label::Options options;
+    options.offset = {0.0f, 0.0f};
+    //options.properties = std::make_shared<Properties>();
+    //options.properties->set("id", id);
+    options.anchors.anchor[0] = LabelProperty::Anchor::center;
+    options.anchors.count = 1;
+
+    return std::unique_ptr<TextLabel>(new TextLabel({{glm::vec3(_transform, 0)}}, _type, options,
+                                                    {}, {10, 10}, dummy, {},
+                                                    TextLabelProperty::Align::none));
+}
+
+TextLabel makeLabelWithAnchorFallbacks(glm::vec2 _transform, glm::vec2 _offset = {0, 0}) {
+    Label::Options options;
+
+    // options.anchors.anchor[0] = LabelProperty::Anchor::center;
+    options.anchors.anchor[0] = LabelProperty::Anchor::right;
+    options.anchors.anchor[1] = LabelProperty::Anchor::bottom;
+    options.anchors.anchor[2] = LabelProperty::Anchor::left;
+    options.anchors.anchor[3] = LabelProperty::Anchor::top;
+    options.anchors.count = 4;
+
+    options.offset = _offset;
+
+    TextRange textRanges;
+
+    return TextLabel({{glm::vec3(_transform, 0)}}, Label::Type::point, options,
+            {}, {10, 10}, dummy, textRanges, TextLabelProperty::Align::none);
+}
+
+#if 0
+TEST_CASE("Test getFeaturesAtPoint", "[Labels][FeaturePicking]") {
+    std::unique_ptr<Labels> labels(new Labels());
+
+    View view(256, 256);
+    view.setPosition(0, 0);
+    view.setZoom(0);
+    view.update(false);
+
+    struct TestLabelMesh : public LabelSet {
+        void addLabel(std::unique_ptr<Label> _label) { m_labels.push_back(std::move(_label)); }
+    };
+
+    auto labelMesh = std::unique_ptr<TestLabelMesh>(new TestLabelMesh());
+    auto textStyle = std::unique_ptr<TextStyle>(new TextStyle("test", nullptr, false));
+    textStyle->setID(0);
+
+    labelMesh->addLabel(makeLabel(glm::vec2{.5f,.5f}, Label::Type::point, "0"));
+    labelMesh->addLabel(makeLabel(glm::vec2{1,0}, Label::Type::point, "1"));
+    labelMesh->addLabel(makeLabel(glm::vec2{1,1}, Label::Type::point, "2"));
+
+    std::shared_ptr<Tile> tile(new Tile({0,0,0}, view.getMapProjection()));
+    tile->initGeometry(1);
+    tile->setMesh(*textStyle.get(), std::move(labelMesh));
+    tile->update(0, view);
+
+    std::vector<std::unique_ptr<Style>> styles;
+    styles.push_back(std::move(textStyle));
+
+    std::vector<std::shared_ptr<Tile>> tiles;
+
+    tiles.push_back(tile);
+    {
+        auto& items = labels->getFeaturesAtPoint(view.state(), 0, styles, tiles, 128, 128, false);
+        REQUIRE(items.size() == 1);
+        REQUIRE(items[0].properties->getString("id") == "0");
+    }
+    {
+        auto& items = labels->getFeaturesAtPoint(view.state(), 0, styles, tiles, 256, 256, false);
+        REQUIRE(items.size() == 1);
+        REQUIRE(items[0].properties->getString("id") == "1");
+    }
+
+    {
+        auto& items = labels->getFeaturesAtPoint(view.state(), 0, styles, tiles, 256, 0, false);
+        REQUIRE(items.size() == 1);
+        REQUIRE(items[0].properties->getString("id") == "2");
+    }
+}
+#endif
+
+TEST_CASE( "Test anchor fallback behavior", "[Labels][AnchorFallback]" ) {
+
+    View view(256, 256);
+    view.setPosition(0, 0);
+    view.setZoom(0);
+    view.update(false);
+
+    Tile tile({0,0,0}, view.getMapProjection());
+    tile.update(0, view);
+
+    struct TestTransform {
+        ScreenTransform transform;
+        TestTransform(ScreenTransform::Buffer& _buffer, Range& _range) : transform(_buffer, _range) {}
+    };
+
+    class TestLabels : public Labels {
+    public:
+        TestLabels(View& _v) {
+            m_isect2d.resize({1, 1}, {_v.getWidth(), _v.getHeight()});
+        }
+
+        ScreenTransform& addLabel(Label* _l, Tile* _t) {
+            m_labels.push_back({_l, _t, false, {}});
+            tmpTransforms.emplace_back(m_transforms, m_labels.back().transformRange);
+            return tmpTransforms.back().transform;
+        }
+        void run(View& _v) { handleOcclusions(_v.state()); }
+        void clear() { m_labels.clear(); }
+
+        std::vector<TestTransform> tmpTransforms;
+
+    };
+
+    {
+        TestLabels labels(view);
+        TextLabel l1 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5});
+        auto& t1 = labels.addLabel(&l1, &tile);
+        l1.update(tile.mvp(), view.state(), bounds, t1);
+
+        TextLabel l2 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5});
+        auto& t2 = labels.addLabel(&l2, &tile);
+        l2.update(tile.mvp(), view.state(), bounds, t2);
+
+        labels.run(view);
+        REQUIRE(l1.isOccluded() == false);
+        REQUIRE(l2.isOccluded() == true);
+
+        REQUIRE(l1.anchorType() == LabelProperty::Anchor::right);
+        REQUIRE(l2.anchorType() == LabelProperty::Anchor::right);
+    }
+
+    {
+        TestLabels labels(view);
+        TextLabel l1 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5});
+        auto& t1 = labels.addLabel(&l1, &tile);
+        l1.update(tile.mvp(), view.state(), bounds, t1);
+
+        // Second label is one pixel left of L1
+        TextLabel l2 = makeLabelWithAnchorFallbacks(glm::vec2{0.5 - 1./256,0.5});
+        auto& t2 = labels.addLabel(&l2, &tile);
+        l2.update(tile.mvp(), view.state(), bounds, t2);
+
+        labels.run(view);
+        // l1.print();
+        // l2.print();
+        REQUIRE(l1.isOccluded() == false);
+        REQUIRE(l2.isOccluded() == false);
+
+        REQUIRE(l1.anchorType() == LabelProperty::Anchor::right);
+        // Check that left-of anchor fallback is used
+        REQUIRE(l2.anchorType() == LabelProperty::Anchor::left);
+    }
+
+    {
+        TestLabels labels(view);
+        TextLabel l1 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5});
+        auto& t1 = labels.addLabel(&l1, &tile);
+        l1.update(tile.mvp(), view.state(), bounds, t1);
+
+        // Second label is 10 pixel top of L1
+        TextLabel l2 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5 + 10./256});
+        auto& t2 = labels.addLabel(&l2, &tile);
+        l2.update(tile.mvp(), view.state(), bounds, t2);
+
+        labels.run(view);
+        REQUIRE(l1.isOccluded() == false);
+        REQUIRE(l2.isOccluded() == false);
+
+        REQUIRE(l1.anchorType() == LabelProperty::Anchor::right);
+        // Check that anchor fallback is used
+        REQUIRE(l2.anchorType() == LabelProperty::Anchor::top);
+    }
+
+    {
+        TestLabels labels(view);
+        TextLabel l1 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5});
+        auto& t1 = labels.addLabel(&l1, &tile);
+        l1.update(tile.mvp(), view.state(), bounds, t1);
+
+        // Second label is 10 pixel below of L1
+        TextLabel l2 = makeLabelWithAnchorFallbacks(glm::vec2{0.5,0.5 - 10./256});
+        auto& t2 = labels.addLabel(&l2, &tile);
+        l2.update(tile.mvp(), view.state(), bounds, t2);
+
+        labels.run(view);
+        REQUIRE(l1.isOccluded() == false);
+        REQUIRE(l2.isOccluded() == false);
+
+        REQUIRE(l1.anchorType() == LabelProperty::Anchor::right);
+        // Check that anchor fallback is used
+        REQUIRE(l2.anchorType() == LabelProperty::Anchor::bottom);
+    }
+
+}
+}
diff --git a/tests/unit/layerTests.cpp b/tests/unit/layerTests.cpp
new file mode 100644 (file)
index 0000000..1e59684
--- /dev/null
@@ -0,0 +1,218 @@
+#include "catch.hpp"
+
+#include "scene/sceneLayer.h"
+#include "data/tileData.h"
+#include "scene/styleContext.h"
+
+using namespace Tangram;
+
+using Context = StyleContext;
+
+// Functions to initialize SceneLayer instances
+const int dg0 = 0;
+const int dg1 = 1;
+const int dg2 = 2;
+
+const int group1 = 1;
+const int group2 = 2;
+
+SceneLayer instance_a() {
+
+    Filter f = Filter(); // passes everything
+
+    DrawRuleData rule = { "dg0", dg0, { { StyleParamKey::order, "value_a" } } };
+
+    return { "layer_a", f, { rule }, {}, true };
+}
+
+SceneLayer instance_b() {
+
+    Filter f = Filter::MatchAny({}); // passes nothing
+
+    DrawRuleData rule = { "dg1", dg1, { { StyleParamKey::order, "value_b" } } };
+
+    return { "layer_b", f, { rule }, {}, true };
+}
+
+SceneLayer instance_c() {
+
+    Filter f = Filter(); // passes everything
+
+    DrawRuleData rule = { "dg2", dg2, { { StyleParamKey::order, "value_c" } } };
+
+    return { "layer_c", f, { rule }, { instance_a(), instance_b() }, true };
+}
+
+SceneLayer instance_d() {
+
+    Filter f = Filter(); // passes everything
+
+    DrawRuleData rule = { "dg0", dg0, { { StyleParamKey::order, "value_d" } } };
+
+    return { "layer_d", f, { rule }, {}, true };
+}
+
+SceneLayer instance_e() {
+
+    Filter f = Filter(); // passes everything
+
+    DrawRuleData rule = { "dg2", dg2, { { StyleParamKey::order, "value_e" } } };
+
+    return { "layer_e", f, { rule }, { instance_c(), instance_d() }, true };
+}
+
+SceneLayer instance_2() {
+
+    Filter f = Filter::MatchExistence("two", true);
+
+    DrawRuleData rule = { "group2", group2, {} };
+
+    return { "subLayer2", f, { rule }, {}, true };
+}
+
+SceneLayer instance_1() {
+
+    Filter f = Filter::MatchExistence("one", true);
+
+    DrawRuleData rule = { "group1", group1, {} };
+
+    return { "subLayer1", f, { rule }, {}, true };
+}
+
+SceneLayer instance() {
+
+    Filter f = Filter::MatchExistence("base", true);
+
+    DrawRuleData rule = { "group1", group1, { {StyleParamKey::order, "a" } } };
+
+    return { "layer", f, { rule }, { instance_1(), instance_2() }, true };
+}
+
+TEST_CASE("SceneLayer", "[SceneLayer][Filter][DrawRule][Match][Merge]") {
+
+    Feature f1;
+    Feature f2;
+    Feature f3;
+    Feature f4;
+    Context ctx;
+
+    auto layer = instance();
+
+    {
+        DrawRuleMergeSet ruleSet;
+        f1.props.set("base", "blah"); // Should match Base Layer
+        ruleSet.match(f1, layer, ctx);
+        auto& matches = ruleSet.matchedRules();
+
+        REQUIRE(matches.size() == 1);
+        REQUIRE(matches[0].getStyleName() == "group1");
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        f2.props.set("one", "blah"); // Should match Base and subLayer1
+        f2.props.set("base", "blah");
+        ruleSet.match(f2, layer, ctx);
+        auto& matches = ruleSet.matchedRules();
+
+        REQUIRE(matches.size() == 1);
+        REQUIRE(matches[0].getStyleName() == "group1");
+        REQUIRE(matches[0].findParameter(StyleParamKey::order).key == StyleParamKey::order);
+        REQUIRE(matches[0].findParameter(StyleParamKey::order).value.get<std::string>() == "a");
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        f3.props.set("two", "blah"); // Should not match anything as uber layer will not be satisfied
+        ruleSet.match(f3, layer, ctx);
+        auto& matches = ruleSet.matchedRules();
+
+        REQUIRE(matches.size() == 0);
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        f4.props.set("two", "blah");
+        f4.props.set("base", "blah"); // Should match Base and subLayer2
+        ruleSet.match(f4, layer, ctx);
+        auto& matches = ruleSet.matchedRules();
+
+        REQUIRE(matches.size() == 2);
+        REQUIRE(matches[0].getStyleName() == "group1");
+        REQUIRE(matches[0].findParameter(StyleParamKey::order).key == StyleParamKey::order);
+        REQUIRE(matches[0].findParameter(StyleParamKey::order).value.get<std::string>() == "a");
+        REQUIRE(matches[1].getStyleName() == "group2");
+    }
+
+}
+
+TEST_CASE("SceneLayer matches correct rules for a feature and context", "[SceneLayer][Filter]") {
+
+    Feature feat;
+    Context ctx;
+
+    {
+        DrawRuleMergeSet ruleSet;
+        auto layer_a = instance_a();
+
+        ruleSet.match(feat, layer_a, ctx);
+        auto& matches_a = ruleSet.matchedRules();
+
+        REQUIRE(matches_a.size() == 1);
+        REQUIRE(matches_a[0].getStyleName() == "dg0");
+    }
+
+    {
+        DrawRuleMergeSet ruleSet;
+        auto layer_b = instance_b();
+
+        ruleSet.match(feat, layer_b, ctx);
+        auto& matches_b = ruleSet.matchedRules();
+
+        REQUIRE(matches_b.size() == 0);
+    }
+
+}
+
+TEST_CASE("SceneLayer matches correct sublayer rules for a feature and context", "[SceneLayer][Filter]") {
+
+    Feature feat;
+    Context ctx;
+    DrawRuleMergeSet ruleSet;
+
+    auto layer_c = instance_c();
+
+    ruleSet.match(feat, layer_c, ctx);
+    auto& matches = ruleSet.matchedRules();
+
+    REQUIRE(matches.size() == 2);
+
+    REQUIRE(matches[0].getStyleName() == "dg2");
+    REQUIRE(matches[1].getStyleName() == "dg0");
+
+}
+
+TEST_CASE("SceneLayer correctly merges rules matched from sublayer", "[SceneLayer][Filter]") {
+
+    Feature feat;
+    Context ctx;
+    DrawRuleMergeSet ruleSet;
+
+    auto layer_e = instance_e();
+
+    ruleSet.match(feat, layer_e, ctx);
+    auto& matches = ruleSet.matchedRules();
+
+    REQUIRE(matches.size() == 2);
+
+    // deeper match from layer_a should override parameters in same style from layer_d
+    REQUIRE(matches[1].getStyleName() == "dg0");
+    REQUIRE(matches[1].findParameter(StyleParamKey::order).key == StyleParamKey::order);
+    REQUIRE(matches[1].findParameter(StyleParamKey::order).value.get<std::string>() == "value_a");
+
+    // deeper match from layer_c should override parameters in same style from layer_e
+    REQUIRE(matches[0].getStyleName() == "dg2");
+    REQUIRE(matches[0].findParameter(StyleParamKey::order).key == StyleParamKey::order);
+    REQUIRE(matches[0].findParameter(StyleParamKey::order).value.get<std::string>() == "value_c");
+
+}
diff --git a/tests/unit/lineWrapTests.cpp b/tests/unit/lineWrapTests.cpp
new file mode 100644 (file)
index 0000000..2c78180
--- /dev/null
@@ -0,0 +1,124 @@
+#include "catch.hpp"
+#include "tangram.h"
+#include "platform_mock.h"
+#include "style/textStyleBuilder.h"
+
+#include <memory>
+
+namespace Tangram {
+
+#define TEST_FONT_SIZE  24
+#define TEST_FONT       "fonts/NotoSans-Regular.ttf"
+#define TEST_FONT_AR   "fonts/NotoNaskh-Regular.ttf"
+#define TEST_FONT_JP    "fonts/DroidSansJapanese.ttf"
+
+struct ScratchBuffer : public alfons::MeshCallback {
+    void drawGlyph(const alfons::Quad& q, const alfons::AtlasGlyph& atlasGlyph) override {}
+    void drawGlyph(const alfons::Rect& q, const alfons::AtlasGlyph& atlasGlyph) override {}
+};
+
+struct AtlasCallback : public alfons::TextureCallback {
+    void addTexture(alfons::AtlasID id, uint16_t textureWidth, uint16_t textureHeight) override {}
+    void addGlyph(alfons::AtlasID id, uint16_t gx, uint16_t gy, uint16_t gw, uint16_t gh,
+            const unsigned char* src, uint16_t padding) override {}
+};
+
+AtlasCallback atlasCb;
+ScratchBuffer buffer;
+
+alfons::TextShaper shaper;
+alfons::GlyphAtlas atlas(atlasCb);
+alfons::TextBatch batch(atlas, buffer);
+alfons::FontManager fontManager;
+std::shared_ptr<alfons::Font> font;
+
+void initFont(std::string _font = TEST_FONT) {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    font = fontManager.addFont("default", TEST_FONT_SIZE, alfons::InputSource(_font));
+
+    auto data = platform->bytesFromFile(_font.c_str());
+    auto face = fontManager.addFontFace(alfons::InputSource(std::move(data)), TEST_FONT_SIZE);
+    font->addFace(face);
+}
+
+TEST_CASE("Ensure empty line is given when giving empty shape to alfons", "[Core][Alfons]") {
+    initFont();
+    auto line = shaper.shape(font, "");
+
+    REQUIRE(line.shapes().size() == 0);
+    TextWrapper textWrap;
+    alfons::LineMetrics metrics;
+
+    float width = textWrap.getShapeRangeWidth(line, 10, 4);
+    int nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+
+    REQUIRE(nbLines == 0);
+}
+
+TEST_CASE() {
+    initFont();
+
+    auto line = shaper.shape(font, "The quick brown fox");
+
+    REQUIRE(line.shapes().size() == 19);
+
+    TextWrapper textWrap;
+    alfons::LineMetrics metrics;
+    float width = textWrap.getShapeRangeWidth(line, 4, 10);
+    int nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 2);
+
+    textWrap.clearWraps();
+    width = textWrap.getShapeRangeWidth(line, 4, 4);
+    nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 3);
+
+    textWrap.clearWraps();
+    width = textWrap.getShapeRangeWidth(line, 0, 1);
+    nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 4);
+
+    textWrap.clearWraps();
+    width = textWrap.getShapeRangeWidth(line, 0, 3);
+    nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 4);
+
+    textWrap.clearWraps();
+    width = textWrap.getShapeRangeWidth(line, 2, 5);
+    nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 4);
+}
+
+TEST_CASE() {
+    initFont(TEST_FONT_AR);
+
+    auto line = shaper.shape(font, "لعدم عليها كلّ.");
+    REQUIRE(line.shapes().size() == 15);
+
+    TextWrapper textWrap;
+    alfons::LineMetrics metrics;
+
+    float width = textWrap.getShapeRangeWidth(line, 0, 1);
+    int nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 3);
+
+    textWrap.clearWraps();
+    width = textWrap.getShapeRangeWidth(line, 0, 10);
+    nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 2);
+}
+
+TEST_CASE() {
+    initFont(TEST_FONT_JP);
+
+    auto line = shaper.shape(font, "日本語のキーボード");
+    REQUIRE(line.shapes().size() == 9);
+
+    TextWrapper textWrap;
+    alfons::LineMetrics metrics;
+    float width = textWrap.getShapeRangeWidth(line, 0, 1);
+    int nbLines = textWrap.draw(batch, width, line, TextLabelProperty::Align::center, 1.0, metrics);
+    REQUIRE(nbLines == 7);
+}
+
+}
diff --git a/tests/unit/mercProjTests.cpp b/tests/unit/mercProjTests.cpp
new file mode 100644 (file)
index 0000000..1045ca5
--- /dev/null
@@ -0,0 +1,32 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <iomanip>
+
+#include "glm/glm.hpp"
+#include "util/mapProjection.h"
+
+#include <stdio.h>
+
+using namespace Tangram;
+
+TEST_CASE( "Testing some functionality for mercator projection", "[MERCATOR][PROJECTION]" ) {
+    MercatorProjection mercProjection = MercatorProjection();
+    glm::dvec2 lonLat = glm::dvec2(0.0,0.0);
+    glm::dvec2 worldCoord = glm::dvec2(0.0, 0.0);
+    //glm::ivec3 tileCoord = glm::ivec3(2, 2, 3);
+    double epsilon = 0.000000000000000001;
+    //check if all the test tileCoordinates are loaded
+    /*REQUIRE(dataSource.JsonRootSize() == 3);
+    //check if all the test tiles have data in the jsonRoots data structure
+    REQUIRE(dataSource.CheckDataExists("14_19293_24641") == true);
+    REQUIRE(dataSource.CheckDataExists("16_19293_24641") == true);
+    REQUIRE(dataSource.CheckDataExists("0_0_0") == true);
+    REQUIRE(dataSource.CheckDataExists("0_1_0") == false);*/
+    glm::dvec2 testMeters = mercProjection.LonLatToMeters(lonLat);
+    glm::dvec2 testLonLat = mercProjection.MetersToLonLat(worldCoord);
+    REQUIRE( (testMeters.x - worldCoord.x) < epsilon);
+    REQUIRE( (testMeters.y - worldCoord.y) < epsilon);
+    REQUIRE( (testLonLat.x - lonLat.x) < epsilon);
+    REQUIRE( (testLonLat.y - lonLat.y) < epsilon);
+}
diff --git a/tests/unit/meshTests.cpp b/tests/unit/meshTests.cpp
new file mode 100644 (file)
index 0000000..21e71b5
--- /dev/null
@@ -0,0 +1,172 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include "gl/mesh.h"
+
+using namespace Tangram;
+
+struct Vertex {
+    float a;
+    float b;
+    short c;
+    char d;
+};
+
+std::shared_ptr<VertexLayout> layout = std::shared_ptr<VertexLayout>(new VertexLayout({
+    {"ab", 2, GL_FLOAT, false, 0},
+    {"c",  1, GL_SHORT, false, 0},
+    {"d",  1, GL_BYTE,  false, 0},
+}));
+
+struct TestMesh : public Mesh<Vertex> {
+    using Base = Mesh<Vertex>;
+    using Base::Base;
+
+    GLsizei getDirtySize() const { return m_dirtySize; }
+    GLintptr getDirtyOffset() const { return m_dirtyOffset; }
+
+    int numVertices() const { return m_nVertices; }
+    int numIndices() const { return m_nIndices; }
+};
+
+std::shared_ptr<TestMesh> newMesh(unsigned int size) {
+    auto mesh = std::make_shared<TestMesh>(layout, GL_TRIANGLES);
+    MeshData<Vertex> meshData;
+
+    for (size_t i = 0; i < size; ++i) {
+        meshData.vertices.push_back({0,0,0,0});
+        meshData.offsets.emplace_back(0, 4);
+    }
+    mesh->compile(meshData);
+    return mesh;
+}
+
+void checkBounds(const std::shared_ptr<TestMesh>& mesh) {
+
+    REQUIRE(mesh->getDirtyOffset() >= 0);
+    REQUIRE(mesh->getDirtyOffset() < mesh->numVertices() * sizeof(Vertex));
+    REQUIRE(long(mesh->getDirtyOffset() + mesh->getDirtySize()) < mesh->numVertices() * sizeof(Vertex));
+
+}
+
+TEST_CASE( "Simple update on vertices", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+
+    REQUIRE(mesh->getDirtyOffset() == 0);
+    REQUIRE(mesh->getDirtySize() == 0);
+
+    mesh->updateVertices({0, 4}, Vertex());
+
+    REQUIRE(mesh->getDirtyOffset() == 0);
+    REQUIRE(mesh->getDirtySize() == 4 * sizeof(Vertex));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Left merge on vertices with bigger left size", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+
+    mesh->updateVertices({2, 2}, Vertex());
+    mesh->updateVertices({0, 8}, Vertex());
+
+    REQUIRE(mesh->getDirtyOffset() == 0);
+    REQUIRE(mesh->getDirtySize() == 8 * sizeof(Vertex));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Left merge on vertices with smaller left size", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+
+    mesh->updateVertices({2, 2}, Vertex());
+    mesh->updateVertices({0, 1}, Vertex());
+
+    REQUIRE(mesh->getDirtyOffset() == 0);
+    REQUIRE(mesh->getDirtySize() == 4 * sizeof(Vertex));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Right merge on vertices dirtiness", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+
+    mesh->updateVertices({2, 2}, Vertex());
+    mesh->updateVertices({4, 2}, Vertex());
+
+    REQUIRE(mesh->getDirtyOffset() == 2 * sizeof(Vertex));
+    REQUIRE(mesh->getDirtySize() == 4 * sizeof(Vertex));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Update on second attribute of the mesh for n vertices", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+    int nVert = 5;
+    size_t stride_b = sizeof(float); // stride of a in the struct
+
+    mesh->updateAttribute({1, nVert}, 0.f, stride_b);
+
+    REQUIRE(mesh->getDirtyOffset() == stride_b + sizeof(Vertex));
+    REQUIRE(mesh->getDirtySize() == (nVert - 1) * sizeof(Vertex) + sizeof(float));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Update on second attribute of the mesh for 1 vertices", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+    size_t stride_b = sizeof(float); // stride of a in the struct
+
+    mesh->updateAttribute({0, 1}, 0.f, stride_b);
+
+    REQUIRE(mesh->getDirtyOffset() == stride_b);
+    REQUIRE(mesh->getDirtySize() == sizeof(float));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Update on second and third attribute of the mesh for n vertices", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+    size_t stride_b = sizeof(float); // stride of b in the struct
+    size_t stride_c = 2 * sizeof(float); // stride of c in the struct
+    short c = 0;
+
+    mesh->updateAttribute({0, 5}, 0.f, stride_b);
+    mesh->updateAttribute({1, 8}, c, stride_c);
+
+    REQUIRE(mesh->getDirtyOffset() == stride_b);
+    int dist = stride_c - stride_b; // distance between b and c
+    REQUIRE(mesh->getDirtySize() == 8 * sizeof(Vertex) + dist + sizeof(short));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Update on second and fourth attribute of the mesh for n vertices", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+    size_t stride_b = sizeof(float); // stride of b in the struct
+    size_t stride_d = 2 * sizeof(float) + sizeof(short); // stride of c in the struct
+    char d = 0;
+
+    mesh->updateAttribute({0, 1}, 0.f, stride_b);
+    mesh->updateAttribute({1, 7}, d, stride_d);
+
+    REQUIRE(mesh->getDirtyOffset() == stride_b);
+    int dist = stride_d - stride_b; // distance between b and c
+    REQUIRE(mesh->getDirtySize() == 7 * sizeof(Vertex) + dist + sizeof(char));
+
+    checkBounds(mesh);
+}
+
+TEST_CASE( "Check overflow", "[Core][TypedMesh]" ) {
+    auto mesh = newMesh(10);
+    size_t stride_b = sizeof(float); // stride of b in the struct
+
+    mesh->updateAttribute({0, 100}, 0.f, stride_b);
+    mesh->updateVertices({0, 100}, Vertex());
+    mesh->updateAttribute({10, 1}, Vertex(), stride_b);
+    mesh->updateAttribute({-100, 10}, Vertex());
+
+    REQUIRE(mesh->getDirtyOffset() == 0);
+    REQUIRE(mesh->getDirtySize() == 0);
+
+    checkBounds(mesh);
+}
diff --git a/tests/unit/sceneImportTests.cpp b/tests/unit/sceneImportTests.cpp
new file mode 100644 (file)
index 0000000..202d141
--- /dev/null
@@ -0,0 +1,315 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <vector>
+
+#include "yaml-cpp/yaml.h"
+#include "platform_mock.h"
+#include "scene/importer.h"
+
+using namespace Tangram;
+using namespace YAML;
+
+class TestImporter : public Importer {
+
+public:
+    TestImporter();
+
+    TestImporter(std::unordered_map<Url, std::string> _testScenes) : m_testScenes(_testScenes) {}
+
+protected:
+    virtual std::string getSceneString(const std::shared_ptr<Platform>& platform,
+            const Url& scenePath, const std::shared_ptr<Asset>& asset = nullptr) override {
+        return m_testScenes[scenePath];
+    }
+
+    std::unordered_map<Url, std::string> m_testScenes;
+};
+
+TestImporter::TestImporter() {
+
+    m_testScenes["/root/a.yaml"] = R"END(
+        import: b.yaml
+        value: a
+        has_a: true
+    )END";
+
+    m_testScenes["/root/b.yaml"] = R"END(
+        value: b
+        has_b: true
+    )END";
+
+    m_testScenes["/root/c.yaml"] = R"END(
+        import: [a.yaml, b.yaml]
+        value: c
+        has_c: true
+    )END";
+
+    m_testScenes["/root/cycle_simple.yaml"] = R"END(
+        import: cycle_simple.yaml
+        value: cyclic
+    )END";
+
+    m_testScenes["/root/cycle_tricky.yaml"] = R"END(
+        import: imports/cycle_tricky.yaml
+        has_cycle_tricky: true
+    )END";
+
+    m_testScenes["/root/imports/cycle_tricky.yaml"] = R"END(
+        import: ../cycle_tricky.yaml
+        has_imports_cycle_tricky: true
+    )END";
+
+    m_testScenes["/root/urls.yaml"] = R"END(
+        import: imports/urls.yaml
+        fonts: { fontA: { url: https://host/font.woff } }
+        sources: { sourceA: { url: 'https://host/tiles/{z}/{y}/{x}.mvt' } }
+        textures:
+            tex1: { url: "path/to/texture.png" }
+            tex2: { url: "../up_a_directory.png" }
+        styles:
+            styleA:
+                texture: "path/to/texture.png"
+                shaders:
+                    uniforms:
+                        u_tex1: "/at_root.png"
+                        u_tex2: ["path/to/texture.png", tex2]
+                        u_tex3: tex3
+                        u_bool: true
+                        u_float: 0.25
+    )END";
+
+    m_testScenes["/root/imports/urls.yaml"] = R"END(
+        fonts: { fontB: [ { url: fonts/0.ttf }, { url: fonts/1.ttf } ] }
+        sources: { sourceB: { url: "tiles/{z}/{y}/{x}.mvt" } }
+        textures:
+            tex3: { url: "in_imports.png" }
+            tex4: { url: "../not_in_imports.png" }
+            tex5: { url: "/at_root.png" }
+        styles:
+            styleB:
+                texture: "in_imports.png"
+                shaders:
+                    uniforms:
+                        u_tex1: "in_imports.png"
+                        u_tex2: tex2
+    )END";
+
+    m_testScenes["/root/globals.yaml"] = R"END(
+        fonts: { aFont: { url: global.fontUrl } }
+        sources: { aSource: { url: global.sourceUrl } }
+        textures: { aTexture: { url: global.textureUrl } }
+        styles: { aStyle: { texture: global.textureUrl, shaders: { uniforms: { aUniform: global.textureUrl } } } }
+    )END";
+}
+
+TEST_CASE("Imported scenes are merged with the parent scene", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    auto scene = std::make_shared<Scene>(platform,  "a.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    CHECK(root["value"].Scalar() == "a");
+    CHECK(root["has_a"].Scalar() == "true");
+    CHECK(root["has_b"].Scalar() == "true");
+}
+
+TEST_CASE("Nested imports are merged recursively", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    auto scene = std::make_shared<Scene>(platform,  "c.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    CHECK(root["value"].Scalar() == "c");
+    CHECK(root["has_a"].Scalar() == "true");
+    CHECK(root["has_b"].Scalar() == "true");
+    CHECK(root["has_c"].Scalar() == "true");
+}
+
+TEST_CASE("Imports that would start a cycle are ignored", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    // If import cycles aren't checked for and stopped, this call won't return.
+    auto scene = std::make_shared<Scene>(platform,  "cycle_simple.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    // Check that the scene values were applied.
+    CHECK(root["value"].Scalar() == "cyclic");
+}
+
+TEST_CASE("Tricky import cycles are ignored", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    // The nested import should resolve to the same path as the original file,
+    // and so the importer should break the cycle.
+    auto scene = std::make_shared<Scene>(platform,  "cycle_tricky.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    // Check that the imported scene values were merged.
+    CHECK(root["has_cycle_tricky"].Scalar() == "true");
+    CHECK(root["has_imports_cycle_tricky"].Scalar() == "true");
+}
+
+TEST_CASE("Scene URLs are resolved against their parent during import", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    auto scene = std::make_shared<Scene>(platform,  "urls.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    // Check that global texture URLs are resolved correctly.
+
+    auto textures = root["textures"];
+
+    CHECK(textures["tex1"]["url"].Scalar() == "/root/path/to/texture.png");
+    CHECK(textures["tex2"]["url"].Scalar() == "/up_a_directory.png");
+    CHECK(textures["tex3"]["url"].Scalar() == "/root/imports/in_imports.png");
+    CHECK(textures["tex4"]["url"].Scalar() == "/root/not_in_imports.png");
+    CHECK(textures["tex5"]["url"].Scalar() == "/at_root.png");
+
+    // Check that "inline" texture URLs are resolved correctly.
+
+    auto styleA = root["styles"]["styleA"];
+
+    CHECK(styleA["texture"].Scalar() == "/root/path/to/texture.png");
+
+    auto uniformsA = styleA["shaders"]["uniforms"];
+
+    CHECK(uniformsA["u_tex1"].Scalar() == "/at_root.png");
+    CHECK(uniformsA["u_tex2"][0].Scalar() == "/root/path/to/texture.png");
+    CHECK(uniformsA["u_tex2"][1].Scalar() == "tex2");
+    CHECK(uniformsA["u_bool"].Scalar() == "true");
+    CHECK(uniformsA["u_float"].Scalar() == "0.25");
+    CHECK(uniformsA["u_tex3"].Scalar() == "tex3");
+
+    auto styleB = root["styles"]["styleB"];
+
+    CHECK(styleB["texture"].Scalar() == "/root/imports/in_imports.png");
+
+    auto uniformsB = styleB["shaders"]["uniforms"];
+
+    CHECK(uniformsB["u_tex1"].Scalar() == "/root/imports/in_imports.png");
+    // Don't use global textures from importing scene
+    CHECK(uniformsB["u_tex2"].Scalar() == "/root/imports/tex2");
+
+    // Check that data source URLs are resolved correctly.
+
+    CHECK(root["sources"]["sourceA"]["url"].Scalar() == "https://host/tiles/{z}/{y}/{x}.mvt");
+    CHECK(root["sources"]["sourceB"]["url"].Scalar() == "/root/imports/tiles/{z}/{y}/{x}.mvt");
+
+    // Check that font URLs are resolved correctly.
+
+    CHECK(root["fonts"]["fontA"]["url"].Scalar() == "https://host/font.woff");
+    CHECK(root["fonts"]["fontB"][0]["url"].Scalar() == "/root/imports/fonts/0.ttf");
+    CHECK(root["fonts"]["fontB"][1]["url"].Scalar() == "/root/imports/fonts/1.ttf");
+
+    // We don't explicitly check that import URLs are resolved correctly because if they were not,
+    // the scenes wouldn't be loaded and merged; i.e. we already test it implicitly.
+}
+
+TEST_CASE("References to globals are not treated like URLs during importing", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    TestImporter importer;
+
+    auto scene = std::make_shared<Scene>(platform,  "globals.yaml");
+    scene->resourceRoot() = "/root/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    // Check that font global references are preserved.
+    CHECK(root["fonts"]["aFont"]["url"].Scalar() == "global.fontUrl");
+
+    // Check that data source global references are preserved.
+    CHECK(root["sources"]["aSource"]["url"].Scalar() == "global.sourceUrl");
+
+    // Check that texture global references are preserved.
+    CHECK(root["textures"]["aTexture"]["url"].Scalar() == "global.textureUrl");
+    CHECK(root["styles"]["aStyle"]["texture"].Scalar() == "global.textureUrl");
+    CHECK(root["styles"]["aStyle"]["shaders"]["uniforms"]["aUniform"].Scalar() == "global.textureUrl");
+}
+
+TEST_CASE("Map overwrites sequence", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::unordered_map<Url, std::string> testScenes;
+    testScenes["/base.yaml"] = R"END(
+        import: [roads.yaml, roads-labels.yaml]
+    )END";
+
+    testScenes["/roads.yaml"] = R"END(
+            filter:
+                - kind: highway
+                - $zoom: { min: 8 }
+    )END";
+
+    testScenes["/roads-labels.yaml"] = R"END(
+                filter: { kind: highway }
+    )END";
+
+    TestImporter importer(testScenes);
+
+    auto scene = std::make_shared<Scene>(platform,  "base.yaml");
+    scene->resourceRoot() = "/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    CHECK(root["filter"].IsMap());
+    CHECK(root["filter"].size() == 1);
+    CHECK(root["filter"]["kind"].Scalar() == "highway");
+}
+
+TEST_CASE("Sequence overwrites map", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::unordered_map<Url, std::string> testScenes;
+    testScenes["/base.yaml"] = R"END(
+        import: [map.yaml, sequence.yaml]
+    )END";
+    testScenes["/map.yaml"] = R"END(
+            a: { b: c }
+    )END";
+
+    testScenes["/sequence.yaml"] = R"END(
+            a: [ b, c]
+    )END";
+
+    TestImporter importer(testScenes);
+
+    auto scene = std::make_shared<Scene>(platform,  "base.yaml");
+    scene->resourceRoot() = "/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    CHECK(root["a"].IsSequence());
+    CHECK(root["a"].size() == 2);
+}
+
+TEST_CASE("Scalar and null overwrite correctly", "[import][core]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::unordered_map<Url, std::string> testScenes;
+    testScenes["/base.yaml"] = R"END(
+        import: [scalar.yaml, null.yaml]
+        scalar_at_end: scalar
+        null_at_end: null
+    )END";
+    testScenes["/scalar.yaml"] = R"END(
+            null_at_end: scalar
+    )END";
+
+    testScenes["/null.yaml"] = R"END(
+            scalar_at_end: null
+    )END";
+
+    TestImporter importer(testScenes);
+
+    auto scene = std::make_shared<Scene>(platform,  "base.yaml");
+    scene->resourceRoot() = "/";
+    auto root = importer.applySceneImports(platform, scene);
+
+    CHECK(root["scalar_at_end"].Scalar() == "scalar");
+    CHECK(root["null_at_end"].IsNull());
+}
diff --git a/tests/unit/sceneLoaderTests.cpp b/tests/unit/sceneLoaderTests.cpp
new file mode 100644 (file)
index 0000000..7395425
--- /dev/null
@@ -0,0 +1,73 @@
+#include "catch.hpp"
+
+#include "yaml-cpp/yaml.h"
+#include "scene/sceneLoader.h"
+#include "scene/scene.h"
+#include "style/material.h"
+#include "style/style.h"
+#include "style/polylineStyle.h"
+#include "style/polygonStyle.h"
+#include "scene/pointLight.h"
+
+#include "platform_mock.h"
+
+using namespace Tangram;
+using YAML::Node;
+
+TEST_CASE("Style with the same name as a built-in style are ignored") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+    SceneLoader::loadStyle(platform, "polygons", Node(), scene);
+    REQUIRE(scene->styles().size() == 0);
+
+}
+
+TEST_CASE("Correctly instantiate a style from a YAML configuration") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+
+    scene->styles().emplace_back(new PolygonStyle("polygons"));
+    scene->styles().emplace_back(new PolylineStyle("lines"));
+
+    YAML::Node node = YAML::Load(R"END(
+        animated: true
+        texcoords: true
+        base: lines
+        mix: tools
+        material:
+            diffuse: .9
+            emission: 0.0
+        )END");
+
+    SceneLoader::loadStyle(platform, "roads", node, scene);
+
+    auto& styles = scene->styles();
+
+    REQUIRE(styles.size() == 3);
+    REQUIRE(styles[0]->getName() == "polygons");
+    REQUIRE(styles[1]->getName() == "lines");
+    REQUIRE(styles[2]->getName() == "roads");
+
+    REQUIRE(styles[2]->isAnimated() == true);
+
+    REQUIRE(styles[2]->getMaterial().hasEmission() == true);
+    REQUIRE(styles[2]->getMaterial().hasDiffuse() == true);
+    REQUIRE(styles[2]->getMaterial().hasAmbient() == false);
+    REQUIRE(styles[2]->getMaterial().hasSpecular() == false);
+}
+
+TEST_CASE("Test light parameter parsing") {
+    YAML::Node node = YAML::Load("position: [100px, 0, 20m]");
+
+    auto light(std::make_unique<PointLight>("light"));
+    SceneLoader::parseLightPosition(node["position"], *light);
+
+    auto pos = light->getPosition();
+
+    REQUIRE(pos.value.x == 100);
+    REQUIRE(pos.value.y == 0);
+    REQUIRE(pos.value.z == 20);
+    REQUIRE(pos.units[0] == Unit::pixel);
+    REQUIRE(pos.units[1] == Unit::meter);
+    REQUIRE(pos.units[2] == Unit::meter);
+}
diff --git a/tests/unit/sceneUpdateTests.cpp b/tests/unit/sceneUpdateTests.cpp
new file mode 100644 (file)
index 0000000..977bda4
--- /dev/null
@@ -0,0 +1,239 @@
+#include "catch.hpp"
+
+#include "yaml-cpp/yaml.h"
+#include "scene/sceneLoader.h"
+#include "style/style.h"
+#include "scene/scene.h"
+#include "log.h"
+#include "tangram.h"
+#include "platform_mock.h"
+
+using YAML::Node;
+using namespace Tangram;
+
+const static std::string sceneString = R"END(
+global:
+    a: global_a_value
+    b: global_b_value
+map:
+    a: map_a_value
+    b: global.b
+seq:
+    - seq_0_value
+    - global.a
+nest:
+    map:
+        a: nest_map_a_value
+        b: nest_map_b_value
+    seq:
+        - nest_seq_0_value
+        - nest_seq_1_value
+)END";
+
+bool loadConfig(const std::string& _sceneString, Node& root) {
+
+    try { root = YAML::Load(_sceneString); }
+    catch (YAML::ParserException e) {
+        LOGE("Parsing scene config '%s'", e.what());
+        return false;
+    }
+    return true;
+}
+
+TEST_CASE("Apply scene update to a top-level node") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"map", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["map"].Scalar() == "new_value");
+}
+
+TEST_CASE("Apply scene update to a map entry") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"map.a", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["map"]["a"].Scalar() == "new_value");
+    // Check that nearby values are unchanged.
+    CHECK(root["map"]["b"].Scalar() == "global.b");
+}
+
+TEST_CASE("Apply scene update to a nested map entry") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"nest.map.a", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["nest"]["map"]["a"].Scalar() == "new_value");
+    // Check that nearby values are unchanged.
+    CHECK(root["nest"]["map"]["b"].Scalar() == "nest_map_b_value");
+}
+
+TEST_CASE("Apply scene update to a sequence node") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"seq", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["seq"].Scalar() == "new_value");
+}
+
+TEST_CASE("Apply scene update to a nested sequence node") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"nest.seq", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["nest"]["seq"].Scalar() == "new_value");
+    // Check that nearby values are unchanged.
+    CHECK(root["nest"]["map"]["a"].Scalar() == "nest_map_a_value");
+}
+
+TEST_CASE("Apply scene update to a new map entry") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"map.c", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["map"]["c"].Scalar() == "new_value");
+    // Check that nearby values are unchanged.
+    CHECK(root["map"]["b"].Scalar() == "global.b");
+}
+
+TEST_CASE("Do not apply scene update to a non-existent node") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"none.a", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    REQUIRE(!root["none"]);
+}
+
+TEST_CASE("Apply scene update that removes a node") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"nest.map", "null"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(!root["nest"]["map"]["a"]);
+    CHECK(root["nest"]["map"].IsNull());
+    CHECK(root["nest"]["seq"]);
+}
+
+TEST_CASE("Apply multiple scene updates in order of request") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"map.a", "first_value"}, {"map.a", "second_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+    CHECK(root["map"]["a"].Scalar() == "second_value");
+    // Check that nearby values are unchanged.
+    CHECK(root["map"]["b"].Scalar() == "global.b");
+}
+
+TEST_CASE("Apply and propogate repeated global value updates") {
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    Node& root = scene.config();
+    // Apply initial globals.
+    SceneLoader::applyGlobals(root, scene);
+    CHECK(root["seq"][1].Scalar() == "global_a_value");
+    CHECK(root["map"]["b"].Scalar() == "global_b_value");
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"global.b", "new_global_b_value"}};
+    // Apply the update.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    CHECK(root["global"]["b"].Scalar() == "new_global_b_value");
+    // Apply updated globals.
+    SceneLoader::applyGlobals(root, scene);
+    CHECK(root["seq"][1].Scalar() == "global_a_value");
+    CHECK(root["map"]["b"].Scalar() == "new_global_b_value");
+    // Add an update.
+    updates = {{"global.b", "newer_global_b_value"}};
+    // Apply the update.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    CHECK(root["global"]["b"].Scalar() == "newer_global_b_value");
+    // Apply updated globals.
+    SceneLoader::applyGlobals(root, scene);
+    CHECK(root["seq"][1].Scalar() == "global_a_value");
+    CHECK(root["map"]["b"].Scalar() == "newer_global_b_value");
+}
+
+TEST_CASE("Regression: scene update requesting a sequence from a scalar") {
+
+    // Setup.
+    auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    // Add an update.
+    std::vector<SceneUpdate> updates = {{"map.a#0", "new_value"}};
+    // Apply scene updates, reload scene.
+    SceneLoader::applyUpdates(platform_mock, scene, updates);
+    const Node& root = scene.config();
+
+    // causes yaml exception 'operator[] call on a scalar'
+}
+
+TEST_CASE("Scene update statuses") {
+ auto platform_mock = std::make_shared<MockPlatform>();
+    Scene scene(platform_mock);
+    REQUIRE(loadConfig(sceneString, scene.config()));
+    Node& root = scene.config();
+    std::vector<SceneUpdate> updates = {{"map.a", "{ first_value"}};
+    SceneLoader::applyUpdates(platform_mock, scene, updates, [](auto updateError) {
+        CHECK(updateError.error == Error::scene_update_value_yaml_syntax_error);
+    });
+    updates = {{"!map#0", "first_value"}};
+    SceneLoader::applyUpdates(platform_mock, scene, updates, [](auto updateError) {
+        CHECK(updateError.error == Error::scene_update_path_yaml_syntax_error);
+    });
+    updates = {{"key_not_existing", "first_value"}};
+    SceneLoader::applyUpdates(platform_mock, scene, updates, [](auto updateError) {
+        CHECK(updateError.error == Error::scene_update_path_not_found);
+    });
+    updates = {{"!map#0", "{ first_value"}};
+    SceneLoader::applyUpdates(platform_mock, scene, updates, [](auto updateError) {
+        CHECK(updateError.error == Error::scene_update_value_yaml_syntax_error);
+    });
+}
+
diff --git a/tests/unit/stopsTests.cpp b/tests/unit/stopsTests.cpp
new file mode 100644 (file)
index 0000000..30e1226
--- /dev/null
@@ -0,0 +1,190 @@
+#include "catch.hpp"
+
+#include "scene/stops.h"
+#include "yaml-cpp/yaml.h"
+#include "util/mapProjection.h"
+
+using namespace Tangram;
+
+Stops instance_color() {
+    return Stops({
+        Stops::Frame(0, Color(0xffffffff)),
+        Stops::Frame(1, Color(0xffeeeeee)),
+        Stops::Frame(5, Color(0xffaaaaaa))
+    });
+}
+
+TEST_CASE("Stops evaluate float values correctly at and between key frames", "[Stops]") {
+
+    Stops stops({
+            Stops::Frame(0, 0.f),
+            Stops::Frame(1, 10.f),
+            Stops::Frame(5, 50.f),
+            Stops::Frame(7, 0.f)
+    });
+
+    REQUIRE(stops.evalFloat(-3) == 0.f);
+    REQUIRE(stops.evalFloat(0) == 0.f);
+    REQUIRE(stops.evalFloat(0.3) == 3.f);
+    REQUIRE(stops.evalFloat(1) == 10.f);
+    REQUIRE(stops.evalFloat(3) == 30.f);
+    REQUIRE(stops.evalFloat(5) == 50.f);
+    REQUIRE(stops.evalFloat(6) == 25.f);
+    REQUIRE(stops.evalFloat(7) == 0.f);
+    REQUIRE(stops.evalFloat(8) == 0.f);
+
+}
+
+TEST_CASE("Stops evaluate vec2 values correctly at and between key frames", "[Stops]") {
+
+    Stops stops({
+            Stops::Frame(0, glm::vec2(0.0)),
+            Stops::Frame(1, glm::vec2(1.0)),
+            Stops::Frame(2, glm::vec2(1.0, 0.0)),
+            Stops::Frame(4, glm::vec2(0.0, 1.0))
+    });
+
+    REQUIRE(stops.evalVec2(-3) == glm::vec2(0.0));
+    REQUIRE(stops.evalVec2(0) == glm::vec2(0.0));
+    REQUIRE(stops.evalVec2(0.3) == glm::vec2(0.3));
+    REQUIRE(stops.evalVec2(1) == glm::vec2(1.0));
+    REQUIRE(stops.evalVec2(1.5) == glm::vec2(1.0, 0.5));
+    REQUIRE(stops.evalVec2(4) == glm::vec2(0.0, 1.0));
+    REQUIRE(stops.evalVec2(3.0) == glm::vec2(0.5));;
+
+}
+
+
+
+TEST_CASE("Stops evaluate width values correctly at and between key frames", "[Stops]") {
+
+    Stops stops({
+            Stops::Frame(0, 0.f),
+            Stops::Frame(1, 10.f),
+            Stops::Frame(5, 50.f),
+            Stops::Frame(7, 0.f),
+            Stops::Frame(8, 3.f),
+            Stops::Frame(10, 3.f),
+
+    });
+
+    REQUIRE(stops.evalExpFloat(-3) == 0.f);
+    REQUIRE(stops.evalExpFloat(0) == 0.f);
+    REQUIRE(std::abs(stops.evalExpFloat(0.3) - 2.31144f) < 0.00001);
+    REQUIRE(stops.evalExpFloat(1) == 10.f);
+    REQUIRE(stops.evalExpFloat(3) == 18.f);
+    REQUIRE(stops.evalExpFloat(5) == 50.f);
+    REQUIRE(std::abs(stops.evalExpFloat(6) - 33.33333f) < 0.00001);
+    REQUIRE(stops.evalExpFloat(7) == 0.f);
+    REQUIRE(stops.evalExpFloat(8) == 3.f);
+    REQUIRE(stops.evalExpFloat(8.4) == 3.f); // flat interpolation
+    REQUIRE(stops.evalExpFloat(9.3) == 3.f); // flat interpolation
+    REQUIRE(stops.evalExpFloat(10) == 3.f);
+
+}
+
+TEST_CASE("Stops evaluate color values correctly at and between key frames", "[Stops]") {
+
+    auto stops = instance_color();
+
+    REQUIRE(stops.evalColor(-1) == 0xffffffff);
+    REQUIRE(stops.evalColor(1) == 0xffeeeeee);
+    REQUIRE(stops.evalColor(2) == 0xffdddddd);
+    REQUIRE(stops.evalColor(7) == 0xffaaaaaa);
+
+}
+
+TEST_CASE("Stops parses correctly from YAML distance values", "[Stops][YAML]") {
+
+    YAML::Node node = YAML::Load("[ [10, 0], [16, .04], [18, .2], [19, .2] ]");
+
+    MercatorProjection proj;
+
+    Stops stops(Stops::Widths(node, proj, {}));
+
+    // +1 added for meter end stop
+    REQUIRE(stops.frames.size() == 5);
+    REQUIRE(stops.frames[0].key == 10.f);
+    REQUIRE(stops.frames[1].key == 16.f);
+    REQUIRE(stops.frames[2].key == 18.f);
+    REQUIRE(stops.frames[3].key == 19.f);
+    REQUIRE(stops.frames[0].value.get<float>() == 0.f);
+
+    // check if same meters have twice the width in pixel one zoom-level above
+    REQUIRE(std::abs(stops.frames[2].value.get<float>() * 2.0 - stops.frames[3].value.get<float>()) < 0.00001);
+}
+
+TEST_CASE("Stops parses correctly from YAML color values", "[Stops][YAML]") {
+
+    YAML::Node node = YAML::Load("[ [10, '#aaa'], [16, [0, .5, 1] ], [18, [0, .25, 1, .5] ] ]");
+
+    Stops stops(Stops::Colors(node));
+
+    REQUIRE(stops.frames.size() == 3);
+    REQUIRE(stops.frames[0].key == 10.f);
+    REQUIRE(stops.frames[1].key == 16.f);
+    REQUIRE(stops.frames[2].key == 18.f);
+    REQUIRE(stops.frames[0].value.get<Color>().abgr == 0xffaaaaaa);
+    REQUIRE(stops.frames[1].value.get<Color>().abgr == 0xffff7f00);
+    REQUIRE(stops.frames[2].value.get<Color>().abgr == 0x7fff3f00);
+
+}
+
+TEST_CASE("Regression test - Dont crash on evaluating empty stops", "[Stops][YAML]") {
+
+    YAML::Node node = YAML::Load("[]");
+
+    {
+        MercatorProjection proj{};
+        std::vector<Unit> units = { Unit::meter };
+        Stops stops(Stops::Widths(node, proj, units));
+        REQUIRE(stops.frames.size() == 0);
+        stops.evalVec2(1);
+    }
+    {
+        Stops stops(Stops::Colors(node));
+        REQUIRE(stops.frames.size() == 0);
+        stops.evalVec2(1);
+    }
+    {
+        std::vector<Unit> units = { Unit::meter };
+        Stops stops(Stops::Offsets(node, units));
+        REQUIRE(stops.frames.size() == 0);
+        stops.evalVec2(1);
+    }
+    {
+        Stops stops(Stops::FontSize(node));
+        REQUIRE(stops.frames.size() == 0);
+        stops.evalVec2(1);
+    }
+
+}
+
+TEST_CASE("2 dimension stops for icon sizes with mixed units", "[Stops][YAML]") {
+    YAML::Node node = YAML::Load(R"END(
+        [[6, [18.0 px, 14px]], [13, [20 m, 15px]], [16, [24, 18]]]
+    )END");
+
+    Stops stops(Stops::Sizes(node, StyleParam::unitsForStyleParam(StyleParamKey::size)));
+
+    REQUIRE(stops.frames.size() == 3);
+
+    REQUIRE(stops.evalSize(0).get<glm::vec2>() == glm::vec2(18, 14));
+    REQUIRE(stops.evalSize(13).get<glm::vec2>() == glm::vec2(20, 15));
+    REQUIRE(stops.evalSize(18).get<glm::vec2>() == glm::vec2(24, 18));
+}
+
+
+TEST_CASE("1 dimension stops for icon sizes", "[Stops][YAML]") {
+    YAML::Node node = YAML::Load(R"END(
+        [[6, 18], [13, 20]]
+    )END");
+
+    Stops stops(Stops::Sizes(node, StyleParam::unitsForStyleParam(StyleParamKey::size)));
+
+    REQUIRE(stops.frames.size() == 2);
+
+    REQUIRE(stops.evalSize(0).get<float>() == 18);
+    REQUIRE(stops.evalSize(18).get<float>() == 20);
+}
+
diff --git a/tests/unit/styleMixerTests.cpp b/tests/unit/styleMixerTests.cpp
new file mode 100644 (file)
index 0000000..d7d7530
--- /dev/null
@@ -0,0 +1,293 @@
+#include "catch.hpp"
+#include "scene/styleMixer.h"
+#include "yaml-cpp/yaml.h"
+#include <iostream>
+#include <set>
+
+using namespace Tangram;
+using YAML::Node;
+
+TEST_CASE("Find the correct set of styles to mix", "[mixing][yaml]") {
+
+    StyleMixer mixer;
+
+    Node stylesMap = YAML::Load(R"END(
+        styleA:
+            base: baseA
+        styleB:
+            mix: styleA
+        styleC:
+            base: baseC
+            mix: [styleB, styleA]
+        )END");
+
+    std::vector<std::string> correctMixesA = { "baseA" };
+    std::vector<std::string> correctMixesB = { "styleA" };
+    std::vector<std::string> correctMixesC = { "baseC", "styleB", "styleA" };
+
+    auto resultMixesA = mixer.getStylesToMix(stylesMap["styleA"]);
+    auto resultMixesB = mixer.getStylesToMix(stylesMap["styleB"]);
+    auto resultMixesC = mixer.getStylesToMix(stylesMap["styleC"]);
+
+    REQUIRE(resultMixesA == correctMixesA);
+    REQUIRE(resultMixesB == correctMixesB);
+    REQUIRE(resultMixesC == correctMixesC);
+
+}
+
+TEST_CASE("Find the correct order of styles to mix", "[mixing][yaml]") {
+
+    StyleMixer mixer;
+
+    Node stylesMap = YAML::Load(R"END(
+        styleA:
+            base: baseA
+        styleB:
+            mix: styleA
+        styleC:
+            base: styleA
+            mix: [styleA, styleD]
+        styleD:
+            mix: [styleB, styleA]
+        )END");
+
+    std::vector<std::string> correctMixOrder = { "baseA", "styleA", "styleB", "styleD", "styleC" };
+
+    auto resultMixOrder = mixer.getMixingOrder(stylesMap);
+
+    REQUIRE(resultMixOrder == correctMixOrder);
+
+}
+
+TEST_CASE("Correctly mix two shader configuration nodes", "[mixing][yaml]") {
+
+    StyleMixer mixer;
+
+    Node shadersMap = YAML::Load(R"END(
+        A:
+            extensions: gl_arb_stuff
+            uniforms:
+                green: 0x00ff00
+                tex: a.png
+            blocks:
+                color: colorBlockA
+                normal: normalBlockA
+        B:
+            extensions: [amd_stuff, nv_stuff]
+            uniforms:
+                red: 0xff0000
+                tex: b.png
+            blocks:
+                color: colorBlockB
+                position: posBlockB
+                global: globalBlockB
+        C:
+            blocks:
+                color: colorBlockC
+        D:
+            blocks:
+                color: colorBlockD
+        E:
+        )END");
+
+    // Mixing is applied in-place, so independent tests need to take copies of the original nodes.
+
+    Node resultAB;
+    {
+        Node shaders = Clone(shadersMap);
+        mixer.applyShaderMixins(shaders["B"], {});
+        mixer.applyShaderMixins(shaders["A"], { shaders["B"] });
+        resultAB = shaders["A"];
+        // std::cout << "### B mixed into A ###\n" << Dump(shaders) << std::endl;
+    }
+    Node resultBA;
+    {
+        Node shaders = Clone(shadersMap);
+        mixer.applyShaderMixins(shaders["A"], {});
+        mixer.applyShaderMixins(shaders["B"], { shaders["A"] });
+        resultBA = shaders["B"];
+        // std::cout << "### A mixed into B ###\n" << Dump(shaders) << std::endl;
+    }
+
+    REQUIRE(resultAB["uniforms"]["red"].Scalar() == "0xff0000");
+    REQUIRE(resultBA["uniforms"]["red"].Scalar() == "0xff0000");
+
+    REQUIRE(resultAB["uniforms"]["green"].Scalar() == "0x00ff00");
+    REQUIRE(resultBA["uniforms"]["green"].Scalar() == "0x00ff00");
+
+    REQUIRE(resultAB["uniforms"]["tex"].Scalar() == "a.png");
+    REQUIRE(resultBA["uniforms"]["tex"].Scalar() == "b.png");
+
+    REQUIRE(resultAB["blocks_mixed"]["color"].size() == 2);
+    REQUIRE(resultAB["blocks_mixed"]["color"][0].Scalar() == "colorBlockB");
+    REQUIRE(resultAB["blocks_mixed"]["color"][1].Scalar() == "colorBlockA");
+
+    REQUIRE(resultBA["blocks_mixed"]["color"].size() == 2);
+    REQUIRE(resultBA["blocks_mixed"]["color"][0].Scalar() == "colorBlockA");
+    REQUIRE(resultBA["blocks_mixed"]["color"][1].Scalar() == "colorBlockB");
+
+    REQUIRE(resultAB["blocks_mixed"]["normal"].size() == 1);
+    REQUIRE(resultAB["blocks_mixed"]["normal"][0].Scalar() == "normalBlockA");
+
+    REQUIRE(resultBA["blocks_mixed"]["normal"].size() == 1);
+    REQUIRE(resultBA["blocks_mixed"]["normal"][0].Scalar() == "normalBlockA");
+
+    REQUIRE(resultBA["blocks_mixed"]["global"].size() == 1);
+    REQUIRE(resultBA["blocks_mixed"]["global"][0].Scalar() == "globalBlockB");
+
+    // Mixed extensions are not in any particular order, so we check them against a set.
+    std::set<std::string> correctExtensions = { "gl_arb_stuff", "amd_stuff", "nv_stuff" };
+
+    std::set<std::string> resultExtensionsAB;
+    for (const auto& ext : resultAB["extensions_mixed"]) {
+        resultExtensionsAB.insert(ext.Scalar());
+    }
+    std::set<std::string> resultExtensionsBA;
+    for (const auto& ext : resultBA["extensions_mixed"]) {
+        resultExtensionsBA.insert(ext.Scalar());
+    }
+
+    REQUIRE(resultExtensionsAB == correctExtensions);
+    REQUIRE(resultExtensionsBA == correctExtensions);
+
+    Node resultABCD;
+    {
+        Node shaders = Clone(shadersMap);
+        mixer.applyShaderMixins(shaders["D"], {});
+        mixer.applyShaderMixins(shaders["C"], { shaders["D"] });
+        mixer.applyShaderMixins(shaders["B"], { shaders["D"] });
+        mixer.applyShaderMixins(shaders["A"], { shaders["B"], shaders["C"] });
+        resultABCD = shaders["A"];
+        // std::cout << "### D mixed into B and C, B and C mixed into A ###\n" << Dump(shaders) << std::endl;
+    }
+
+    // Check that "diamond inheritance" doesn't result in repeated blocks.
+    REQUIRE(resultABCD["blocks_mixed"]["color"].size() == 4);
+
+    Node resultEA;
+    {
+        Node shaders = Clone(shadersMap);
+        mixer.applyShaderMixins(shaders["A"], {});
+        mixer.applyShaderMixins(shaders["E"], { shaders["A"] });
+        resultEA = shaders["E"];
+    }
+
+    REQUIRE(resultEA["extensions_mixed"].IsSequence() == true);
+    correctExtensions = { "gl_arb_stuff" };
+    std::set<std::string> resultExtensionsEA;
+    for (const auto& ext : resultEA["extensions_mixed"]) {
+        resultExtensionsEA.insert(ext.Scalar());
+    }
+    REQUIRE(resultExtensionsEA == correctExtensions);
+    REQUIRE(resultEA["uniforms"]["green"].Scalar() == "0x00ff00");
+    REQUIRE(resultEA["uniforms"]["tex"].Scalar() == "a.png");
+    REQUIRE(resultEA["blocks_mixed"]["color"].size() == 1);
+    REQUIRE(resultEA["blocks_mixed"]["color"][0].Scalar() == "colorBlockA");
+    REQUIRE(resultEA["blocks_mixed"]["normal"].size() == 1);
+    REQUIRE(resultEA["blocks_mixed"]["normal"][0].Scalar() == "normalBlockA");
+}
+
+TEST_CASE("Correctly mix two style config nodes", "[yaml][mixing]") {
+
+    StyleMixer mixer;
+
+    Node stylesMap = YAML::Load(R"END(
+        styleA:
+            base: baseA
+            animated: false
+            texcoords: false
+            lighting: vertex
+            texture: a.png
+            # blend: none
+            blend_order: 1
+            material:
+                diffuse: 0.5
+                specular: mat.png
+        styleB:
+            base: baseB
+            animated: true
+            texcoords: false
+            lighting: fragment
+            texture: b.png
+            blend: overlay
+            blend_order: 2
+            material:
+                diffuse: mat.png
+                specular: green
+        )END");
+
+    Node resultAB;
+    {
+        Node styles = Clone(stylesMap);
+        mixer.applyStyleMixins(styles["styleA"], { styles["styleB"] });
+        resultAB = styles["styleA"];
+    }
+    Node resultBA;
+    {
+        Node styles = Clone(stylesMap);
+        mixer.applyStyleMixins(styles["styleB"], { styles["styleA"] });
+        resultBA = styles["styleB"];
+    }
+
+    REQUIRE(resultAB["base"].Scalar() == "baseA");
+    REQUIRE(resultBA["base"].Scalar() == "baseB");
+
+    REQUIRE(resultAB["animated"].Scalar() == "true");
+    REQUIRE(resultBA["animated"].Scalar() == "true");
+
+    REQUIRE(resultAB["texcoords"].Scalar() == "false");
+    REQUIRE(resultBA["texcoords"].Scalar() == "false");
+
+    REQUIRE(resultAB["lighting"].Scalar() == "vertex");
+    REQUIRE(resultBA["lighting"].Scalar() == "fragment");
+
+    REQUIRE(resultAB["texture"].Scalar() == "a.png");
+    REQUIRE(resultBA["texture"].Scalar() == "b.png");
+
+    REQUIRE(resultAB["blend"].Scalar() == "overlay");
+    REQUIRE(resultBA["blend"].Scalar() == "overlay");
+
+    REQUIRE(resultAB["blend_order"].Scalar() == "1");
+    REQUIRE(resultBA["blend_order"].Scalar() == "2");
+
+    REQUIRE(resultAB["material"]["diffuse"].Scalar() == "0.5");
+    REQUIRE(resultBA["material"]["diffuse"].Scalar() == "mat.png");
+
+    REQUIRE(resultAB["material"]["specular"].Scalar() == "mat.png");
+    REQUIRE(resultBA["material"]["specular"].Scalar() == "green");
+
+}
+
+TEST_CASE("fix:mergeMapFieldTakingLast: Correctly mix two style config nodes", "[yaml][mixing]") {
+
+    StyleMixer mixer;
+
+    Node styles = YAML::Load(R"END(
+        styleA:
+        styleB:
+            base: styleA
+            animated: true
+            texcoords: false
+            lighting: fragment
+            texture: b.png
+            blend: overlay
+            blend_order: 2
+            material:
+                diffuse: mat.png
+                specular: green
+        )END");
+
+    mixer.applyStyleMixins(styles["styleB"], { styles["styleA"] });
+    auto resultB = styles["styleB"];
+
+    REQUIRE(resultB["base"].Scalar() == "styleA");
+    REQUIRE(resultB["animated"].Scalar() == "true");
+    REQUIRE(resultB["texcoords"].Scalar() == "false");
+    REQUIRE(resultB["lighting"].Scalar() == "fragment");
+    REQUIRE(resultB["texture"].Scalar() == "b.png");
+    REQUIRE(resultB["blend"].Scalar() == "overlay");
+    REQUIRE(resultB["blend_order"].Scalar() == "2");
+    REQUIRE(resultB["material"]["diffuse"].Scalar() == "mat.png");
+    REQUIRE(resultB["material"]["specular"].Scalar() == "green");
+
+}
diff --git a/tests/unit/styleSortingTests.cpp b/tests/unit/styleSortingTests.cpp
new file mode 100644 (file)
index 0000000..4f4492b
--- /dev/null
@@ -0,0 +1,60 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <vector>
+#include <string>
+
+#include "yaml-cpp/yaml.h"
+#include "scene/filters.h"
+#include "scene/sceneLoader.h"
+#include "style/polygonStyle.h"
+
+using namespace Tangram;
+using YAML::Node;
+
+TEST_CASE( "Style Sorting Test", "[styleSorting][core][yaml]") {
+
+    std::vector<std::unique_ptr<Style>> styles;
+
+    std::unique_ptr<PolygonStyle> s1(new PolygonStyle("s-none-none"));
+    std::unique_ptr<PolygonStyle> s2(new PolygonStyle("t-overlay-3"));
+    std::unique_ptr<PolygonStyle> s3(new PolygonStyle("a-add-10"));
+    std::unique_ptr<PolygonStyle> s4(new PolygonStyle("r-none-none"));
+    std::unique_ptr<PolygonStyle> s5(new PolygonStyle("w-inlay-0"));
+    std::unique_ptr<PolygonStyle> s6(new PolygonStyle("a2-overlay-3"));
+    std::unique_ptr<PolygonStyle> s7(new PolygonStyle("r2-none-4"));
+    std::unique_ptr<PolygonStyle> s8(new PolygonStyle("s2-multiply-10"));
+
+    s2->setBlendMode(Blending::overlay);
+    s3->setBlendMode(Blending::add);
+    s5->setBlendMode(Blending::inlay);
+    s8->setBlendMode(Blending::multiply);
+    s6->setBlendMode(Blending::overlay);
+
+    s7->setBlendOrder(4); //Test opaque style with a blend order (should not matter)
+    s2->setBlendOrder(3);
+    s3->setBlendOrder(10);
+    s5->setBlendOrder(0);
+    s8->setBlendOrder(10);
+    s6->setBlendOrder(3);
+
+    styles.push_back(std::move(s1));
+    styles.push_back(std::move(s2));
+    styles.push_back(std::move(s3));
+    styles.push_back(std::move(s4));
+    styles.push_back(std::move(s5));
+    styles.push_back(std::move(s6));
+    styles.push_back(std::move(s7));
+    styles.push_back(std::move(s8));
+
+    std::sort(styles.begin(), styles.end(), Style::compare);
+
+    REQUIRE(styles[0]->getName() == "r-none-none");
+    REQUIRE(styles[1]->getName() == "r2-none-4");
+    REQUIRE(styles[2]->getName() == "s-none-none");
+    REQUIRE(styles[3]->getName() == "w-inlay-0");
+    REQUIRE(styles[4]->getName() == "a2-overlay-3");
+    REQUIRE(styles[5]->getName() == "t-overlay-3");
+    REQUIRE(styles[6]->getName() == "a-add-10");
+    REQUIRE(styles[7]->getName() == "s2-multiply-10");
+}
diff --git a/tests/unit/styleUniformsTests.cpp b/tests/unit/styleUniformsTests.cpp
new file mode 100644 (file)
index 0000000..71b5b32
--- /dev/null
@@ -0,0 +1,179 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <vector>
+#include <string>
+#include <unordered_map>
+
+#include "yaml-cpp/yaml.h"
+#include "scene/filters.h"
+#include "scene/importer.h"
+#include "scene/sceneLoader.h"
+#include "scene/scene.h"
+#include "util/variant.h"
+#include "platform_mock.h"
+#include "log.h"
+
+using namespace Tangram;
+using YAML::Node;
+
+class TestImporter : public Importer {
+
+public:
+    TestImporter(std::unordered_map<Url, std::string> _testScenes) : m_testScenes(_testScenes) {}
+
+protected:
+    virtual std::string getSceneString(const std::shared_ptr<Platform>& platform,
+            const Url& scenePath, const std::shared_ptr<Asset>& asset = nullptr) override {
+        return m_testScenes[scenePath];
+    }
+
+    std::unordered_map<Url, std::string> m_testScenes;
+};
+
+TEST_CASE( "Style Uniforms Parsing and Injection Test: Float uniform value", "[StyleUniforms][core][yaml]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+
+    Node node = YAML::Load(R"END(
+        u_float: 0.5
+        )END");
+
+    StyleUniform uniformValues;
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_float"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<float>());
+    REQUIRE(uniformValues.value.get<float>() == 0.5);
+    REQUIRE(uniformValues.type == "float");
+}
+
+TEST_CASE( "Style Uniforms Parsing and Injection Test: Boolean uniform value", "[StyleUniforms][core][yaml]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+
+    Node node = YAML::Load(R"END(
+        u_true: true
+        u_false: false
+        )END");
+
+    StyleUniform uniformValues;
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_true"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<bool>());
+    REQUIRE(uniformValues.value.get<bool>() == 1);
+    REQUIRE(uniformValues.type == "bool");
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_false"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<bool>());
+    REQUIRE(uniformValues.value.get<bool>() == 0);
+    REQUIRE(uniformValues.type == "bool");
+}
+
+TEST_CASE( "Style Uniforms Parsing and Injection Test: vec2, vec3, vec4 uniform value", "[StyleUniforms][core][yaml]") {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    std::shared_ptr<Scene> scene = std::make_shared<Scene>(platform);
+
+    Node node = YAML::Load(R"END(
+        u_vec2: [0.1, 0.2]
+        u_vec3: [0.1, 0.2, 0.3]
+        u_vec4: [0.1, 0.2, 0.3, 0.4]
+        u_array: [0.1, 0.2, 0.3, 0.4, 0.5]
+        )END");
+
+    StyleUniform uniformValues;
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_vec2"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<glm::vec2>());
+    REQUIRE(uniformValues.value.get<glm::vec2>().x == 0.1f);
+    REQUIRE(uniformValues.value.get<glm::vec2>().y == 0.2f);
+    REQUIRE(uniformValues.type == "vec2");
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_vec3"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<glm::vec3>());
+    REQUIRE(uniformValues.value.get<glm::vec3>().x == 0.1f);
+    REQUIRE(uniformValues.value.get<glm::vec3>().y == 0.2f);
+    REQUIRE(uniformValues.value.get<glm::vec3>().z == 0.3f);
+    REQUIRE(uniformValues.type == "vec3");
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_vec4"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<glm::vec4>());
+    REQUIRE(uniformValues.value.get<glm::vec4>().x == 0.1f);
+    REQUIRE(uniformValues.value.get<glm::vec4>().y == 0.2f);
+    REQUIRE(uniformValues.value.get<glm::vec4>().z == 0.3f);
+    REQUIRE(uniformValues.value.get<glm::vec4>().w == 0.4f);
+    REQUIRE(uniformValues.type == "vec4");
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_array"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<UniformArray1f>());
+    REQUIRE(uniformValues.value.get<UniformArray1f>()[0] == 0.1f);
+    REQUIRE(uniformValues.value.get<UniformArray1f>()[1] == 0.2f);
+    REQUIRE(uniformValues.value.get<UniformArray1f>()[2] == 0.3f);
+    REQUIRE(uniformValues.value.get<UniformArray1f>()[3] == 0.4f);
+    REQUIRE(uniformValues.value.get<UniformArray1f>()[4] == 0.5f);
+}
+
+TEST_CASE( "Style Uniforms Parsing and Injection Test: textures uniform value", "[StyleUniforms][core][yaml]") {
+    std::unordered_map<Url, std::string> testScenes;
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+
+    testScenes["test.yaml"] = R"END(
+        styles:
+            test:
+                shaders:
+                    uniforms:
+                        u_tex: "img/cross.png"
+                        u_tex2: ["img/cross.png", "img/normals.jpg", "img/sem.jpg"]
+    )END";
+
+    TestImporter importer(testScenes);
+
+    auto scene = std::make_shared<Scene>(platform, "test.yaml");
+    auto root = importer.applySceneImports(platform, scene);
+
+    StyleUniform uniformValues;
+
+    const auto& node = root["styles"]["test"]["shaders"]["uniforms"];
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_tex"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<std::string>());
+    REQUIRE(uniformValues.value.get<std::string>() == "img/cross.png");
+    REQUIRE(uniformValues.type == "sampler2D");
+
+    REQUIRE(SceneLoader::parseStyleUniforms(platform, node["u_tex2"], scene, uniformValues));
+    REQUIRE(uniformValues.value.is<UniformTextureArray>());
+    REQUIRE(uniformValues.value.get<UniformTextureArray>().names.size() == 3);
+    REQUIRE(uniformValues.value.get<UniformTextureArray>().names[0] == "img/cross.png");
+    REQUIRE(uniformValues.value.get<UniformTextureArray>().names[1] == "img/normals.jpg");
+    REQUIRE(uniformValues.value.get<UniformTextureArray>().names[2] == "img/sem.jpg");
+}
+
+TEST_CASE( "Style Uniforms Parsing failure Tests: textures uniform value", "[StyleUniforms][core][yaml]") {
+    std::unordered_map<Url, std::string> testScenes;
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+
+    testScenes["test.yaml"] = R"END(
+        styles:
+            test:
+                shaders:
+                    uniforms:
+                        u_tex : not_a_texture
+                        u_tex2 : [not_a_texture_path2, not_a_texture_path_1]
+                        u_uniform_float0: 0.5f
+                        u_uniform_float1: 0s.5
+    )END";
+
+    TestImporter importer(testScenes);
+
+    auto scene = std::make_shared<Scene>(platform, "test.yaml");
+    auto root = importer.applySceneImports(platform, scene);
+
+    StyleUniform uniformValues;
+
+    const auto& node = root["styles"]["test"]["shaders"]["uniforms"];
+
+    REQUIRE(!SceneLoader::parseStyleUniforms(platform, node["u_tex"], scene, uniformValues));
+    REQUIRE(!SceneLoader::parseStyleUniforms(platform, node["u_tex2"], scene, uniformValues));
+    REQUIRE(!SceneLoader::parseStyleUniforms(platform, node["u_uniform_float0"], scene, uniformValues));
+    REQUIRE(!SceneLoader::parseStyleUniforms(platform, node["u_uniform_float1"], scene, uniformValues));
+}
+
diff --git a/tests/unit/textureTests.cpp b/tests/unit/textureTests.cpp
new file mode 100644 (file)
index 0000000..73aa613
--- /dev/null
@@ -0,0 +1,115 @@
+#define CATCH_CONFIG_MAIN
+#include "catch.hpp"
+
+#include "gl/texture.h"
+
+using namespace Tangram;
+
+class TestTexture : public Texture {
+public:
+    using Texture::Texture;
+    const std::vector<DirtyRange>& dirtyRanges() { return m_dirtyRanges; }
+};
+
+TEST_CASE("Merging of dirty Regions - Non overlapping, test ordering", "[Texture]") {
+    TestTexture texture(512, 512);
+    REQUIRE(texture.dirtyRanges().size() == 0);
+
+    // A range from 20-30
+    texture.setDirty(20, 10);
+    REQUIRE(texture.dirtyRanges().size() == 1);
+
+    // B range from 0-10
+    texture.setDirty(0, 10);
+    REQUIRE(texture.dirtyRanges().size() == 2);
+
+    // C range from 40-60
+    texture.setDirty(40, 20);
+    REQUIRE(texture.dirtyRanges().size() == 3);
+
+    // B
+    REQUIRE(texture.dirtyRanges()[0].min == 0);
+    REQUIRE(texture.dirtyRanges()[0].max == 10);
+
+    // A
+    REQUIRE(texture.dirtyRanges()[1].min == 20);
+    REQUIRE(texture.dirtyRanges()[1].max == 30);
+
+    // C
+    REQUIRE(texture.dirtyRanges()[2].min == 40);
+    REQUIRE(texture.dirtyRanges()[2].max == 60);
+
+}
+
+TEST_CASE("Merging of dirty Regions - Merge overlapping", "[Texture]") {
+    TestTexture texture(512, 512);
+    REQUIRE(texture.dirtyRanges().size() == 0);
+
+    // range from 50-100
+    texture.setDirty(50, 50);
+    REQUIRE(texture.dirtyRanges().size() == 1);
+
+    // range from 20-70
+    texture.setDirty(20, 50);
+    REQUIRE(texture.dirtyRanges().size() == 1);
+
+    REQUIRE(texture.dirtyRanges()[0].min == 20);
+    REQUIRE(texture.dirtyRanges()[0].max == 100);
+}
+
+TEST_CASE("Merging of dirty Regions - Merge three regions, when 3rd region is added", "[Texture]") {
+    { // just touching
+
+        TestTexture texture(512, 512);
+        REQUIRE(texture.dirtyRanges().size() == 0);
+
+        // range from 50-100
+        texture.setDirty(50, 50);
+        REQUIRE(texture.dirtyRanges().size() == 1);
+        REQUIRE(texture.dirtyRanges()[0].min == 50);
+        REQUIRE(texture.dirtyRanges()[0].max == 100);
+
+        // range from 200-250
+        texture.setDirty(200, 50);
+        REQUIRE(texture.dirtyRanges().size() == 2);
+        REQUIRE(texture.dirtyRanges()[1].min == 200);
+        REQUIRE(texture.dirtyRanges()[1].max == 250);
+
+        // range from 100-200
+        texture.setDirty(100, 100);
+        REQUIRE(texture.dirtyRanges().size() == 1);
+        REQUIRE(texture.dirtyRanges()[0].min == 50);
+        REQUIRE(texture.dirtyRanges()[0].max == 250);
+    }
+
+    { // overlapping
+
+        TestTexture texture(512, 512);
+        REQUIRE(texture.dirtyRanges().size() == 0);
+
+        // range from 50-150
+        texture.setDirty(50, 100);
+        REQUIRE(texture.dirtyRanges().size() == 1);
+        REQUIRE(texture.dirtyRanges()[0].min == 50);
+        REQUIRE(texture.dirtyRanges()[0].max == 150);
+
+        // range from 200-250
+        texture.setDirty(200, 50);
+        REQUIRE(texture.dirtyRanges().size() == 2);
+        REQUIRE(texture.dirtyRanges()[1].min == 200);
+        REQUIRE(texture.dirtyRanges()[1].max == 250);
+
+        // range from 300-350
+        texture.setDirty(300, 50);
+        REQUIRE(texture.dirtyRanges().size() == 3);
+        REQUIRE(texture.dirtyRanges()[2].min == 300);
+        REQUIRE(texture.dirtyRanges()[2].max == 350);
+
+        // range from 100-300
+        texture.setDirty(100, 200);
+        REQUIRE(texture.dirtyRanges().size() == 1);
+        REQUIRE(texture.dirtyRanges()[0].min == 50);
+        REQUIRE(texture.dirtyRanges()[0].max == 350);
+    }
+
+}
diff --git a/tests/unit/tileIDTests.cpp b/tests/unit/tileIDTests.cpp
new file mode 100644 (file)
index 0000000..cad1d66
--- /dev/null
@@ -0,0 +1,146 @@
+#include "catch.hpp"
+
+#include "tile/tileID.h"
+#include <set>
+
+using namespace Tangram;
+
+TEST_CASE( "Create TileIDs and check that they are correctly ordered", "[Core][TileID]" ) {
+
+    TileID a = TileID(1, 1, 1);
+
+    REQUIRE(a.x == 1);
+    REQUIRE(a.y == 1);
+    REQUIRE(a.z == 1);
+
+    TileID b = TileID(2, 1, 1);
+    TileID c = TileID(1, 2, 1);
+    TileID d = TileID(1, 1, 2);
+
+    REQUIRE(a < b);
+    REQUIRE(b > a);
+
+    REQUIRE(a < c);
+    REQUIRE(c > a);
+
+    REQUIRE(a > d);
+    REQUIRE(d < a);
+
+    REQUIRE(c < b);
+    REQUIRE(b > c);
+
+    REQUIRE(b > d);
+    REQUIRE(d < b);
+
+    REQUIRE(c > d);
+    REQUIRE(d < c);
+
+}
+
+TEST_CASE( "Create TileIDs and find their parents and children", "[Core][TileID]" ) {
+
+    TileID a = TileID(1, 2, 3);
+
+    TileID parent = a.getParent();
+
+    REQUIRE(parent == TileID(0, 1, 2));
+
+    std::set<TileID> children;
+
+    for (int i = 0; i < 4; i++) {
+        children.insert(a.getChild(i, 5));
+    }
+
+    std::set<TileID> requiredChildren = { TileID(2, 4, 4), TileID(3, 4, 4), TileID(2, 5, 4), TileID(3, 5, 4) };
+
+    REQUIRE(children == requiredChildren);
+
+    for (const TileID& t : requiredChildren) {
+        REQUIRE(t.getParent() == a);
+    }
+
+}
+
+TEST_CASE( "Ensure TileIDs correctly evaluate their validity", "[Core][TileID]") {
+
+    REQUIRE(TileID(1, 1, 1).isValid());
+    REQUIRE(TileID(1, 1, 1).isValid(1));
+    REQUIRE(!TileID(1, 1, 2).isValid(1));
+
+    REQUIRE(!TileID(-1,  0,  0).isValid());
+    REQUIRE(!TileID( 0, -1,  0).isValid());
+    REQUIRE(!TileID( 0,  0, -1).isValid());
+    REQUIRE(!TileID( 1,  0,  0).isValid());
+    REQUIRE(!TileID( 0,  1,  0).isValid());
+
+    REQUIRE(!NOT_A_TILE.isValid());
+
+}
+
+TEST_CASE("TileID correctly applies source zoom limits", "[Core][TileID]") {
+
+    auto a = TileID(1, 2, 4);
+    REQUIRE(a.withMaxSourceZoom(4) == a);
+    REQUIRE(a.withMaxSourceZoom(3) == TileID(0, 1, 3, 4, 0));
+    REQUIRE(a.withMaxSourceZoom(2) == TileID(0, 0, 2, 4, 0));
+
+    auto b = TileID(2, 1, 4, 6, 0); // Over-zoomed to zoom 6 with a limit of 4
+    auto c = b.getParent();
+    auto d = c.getParent();
+    auto e = d.getParent();
+    REQUIRE(c == TileID(2, 1, 4, 5, 0));
+    REQUIRE(d == TileID(2, 1, 4, 4, 0));
+    REQUIRE(e == TileID(1, 0, 3, 3, 0));
+
+    //Child tiles
+    auto f = TileID(2, 1, 4, 4, 0);
+    auto g = f.getChild(0, 5);
+    auto h = g.getChild(0, 5);
+    auto i = h.getChild(0, 5);
+    REQUIRE(g == TileID(4, 2, 5, 5, 0));
+    REQUIRE(h == TileID(4, 2, 5, 6, 0));
+    REQUIRE(i == TileID(4, 2, 5, 7, 0));
+}
+
+TEST_CASE("TileID correctly applies source zoom limits for scaled tiles", "[Core][TileID]") {
+    // maxZoom: 6, scale: 1
+    auto aScaled = TileID(8, 4, 6);
+    aScaled = aScaled.zoomBiasAdjusted(1);
+    aScaled = aScaled.withMaxSourceZoom(6);
+    auto aScaledMax5 = aScaled.withMaxSourceZoom(5);
+    auto aScaledMax4 = aScaled.withMaxSourceZoom(4);
+
+    REQUIRE(aScaled ==  TileID(4, 2, 5, 6, 0));
+    REQUIRE(aScaledMax5 == TileID(4, 2, 5, 6, 0));
+    REQUIRE(aScaledMax4 == TileID(2, 1, 4, 6, 0));
+
+    auto b = aScaled.getParent(1);
+    auto c = aScaledMax5.getParent(1);
+    auto d = aScaledMax4.getParent(1);
+    REQUIRE(b == TileID(2, 1, 4, 5, 0));
+    REQUIRE(c == TileID(2, 1, 4, 5, 0));
+    REQUIRE(d == TileID(2, 1, 4, 5, 0));
+
+    auto e = b.getParent(1); // grand parent of original aScaled tile
+    auto f = e.getParent(1); // grand grand
+    auto g = f.getParent(1); // grand grand grand
+    REQUIRE(e == TileID(1, 0, 3, 4, 0));
+    REQUIRE(f == TileID(0, 0, 2, 3, 0));
+    REQUIRE(g == TileID(0, 0, 1, 2, 0));
+
+    // child tiles
+    b = aScaled.getChild(0, 6);
+    c = aScaledMax5.getChild(0, 5);
+    d = aScaledMax4.getChild(0, 4);
+    REQUIRE(b == TileID(8, 4, 6, 7, 0));
+    REQUIRE(c == TileID(4, 2, 5, 7, 0));
+    REQUIRE(d == TileID(2, 1, 4, 7, 0));
+
+    e = b.getChild(0, 6);
+    f = e.getChild(0, 6);
+    g = f.getChild(0, 6);
+    REQUIRE(e == TileID(8, 4, 6, 8, 0));
+    REQUIRE(f == TileID(8, 4, 6, 9, 0));
+    REQUIRE(g == TileID(8, 4, 6, 10, 0));
+
+}
diff --git a/tests/unit/tileManagerTests.cpp b/tests/unit/tileManagerTests.cpp
new file mode 100644 (file)
index 0000000..cbd8c9a
--- /dev/null
@@ -0,0 +1,304 @@
+#include "catch.hpp"
+
+#include "data/tileSource.h"
+#include "tile/tileManager.h"
+#include "tile/tileWorker.h"
+#include "util/mapProjection.h"
+#include "util/fastmap.h"
+#include "view/view.h"
+#include "platform_mock.h"
+
+#include <deque>
+
+using namespace Tangram;
+
+MercatorProjection s_projection;
+ViewState viewState { &s_projection, true, glm::vec2(0), 1, 0, 1.f, glm::vec2(0), 256.f };
+
+struct TestTileWorker : TileTaskQueue {
+    int processedCount = 0;
+    bool pendingTiles = false;
+
+    std::deque<std::shared_ptr<TileTask>> tasks;
+
+    void enqueue(std::shared_ptr<TileTask> task) override{
+        tasks.push_back(std::move(task));
+    }
+
+    bool checkProcessedTiles() {
+        if (pendingTiles) {
+            pendingTiles = false;
+            return true;
+        }
+        return false;
+    }
+
+    void processTask() {
+        while (!tasks.empty()) {
+            auto task = tasks.front();
+            tasks.pop_front();
+            if (task->isCanceled()) {
+                continue;
+            }
+
+            task->tile() = std::make_shared<Tile>(task->tileId(), s_projection, &task->source());
+
+            pendingTiles = true;
+            processedCount++;
+            break;
+        }
+    }
+    void processTask(int position) {
+
+        auto task = tasks[position];
+        tasks.erase(tasks.begin() + position);
+
+        task->tile() = std::make_shared<Tile>(task->tileId(), s_projection, &task->source());
+
+        pendingTiles = true;
+        processedCount++;
+    }
+
+    void dropTask() {
+        if (!tasks.empty()) {
+            auto task = tasks.front();
+            tasks.pop_front();
+            task->cancel();
+        }
+    }
+};
+
+struct TestTileSource : TileSource {
+    class Task : public TileTask {
+    public:
+        bool gotData = false;
+
+        Task(TileID& _tileId, std::shared_ptr<TileSource> _source, bool _subTask)
+            : TileTask(_tileId, _source, _subTask) {}
+
+        bool hasData() const override { return gotData; }
+    };
+
+    int tileTaskCount = 0;
+
+    TestTileSource() : TileSource("test", nullptr) {
+        m_generateGeometry = true;
+    }
+
+    void loadTileData(std::shared_ptr<TileTask> _task, TileTaskCb _cb) override {
+        tileTaskCount++;
+        static_cast<Task*>(_task.get())->gotData = true;
+        _task->startedLoading();
+        _cb.func(std::move(_task));
+    }
+
+    void cancelLoadingTile(const TileID& _tile) override {}
+
+    std::shared_ptr<TileData> parse(const TileTask& _task,
+                                    const MapProjection& _projection) const override{
+        return nullptr;
+    };
+
+    void clearData() override {}
+
+    std::shared_ptr<TileTask> createTask(TileID _tileId, int _subTask) override {
+        return std::make_shared<Task>(_tileId, shared_from_this(), _subTask);
+    }
+};
+
+class TestTileManager : public TileManager {
+public:
+    using Base = TileManager;
+    using Base::Base;
+
+    void updateTiles(const ViewState& _view, std::set<TileID> _visibleTiles) {
+        // Mimic TileManager::updateTileSets(View& _view)
+        m_tiles.clear();
+        m_tilesInProgress = 0;
+        m_tileSetChanged = false;
+
+        TileSet& tileSet = m_tileSets[0];
+
+        tileSet.visibleTiles = _visibleTiles;
+
+        TileManager::updateTileSet(tileSet, _view);
+
+        loadTiles();
+
+        // Make m_tiles an unique list of tiles for rendering sorted from
+        // high to low zoom-levels.
+        std::sort(m_tiles.begin(), m_tiles.end(), [](auto& a, auto& b){
+                return a->getID() < b->getID(); });
+
+        // Remove duplicates: Proxy tiles could have been added more than once
+        m_tiles.erase(std::unique(m_tiles.begin(), m_tiles.end()), m_tiles.end());
+
+    }
+};
+
+TEST_CASE( "Use proxy Tile - Dont remove proxy if it is now visible", "[TileManager][updateTileSets]" ) {
+    TestTileWorker worker;
+    TestTileManager tileManager(std::make_shared<MockPlatform>(), worker);
+
+    auto source = std::make_shared<TestTileSource>();
+    std::vector<std::shared_ptr<TileSource>> sources = { source };
+    tileManager.setTileSources(sources);
+
+    /// Start loading tile 0/0/0
+    std::set<TileID> visibleTiles_1 = {TileID{0,0,0}};
+    tileManager.updateTiles(viewState, visibleTiles_1);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 1);
+    REQUIRE(worker.processedCount == 0);
+
+    /// Start loading tile 0/0/1 - uses 0/0/0 as proxy
+    std::set<TileID> visibleTiles_2 = {TileID{0,0,1}};
+
+    tileManager.updateTiles(viewState, visibleTiles_2);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 0);
+
+    /// Process tile task 0/0/1
+    worker.processTask(1);
+
+    /// Go back to tile 0/0/0 - uses 0/0/1 as proxy
+    tileManager.updateTiles(viewState, visibleTiles_1);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 1);
+    REQUIRE(tileManager.getVisibleTiles()[0]->isProxy() == true);
+    REQUIRE(tileManager.getVisibleTiles()[0]->getID() == TileID(0,0,1));
+
+    // Process tile task 0/0/0
+    worker.processTask(0);
+    tileManager.updateTiles(viewState, visibleTiles_1);
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(tileManager.getVisibleTiles()[0]->isProxy() == false);
+    REQUIRE(tileManager.getVisibleTiles()[0]->getID() == TileID(0,0,0));
+}
+
+TEST_CASE( "Mock TileWorker Initialization", "[TileManager][Constructor]" ) {
+
+    TestTileWorker worker;
+    TileManager tileManager(std::shared_ptr<MockPlatform>(), worker);
+}
+
+TEST_CASE( "Real TileWorker Initialization", "[TileManager][Constructor]" ) {
+    auto platform = std::make_shared<MockPlatform>();
+    TileWorker worker(platform, 1);
+    TileManager tileManager(platform, worker);
+}
+
+TEST_CASE( "Load visible Tile", "[TileManager][updateTileSets]" ) {
+    TestTileWorker worker;
+    TestTileManager tileManager(std::make_shared<MockPlatform>(), worker);
+
+    auto source = std::make_shared<TestTileSource>();
+    std::vector<std::shared_ptr<TileSource>> sources = { source };
+    tileManager.setTileSources(sources);
+
+    std::set<TileID> visibleTiles = {TileID{0,0,0}};
+    tileManager.updateTiles(viewState, visibleTiles);
+    worker.processTask();
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 1);
+    REQUIRE(worker.processedCount == 1);
+
+    tileManager.updateTiles(viewState, visibleTiles);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(source->tileTaskCount == 1);
+    REQUIRE(worker.processedCount == 1);
+
+}
+
+
+TEST_CASE( "Use proxy Tile", "[TileManager][updateTileSets]" ) {
+    TestTileWorker worker;
+    TestTileManager tileManager(std::make_shared<MockPlatform>(), worker);
+
+    auto source = std::make_shared<TestTileSource>();
+    std::vector<std::shared_ptr<TileSource>> sources = { source };
+    tileManager.setTileSources(sources);
+
+    std::set<TileID> visibleTiles = {TileID{0,0,0}};
+    tileManager.updateTiles(viewState, visibleTiles);
+    worker.processTask();
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 1);
+    REQUIRE(worker.processedCount == 1);
+
+    std::set<TileID> visibleTiles2 = {TileID{0,0,1}};
+    tileManager.updateTiles(viewState, visibleTiles2);
+    worker.processTask();
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(tileManager.getVisibleTiles()[0]->isProxy() == true);
+    REQUIRE(tileManager.getVisibleTiles()[0]->getID() == TileID(0,0,0));
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 2);
+
+    tileManager.updateTiles(viewState, visibleTiles2);
+    worker.processTask();
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(tileManager.getVisibleTiles()[0]->isProxy() == false);
+    REQUIRE(tileManager.getVisibleTiles()[0]->getID() == TileID(0,0,1));
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 2);
+
+}
+
+
+TEST_CASE( "Use proxy Tile - circular proxies", "[TileManager][updateTileSets]" ) {
+    TestTileWorker worker;
+    TestTileManager tileManager(std::make_shared<MockPlatform>(), worker);
+
+    auto source = std::make_shared<TestTileSource>();
+    std::vector<std::shared_ptr<TileSource>> sources = { source };
+    tileManager.setTileSources(sources);
+
+    /// Start loading tile 0/0/0
+    std::set<TileID> visibleTiles_1 = {TileID{0,0,0}};
+    tileManager.updateTiles(viewState, visibleTiles_1);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 1);
+    REQUIRE(worker.processedCount == 0);
+
+    /// Start loading tile 0/0/1 - add 0/0/0 as proxy
+    std::set<TileID> visibleTiles_2 = {TileID{0,0,1}};
+    tileManager.updateTiles(viewState, visibleTiles_2);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 0);
+
+    /// Go back to tile 0/0/0
+    /// NB: does not add 0/0/1 as proxy, since no newTiles were loaded
+    tileManager.updateTiles(viewState, visibleTiles_1);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 0);
+    REQUIRE(source->tileTaskCount == 2);
+    REQUIRE(worker.processedCount == 0);
+
+    REQUIRE(worker.tasks.size() == 2);
+    // tile 0/0/0 still loading
+    REQUIRE(worker.tasks[0]->isCanceled() == false);
+    // tile 0/0/1 canceled
+    REQUIRE(worker.tasks[1]->isCanceled() == true);
+
+    worker.processTask();
+    tileManager.updateTiles(viewState, visibleTiles_1);
+
+    REQUIRE(tileManager.getVisibleTiles().size() == 1);
+    REQUIRE(tileManager.getVisibleTiles()[0]->isProxy() == false);
+    REQUIRE(tileManager.getVisibleTiles()[0]->getID() == TileID(0,0,0));
+
+}
diff --git a/tests/unit/urlTests.cpp b/tests/unit/urlTests.cpp
new file mode 100644 (file)
index 0000000..e77f9b6
--- /dev/null
@@ -0,0 +1,239 @@
+#include "catch.hpp"
+
+#include "util/url.h"
+
+using namespace Tangram;
+
+TEST_CASE("Parse components of a correctly formatted URL", "[Url]") {
+
+    // Tests conformance to https://tools.ietf.org/html/rfc1808#section-2.1
+
+    Url url("https://some.domain:9000/path/to/file.html;param=val?api_key=mapsRcool#yolo");
+
+    CHECK(!url.isEmpty());
+    CHECK(url.isAbsolute());
+    CHECK(!url.hasDataScheme());
+    CHECK(!url.hasBase64Data());
+    CHECK(!url.hasFileScheme());
+    CHECK(url.hasHttpScheme());
+    CHECK(url.hasScheme());
+    CHECK(url.scheme() == "https");
+    CHECK(url.hasNetLocation());
+    CHECK(url.netLocation() == "some.domain:9000");
+    CHECK(url.hasPath());
+    CHECK(url.path() == "/path/to/file.html");
+    CHECK(url.hasParameters());
+    CHECK(url.parameters() == "param=val");
+    CHECK(url.hasQuery());
+    CHECK(url.query() == "api_key=mapsRcool");
+    CHECK(url.hasFragment());
+    CHECK(url.fragment() == "yolo");
+    CHECK(!url.hasMediaType());
+    CHECK(!url.hasData());
+
+}
+
+TEST_CASE("Parse components of a correctly formatted data URI", "[Url]") {
+
+    // Tests conformance to https://tools.ietf.org/html/rfc2397#section-3
+
+    Url url("data:text/html;charset=utf-8;base64,YmFzZTY0");
+
+    CHECK(!url.isEmpty());
+    CHECK(url.isAbsolute());
+    CHECK(url.hasDataScheme());
+    CHECK(url.hasBase64Data());
+    CHECK(!url.hasFileScheme());
+    CHECK(!url.hasHttpScheme());
+    CHECK(url.hasScheme());
+    CHECK(url.scheme() == "data");
+    CHECK(!url.hasNetLocation());
+    CHECK(!url.hasPath());
+    CHECK(!url.hasParameters());
+    CHECK(!url.hasQuery());
+    CHECK(!url.hasFragment());
+    CHECK(url.hasMediaType());
+    CHECK(url.mediaType() == "text/html;charset=utf-8");
+    CHECK(url.hasData());
+    CHECK(url.data() == "YmFzZTY0");
+
+}
+
+TEST_CASE("Parse an empty URL", "[Url]") {
+
+    Url url("");
+
+    CHECK(url.isEmpty());
+    CHECK(!url.isAbsolute());
+    CHECK(!url.hasDataScheme());
+    CHECK(!url.hasBase64Data());
+    CHECK(!url.hasScheme());
+    CHECK(!url.hasNetLocation());
+    CHECK(!url.hasPath());
+    CHECK(!url.hasParameters());
+    CHECK(!url.hasQuery());
+    CHECK(!url.hasFragment());
+    CHECK(!url.hasMediaType());
+    CHECK(!url.hasData());
+
+}
+
+TEST_CASE("Remove dot segments from a path", "[Url]") {
+
+    // Tests conformance to https://tools.ietf.org/html/rfc3986#section-5.2.4
+
+    CHECK(Url::removeDotSegmentsFromString("") == "");
+    CHECK(Url::removeDotSegmentsFromString("a/b/c") == "a/b/c");
+    CHECK(Url::removeDotSegmentsFromString("a/b=?.;5/c") == "a/b=?.;5/c");
+    CHECK(Url::removeDotSegmentsFromString("/a/b/c/./../../g") == "/a/g");
+    CHECK(Url::removeDotSegmentsFromString("../a/b") == "a/b");
+    CHECK(Url::removeDotSegmentsFromString("./") == "");
+    CHECK(Url::removeDotSegmentsFromString("..") == "");
+    CHECK(Url::removeDotSegmentsFromString("a/b/../../..") == "");
+    CHECK(Url::removeDotSegmentsFromString("a/b/../c/../d/./e/..") == "a/d");
+    CHECK(Url::removeDotSegmentsFromString("a//b//c") == "a//b//c");
+    CHECK(Url::removeDotSegmentsFromString("a./b../..c/.d") == "a./b../..c/.d");
+
+}
+
+TEST_CASE("Produce a 'standardized' URL", "[Url]") {
+
+    CHECK(Url("http://example.com/path/oops/not/here/../../../file.txt;p?q#f").standardized().string() == "http://example.com/path/file.txt;p?q#f");
+    CHECK(Url("http://example.com/../../no/going/back/file.txt;p?q#f").standardized().string() == "http://example.com/no/going/back/file.txt;p?q#f");
+    CHECK(Url("data:text/html;charset=utf-8,LoremIpsum").standardized().string() == "data:text/html;charset=utf-8,LoremIpsum");
+
+}
+
+TEST_CASE("Maintain URL components when 'standardized'", "[URL]") {
+
+    Url url(Url("http://mapzen.com/nothing/to/see/here/../../../../index.html;p?q#f").standardized());
+
+    CHECK(!url.isEmpty());
+    CHECK(url.isAbsolute());
+    CHECK(!url.hasDataScheme());
+    CHECK(!url.hasBase64Data());
+    CHECK(!url.hasFileScheme());
+    CHECK(url.hasHttpScheme());
+    CHECK(url.hasScheme());
+    CHECK(url.scheme() == "http");
+    CHECK(url.hasNetLocation());
+    CHECK(url.netLocation() == "mapzen.com");
+    CHECK(url.hasPath());
+    CHECK(url.path() == "/index.html");
+    CHECK(url.hasParameters());
+    CHECK(url.parameters() == "p");
+    CHECK(url.hasQuery());
+    CHECK(url.query() == "q");
+    CHECK(url.hasFragment());
+    CHECK(url.fragment() == "f");
+    CHECK(!url.hasMediaType());
+    CHECK(!url.hasData());
+
+}
+
+TEST_CASE("Resolve a URL against an absolute base URL", "[Url]") {
+
+    // https://tools.ietf.org/html/rfc3986#section-5.4.1
+
+    Url base("http://a/b/c/d;p?q");
+
+    CHECK(Url("g:h").resolved(base).string() == "g:h");
+    CHECK(Url("g").resolved(base).string() == "http://a/b/c/g");
+    CHECK(Url("./g").resolved(base).string() == "http://a/b/c/g");
+    CHECK(Url("g/").resolved(base).string() == "http://a/b/c/g/");
+    CHECK(Url("/g").resolved(base).string() == "http://a/g");
+    CHECK(Url("?y").resolved(base).string() == "http://a/b/c/d;p?y");
+    CHECK(Url("g?y").resolved(base).string() == "http://a/b/c/g?y");
+    CHECK(Url("#s").resolved(base).string() == "http://a/b/c/d;p?q#s");
+    CHECK(Url("g#s").resolved(base).string() == "http://a/b/c/g#s");
+    CHECK(Url("g?y#s").resolved(base).string() == "http://a/b/c/g?y#s");
+    CHECK(Url(";x").resolved(base).string() == "http://a/b/c/d;x"); // See [1] below.
+    CHECK(Url("g;x").resolved(base).string() == "http://a/b/c/g;x");
+    CHECK(Url("g;x?y#s").resolved(base).string() == "http://a/b/c/g;x?y#s");
+    CHECK(Url("").resolved(base).string() == "http://a/b/c/d;p?q");
+
+}
+
+TEST_CASE("Resolve a URL against a relative base URL", "[Url]") {
+
+    Url base("a/b/c/d;p?q");
+
+    CHECK(Url("g:h").resolved(base).string() == "g:h");
+    CHECK(Url("g").resolved(base).string() == "a/b/c/g");
+    CHECK(Url("./g").resolved(base).string() == "a/b/c/g");
+    CHECK(Url("g/").resolved(base).string() == "a/b/c/g/");
+    CHECK(Url("/g").resolved(base).string() == "/g");
+    CHECK(Url("?y").resolved(base).string() == "a/b/c/d;p?y");
+    CHECK(Url("g?y").resolved(base).string() == "a/b/c/g?y");
+    CHECK(Url("#s").resolved(base).string() == "a/b/c/d;p?q#s");
+    CHECK(Url("g#s").resolved(base).string() == "a/b/c/g#s");
+    CHECK(Url("g?y#s").resolved(base).string() == "a/b/c/g?y#s");
+    CHECK(Url(";x").resolved(base).string() == "a/b/c/d;x"); // See [1] below.
+    CHECK(Url("g;x").resolved(base).string() == "a/b/c/g;x");
+    CHECK(Url("g;x?y#s").resolved(base).string() == "a/b/c/g;x?y#s");
+    CHECK(Url("").resolved(base).string() == "a/b/c/d;p?q");
+
+}
+
+TEST_CASE("Resolve a relative URL against an empty base URL", "[Url]") {
+
+    Url base("");
+
+    CHECK(Url("g:h").resolved(base).string() == "g:h");
+    CHECK(Url("g").resolved(base).string() == "g");
+    CHECK(Url("./g").resolved(base).string() == "g");
+    CHECK(Url("g/").resolved(base).string() == "g/");
+    CHECK(Url("/g").resolved(base).string() == "/g");
+    CHECK(Url("?y").resolved(base).string() == "?y");
+    CHECK(Url("g?y").resolved(base).string() == "g?y");
+    CHECK(Url("#s").resolved(base).string() == "#s");
+    CHECK(Url("g#s").resolved(base).string() == "g#s");
+    CHECK(Url("g?y#s").resolved(base).string() == "g?y#s");
+    CHECK(Url(";x").resolved(base).string() == ";x");
+    CHECK(Url("g;x").resolved(base).string() == "g;x");
+    CHECK(Url("g;x?y#s").resolved(base).string() == "g;x?y#s");
+    CHECK(Url("").resolved(base).string() == "");
+
+}
+
+TEST_CASE("Resolve an abnormal relative URL against an absolute base URL", "[Url]") {
+
+    // https://tools.ietf.org/html/rfc3986#section-5.4.2
+
+    Url base("http://a/b/c/d;p?q");
+
+    CHECK(Url("../../../g").resolved(base).string() == "http://a/g");
+    CHECK(Url("../../../../g").resolved(base).string() == "http://a/g");
+    CHECK(Url("/./g").resolved(base).string() == "http://a/g");
+    CHECK(Url("/../g").resolved(base).string() == "http://a/g");
+    CHECK(Url("g.").resolved(base).string() == "http://a/b/c/g.");
+    CHECK(Url(".g").resolved(base).string() == "http://a/b/c/.g");
+    CHECK(Url("g..").resolved(base).string() == "http://a/b/c/g..");
+    CHECK(Url("..g").resolved(base).string() == "http://a/b/c/..g");
+    CHECK(Url("./../g").resolved(base).string() == "http://a/b/g");
+    CHECK(Url("./g/.").resolved(base).string() == "http://a/b/c/g/");
+    CHECK(Url("g/./h").resolved(base).string() == "http://a/b/c/g/h");
+    CHECK(Url("g/../h").resolved(base).string() == "http://a/b/c/h");
+    CHECK(Url("g;x=1/./y").resolved(base).string() == "http://a/b/c/g;x=1/./y"); // See [1] below.
+    CHECK(Url("g;x=1/../y").resolved(base).string() == "http://a/b/c/g;x=1/../y"); // See [1] below.
+
+}
+
+TEST_CASE("Retrieve the file extension from a path string", "[Url]") {
+
+    CHECK(Url::getPathExtension("file.txt") == "txt");
+    CHECK(Url::getPathExtension("file.txt.gz") == "gz");
+    CHECK(Url::getPathExtension("/path/to/a/file.txt") == "txt");
+    CHECK(Url::getPathExtension("/path/to/some/other/.././file.txt") == "txt");
+    CHECK(Url::getPathExtension("/path/to/some/other/.././folder") == "");
+    CHECK(Url::getPathExtension("/path/to/a/file") == "");
+    CHECK(Url::getPathExtension("/path/to/a/.txt") == "");
+    CHECK(Url::getPathExtension("/path/to/a/file.") == "");
+
+}
+
+// [1]:
+// Some of the examples for path resolution given in RFC 3986 don't produce the same result
+// in our implementation because the interpretation of the parameters string in RFC 3986 is
+// in conflict with RFC 1808, which many URL utilities adhere to (e.g. NSURL). In RFC 1808
+// the 'path' component stops at a ';', but in RFC 3986 it goes up to a '?'.
diff --git a/tests/unit/yamlFilterTests.cpp b/tests/unit/yamlFilterTests.cpp
new file mode 100644 (file)
index 0000000..af5204c
--- /dev/null
@@ -0,0 +1,251 @@
+#include "catch.hpp"
+
+#include <iostream>
+#include <vector>
+
+#include "yaml-cpp/yaml.h"
+#include "scene/filters.h"
+#include "data/tileData.h"
+#include "scene/sceneLoader.h"
+#include "scene/scene.h"
+#include "scene/styleContext.h"
+#include "platform_mock.h"
+
+using namespace Tangram;
+using YAML::Node;
+
+using Context = StyleContext;
+
+Context ctx;
+
+Feature civic, bmw1, bike;
+
+Filter load(const std::string& filterYaml) {
+    std::shared_ptr<Platform> platform = std::make_shared<MockPlatform>();
+    Scene scene(platform);
+    YAML::Node node = YAML::Load(filterYaml);
+    auto filter = SceneLoader::generateFilter(node["filter"], scene);
+    ctx.initFunctions(scene);
+    return filter;
+}
+
+void init() {
+
+    civic.props.clear();
+    civic.props.set("name", "civic");
+    civic.props.set("brand", "honda");
+    civic.props.set("wheel",  4);
+    civic.props.set("drive", "fwd");
+    civic.props.set("type", "car");
+
+    bmw1.props.clear();
+    bmw1.props.set("name", "bmw320i");
+    bmw1.props.set("brand", "bmw");
+    bmw1.props.set("check", "false");
+    bmw1.props.set("series", "3");
+    bmw1.props.set("wheel", 4);
+    bmw1.props.set("drive", "all");
+    bmw1.props.set("type", "car");
+    bmw1.props.set("serial", 4398046511104); // 2^42
+
+    bike.props.clear();
+    bike.props.set("name", "cb1100");
+    bike.props.set("brand", "honda");
+    bike.props.set("wheel", 2);
+    bike.props.set("type", "bike");
+    bike.props.set("series", "CB");
+    bike.props.set("check", "available");
+    bike.props.set("serial", 4398046511105); // 2^42 + 1
+
+    ctx.setKeyword("$geometry", Value(1));
+    ctx.setKeyword("$zoom", Value("false"));
+}
+
+
+//1. basic predicate
+TEST_CASE( "yaml-filter-tests: basic predicate test", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: { series: !!str 3}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//2. predicate with valueList
+TEST_CASE( "yaml-filter-tests: predicate with valueList", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: { name : [civic, bmw320i] }");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//3. range min
+TEST_CASE( "yaml-filter-tests: range min", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {wheel : {min : 3}}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//4. range max
+TEST_CASE( "yaml-filter-tests: range max", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {wheel : {max : 2}}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//5. range min max
+TEST_CASE( "yaml-filter-tests: range min max", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {wheel : {min : 2, max : 5}}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+//6. any
+TEST_CASE( "yaml-filter-tests: any", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {any : [{name : civic}, {name : bmw320i}]}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//7. all
+TEST_CASE( "yaml-filter-tests: all", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {all : [ {name : civic}, {brand : honda}, {wheel: 4} ] }");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+//8. none
+TEST_CASE( "yaml-filter-tests: none", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {none : [{name : civic}, {name : bmw320i}]}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+//9. not
+TEST_CASE( "yaml-filter-tests: not", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {not : { any: [{name : civic}, {name : bmw320i}]}}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+//10. basic predicate with context
+TEST_CASE( "yaml-filter-tests: context filter", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {$geometry : 1}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: bogus filter", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {max: bogus}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: boolean true filter as existence check", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: { drive : true }");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: boolean false filter as existence check", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: { drive : false}");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: boolean true filter as existence check for keyword", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {$geometry : 1}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: boolean false filter as existence check for keyword", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: {$zoom : false}");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(filter.eval(bike, ctx));
+
+}
+
+TEST_CASE( "yaml-filter-tests: predicate with large integers", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: { serial : [4398046511104] }");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+
+}
+
+TEST_CASE("Filters specified as a javascript function evaluate correctly", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: 'function() { return false; }'");
+
+    REQUIRE(!filter.eval(civic, ctx));
+    REQUIRE(!filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+}
+
+TEST_CASE("Sequences in filters implicitly create an 'any' filter", "[filters][core][yaml]") {
+    init();
+    Filter filter = load("filter: [ { brand: 'bmw' }, { type: 'car' } ]");
+
+    REQUIRE(filter.eval(civic, ctx));
+    REQUIRE(filter.eval(bmw1, ctx));
+    REQUIRE(!filter.eval(bike, ctx));
+}
diff --git a/toolchains/android.cmake b/toolchains/android.cmake
new file mode 100644 (file)
index 0000000..cb2ba37
--- /dev/null
@@ -0,0 +1,24 @@
+add_definitions(-DPLATFORM_ANDROID)
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+set(ANDROID_PROJECT_DIR ${PROJECT_SOURCE_DIR}/platforms/android/tangram)
+
+set(LIB_NAME tangram) # in order to have libtangram.so
+
+add_library(${LIB_NAME} SHARED
+  ${CMAKE_SOURCE_DIR}/platforms/common/platform_gl.cpp
+  ${CMAKE_SOURCE_DIR}/platforms/android/tangram/src/main/cpp/jniExports.cpp
+  ${CMAKE_SOURCE_DIR}/platforms/android/tangram/src/main/cpp/platform_android.cpp
+  ${CMAKE_SOURCE_DIR}/platforms/android/tangram/src/main/cpp/sqlite3ndk.cpp)
+
+target_include_directories(${LIB_NAME} PUBLIC
+  ${CMAKE_SOURCE_DIR}/core/deps/SQLiteCpp/sqlite3) # sqlite3ndk.cpp needs sqlite3.h
+
+target_link_libraries(${LIB_NAME}
+  PUBLIC
+  ${CORE_LIBRARY}
+  # android libaries
+  GLESv2 log z atomic android)
+
diff --git a/toolchains/darwin.cmake b/toolchains/darwin.cmake
new file mode 100644 (file)
index 0000000..28951bd
--- /dev/null
@@ -0,0 +1,69 @@
+# set for test in other cmake files
+set(PLATFORM_OSX ON)
+
+check_unsupported_compiler_version()
+
+# options
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++ -std=c++1y")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wreturn-type -Wsign-compare -Wignored-qualifiers -Wtype-limits -Wmissing-field-initializers")
+set(CXX_FLAGS_DEBUG "-g -O0")
+
+# compile definitions (adds -DPLATFORM_OSX)
+set(CORE_COMPILE_DEFS PLATFORM_OSX)
+
+# Build core library with dependencies.
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+if(APPLICATION)
+
+  set(EXECUTABLE_NAME "tangram")
+
+  get_mapzen_api_key(MAPZEN_API_KEY)
+  add_definitions(-DMAPZEN_API_KEY="${MAPZEN_API_KEY}")
+
+  find_package(OpenGL REQUIRED)
+
+  # Build GLFW.
+  if (USE_SYSTEM_GLFW_LIBS)
+    include(FindPkgConfig)
+    pkg_check_modules(GLFW REQUIRED glfw3)
+  else()
+    # configure GLFW to build only the library
+    set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "Build the GLFW example programs")
+    set(GLFW_BUILD_TESTS OFF CACHE BOOL "Build the GLFW test programs")
+    set(GLFW_BUILD_DOCS OFF CACHE BOOL "Build the GLFW documentation")
+    set(GLFW_INSTALL OFF CACHE BOOL "Generate installation target")
+    add_subdirectory(${PROJECT_SOURCE_DIR}/platforms/common/glfw)
+  endif()
+
+  # add sources and include headers
+  set(OSX_EXTENSIONS_FILES *.mm *.cpp)
+  foreach(_ext ${OSX_EXTENSIONS_FILES})
+    find_sources_and_include_directories(
+      ${PROJECT_SOURCE_DIR}/platforms/osx/src/*.h
+      ${PROJECT_SOURCE_DIR}/platforms/osx/src/${_ext})
+  endforeach()
+
+  add_bundle_resources(RESOURCES "${PROJECT_SOURCE_DIR}/scenes" "Resources")
+
+  set(SOURCES ${SOURCES} ${PROJECT_SOURCE_DIR}/platforms/common/platform_gl.cpp ${PROJECT_SOURCE_DIR}/platforms/common/glfwApp.cpp)
+
+  add_executable(${EXECUTABLE_NAME} MACOSX_BUNDLE ${SOURCES} ${RESOURCES} ${OSX_RESOURCES})
+
+  target_include_directories(${EXECUTABLE_NAME}
+    PUBLIC
+    ${GLFW_SOURCE_DIR}/include
+    ${PROJECT_SOURCE_DIR}/platforms/common)
+
+  target_link_libraries(${EXECUTABLE_NAME}
+    ${CORE_LIBRARY}
+    glfw
+    ${GLFW_LIBRARIES}
+    ${OPENGL_LIBRARIES})
+
+  # add resource files and property list
+  set_target_properties(${EXECUTABLE_NAME} PROPERTIES
+    MACOSX_BUNDLE_INFO_PLIST "${PROJECT_SOURCE_DIR}/platforms/osx/Info.plist"
+    RESOURCE "${OSX_RESOURCES}")
+
+endif()
diff --git a/toolchains/iOS.cmake b/toolchains/iOS.cmake
new file mode 100644 (file)
index 0000000..45a318a
--- /dev/null
@@ -0,0 +1,58 @@
+include(${CMAKE_SOURCE_DIR}/toolchains/iOS.toolchain.cmake)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
+set(ARCH "armv7 armv7s arm64 i386 x86_64")
+set(SUPPORTED_PLATFORMS "iphonesimulator iphoneos")
+set(TANGRAM_FRAMEWORK ${PROJECT_SOURCE_DIR}/${TANGRAM_FRAMEWORK})
+set(EXECUTABLE_NAME "tangram")
+set(FRAMEWORKS CoreGraphics CoreFoundation QuartzCore UIKit OpenGLES Security CFNetwork GLKit)
+
+message(STATUS "Linking with Tangram Framework " ${TANGRAM_FRAMEWORK})
+message(STATUS "Building for architectures " ${ARCH})
+
+# ios source files
+set(IOS_EXTENSIONS_FILES *.mm *.cpp *.m)
+foreach(_ext ${IOS_EXTENSIONS_FILES})
+    find_sources_and_include_directories(
+        ${PROJECT_SOURCE_DIR}/platforms/ios/demo/src/*.h
+        ${PROJECT_SOURCE_DIR}/platforms/ios/demo/src/${_ext})
+endforeach()
+
+get_mapzen_api_key(MAPZEN_API_KEY)
+add_definitions(-DMAPZEN_API_KEY="${MAPZEN_API_KEY}")
+
+# Generate demo app configuration plist file to inject API key
+configure_file(${PROJECT_SOURCE_DIR}/platforms/ios/demo/Config.plist.in
+    ${PROJECT_SOURCE_DIR}/platforms/ios/demo/resources/Config.plist)
+
+add_bundle_resources(IOS_DEMO_RESOURCES "${PROJECT_SOURCE_DIR}/platforms/ios/demo/resources/" "Resources")
+file(GLOB_RECURSE IOS_DEMO_SOURCES ${PROJECT_SOURCE_DIR}/platforms/ios/demo/src/**)
+
+add_executable(${EXECUTABLE_NAME} MACOSX_BUNDLE ${HEADERS} ${SOURCES}
+    ${RESOURCES} ${IOS_DEMO_RESOURCES} ${TANGRAM_FRAMEWORK})
+
+target_link_libraries(${EXECUTABLE_NAME} ${TANGRAM_FRAMEWORK})
+
+# setting xcode properties
+set_target_properties(${EXECUTABLE_NAME} PROPERTIES
+    MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/platforms/ios/demo/Info.plist
+    MACOSX_FRAMEWORK_IDENTIFIER "com.mapzen.\${PRODUCT_NAME:{EXECUTABLE_NAME}}"
+    RESOURCE "${IOS_DEMO_RESOURCES}")
+
+set_source_files_properties(${TANGRAM_FRAMEWORK} PROPERTIES
+    MACOSX_PACKAGE_LOCATION ${EXECUTABLE_NAME}.app/Frameworks)
+
+if(NOT ${CMAKE_BUILD_TYPE} STREQUAL "Release")
+    set_xcode_property(${EXECUTABLE_NAME} GCC_GENERATE_DEBUGGING_SYMBOLS YES)
+endif()
+
+set_xcode_property(${EXECUTABLE_NAME} CODE_SIGN_IDENTITY "iPhone Developer")
+set_xcode_property(${EXECUTABLE_NAME} SUPPORTED_PLATFORMS ${SUPPORTED_PLATFORMS})
+set_xcode_property(${EXECUTABLE_NAME} ONLY_ACTIVE_ARCH "YES")
+set_xcode_property(${EXECUTABLE_NAME} VALID_ARCHS "${ARCH}")
+set_xcode_property(${EXECUTABLE_NAME} TARGETED_DEVICE_FAMILY "1,2")
+set_xcode_property(${EXECUTABLE_NAME} LD_RUNPATH_SEARCH_PATHS "@executable_path/Frameworks")
+
+foreach(_framework ${FRAMEWORKS})
+    add_framework(${_framework} ${EXECUTABLE_NAME} ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+endforeach()
diff --git a/toolchains/iOS.framework.cmake b/toolchains/iOS.framework.cmake
new file mode 100644 (file)
index 0000000..4caa241
--- /dev/null
@@ -0,0 +1,144 @@
+include(${CMAKE_SOURCE_DIR}/toolchains/iOS.toolchain.cmake)
+
+set(FRAMEWORK_VERSION "0.7.0")
+
+message(STATUS "Build for iOS archs " ${IOS_ARCH})
+
+set(FRAMEWORK_NAME TangramMap)
+
+add_definitions(-DPLATFORM_IOS)
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}
+    -fobjc-abi-version=2
+    -fobjc-arc
+    -std=c++14
+    -stdlib=libc++
+    -w
+    -isysroot ${CMAKE_IOS_SDK_ROOT}")
+
+set(CMAKE_CXX_FLAGS_DEBUG "-g -O0")
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS}
+    -fobjc-abi-version=2
+    -fobjc-arc
+    -w
+    -isysroot ${CMAKE_IOS_SDK_ROOT}")
+
+if(${IOS_PLATFORM} STREQUAL "SIMULATOR")
+    set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mios-simulator-version-min=6.0")
+else()
+    if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
+        set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fembed-bitcode")
+        add_compile_options("-fembed-bitcode")
+    endif()
+endif()
+
+set(FRAMEWORKS CoreGraphics CoreFoundation QuartzCore UIKit OpenGLES Security CFNetwork GLKit)
+
+# Tell SQLiteCpp to not build its own copy of SQLite, we will use the system library instead.
+set(SQLITECPP_INTERNAL_SQLITE OFF CACHE BOOL "")
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+set(SOURCES
+    ${PROJECT_SOURCE_DIR}/platforms/common/platform_gl.cpp
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/platform_ios.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGHelpers.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGFontConverter.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGGeoPolyline.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGGeoPolygon.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGHttpHandler.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapData.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGSceneUpdate.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGLabelPickResult.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarkerPickResult.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarker.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGTypes.mm
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapViewController.mm)
+
+set(FRAMEWORK_HEADERS
+    ${PROJECT_SOURCE_DIR}/platforms/ios/framework/TangramMap.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGGeoPolyline.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGGeoPolygon.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGGeoPoint.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarker.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGSceneUpdate.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapData.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGTypes.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGHttpHandler.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGLabelPickResult.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarkerPickResult.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapViewController.h)
+
+set(HEADERS
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/platform_ios.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarkerPickResult+Internal.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGLabelPickResult+Internal.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapViewController+Internal.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMapData+Internal.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGMarker+Internal.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGHelpers.h
+    ${PROJECT_SOURCE_DIR}/platforms/ios/src/TangramMap/TGFontConverter.h
+    ${FRAMEWORK_HEADERS})
+
+# add_bundle_resources(RESOURCES "${PROJECT_SOURCE_DIR}/scenes/fonts" "./fonts")
+add_bundle_resources(RESOURCES "${PROJECT_SOURCE_DIR}/platforms/ios/framework/Modules" "./Modules")
+
+add_library(${FRAMEWORK_NAME} SHARED ${SOURCES} ${HEADERS} ${RESOURCES})
+target_link_libraries(${FRAMEWORK_NAME} ${CORE_LIBRARY})
+
+# Link with SQLite, needed for MBTiles access.
+target_link_libraries(${FRAMEWORK_NAME} sqlite3)
+
+set(IOS_FRAMEWORK_RESOURCES ${PROJECT_SOURCE_DIR}/platforms/ios/framework/Info.plist)
+
+set_target_properties(${FRAMEWORK_NAME} PROPERTIES
+    CLEAN_DIRECT_OUTPUT 1
+    FRAMEWORK TRUE
+    MACOSX_FRAMEWORK_IDENTIFIER com.mapzen.tangramMap
+    MACOSX_FRAMEWORK_INFO_PLIST ${IOS_FRAMEWORK_RESOURCES}
+    PUBLIC_HEADER "${FRAMEWORK_HEADERS}"
+    RESOURCE "${IOS_FRAMEWORK_RESOURCES}"
+    )
+
+set_xcode_property(${FRAMEWORK_NAME} CODE_SIGN_IDENTITY "")
+set_xcode_property(${FRAMEWORK_NAME} CODE_SIGNING_REQUIRED "NO")
+set_xcode_property(${FRAMEWORK_NAME} CODE_SIGN_ENTITLEMENTS "")
+set_xcode_property(${FRAMEWORK_NAME} CODE_SIGNING_ALLOWED "NO")
+
+if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
+    set_xcode_property(${FRAMEWORK_NAME} GCC_GENERATE_DEBUGGING_SYMBOLS NO)
+    set_xcode_property(${FRAMEWORK_NAME} DEPLOYMENT_POSTPROCESSING YES)
+    set_xcode_property(${FRAMEWORK_NAME} COPY_PHASE_STRIP NO)
+    set_xcode_property(${FRAMEWORK_NAME} STRIP_INSTALLED_PRODUCT YES)
+    set_xcode_property(${FRAMEWORK_NAME} STRIP_STYLE non-global)
+    set_xcode_property(${FRAMEWORK_NAME} SEPARATE_STRIP YES)
+    set_xcode_property(${FRAMEWORK_NAME} DEAD_CODE_STRIPPING YES)
+else()
+    set_xcode_property(${FRAMEWORK_NAME} GCC_GENERATE_DEBUGGING_SYMBOLS YES)
+endif()
+
+if(${IOS_PLATFORM} STREQUAL "SIMULATOR")
+    # properties for simulator architectures
+else()
+    if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
+        set_xcode_property(${FRAMEWORK_NAME} ENABLE_BITCODE "YES")
+        set_xcode_property(${FRAMEWORK_NAME} BITCODE_GENERATION_MODE bitcode)
+    endif()
+endif()
+
+set_xcode_property(${FRAMEWORK_NAME} SUPPORTED_PLATFORMS "iphonesimulator iphoneos")
+set_xcode_property(${FRAMEWORK_NAME} ONLY_ACTIVE_ARCH "NO")
+set_xcode_property(${FRAMEWORK_NAME} VALID_ARCHS "${IOS_ARCH}")
+set_xcode_property(${FRAMEWORK_NAME} ARCHS "${IOS_ARCH}")
+set_xcode_property(${FRAMEWORK_NAME} DEFINES_MODULE "YES")
+set_xcode_property(${FRAMEWORK_NAME} CURRENT_PROJECT_VERSION "${FRAMEWORK_VERSION}")
+
+# Set RPATH to be within the application /Frameworks directory
+set_xcode_property(${FRAMEWORK_NAME} LD_DYLIB_INSTALL_NAME "@rpath/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}")
+
+foreach(_framework ${FRAMEWORKS})
+    add_framework(${_framework} ${FRAMEWORK_NAME} ${CMAKE_SYSTEM_FRAMEWORK_PATH})
+endforeach()
+
diff --git a/toolchains/iOS.toolchain.cmake b/toolchains/iOS.toolchain.cmake
new file mode 100644 (file)
index 0000000..11a60fe
--- /dev/null
@@ -0,0 +1,193 @@
+# This file is based off of the Platform/Darwin.cmake and Platform/UnixPaths.cmake
+# files which are included with CMake 2.8.4
+# It has been altered for iOS development
+
+# Options:
+#
+# IOS_PLATFORM = OS (default) or SIMULATOR
+#   This decides if SDKS will be selected from the iPhoneOS.platform or iPhoneSimulator.platform folders
+#   OS - the default, used to build for iPhone and iPad physical devices, which have an arm arch.
+#   SIMULATOR - used to build for the Simulator platforms, which have an x86 arch.
+#
+# CMAKE_IOS_DEVELOPER_ROOT = automatic(default) or /path/to/platform/Developer folder
+#   By default this location is automatcially chosen based on the IOS_PLATFORM value above.
+#   If set manually, it will override the default location and force the user of a particular Developer Platform
+#
+# CMAKE_IOS_SDK_ROOT = automatic(default) or /path/to/platform/Developer/SDKs/SDK folder
+#   By default this location is automatcially chosen based on the CMAKE_IOS_DEVELOPER_ROOT value.
+#   In this case it will always be the most up-to-date SDK found in the CMAKE_IOS_DEVELOPER_ROOT path.
+#   If set manually, this will force the use of a specific SDK version
+
+# Macros:
+#
+# set_xcode_property (TARGET XCODE_PROPERTY XCODE_VALUE)
+#  A convenience macro for setting xcode specific properties on targets
+#  example: set_xcode_property (myioslib IPHONEOS_DEPLOYMENT_TARGET "3.1")
+#
+# find_host_package (PROGRAM ARGS)
+#  A macro used to find executable programs on the host system, not within the iOS environment.
+#  Thanks to the android-cmake project for providing the command
+
+# Standard settings
+cmake_minimum_required(VERSION 3.0)
+set (CMAKE_SYSTEM_NAME Darwin)
+set (CMAKE_SYSTEM_VERSION 1)
+set (UNIX True)
+set (APPLE True)
+set (IOS True)
+
+# Required as of cmake 2.8.10
+set (CMAKE_OSX_DEPLOYMENT_TARGET "" CACHE STRING "Force unset of the deployment target for iOS" FORCE)
+
+# Determine the cmake host system version so we know where to find the iOS SDKs
+find_program (CMAKE_UNAME uname /bin /usr/bin /usr/local/bin)
+if (CMAKE_UNAME)
+       exec_program(uname ARGS -r OUTPUT_VARIABLE CMAKE_HOST_SYSTEM_VERSION)
+       string (REGEX REPLACE "^([0-9]+)\\.([0-9]+).*$" "\\1" DARWIN_MAJOR_VERSION "${CMAKE_HOST_SYSTEM_VERSION}")
+endif (CMAKE_UNAME)
+
+# Force the compilers to gcc for iOS
+include (CMakeForceCompiler)
+set(CMAKE_AR ar CACHE FILEPATH "" FORCE)
+
+# Skip the platform compiler checks for cross compiling
+set (CMAKE_CXX_COMPILER_WORKS TRUE)
+set (CMAKE_C_COMPILER_WORKS TRUE)
+
+# All iOS/Darwin specific settings - some may be redundant
+set (CMAKE_SHARED_LIBRARY_PREFIX "lib")
+set (CMAKE_SHARED_LIBRARY_SUFFIX ".dylib")
+set (CMAKE_SHARED_MODULE_PREFIX "lib")
+set (CMAKE_SHARED_MODULE_SUFFIX ".so")
+set (CMAKE_MODULE_EXISTS 1)
+set (CMAKE_DL_LIBS "")
+
+set (CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG "-compatibility_version ")
+set (CMAKE_C_OSX_CURRENT_VERSION_FLAG "-current_version ")
+set (CMAKE_CXX_OSX_COMPATIBILITY_VERSION_FLAG "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}")
+set (CMAKE_CXX_OSX_CURRENT_VERSION_FLAG "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}")
+
+# Hidden visibilty is required for cxx on iOS
+set (CMAKE_C_FLAGS_INIT "")
+
+if (NOT BUILD_IOS_FRAMEWORK)
+    set (CMAKE_CXX_FLAGS_INIT "-fvisibility=hidden -fvisibility-inlines-hidden -isysroot ${CMAKE_OSX_SYSROOT}")
+endif ()
+
+set (CMAKE_C_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_C_LINK_FLAGS}")
+set (CMAKE_CXX_LINK_FLAGS "-Wl,-search_paths_first ${CMAKE_CXX_LINK_FLAGS}")
+
+set (CMAKE_PLATFORM_HAS_INSTALLNAME 1)
+set (CMAKE_SHARED_LIBRARY_CREATE_C_FLAGS "-dynamiclib -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_CREATE_C_FLAGS "-bundle -headerpad_max_install_names")
+set (CMAKE_SHARED_MODULE_LOADER_C_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_SHARED_MODULE_LOADER_CXX_FLAG "-Wl,-bundle_loader,")
+set (CMAKE_FIND_LIBRARY_SUFFIXES ".dylib" ".so" ".a")
+
+# hack: if a new cmake (which uses CMAKE_INSTALL_NAME_TOOL) runs on an old build tree
+# (where install_name_tool was hardcoded) and where CMAKE_INSTALL_NAME_TOOL isn't in the cache
+# and still cmake didn't fail in CMakeFindBinUtils.cmake (because it isn't rerun)
+# hardcode CMAKE_INSTALL_NAME_TOOL here to install_name_tool, so it behaves as it did before, Alex
+if (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+       find_program(CMAKE_INSTALL_NAME_TOOL install_name_tool)
+endif (NOT DEFINED CMAKE_INSTALL_NAME_TOOL)
+
+# Setup iOS platform unless specified manually with IOS_PLATFORM
+if (NOT DEFINED IOS_PLATFORM)
+       set (IOS_PLATFORM "OS")
+endif (NOT DEFINED IOS_PLATFORM)
+set (IOS_PLATFORM ${IOS_PLATFORM} CACHE STRING "Type of iOS Platform")
+
+# Check the platform selection and setup for developer root
+if (${IOS_PLATFORM} STREQUAL "OS")
+       set (IOS_PLATFORM_LOCATION "iPhoneOS.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphoneos")
+elseif (${IOS_PLATFORM} STREQUAL "SIMULATOR")
+       set (IOS_PLATFORM_LOCATION "iPhoneSimulator.platform")
+
+       # This causes the installers to properly locate the output libraries
+       set (CMAKE_XCODE_EFFECTIVE_PLATFORMS "-iphonesimulator")
+else (${IOS_PLATFORM} STREQUAL "OS")
+       message (FATAL_ERROR "Unsupported IOS_PLATFORM value selected. Please choose OS or SIMULATOR")
+endif (${IOS_PLATFORM} STREQUAL "OS")
+
+# Setup iOS developer location unless specified manually with CMAKE_IOS_DEVELOPER_ROOT
+if (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+    if (${IOS_PLATFORM} STREQUAL "SIMULATOR")
+        execute_process(COMMAND xcrun --sdk iphonesimulator --show-sdk-platform-path OUTPUT_VARIABLE XCRUN_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
+    else()
+        execute_process(COMMAND xcrun --sdk iphoneos --show-sdk-platform-path OUTPUT_VARIABLE XCRUN_OUTPUT OUTPUT_STRIP_TRAILING_WHITESPACE)
+    endif()
+       if (DEFINED XCRUN_OUTPUT)
+               set (CMAKE_IOS_DEVELOPER_ROOT "${XCRUN_OUTPUT}/Developer")
+       endif (DEFINED XCRUN_OUTPUT)
+endif (NOT DEFINED CMAKE_IOS_DEVELOPER_ROOT)
+set (CMAKE_IOS_DEVELOPER_ROOT ${CMAKE_IOS_DEVELOPER_ROOT} CACHE PATH "Location of iOS Platform")
+
+# Find and use the most recent iOS sdk unless specified manually with CMAKE_IOS_SDK_ROOT
+if (NOT DEFINED CMAKE_IOS_SDK_ROOT)
+       file (GLOB _CMAKE_IOS_SDKS "${CMAKE_IOS_DEVELOPER_ROOT}/SDKs/*")
+       if (_CMAKE_IOS_SDKS)
+               list (SORT _CMAKE_IOS_SDKS)
+               list (REVERSE _CMAKE_IOS_SDKS)
+               list (GET _CMAKE_IOS_SDKS 0 CMAKE_IOS_SDK_ROOT)
+       else (_CMAKE_IOS_SDKS)
+               message (FATAL_ERROR "No iOS SDK's found in default search path ${CMAKE_IOS_DEVELOPER_ROOT}. Manually set CMAKE_IOS_SDK_ROOT or install the iOS SDK.")
+       endif (_CMAKE_IOS_SDKS)
+       message (STATUS "Toolchain using default iOS SDK: ${CMAKE_IOS_SDK_ROOT}")
+endif (NOT DEFINED CMAKE_IOS_SDK_ROOT)
+set (CMAKE_IOS_SDK_ROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Location of the selected iOS SDK")
+
+# Set the sysroot default to the most recent SDK
+set (CMAKE_OSX_SYSROOT ${CMAKE_IOS_SDK_ROOT} CACHE PATH "Sysroot used for iOS support")
+
+# set the architecture for iOS
+# NOTE: Currently both ARCHS_STANDARD_32_BIT and ARCHS_UNIVERSAL_IPHONE_OS set armv7 only, so set both manually
+if (${IOS_PLATFORM} STREQUAL "OS")
+    set (IOS_ARCH ${IOS_DEVICE_ARCHS})
+else (${IOS_PLATFORM} STREQUAL "OS")
+    set (IOS_ARCH ${IOS_SIMULATOR_ARCHS})
+endif (${IOS_PLATFORM} STREQUAL "OS")
+
+set (CMAKE_OSX_ARCHITECTURES ${IOS_ARCH} CACHE string  "Build architecture for iOS")
+
+# Set the find root to the iOS developer roots and to user defined paths
+set (CMAKE_FIND_ROOT_PATH ${CMAKE_IOS_DEVELOPER_ROOT} ${CMAKE_IOS_SDK_ROOT} ${CMAKE_PREFIX_PATH} CACHE string  "iOS find search path root")
+
+# default to searching for frameworks first
+set (CMAKE_FIND_FRAMEWORK FIRST)
+
+# set up the default search directories for frameworks
+set (CMAKE_SYSTEM_FRAMEWORK_PATH
+       ${CMAKE_IOS_SDK_ROOT}/System/Library/Frameworks
+       ${CMAKE_IOS_SDK_ROOT}/System/Library/PrivateFrameworks
+       ${CMAKE_IOS_SDK_ROOT}/Developer/Library/Frameworks
+)
+
+# only search the iOS sdks, not the remainder of the host filesystem
+set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+
+# This little macro lets you set any XCode specific property
+macro (set_xcode_property TARGET XCODE_PROPERTY XCODE_VALUE)
+       set_property (TARGET ${TARGET} PROPERTY XCODE_ATTRIBUTE_${XCODE_PROPERTY} ${XCODE_VALUE})
+endmacro (set_xcode_property)
+
+
+# This macro lets you find executable programs on the host system
+macro (find_host_package)
+       set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+       set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY NEVER)
+       set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE NEVER)
+       set (IOS FALSE)
+
+       find_package(${ARGN})
+
+       set (IOS TRUE)
+       set (CMAKE_FIND_ROOT_PATH_MODE_PROGRAM ONLY)
+       set (CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+       set (CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
+endmacro (find_host_package)
diff --git a/toolchains/linux.cmake b/toolchains/linux.cmake
new file mode 100644 (file)
index 0000000..3022c99
--- /dev/null
@@ -0,0 +1,87 @@
+# set for test in other cmake files
+set(PLATFORM_LINUX ON)
+
+# global compile options
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++1y")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Wignored-qualifiers -Wtype-limits -Wmissing-field-initializers")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS}  -lc++ -lc++abi")
+endif()
+
+if (CMAKE_COMPILER_IS_GNUCC)
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
+    OUTPUT_VARIABLE GCC_VERSION)
+  string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
+  list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
+  list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
+
+  message(STATUS "Using gcc ${GCC_VERSION}")
+  if (GCC_VERSION VERSION_GREATER 5.1)
+    message(STATUS "USE CXX11_ABI")
+    add_definitions("-D_GLIBCXX_USE_CXX11_ABI=1")
+  endif()
+endif()
+
+check_unsupported_compiler_version()
+
+# compile definitions (adds -DPLATFORM_LINUX)
+set(CORE_COMPILE_DEFS PLATFORM_LINUX)
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+if(APPLICATION)
+
+  set(EXECUTABLE_NAME "tangram")
+
+  get_mapzen_api_key(MAPZEN_API_KEY)
+  add_definitions(-DMAPZEN_API_KEY="${MAPZEN_API_KEY}")
+
+  find_package(OpenGL REQUIRED)
+
+  # Build GLFW.
+  if (USE_SYSTEM_GLFW_LIBS)
+    include(FindPkgConfig)
+    pkg_check_modules(GLFW REQUIRED glfw3)
+  else()
+    # configure GLFW to build only the library
+    set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "Build the GLFW example programs")
+    set(GLFW_BUILD_TESTS OFF CACHE BOOL "Build the GLFW test programs")
+    set(GLFW_BUILD_DOCS OFF CACHE BOOL "Build the GLFW documentation")
+    set(GLFW_INSTALL OFF CACHE BOOL "Generate installation target")
+    add_subdirectory(${PROJECT_SOURCE_DIR}/platforms/common/glfw)
+  endif()
+
+  # add sources and include headers
+  find_sources_and_include_directories(
+    ${PROJECT_SOURCE_DIR}/platforms/linux/src/*.h
+    ${PROJECT_SOURCE_DIR}/platforms/linux/src/*.cpp)
+
+  add_executable(${EXECUTABLE_NAME}
+    ${SOURCES}
+    ${PROJECT_SOURCE_DIR}/platforms/common/platform_gl.cpp
+    ${PROJECT_SOURCE_DIR}/platforms/common/urlClient.cpp
+    ${PROJECT_SOURCE_DIR}/platforms/common/glfwApp.cpp
+    )
+
+  target_include_directories(${EXECUTABLE_NAME}
+    PUBLIC
+    ${GLFW_SOURCE_DIR}/include
+    ${PROJECT_SOURCE_DIR}/platforms/common)
+
+  target_link_libraries(${EXECUTABLE_NAME}
+    ${CORE_LIBRARY}
+    -lcurl glfw
+    # only used when not using external lib
+    -ldl
+    -pthread
+    ${GLFW_LIBRARIES}
+    ${OPENGL_LIBRARIES})
+
+  add_resources(${EXECUTABLE_NAME} "${PROJECT_SOURCE_DIR}/scenes")
+
+endif()
diff --git a/toolchains/raspberrypi.cmake b/toolchains/raspberrypi.cmake
new file mode 100644 (file)
index 0000000..80973da
--- /dev/null
@@ -0,0 +1,44 @@
+# options
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -fpermissive -g")
+set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_CXX_FLAGS} -L/opt/vc/lib/ -lGLESv2 -lEGL -lbcm_host -lvchiq_arm -lvcos -lrt -lpthread")
+set(CXX_FLAGS_DEBUG "-g -O0")
+set(EXECUTABLE_NAME "tangram")
+
+add_definitions(-DPLATFORM_RPI)
+
+check_unsupported_compiler_version()
+
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14")
+
+get_mapzen_api_key(MAPZEN_API_KEY)
+add_definitions(-DMAPZEN_API_KEY="${MAPZEN_API_KEY}")
+
+# add sources and include headers
+find_sources_and_include_directories(
+  ${PROJECT_SOURCE_DIR}/platforms/rpi/src/*.h
+  ${PROJECT_SOURCE_DIR}/platforms/rpi/src/*.cpp)
+
+set(COMMON_SOURCES
+    ${PROJECT_SOURCE_DIR}/platforms/common/urlClient.cpp
+    ${PROJECT_SOURCE_DIR}/platforms/common/platform_gl.cpp)
+include_directories(${PROJECT_SOURCE_DIR}/platforms/common)
+
+# add linux dependencies
+set(LINUX_SOURCES
+    ${PROJECT_SOURCE_DIR}/platforms/linux/src/platform_linux.cpp)
+include_directories(${PROJECT_SOURCE_DIR}/platforms/linux/src)
+
+# include headers for rpi-installed libraries
+include_directories(/opt/vc/include/)
+include_directories(/opt/vc/include/interface/vcos/pthreads)
+include_directories(/opt/vc/include/interface/vmcs_host/linux)
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+add_executable(${EXECUTABLE_NAME} ${SOURCES} ${COMMON_SOURCES} ${LINUX_SOURCES})
+
+target_link_libraries(${EXECUTABLE_NAME}
+  ${CORE_LIBRARY} -lcurl)
+
+add_resources(${EXECUTABLE_NAME} "${PROJECT_SOURCE_DIR}/scenes")
diff --git a/toolchains/tizen-lib.cmake b/toolchains/tizen-lib.cmake
new file mode 100644 (file)
index 0000000..007d0c9
--- /dev/null
@@ -0,0 +1,88 @@
+
+# set for test in other cmake files
+set(PLATFORM_TIZEN ON)
+
+# use freetype2/icu/harfbuzz system libs for alfons
+set(USE_SYSTEM_FONT_LIBS ON)
+
+# Tell SQLiteCpp to not build its own copy of SQLite, we will use the system library instead.
+set(SQLITECPP_INTERNAL_SQLITE OFF)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIC")
+
+# global compile options
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y -fPIC")
+#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+endif()
+
+if (CMAKE_COMPILER_IS_GNUCC)
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
+    OUTPUT_VARIABLE GCC_VERSION)
+  string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
+  list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
+  list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
+
+  message(STATUS "Using gcc ${GCC_VERSION}")
+  if (GCC_VERSION VERSION_GREATER 5.1)
+    message(STATUS "USE CXX11_ABI")
+    add_definitions("-D_GLIBCXX_USE_CXX11_ABI=1")
+  endif()
+endif()
+
+check_unsupported_compiler_version()
+
+# compile definitions (adds -DPLATFORM_LINUX)
+set(CORE_COMPILE_DEFS PLATFORM_TIZEN PLATFORM_LINUX)
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+set(LIB_NAME tangram) # in order to have libtangram.so
+
+add_library(${LIB_NAME} SHARED
+  ${PROJECT_SOURCE_DIR}/platforms/tizen/src/platform_tizen.cpp
+  ${PROJECT_SOURCE_DIR}/platforms/tizen/src/tizen_gl.cpp
+  ${PROJECT_SOURCE_DIR}/platforms/common/urlClient.cpp)
+
+include(FindPkgConfig)
+pkg_check_modules(EVAS REQUIRED "evas")
+pkg_check_modules(DLOG REQUIRED "dlog")
+pkg_check_modules(FONTCONFIG REQUIRED "fontconfig")
+pkg_check_modules(SQLITE REQUIRED "sqlite3")
+
+# link to the core library, forcing all symbols to be added
+# (whole-archive must be turned off after core so that lc++ symbols aren't duplicated)
+target_link_libraries(${LIB_NAME}
+  PUBLIC
+  "-Wl,-whole-archive"
+  ${CORE_LIBRARY}
+  "-Wl,-no-whole-archive"
+  PRIVATE
+  ${EVAS_LDFLAGS}
+  ${DLOG_LDFLAGS}
+  ${SQLITE_LDFLAGS}
+  ${FONTCONFIG_LDFLAGS})
+
+target_include_directories(${LIB_NAME}
+  PRIVATE
+  ${PROJECT_SOURCE_DIR}/platforms/common
+  ${EVAS_INCLUDE_DIRS}
+  ${DLOG_INCLUDE_DIRS}
+  ${SQLITE_INCLUDE_DIRS}
+  ${FONTCONFIG_INCLUDE_DIRS})
+
+target_compile_options(${LIB_NAME}
+  PUBLIC
+  -fPIC
+  -Wl,-z,defs)
+
+
+if (${ARCH} MATCHES "x86_64" OR ${ARCH} MATCHES "aarch64")
+install(TARGETS ${LIB_NAME} DESTINATION lib64)
+else ()
+install(TARGETS ${LIB_NAME} DESTINATION lib)
+endif()
diff --git a/toolchains/tizen.cmake b/toolchains/tizen.cmake
new file mode 100644 (file)
index 0000000..497d06b
--- /dev/null
@@ -0,0 +1,72 @@
+if(NOT TIZEN_SDK)
+    message(SEND_ERROR "Set tizen sdk path: $TIZEN_SDK or -DTIZEN_SDK")
+    return()
+endif()
+
+# set for test in other cmake files
+set(PLATFORM_TIZEN ON)
+
+# Tell SQLiteCpp to not build its own copy of SQLite, we will use the system library instead.
+set(SQLITECPP_INTERNAL_SQLITE OFF)
+
+set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Wall -fPIC")
+
+# global compile options
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -std=c++1y -fPIC")
+set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-omit-frame-pointer")
+
+if (NOT ${TIZEN_DEVICE})
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -march=i486")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -march=i486")
+endif()
+
+if (CMAKE_CXX_COMPILER_ID MATCHES "Clang")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-gnu-zero-variadic-macro-arguments")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -stdlib=libc++")
+endif()
+
+if (CMAKE_COMPILER_IS_GNUCC)
+  execute_process(COMMAND ${CMAKE_CXX_COMPILER} -dumpversion
+    OUTPUT_VARIABLE GCC_VERSION)
+  string(REGEX MATCHALL "[0-9]+" GCC_VERSION_COMPONENTS ${GCC_VERSION})
+  list(GET GCC_VERSION_COMPONENTS 0 GCC_MAJOR)
+  list(GET GCC_VERSION_COMPONENTS 1 GCC_MINOR)
+
+  message(STATUS "Using gcc ${GCC_VERSION}")
+  if (GCC_VERSION VERSION_GREATER 5.1)
+    message(STATUS "USE CXX11_ABI")
+    add_definitions("-D_GLIBCXX_USE_CXX11_ABI=1")
+  endif()
+endif()
+
+check_unsupported_compiler_version()
+
+# compile definitions (adds -DPLATFORM_LINUX)
+set(CORE_COMPILE_DEFS PLATFORM_TIZEN)
+
+# load core library
+add_subdirectory(${PROJECT_SOURCE_DIR}/core)
+
+set(LIB_NAME tangram) # in order to have libtangram.so
+
+add_library(${LIB_NAME} SHARED
+  ${PROJECT_SOURCE_DIR}/platforms/tizen/src/platform_tizen.cpp
+  ${PROJECT_SOURCE_DIR}/platforms/tizen/src/tizen_gl.cpp
+  ${PROJECT_SOURCE_DIR}/platforms/common/urlClient.cpp)
+
+target_include_directories(${LIB_NAME}
+    PUBLIC
+    ${GLFW_SOURCE_DIR}/include
+    ${PROJECT_SOURCE_DIR}/platforms/common)
+
+# link to the core library, forcing all symbols to be added
+# (whole-archive must be turned off after core so that lc++ symbols aren't duplicated)
+target_link_libraries(${LIB_NAME}
+  PUBLIC
+  "-Wl,-whole-archive"
+  ${CORE_LIBRARY}
+  "-Wl,-no-whole-archive")
+
+target_compile_options(${LIB_NAME}
+  PUBLIC
+  -fPIC)
diff --git a/toolchains/tizen.toolchain.cmake b/toolchains/tizen.toolchain.cmake
new file mode 100644 (file)
index 0000000..228b75e
--- /dev/null
@@ -0,0 +1,106 @@
+set(CMAKE_SYSTEM_NAME Linux)
+set(CMAKE_SYSTEM_VERSION 1)
+
+message(STATUS "Tizen SDK path: ${TIZEN_SDK}, Device: ${TIZEN_DEVICE}")
+
+set(CMAKE_C_COMPILER_WORKS TRUE)
+set(CMAKE_CXX_COMPILER_WORKS TRUE)
+
+set(CMAKE_C_COMPILER ${TIZEN_SDK}/tools/${TIZEN_ARCH}-linux-gnueabi-gcc-6.2/bin/${TIZEN_ARCH}-linux-gnueabi-gcc)
+set(CMAKE_CXX_COMPILER ${TIZEN_SDK}/tools/${TIZEN_ARCH}-linux-gnueabi-gcc-6.2/bin/${TIZEN_ARCH}-linux-gnueabi-g++)
+
+# Optimize for size and strip symbols and relocation information for release builds.
+set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} -Os -s")
+set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -Os -s")
+
+set(CMAKE_FIND_ROOT_PATH ${TIZEN_SYSROOT})
+set(CMAKE_SYSROOT ${TIZEN_SYSROOT})
+include_directories(SYSTEM
+  "${TIZEN_SYSROOT}/usr/include/libxml2"
+  "${TIZEN_SYSROOT}/usr/include"
+  "${TIZEN_SYSROOT}/usr/include/appcore-agent"
+  "${TIZEN_SYSROOT}/usr/include/appfw"
+  "${TIZEN_SYSROOT}/usr/include/attach-panel"
+  "${TIZEN_SYSROOT}/usr/include/badge"
+  "${TIZEN_SYSROOT}/usr/include/base"
+  "${TIZEN_SYSROOT}/usr/include/cairo"
+  "${TIZEN_SYSROOT}/usr/include/calendar-service2"
+  "${TIZEN_SYSROOT}/usr/include/chromium-ewk"
+  "${TIZEN_SYSROOT}/usr/include/ckm"
+  "${TIZEN_SYSROOT}/usr/include/contacts-svc"
+  "${TIZEN_SYSROOT}/usr/include/content"
+  "${TIZEN_SYSROOT}/usr/include/context-service"
+  "${TIZEN_SYSROOT}/usr/include/dali"
+  "${TIZEN_SYSROOT}/usr/include/dali-toolkit"
+  "${TIZEN_SYSROOT}/usr/include/dbus-1.0"
+  "${TIZEN_SYSROOT}/usr/include/device"
+  "${TIZEN_SYSROOT}/usr/include/dlog"
+  "${TIZEN_SYSROOT}/usr/include/ecore-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-buffer-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-con-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-evas-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-file-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-imf-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-imf-evas-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-input-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-input-evas-1"
+  "${TIZEN_SYSROOT}/usr/include/ecore-ipc-1"
+  "${TIZEN_SYSROOT}/usr/include/ector-1"
+  "${TIZEN_SYSROOT}/usr/include/e_dbus-1"
+  "${TIZEN_SYSROOT}/usr/include/edje-1"
+  "${TIZEN_SYSROOT}/usr/include/eet-1"
+  "${TIZEN_SYSROOT}/usr/include/efl-1"
+  "${TIZEN_SYSROOT}/usr/include/efl-extension"
+  "${TIZEN_SYSROOT}/usr/include/efreet-1"
+  "${TIZEN_SYSROOT}/usr/include/eina-1"
+  "${TIZEN_SYSROOT}/usr/include/eina-1/eina"
+  "${TIZEN_SYSROOT}/usr/include/eio-1"
+  "${TIZEN_SYSROOT}/usr/include/eldbus-1"
+  "${TIZEN_SYSROOT}/usr/include/elementary-1"
+  "${TIZEN_SYSROOT}/usr/include/embryo-1"
+  "${TIZEN_SYSROOT}/usr/include/emile-1"
+  "${TIZEN_SYSROOT}/usr/include/eo-1"
+  "${TIZEN_SYSROOT}/usr/include/eom"
+  "${TIZEN_SYSROOT}/usr/include/ethumb-1"
+  "${TIZEN_SYSROOT}/usr/include/ethumb-client-1"
+  "${TIZEN_SYSROOT}/usr/include/evas-1"
+  "${TIZEN_SYSROOT}/usr/include/feedback"
+  "${TIZEN_SYSROOT}/usr/include/fontconfig"
+  "${TIZEN_SYSROOT}/usr/include/freetype2"
+  "${TIZEN_SYSROOT}/usr/include/geofence"
+  "${TIZEN_SYSROOT}/usr/include/gio-unix-2.0"
+  "${TIZEN_SYSROOT}/usr/include/glib-2.0"
+  "${TIZEN_SYSROOT}/usr/include/harfbuzz"
+  "${TIZEN_SYSROOT}/usr/include/iotcon"
+  "${TIZEN_SYSROOT}/usr/include/json-glib-1.0"
+  "${TIZEN_SYSROOT}/usr/include/location"
+  "${TIZEN_SYSROOT}/usr/include/maps"
+  "${TIZEN_SYSROOT}/usr/include/media"
+  "${TIZEN_SYSROOT}/usr/include/media-content"
+  "${TIZEN_SYSROOT}/usr/include/messaging"
+  "${TIZEN_SYSROOT}/usr/include/metadata-editor"
+  "${TIZEN_SYSROOT}/usr/include/minicontrol"
+  "${TIZEN_SYSROOT}/usr/include/minizip"
+  "${TIZEN_SYSROOT}/usr/include/network"
+  "${TIZEN_SYSROOT}/usr/include/notification"
+  "${TIZEN_SYSROOT}/usr/include/nsd/"
+  "${TIZEN_SYSROOT}/usr/include/phonenumber-utils"
+  "${TIZEN_SYSROOT}/usr/include/sensor"
+  "${TIZEN_SYSROOT}/usr/include/service-adaptor"
+  "${TIZEN_SYSROOT}/usr/include/shortcut"
+  "${TIZEN_SYSROOT}/usr/include/storage"
+  "${TIZEN_SYSROOT}/usr/include/system"
+  "${TIZEN_SYSROOT}/usr/include/telephony"
+  "${TIZEN_SYSROOT}/usr/include/ui"
+  "${TIZEN_SYSROOT}/usr/include/web"
+  "${TIZEN_SYSROOT}/usr/include/widget_service"
+  "${TIZEN_SYSROOT}/usr/include/widget_viewer_evas"
+  "${TIZEN_SYSROOT}/usr/include/wifi-direct"
+  "${TIZEN_SYSROOT}/usr/lib/dbus-1.0/include"
+  "${TIZEN_SYSROOT}/usr/lib/glib-2.0/include")
+
+message(STATUS "SYSROOT: ${CMAKE_SYSROOT}")
+
+set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
+set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
+set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
diff --git a/toolchains/utils.cmake b/toolchains/utils.cmake
new file mode 100644 (file)
index 0000000..9387e09
--- /dev/null
@@ -0,0 +1,140 @@
+function(check_unsupported_compiler_version)
+
+    set(MIN_GCC 4.9)
+    set(MIN_CLANG 3.4)
+    set(MIN_APPLECLANG 6.0)
+
+    if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${MIN_GCC})
+            message(FATAL_ERROR "Your GCC version does not support C++14, please install version ${MIN_GCC} or higher")
+        endif()
+    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${MIN_CLANG})
+            message(FATAL_ERROR "Your Clang version does not support C++14, please install version ${MIN_CLANG} or higher")
+        endif()
+    elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang")
+        if(CMAKE_CXX_COMPILER_VERSION VERSION_LESS ${MIN_APPLECLANG})
+            message(FATAL_ERROR "Your Xcode version does not support C++14, please install version ${MIN_APPLECLANG} or higher")
+        endif()
+    else()
+        message(WARNING "Compilation has only been tested with Clang, AppleClang, and GCC")
+    endif()
+
+endfunction(check_unsupported_compiler_version)
+
+function(get_mapzen_api_key KEY_RESULT)
+
+    set(${KEY_RESULT} $ENV{MAPZEN_API_KEY} PARENT_SCOPE)
+
+    if(${KEY_RESULT} STREQUAL "")
+        message(SEND_ERROR
+            "Make sure to provide an api key to build the demo application, "
+            "you can create an API key at https://mapzen.com/developers. "
+            "Then run 'export MAPZEN_API_KEY mapzen-xxxx' or specify `MAPZEN_API_KEY=mapzen-xxxx` as an argument to the make command")
+        return()
+    endif()
+
+endfunction(get_mapzen_api_key)
+
+
+function(find_sources_and_include_directories HEADERS_PATH SOURCES_PATH)
+    include_recursive_dirs(${HEADERS_PATH})
+    file(GLOB_RECURSE FOUND_SOURCES ${SOURCES_PATH})
+
+    set(SOURCES
+        ${SOURCES}
+        ${FOUND_SOURCES}
+        CACHE INTERNAL "sources" FORCE)
+    list(REMOVE_DUPLICATES SOURCES)
+endfunction(find_sources_and_include_directories)
+
+function(include_recursive_dirs HEADERS_PATH)
+    file(GLOB_RECURSE FOUND_HEADERS ${HEADERS_PATH})
+
+    set(INCLUDE_DIRS "")
+    foreach(_headerFile ${FOUND_HEADERS})
+        get_filename_component(_dir ${_headerFile} PATH)
+        list(APPEND INCLUDE_DIRS ${_dir})
+    endforeach()
+    list(REMOVE_DUPLICATES INCLUDE_DIRS)
+
+    include_directories(${INCLUDE_DIRS})
+
+    set(HEADERS
+        ${HEADERS}
+        ${FOUND_HEADERS}
+        CACHE INTERNAL "headers" FORCE)
+    list(REMOVE_DUPLICATES HEADERS)
+endfunction(include_recursive_dirs)
+
+function(check_and_link_libraries TARGET)
+    foreach(_lib ${ARGN})
+        string(TOUPPER ${_lib} LIB)
+        find_package (${_lib})
+        if(${LIB}_FOUND)
+            include_directories(${${LIB}_INCLUDE_DIR})
+            target_link_libraries(${TARGET} ${${LIB}_LIBRARIES})
+        else()
+            message(SEND_ERROR "You NEED ${_lib} library.")
+            return()
+        endif ()
+    endforeach()
+endfunction(check_and_link_libraries)
+
+macro(group_recursive_sources CURDIR CURGROUP)
+    file(GLOB children ${CURDIR}/*)
+
+    foreach(child ${children})
+        if(IS_DIRECTORY ${child})
+            file(GLOB FOUND_HEADERS ${child}/*.h)
+            file(GLOB FOUND_SOURCES ${child}/*.cpp)
+            string(REGEX MATCH "([^/]+)$" group ${child})
+
+            if("${CURGROUP}" STREQUAL "")
+                source_group(${group} FILES ${FOUND_HEADERS} ${FOUND_SOURCES})
+            else()
+                source_group(${CURGROUP}/${group} FILES ${FOUND_HEADERS} ${FOUND_SOURCES})
+                set(group ${CURGROUP}/${group})
+            endif()
+
+            group_recursive_sources(${child} ${group})
+        endif()
+    endforeach()
+
+    # add files from top level group
+    file(GLOB FOUND_HEADERS ${CURGROUP}/*.h)
+    file(GLOB FOUND_SOURCES ${CURGROUP}/*.cpp)
+    source_group(${CURGROUP} FILES ${FOUND_HEADERS} ${FOUND_SOURCES})
+endmacro()
+
+macro(add_bundle_resources RESOURCE_LIST RESOURCE_DIR RESOURCE_BASE)
+
+    file(GLOB_RECURSE FULL_RESOURCE_PATHS "${RESOURCE_DIR}/[^.]**")
+    foreach(_full_resource_path ${FULL_RESOURCE_PATHS})
+        file(RELATIVE_PATH REL_RESOURCE_PATH ${RESOURCE_DIR} ${_full_resource_path})
+        get_filename_component(REL_RESOURCE_DIR ${REL_RESOURCE_PATH} PATH)
+        set_source_files_properties(${_full_resource_path} PROPERTIES MACOSX_PACKAGE_LOCATION "${RESOURCE_BASE}/${REL_RESOURCE_DIR}")
+        # message(STATUS "resource at: ${_full_resource_path}\n   remapped to: ${RESOURCE_BASE}/${REL_RESOURCE_DIR}")
+    endforeach()
+    list(APPEND ${RESOURCE_LIST} ${FULL_RESOURCE_PATHS})
+
+endmacro(add_bundle_resources)
+
+macro(add_resources TARGET RESOURCE_DIR)
+
+    add_custom_command(TARGET ${TARGET}
+        POST_BUILD
+        COMMAND ${CMAKE_COMMAND} -E copy_directory ${RESOURCE_DIR} ${CMAKE_BINARY_DIR}/bin)
+
+endmacro(add_resources)
+
+macro(add_framework FWNAME APPNAME LIBPATH)
+    find_library(FRAMEWORK_${FWNAME} NAMES ${FWNAME} PATHS ${LIBPATH} PATH_SUFFIXES Frameworks NO_DEFAULT_PATH)
+    if(${FRAMEWORK_${FWNAME}} STREQUAL FRAMEWORK_${FWNAME}-NOTFOUND)
+        message(ERROR ": Framework ${FWNAME} not found")
+    else()
+        target_link_libraries(${APPNAME} ${FRAMEWORK_${FWNAME}})
+        message(STATUS "Framework ${FWNAME} found")
+    endif()
+endmacro(add_framework)
+