Repository: android/ndk-samples Branch: main Commit: 988d73bed0fd Files: 797 Total size: 6.0 MB Directory structure: gitextract_om9grlgx/ ├── .clang-format ├── .github/ │ └── workflows/ │ └── build.yml ├── .gitignore ├── .google/ │ └── packaging.yaml ├── .pre-commit-config.yaml ├── ARCHITECTURE.md ├── CONTRIBUTING.md ├── LICENSE ├── README.md ├── REFERENCE.md ├── audio-echo/ │ └── README.md ├── base/ │ ├── .gitignore │ ├── build.gradle.kts │ └── src/ │ └── main/ │ └── cpp/ │ ├── CMakeLists.txt │ ├── include/ │ │ └── base/ │ │ ├── errno_restorer.h │ │ ├── logging.h │ │ └── macros.h │ ├── logging.cpp │ └── logging_splitters.h ├── bitmap-plasma/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── jni.cpp │ │ ├── libplasma.map.txt │ │ ├── plasma.cpp │ │ └── plasma.h │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── plasma/ │ │ └── Plasma.java │ └── res/ │ └── values/ │ └── strings.xml ├── build-logic/ │ ├── .gitignore │ ├── README.md │ ├── build.gradle.kts │ ├── settings.gradle.kts │ └── src/ │ └── main/ │ └── java/ │ └── com/ │ └── android/ │ └── ndk/ │ └── samples/ │ └── buildlogic/ │ ├── AndroidApplicationConventionPlugin.kt │ ├── AndroidLibraryConventionPlugin.kt │ ├── KotlinConventionPlugin.kt │ └── Versions.kt ├── build.gradle ├── camera/ │ ├── README.md │ ├── basic/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── cpp/ │ │ │ ├── CMakeLists.txt │ │ │ ├── android_main.cpp │ │ │ ├── camera_engine.cpp │ │ │ ├── camera_engine.h │ │ │ ├── camera_listeners.cpp │ │ │ ├── camera_manager.cpp │ │ │ ├── camera_manager.h │ │ │ ├── camera_ui.cpp │ │ │ ├── image_reader.cpp │ │ │ ├── image_reader.h │ │ │ └── libndk_camera.map.txt │ │ ├── java/ │ │ │ └── com/ │ │ │ └── sample/ │ │ │ └── camera/ │ │ │ └── basic/ │ │ │ └── CameraActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── widgets.xml │ │ └── values/ │ │ └── strings.xml │ ├── camera-utils/ │ │ ├── build.gradle.kts │ │ └── src/ │ │ └── main/ │ │ └── cpp/ │ │ ├── CMakeLists.txt │ │ ├── camera_utils.cpp │ │ └── include/ │ │ └── ndksamples/ │ │ └── camera/ │ │ ├── camera_utils.h │ │ └── native_debug.h │ └── texture-view/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── android_main.cpp │ │ ├── camera_engine.cpp │ │ ├── camera_engine.h │ │ ├── camera_listeners.cpp │ │ ├── camera_manager.cpp │ │ ├── camera_manager.h │ │ └── libcamera_textureview.map.txt │ ├── java/ │ │ └── com/ │ │ └── sample/ │ │ └── textureview/ │ │ └── ViewActivity.java │ └── res/ │ ├── layout/ │ │ └── activity_main.xml │ └── values/ │ └── strings.xml ├── cmake/ │ └── AppLibrary.cmake ├── endless-tunnel/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── android_main.cpp │ │ ├── anim.cpp │ │ ├── anim.hpp │ │ ├── ascii_to_geom.cpp │ │ ├── ascii_to_geom.hpp │ │ ├── common.hpp │ │ ├── data/ │ │ │ ├── alphabet.inl │ │ │ ├── ascii_art.inl │ │ │ ├── blurb.inl │ │ │ ├── cube_geom.inl │ │ │ ├── our_shader.inl │ │ │ ├── strings.inl │ │ │ └── tunnel_geom.inl │ │ ├── dialog_scene.cpp │ │ ├── dialog_scene.hpp │ │ ├── engine.hpp │ │ ├── game_consts.hpp │ │ ├── glm/ │ │ │ ├── CMakeLists.txt │ │ │ ├── common.hpp │ │ │ ├── detail/ │ │ │ │ ├── _features.hpp │ │ │ │ ├── _fixes.hpp │ │ │ │ ├── _literals.hpp │ │ │ │ ├── _noise.hpp │ │ │ │ ├── _swizzle.hpp │ │ │ │ ├── _swizzle_func.hpp │ │ │ │ ├── _vectorize.hpp │ │ │ │ ├── func_common.hpp │ │ │ │ ├── func_common.inl │ │ │ │ ├── func_exponential.hpp │ │ │ │ ├── func_exponential.inl │ │ │ │ ├── func_geometric.hpp │ │ │ │ ├── func_geometric.inl │ │ │ │ ├── func_integer.hpp │ │ │ │ ├── func_integer.inl │ │ │ │ ├── func_matrix.hpp │ │ │ │ ├── func_matrix.inl │ │ │ │ ├── func_noise.hpp │ │ │ │ ├── func_noise.inl │ │ │ │ ├── func_packing.hpp │ │ │ │ ├── func_packing.inl │ │ │ │ ├── func_trigonometric.hpp │ │ │ │ ├── func_trigonometric.inl │ │ │ │ ├── func_vector_relational.hpp │ │ │ │ ├── func_vector_relational.inl │ │ │ │ ├── glm.cpp │ │ │ │ ├── hint.hpp │ │ │ │ ├── intrinsic_common.hpp │ │ │ │ ├── intrinsic_common.inl │ │ │ │ ├── intrinsic_exponential.hpp │ │ │ │ ├── intrinsic_exponential.inl │ │ │ │ ├── intrinsic_geometric.hpp │ │ │ │ ├── intrinsic_geometric.inl │ │ │ │ ├── intrinsic_integer.hpp │ │ │ │ ├── intrinsic_integer.inl │ │ │ │ ├── intrinsic_matrix.hpp │ │ │ │ ├── intrinsic_matrix.inl │ │ │ │ ├── intrinsic_trigonometric.hpp │ │ │ │ ├── intrinsic_trigonometric.inl │ │ │ │ ├── intrinsic_vector_relational.hpp │ │ │ │ ├── intrinsic_vector_relational.inl │ │ │ │ ├── precision.hpp │ │ │ │ ├── precision.inl │ │ │ │ ├── setup.hpp │ │ │ │ ├── type_float.hpp │ │ │ │ ├── type_gentype.hpp │ │ │ │ ├── type_gentype.inl │ │ │ │ ├── type_half.hpp │ │ │ │ ├── type_half.inl │ │ │ │ ├── type_int.hpp │ │ │ │ ├── type_mat.hpp │ │ │ │ ├── type_mat.inl │ │ │ │ ├── type_mat2x2.hpp │ │ │ │ ├── type_mat2x2.inl │ │ │ │ ├── type_mat2x3.hpp │ │ │ │ ├── type_mat2x3.inl │ │ │ │ ├── type_mat2x4.hpp │ │ │ │ ├── type_mat2x4.inl │ │ │ │ ├── type_mat3x2.hpp │ │ │ │ ├── type_mat3x2.inl │ │ │ │ ├── type_mat3x3.hpp │ │ │ │ ├── type_mat3x3.inl │ │ │ │ ├── type_mat3x4.hpp │ │ │ │ ├── type_mat3x4.inl │ │ │ │ ├── type_mat4x2.hpp │ │ │ │ ├── type_mat4x2.inl │ │ │ │ ├── type_mat4x3.hpp │ │ │ │ ├── type_mat4x3.inl │ │ │ │ ├── type_mat4x4.hpp │ │ │ │ ├── type_mat4x4.inl │ │ │ │ ├── type_vec.hpp │ │ │ │ ├── type_vec.inl │ │ │ │ ├── type_vec1.hpp │ │ │ │ ├── type_vec1.inl │ │ │ │ ├── type_vec2.hpp │ │ │ │ ├── type_vec2.inl │ │ │ │ ├── type_vec3.hpp │ │ │ │ ├── type_vec3.inl │ │ │ │ ├── type_vec4.hpp │ │ │ │ └── type_vec4.inl │ │ │ ├── exponential.hpp │ │ │ ├── ext.hpp │ │ │ ├── fwd.hpp │ │ │ ├── geometric.hpp │ │ │ ├── glm.hpp │ │ │ ├── gtc/ │ │ │ │ ├── constants.hpp │ │ │ │ ├── constants.inl │ │ │ │ ├── epsilon.hpp │ │ │ │ ├── epsilon.inl │ │ │ │ ├── matrix_access.hpp │ │ │ │ ├── matrix_access.inl │ │ │ │ ├── matrix_integer.hpp │ │ │ │ ├── matrix_inverse.hpp │ │ │ │ ├── matrix_inverse.inl │ │ │ │ ├── matrix_transform.hpp │ │ │ │ ├── matrix_transform.inl │ │ │ │ ├── noise.hpp │ │ │ │ ├── noise.inl │ │ │ │ ├── packing.hpp │ │ │ │ ├── packing.inl │ │ │ │ ├── quaternion.hpp │ │ │ │ ├── quaternion.inl │ │ │ │ ├── random.hpp │ │ │ │ ├── random.inl │ │ │ │ ├── reciprocal.hpp │ │ │ │ ├── reciprocal.inl │ │ │ │ ├── type_precision.hpp │ │ │ │ ├── type_precision.inl │ │ │ │ ├── type_ptr.hpp │ │ │ │ ├── type_ptr.inl │ │ │ │ ├── ulp.hpp │ │ │ │ └── ulp.inl │ │ │ ├── gtx/ │ │ │ │ ├── associated_min_max.hpp │ │ │ │ ├── associated_min_max.inl │ │ │ │ ├── bit.hpp │ │ │ │ ├── bit.inl │ │ │ │ ├── closest_point.hpp │ │ │ │ ├── closest_point.inl │ │ │ │ ├── color_space.hpp │ │ │ │ ├── color_space.inl │ │ │ │ ├── color_space_YCoCg.hpp │ │ │ │ ├── color_space_YCoCg.inl │ │ │ │ ├── compatibility.hpp │ │ │ │ ├── compatibility.inl │ │ │ │ ├── component_wise.hpp │ │ │ │ ├── component_wise.inl │ │ │ │ ├── constants.hpp │ │ │ │ ├── dual_quaternion.hpp │ │ │ │ ├── dual_quaternion.inl │ │ │ │ ├── epsilon.hpp │ │ │ │ ├── euler_angles.hpp │ │ │ │ ├── euler_angles.inl │ │ │ │ ├── extend.hpp │ │ │ │ ├── extend.inl │ │ │ │ ├── extented_min_max.hpp │ │ │ │ ├── extented_min_max.inl │ │ │ │ ├── fast_exponential.hpp │ │ │ │ ├── fast_exponential.inl │ │ │ │ ├── fast_square_root.hpp │ │ │ │ ├── fast_square_root.inl │ │ │ │ ├── fast_trigonometry.hpp │ │ │ │ ├── fast_trigonometry.inl │ │ │ │ ├── gradient_paint.hpp │ │ │ │ ├── gradient_paint.inl │ │ │ │ ├── handed_coordinate_space.hpp │ │ │ │ ├── handed_coordinate_space.inl │ │ │ │ ├── inertia.hpp │ │ │ │ ├── inertia.inl │ │ │ │ ├── int_10_10_10_2.hpp │ │ │ │ ├── int_10_10_10_2.inl │ │ │ │ ├── integer.hpp │ │ │ │ ├── integer.inl │ │ │ │ ├── intersect.hpp │ │ │ │ ├── intersect.inl │ │ │ │ ├── io.hpp │ │ │ │ ├── io.inl │ │ │ │ ├── log_base.hpp │ │ │ │ ├── log_base.inl │ │ │ │ ├── matrix_cross_product.hpp │ │ │ │ ├── matrix_cross_product.inl │ │ │ │ ├── matrix_interpolation.hpp │ │ │ │ ├── matrix_interpolation.inl │ │ │ │ ├── matrix_major_storage.hpp │ │ │ │ ├── matrix_major_storage.inl │ │ │ │ ├── matrix_operation.hpp │ │ │ │ ├── matrix_operation.inl │ │ │ │ ├── matrix_query.hpp │ │ │ │ ├── matrix_query.inl │ │ │ │ ├── matrix_transform_2d.hpp │ │ │ │ ├── matrix_transform_2d.inl │ │ │ │ ├── mixed_product.hpp │ │ │ │ ├── mixed_product.inl │ │ │ │ ├── multiple.hpp │ │ │ │ ├── multiple.inl │ │ │ │ ├── noise.hpp │ │ │ │ ├── norm.hpp │ │ │ │ ├── norm.inl │ │ │ │ ├── normal.hpp │ │ │ │ ├── normal.inl │ │ │ │ ├── normalize_dot.hpp │ │ │ │ ├── normalize_dot.inl │ │ │ │ ├── number_precision.hpp │ │ │ │ ├── number_precision.inl │ │ │ │ ├── optimum_pow.hpp │ │ │ │ ├── optimum_pow.inl │ │ │ │ ├── orthonormalize.hpp │ │ │ │ ├── orthonormalize.inl │ │ │ │ ├── perpendicular.hpp │ │ │ │ ├── perpendicular.inl │ │ │ │ ├── polar_coordinates.hpp │ │ │ │ ├── polar_coordinates.inl │ │ │ │ ├── projection.hpp │ │ │ │ ├── projection.inl │ │ │ │ ├── quaternion.hpp │ │ │ │ ├── quaternion.inl │ │ │ │ ├── random.hpp │ │ │ │ ├── raw_data.hpp │ │ │ │ ├── raw_data.inl │ │ │ │ ├── reciprocal.hpp │ │ │ │ ├── rotate_normalized_axis.hpp │ │ │ │ ├── rotate_normalized_axis.inl │ │ │ │ ├── rotate_vector.hpp │ │ │ │ ├── rotate_vector.inl │ │ │ │ ├── scalar_relational.hpp │ │ │ │ ├── scalar_relational.inl │ │ │ │ ├── simd_mat4.hpp │ │ │ │ ├── simd_mat4.inl │ │ │ │ ├── simd_quat.hpp │ │ │ │ ├── simd_quat.inl │ │ │ │ ├── simd_vec4.hpp │ │ │ │ ├── simd_vec4.inl │ │ │ │ ├── spline.hpp │ │ │ │ ├── spline.inl │ │ │ │ ├── std_based_type.hpp │ │ │ │ ├── std_based_type.inl │ │ │ │ ├── string_cast.hpp │ │ │ │ ├── string_cast.inl │ │ │ │ ├── transform.hpp │ │ │ │ ├── transform.inl │ │ │ │ ├── transform2.hpp │ │ │ │ ├── transform2.inl │ │ │ │ ├── ulp.hpp │ │ │ │ ├── unsigned_int.hpp │ │ │ │ ├── unsigned_int.inl │ │ │ │ ├── vec1.hpp │ │ │ │ ├── vec1.inl │ │ │ │ ├── vector_angle.hpp │ │ │ │ ├── vector_angle.inl │ │ │ │ ├── vector_query.hpp │ │ │ │ ├── vector_query.inl │ │ │ │ ├── wrap.hpp │ │ │ │ └── wrap.inl │ │ │ ├── integer.hpp │ │ │ ├── mat2x2.hpp │ │ │ ├── mat2x3.hpp │ │ │ ├── mat2x4.hpp │ │ │ ├── mat3x2.hpp │ │ │ ├── mat3x3.hpp │ │ │ ├── mat3x4.hpp │ │ │ ├── mat4x2.hpp │ │ │ ├── mat4x3.hpp │ │ │ ├── mat4x4.hpp │ │ │ ├── matrix.hpp │ │ │ ├── packing.hpp │ │ │ ├── trigonometric.hpp │ │ │ ├── vec2.hpp │ │ │ ├── vec3.hpp │ │ │ ├── vec4.hpp │ │ │ ├── vector_relational.hpp │ │ │ └── virtrev/ │ │ │ └── xstream.hpp │ │ ├── indexbuf.cpp │ │ ├── indexbuf.hpp │ │ ├── input_util.cpp │ │ ├── input_util.hpp │ │ ├── jni_util.cpp │ │ ├── jni_util.hpp │ │ ├── joystick-support.hpp │ │ ├── libgame.map.txt │ │ ├── native_engine.cpp │ │ ├── native_engine.hpp │ │ ├── obstacle.cpp │ │ ├── obstacle.hpp │ │ ├── obstacle_generator.cpp │ │ ├── obstacle_generator.hpp │ │ ├── our_key_codes.hpp │ │ ├── our_shader.cpp │ │ ├── our_shader.hpp │ │ ├── play_scene.cpp │ │ ├── play_scene.hpp │ │ ├── scene.cpp │ │ ├── scene.hpp │ │ ├── scene_manager.cpp │ │ ├── scene_manager.hpp │ │ ├── sfxman.cpp │ │ ├── sfxman.hpp │ │ ├── shader.cpp │ │ ├── shader.hpp │ │ ├── shape_renderer.cpp │ │ ├── shape_renderer.hpp │ │ ├── simplegeom.hpp │ │ ├── tex_quad.cpp │ │ ├── tex_quad.hpp │ │ ├── text_renderer.cpp │ │ ├── text_renderer.hpp │ │ ├── texture.cpp │ │ ├── texture.hpp │ │ ├── ui_scene.cpp │ │ ├── ui_scene.hpp │ │ ├── util.cpp │ │ ├── util.hpp │ │ ├── vertexbuf.cpp │ │ ├── vertexbuf.hpp │ │ ├── welcome_scene.cpp │ │ └── welcome_scene.hpp │ └── res/ │ └── values/ │ ├── strings.xml │ └── styles.xml ├── exceptions/ │ ├── .gitignore │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── exception_helper.cpp │ │ ├── exception_helper.h │ │ ├── libexceptions.map.txt │ │ └── native-lib.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── exceptions/ │ │ └── MainActivity.kt │ └── res/ │ ├── drawable/ │ │ └── ic_launcher_background.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── layout/ │ │ └── activity_main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ ├── values-night/ │ │ └── themes.xml │ └── xml/ │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── gles3jni/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── RendererES2.cpp │ │ ├── RendererES3.cpp │ │ ├── gles3jni.cpp │ │ ├── gles3jni.h │ │ └── libgles3jni.map.txt │ ├── java/ │ │ └── com/ │ │ └── android/ │ │ └── gles3jni/ │ │ ├── GLES3JNIActivity.java │ │ ├── GLES3JNILib.java │ │ └── GLES3JNIView.java │ └── res/ │ └── values/ │ └── strings.xml ├── gradle/ │ ├── libs.versions.toml │ └── wrapper/ │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradle.properties ├── gradlew ├── gradlew.bat ├── hello-gl2/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── gl_code.cpp │ │ └── libgl2jni.map.txt │ ├── java/ │ │ └── com/ │ │ └── android/ │ │ └── gl2jni/ │ │ ├── GL2JNIActivity.java │ │ ├── GL2JNILib.java │ │ └── GL2JNIView.java │ └── res/ │ └── values/ │ └── strings.xml ├── hello-jni/ │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── hello-jni.cpp │ │ └── libhello-jni.map.txt │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── hellojni/ │ │ └── HelloJni.kt │ └── res/ │ ├── layout/ │ │ └── activity_hello_jni.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── values-w820dp/ │ └── dimens.xml ├── hello-jniCallback/ │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── hello-jnicallback.cpp │ │ └── libhello-jnicallback.map.txt │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── hellojnicallback/ │ │ ├── JniHandler.java │ │ └── MainActivity.java │ └── res/ │ ├── layout/ │ │ └── activity_main.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── values-w820dp/ │ └── dimens.xml ├── hello-oboe/ │ └── README.md ├── hello-vulkan/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── hellovk.h │ │ ├── libhellovkjni.map.txt │ │ └── vk_main.cpp │ ├── java/ │ │ └── com/ │ │ └── android/ │ │ └── hellovk/ │ │ └── VulkanActivity.kt │ ├── res/ │ │ └── values/ │ │ ├── strings.xml │ │ └── themes.xml │ └── shaders/ │ ├── shader.frag │ └── shader.vert ├── native-activity/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── libnative-activity.map.txt │ │ └── main.cpp │ └── res/ │ └── values/ │ └── strings.xml ├── native-audio/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── assets/ │ │ └── README.txt │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── android_clip.h │ │ ├── hello_clip.h │ │ ├── libnative-audio-jni.map.txt │ │ └── native-audio-jni.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── nativeaudio/ │ │ └── NativeAudio.java │ └── res/ │ ├── layout/ │ │ └── main.xml │ └── values/ │ └── strings.xml ├── native-codec/ │ ├── README.md │ └── app/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── libnative-codec-jni.map.txt │ │ ├── looper.cpp │ │ ├── looper.h │ │ └── native-codec-jni.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── nativecodec/ │ │ ├── MyGLSurfaceView.java │ │ └── NativeCodec.java │ └── res/ │ ├── layout/ │ │ └── main.xml │ └── values/ │ └── strings.xml ├── native-media/ │ └── README.md ├── native-midi/ │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── AndroidDebug.h │ │ ├── AppMidiManager.cpp │ │ ├── CMakeLists.txt │ │ ├── MainActivity.cpp │ │ ├── MidiSpec.h │ │ └── libnative_midi.map.txt │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── nativemidi/ │ │ ├── AppMidiManager.java │ │ ├── MainActivity.java │ │ ├── MidiDataHelper.java │ │ └── MidiSpec.java │ └── res/ │ ├── drawable/ │ │ └── ic_launcher_background.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── layout/ │ │ └── activity_main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── dimens.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── values-w820dp/ │ └── dimens.xml ├── nn-samples/ │ └── README.md ├── orderfile/ │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── demo.orderfile │ │ ├── liborderfiledemo.map.txt │ │ └── orderfile.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── orderfiledemo/ │ │ └── MainActivity.kt │ └── res/ │ ├── drawable/ │ │ └── ic_launcher_background.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── layout/ │ │ └── activity_main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ └── values-night/ │ └── themes.xml ├── prefab/ │ └── README.md ├── san-angeles/ │ └── README.md ├── sanitizers/ │ ├── .gitignore │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── asan/ │ │ └── resources/ │ │ └── .gitignore │ ├── hwasan/ │ │ └── resources/ │ │ └── lib/ │ │ └── arm64-v8a/ │ │ └── wrap.sh │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── libsanitizers.map.txt │ │ └── native-lib.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── sanitizers/ │ │ └── MainActivity.kt │ └── res/ │ ├── drawable/ │ │ └── ic_launcher_background.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── layout/ │ │ └── activity_main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ ├── values-night/ │ │ └── themes.xml │ └── xml/ │ ├── backup_rules.xml │ └── data_extraction_rules.xml ├── sensor-graph/ │ ├── README.md │ └── accelerometer/ │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── assets/ │ │ ├── shader.glslf │ │ └── shader.glslv │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── libaccelerometergraph.map.txt │ │ └── sensorgraph.cpp │ ├── java/ │ │ └── com/ │ │ └── android/ │ │ └── accelerometergraph/ │ │ ├── AccelerometerGraphActivity.java │ │ └── AccelerometerGraphJNI.java │ └── res/ │ └── values/ │ └── strings.xml ├── settings.gradle ├── teapots/ │ ├── .gitignore │ ├── README.md │ ├── choreographer-30fps/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── Shaders/ │ │ │ ├── ShaderPlain.fsh │ │ │ └── VS_ShaderPlain.vsh │ │ ├── cpp/ │ │ │ ├── CMakeLists.txt │ │ │ ├── ChoreographerNativeActivity.cpp │ │ │ ├── TeapotRenderer.cpp │ │ │ ├── TeapotRenderer.h │ │ │ ├── libChoreographerNativeActivity.map.txt │ │ │ └── teapot.inl │ │ ├── java/ │ │ │ └── com/ │ │ │ └── sample/ │ │ │ ├── choreographer/ │ │ │ │ ├── ChoreographerApplication.java │ │ │ │ └── ChoreographerNativeActivity.java │ │ │ └── helper/ │ │ │ └── NDKHelper.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── widgets.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ ├── classic-teapot/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── Shaders/ │ │ │ ├── ShaderPlain.fsh │ │ │ └── VS_ShaderPlain.vsh │ │ ├── cpp/ │ │ │ ├── CMakeLists.txt │ │ │ ├── TeapotNativeActivity.cpp │ │ │ ├── TeapotRenderer.cpp │ │ │ ├── TeapotRenderer.h │ │ │ ├── libTeapotNativeActivity.map.txt │ │ │ └── teapot.inl │ │ ├── java/ │ │ │ └── com/ │ │ │ └── sample/ │ │ │ ├── helper/ │ │ │ │ └── NDKHelper.java │ │ │ └── teapot/ │ │ │ ├── TeapotApplication.java │ │ │ └── TeapotNativeActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── widgets.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ ├── common/ │ │ └── ndk_helper/ │ │ ├── CMakeLists.txt │ │ ├── GLContext.cpp │ │ ├── GLContext.h │ │ ├── JNIHelper.cpp │ │ ├── JNIHelper.h │ │ ├── NDKHelper.h │ │ ├── gestureDetector.cpp │ │ ├── gestureDetector.h │ │ ├── gl3stub.c │ │ ├── gl3stub.cpp │ │ ├── gl3stub.h │ │ ├── interpolator.cpp │ │ ├── interpolator.h │ │ ├── perfMonitor.cpp │ │ ├── perfMonitor.h │ │ ├── sensorManager.cpp │ │ ├── sensorManager.h │ │ ├── shader.cpp │ │ ├── shader.h │ │ ├── tapCamera.cpp │ │ ├── tapCamera.h │ │ ├── vecmath.cpp │ │ └── vecmath.h │ ├── image-decoder/ │ │ ├── README.md │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── Shaders/ │ │ │ ├── 2DTexture.fsh │ │ │ ├── 2DTexture.vsh │ │ │ ├── Cubemap.fsh │ │ │ ├── Cubemap.vsh │ │ │ ├── ShaderPlain.fsh │ │ │ └── VS_ShaderPlain.vsh │ │ ├── cpp/ │ │ │ ├── CMakeLists.txt │ │ │ ├── ImageDecoderRender.cpp │ │ │ ├── ImageDecoderRender.h │ │ │ ├── TeapotNativeActivity.cpp │ │ │ ├── TeapotRenderer.cpp │ │ │ ├── TeapotRenderer.h │ │ │ ├── Texture.cpp │ │ │ ├── Texture.h │ │ │ ├── android_debug.h │ │ │ ├── libImageDecoderNativeActivity.map.txt │ │ │ └── teapot.inl │ │ ├── java/ │ │ │ └── com/ │ │ │ └── sample/ │ │ │ ├── helper/ │ │ │ │ └── NDKHelper.java │ │ │ └── imagedecoder/ │ │ │ ├── TeapotApplication.java │ │ │ └── TeapotNativeActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── widgets.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ ├── more-teapots/ │ │ ├── build.gradle │ │ └── src/ │ │ └── main/ │ │ ├── AndroidManifest.xml │ │ ├── assets/ │ │ │ └── Shaders/ │ │ │ ├── ShaderPlain.fsh │ │ │ ├── ShaderPlainES3.fsh │ │ │ ├── VS_ShaderPlain.vsh │ │ │ └── VS_ShaderPlainES3.vsh │ │ ├── cpp/ │ │ │ ├── CMakeLists.txt │ │ │ ├── MoreTeapotsNativeActivity.cpp │ │ │ ├── MoreTeapotsRenderer.cpp │ │ │ ├── MoreTeapotsRenderer.h │ │ │ ├── libMoreTeapotsNativeActivity.map.txt │ │ │ └── teapot.inl │ │ ├── java/ │ │ │ └── com/ │ │ │ └── sample/ │ │ │ ├── helper/ │ │ │ │ └── NDKHelper.java │ │ │ └── moreteapots/ │ │ │ ├── MoreTeapotsApplication.java │ │ │ └── MoreTeapotsNativeActivity.java │ │ └── res/ │ │ ├── layout/ │ │ │ └── widgets.xml │ │ ├── values/ │ │ │ ├── strings.xml │ │ │ └── styles.xml │ │ ├── values-v11/ │ │ │ └── styles.xml │ │ └── values-v14/ │ │ └── styles.xml │ └── textured-teapot/ │ ├── README.md │ ├── build.gradle │ └── src/ │ └── main/ │ ├── AndroidManifest.xml │ ├── assets/ │ │ ├── Shaders/ │ │ │ ├── 2DTexture.fsh │ │ │ ├── 2DTexture.vsh │ │ │ ├── Cubemap.fsh │ │ │ ├── Cubemap.vsh │ │ │ ├── ShaderPlain.fsh │ │ │ └── VS_ShaderPlain.vsh │ │ └── Textures/ │ │ ├── back.tga │ │ ├── bottom.tga │ │ ├── front.tga │ │ ├── left.tga │ │ ├── right.tga │ │ └── top.tga │ ├── cpp/ │ │ ├── AssetUtil.cpp │ │ ├── AssetUtil.h │ │ ├── CMakeLists.txt │ │ ├── TeapotNativeActivity.cpp │ │ ├── TeapotRenderer.cpp │ │ ├── TeapotRenderer.h │ │ ├── Texture.cpp │ │ ├── Texture.h │ │ ├── TexturedTeapotRender.cpp │ │ ├── TexturedTeapotRender.h │ │ ├── android_debug.h │ │ ├── libTexturedTeapotNativeActivity.map.txt │ │ └── teapot.inl │ ├── java/ │ │ └── com/ │ │ └── sample/ │ │ ├── helper/ │ │ │ └── NDKHelper.java │ │ └── texturedteapot/ │ │ ├── TeapotApplication.java │ │ └── TeapotNativeActivity.java │ └── res/ │ ├── layout/ │ │ └── widgets.xml │ ├── values/ │ │ ├── strings.xml │ │ └── styles.xml │ ├── values-v11/ │ │ └── styles.xml │ └── values-v14/ │ └── styles.xml ├── unit-test/ │ ├── .gitignore │ ├── README.md │ └── app/ │ ├── .gitignore │ ├── build.gradle │ ├── proguard-rules.pro │ └── src/ │ ├── androidTest/ │ │ └── java/ │ │ └── com/ │ │ └── example/ │ │ └── unittest/ │ │ └── NativeTests.kt │ └── main/ │ ├── AndroidManifest.xml │ ├── cpp/ │ │ ├── CMakeLists.txt │ │ ├── adder.cpp │ │ ├── adder.h │ │ ├── adder_test.cpp │ │ ├── libunittest.map.txt │ │ └── native-lib.cpp │ ├── java/ │ │ └── com/ │ │ └── example/ │ │ └── unittest/ │ │ └── MainActivity.kt │ └── res/ │ ├── drawable/ │ │ └── ic_launcher_background.xml │ ├── drawable-v24/ │ │ └── ic_launcher_foreground.xml │ ├── layout/ │ │ └── activity_main.xml │ ├── mipmap-anydpi-v26/ │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ ├── values/ │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── themes.xml │ ├── values-night/ │ │ └── themes.xml │ └── xml/ │ ├── backup_rules.xml │ └── data_extraction_rules.xml └── vectorization/ ├── .gitignore ├── README.md ├── build.gradle.kts └── src/ └── main/ ├── AndroidManifest.xml ├── cpp/ │ ├── CMakeLists.txt │ ├── auto_vectorization.h │ ├── benchmark.cpp │ ├── benchmark.h │ ├── clang_vector.h │ ├── jni.cpp │ ├── libapp.map.txt │ ├── matrix.h │ └── omp_simd.h ├── java/ │ └── com/ │ └── android/ │ └── ndk/ │ └── samples/ │ └── vectorization/ │ ├── VectorizationActivity.kt │ └── ui/ │ └── theme/ │ ├── Color.kt │ ├── Theme.kt │ └── Type.kt └── res/ ├── drawable/ │ └── ic_launcher_background.xml ├── drawable-v24/ │ └── ic_launcher_foreground.xml ├── mipmap-anydpi-v26/ │ ├── ic_launcher.xml │ └── ic_launcher_round.xml └── values/ ├── colors.xml ├── strings.xml └── themes.xml ================================================ FILE CONTENTS ================================================ ================================================ FILE: .clang-format ================================================ BasedOnStyle: Google DerivePointerAlignment: false ================================================ FILE: .github/workflows/build.yml ================================================ name: build on: workflow_dispatch: push: pull_request: jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - name: set up JDK 21 uses: actions/setup-java@v1 with: java-version: 21 - uses: pre-commit/action@v3.0.0 - name: Setup Android SDK uses: android-actions/setup-android@v3 with: packages: "cmake;4.1.0" - name: build samples run: | ./gradlew build ================================================ FILE: .gitignore ================================================ .gradle .idea **/*.iml local.properties build *~ .externalNativeBuild libwebp .DS_Store **/ndkHelperBin **/.cxx display-p3/third_party ================================================ FILE: .google/packaging.yaml ================================================ status: PUBLISHED technologies: - Android - NDK - Platform categories: - NDK languages: - C++ solutions: - Mobile github: android/ndk-samples license: apache2 ================================================ FILE: .pre-commit-config.yaml ================================================ repos: - repo: https://github.com/pre-commit/pre-commit-hooks rev: v4.4.0 hooks: - id: check-xml - id: check-yaml ================================================ FILE: ARCHITECTURE.md ================================================ # Architecture This document describes the layout of the samples repository. The top level directory is a Gradle project. This directory can be opened in Android Studio (and that will be the easiest way to work with the samples). ## Directory structure ### Samples Most subdirectories are the individual sample apps. These can't be opened in Android Studio individually, as they rely on common code from the top level project. These subdirectories have their own `build.gradle` (the Groovy DSL) or `build.gradle.kts` (the Kotlin DSL) files. In Gradle terms these are "projects". Android Studio calls them "modules". The documentation in this repository will typically call them "modules". Each sample has its own README.md that explains what features it demonstrates, as well as any unique requirements. To run a sample, use the configuration selector in the top panel of Android Studio to select the sample and then click run. For example, to run the endless-tunnel sample game: ![Select and run a sample][docs/run-sample.png] #### Build types Android Gradle modules have multiple "build types", sometimes called "variants". For most of the samples, there are only two build types: debug and release. A few samples, notably the sanitizers sample, have more. To view the build types for the modules in this repository, in the Android Studio application menu, select View -> Tool Windows -> Build Variants. A window will open that lets you select the active variant for each sample. ### build-logic The `build-logic` directory contains Gradle convention plugins used by this repository. This is where Gradle policy decisions that apply to the whole repository are made. See the README.md in that directory for more details. ### docs Documentation and supporting artifacts for this repository. Yes, for now it's just images for the READMEs and this doc. ### gradle/libs.versions.toml This is a Gradle [version catalog]. It's the central location that defines the library and plugin dependencies for each sample. The Android Gradle Plugin does not support evaluating version catalog fields in its DSL, so versions for SDK and NDK tools (`ndkVersion`, `compileSdkVersion`, `targetSdkVersion`, etc) are all defined by the convention plugins in [build-logic](#build-logic). [version catalog]: https://docs.gradle.org/current/userguide/platforms.html ### Gradle wrapper The `gradlew` and `gradlew.bat` scripts are the Gradle wrappers, macOS/Linux- and Windows batch-compatible respectively. They will manage the Gradle installation used by this repository for you, ensuring that the correct versions and environment are used. These should be used instead of running `gradle` directly. `gradle/wrapper/gradle-wrapper.properties` defines which version of Gradle will be used. This should rarely be modified manually. Android Studio's Upgrade Assistant will manage that file and upgrade to whatever version of Gradle it prefers for that version of Android Studio and Android Gradle. ### build.gradle and settings.gradle The build.gradle (or build.gradle.kts) file is the top level build file. It doesn't do anything interesting but declares which plugins will be used by the child modules. Each sample's module has its own build.gradle file that defines properties of the app. The settings.gradle (or settings.gradle.kts) file configures repositories for fetching dependencies, and declares each app module. ### Metadata directories #### .github This directory contains GitHub metadata files, such as GitHub Action workflows and Issue templates. #### .google The `packaging.yaml` file in this directory is used by Android Studio to enable the File -> New -> Import Sample feature. As this repository is a monolithic sample project, it should not need to be changed. ================================================ FILE: CONTRIBUTING.md ================================================ # How to become a contributor and submit your own code ## Contributor License Agreements We'd love to accept your sample apps and patches! Before we can take them, we have to jump a couple of legal hurdles. Please fill out either the individual or corporate Contributor License Agreement (CLA). - If you are an individual writing original source code and you're sure you own the intellectual property, then you'll need to sign an [individual CLA](http://code.google.com/legal/individual-cla-v1.0.html). - If you work for a company that wants to allow you to contribute your work, then you'll need to sign a [corporate CLA](http://code.google.com/legal/corporate-cla-v1.0.html). Follow either of the two links above to access the appropriate CLA and instructions for how to sign and return it. Once we receive it, we'll be able to accept your pull requests. ## Contributing a Patch 1. Sign a Contributor License Agreement, if you have not yet done so (see details above). 1. Create your change to the repo in question. - Fork the desired repo, develop and test your code changes. - Ensure that your code is clear and comprehensible. - Ensure that your code has an appropriate set of unit tests which all pass. 1. Submit a pull request. 1. The repo owner will review your request. If it is approved, the change will be merged. If it needs additional work, the repo owner will respond with useful comments. ================================================ FILE: LICENSE ================================================ Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: You must give any other recipients of the Work or Derivative Works a copy of this License; and You must cause any modified files to carry prominent notices stating that You changed the files; and You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. ================================================ FILE: README.md ================================================ # Android NDK Samples This repository contains sample apps that use the [Android NDK]. For an explanation of the layout of this repository, see [ARCHITECTURE.md](ARCHITECTURE.md). ## Build and run [![build](https://github.com/android/ndk-samples/actions/workflows/build.yml/badge.svg)](https://github.com/android/ndk-samples/actions) 1. Clone the repository 2. Open the whole project in Android Studio 3. Install CMake 4.1.0 via the SDK Manager (must be done manually until https://issuetracker.google.com/443137057 is fixed). 4. Select the sample you want to run in the top bar (you may need to sync gradle first) 5. Click the play button to run the sample You can also build the samples from the command line if you prefer. Use `./gradlew build` to build everything (if you're on Windows, use `.\gradlew.bat` instead of `./gradlew`). For individual tasks, see `./gradlew tasks`. To see the tasks for an individual sample, run the `tasks` task for that directory. For example, `./gradlew :camera:basic:tasks` will show the tasks for the `camera/basic` app. ## I just want something to copy from as a starting point The samples in this repository are generally not a good starting point for a production quality app. They aim to demonstrate individual NDK APIs, but often make sacrifices to be succinct that make them unsuitable for a production app. This is gradually changing, but for now you should not do this. [Now in Android](https://github.com/android/nowinandroid/) is an excellent resource for production quality apps in general, but does not touch on NDK- specific issues. https://github.com/DanAlbert/ndk-app-template can help some with that until this repository is able to. You're most likely best served by using the New Project wizard in Android Studio to create a new app, then using those resources and the samples here as a reference. Android Studio's "Native C++" template is a good starting point for typical applications that need to use some C++ via JNI. The "Game Activity" template is a good starting point for game-like apps (that is, apps that do not use the Android UI, but instead render their own UI using OpenGL or Vulkan). ## Best practices shown here There are a few best practices shown throughout this repository that should be explained, but there's no central place to discuss those in the code, so we'll discuss those here. ### `RegisterNatives` We prefer using `RegisterNatives()` via `JNI_OnLoad()` over the name-based matching that Studio's New Project Wizard will typically create, e.g. JNI functions that follow the pattern `JNIEXPORT void JNICALL Java_com_etc_ClassName_methodName()`. That approach to matching C/C++ functions to their Java `native` function (or Kotlin `external fun`) makes for a shorter demo when there are only a small number of functions, but it has a number of disadvantages. See the [JNI tips] guide for details. [JNI tips]: https://developer.android.com/ndk/guides/jni-tips#native-libraries ### Version scripts All of the app libraries shown here are built using a version script. This is a file that explicitly lists which symbols should be exported from the library, and hides all the others. Version scripts function similarly to `-fvisibility=hidden`, but can go a step further and are capable of hiding symbols in static libraries that are used by your app. Hiding as many symbols as possible results in smaller binaries that load faster, as there are fewer relocations required and LTO can do a better job. They also run faster as same-library function calls do not need to be made through the PLT. There are no good reasons to not use a version script for your NDK code. See the NDK documentation on [controlling symbol visibility] for more information. You can find these in each sample as the `lib.map.txt` file (where `` is the name of the library passed to `add_app_library()` in the `CMakeLists.txt` file). The build plumbing that uses the version scripts is in the definition of `add_app_library()` in `cmake/AppLibrary.cmake`. [controlling symbol visibility]: https://developer.android.com/ndk/guides/symbol-visibility ## Additional documentation - [Add Native Code to Your Project](https://developer.android.com/studio/projects/add-native-code.html) - [Configure NDK for Android Studio/Gradle Plugin](https://developer.android.com/studio/projects/configure-agp-ndk) - [CMake for NDK](https://developer.android.com/ndk/guides/cmake.html) ## Support If you've found an issue with a sample and you know how to fix it, please [send us a PR!](CONTRIBUTING.md). If you need to report a bug, where it needs to be filed depends on the type of issue: - Problems with the samples themselves: https://github.com/googlesamples/android-ndk/issues - Problems with the OS APIs: http://b.android.com (usually the Framework component) - Problems with NDK (that is, the compiler): https://github.com/android/ndk/issues For questions about using the NDK or the platform APIs, you can ask on: - [The NDK mailing list](https://groups.google.com/g/android-ndk) (best if you're not sure where else to ask) - The [Discussions](https://github.com/android/ndk-samples/discussions) tab of this repo (best for questions about the samples themselves) - The NDK's [Discussions](https://github.com/android/ndk/discussions) (best for questions about the NDK compilers and build systems) - [Stack Overflow](https://stackoverflow.com/questions/tagged/android) ## Additional NDK samples: - [Google Play Game Samples with Android Studio](https://github.com/playgameservices/cpp-android-basic-samples) - [Google Android Vulkan Tutorials](https://github.com/googlesamples/android-vulkan-tutorials) - [Android Vulkan API Basic Samples](https://github.com/googlesamples/vulkan-basic-samples) - [Android High Performance Audio](https://github.com/googlesamples/android-audio-high-performance) ## License Copyright 2015 The Android Open Source Project, Inc. Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you 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 https://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. [LICENSE](LICENSE) [Android NDK]: https://developer.android.com/ndk ================================================ FILE: REFERENCE.md ================================================ Android Studio/Gradle DSL References | Name | Function | Type | Options | Default | | -------------- | ------------------- | :--: | ------------ | ------- | | debuggable | Debugging Java code | bool | true / false | | | ndk.debuggable | Debugging JNI code | bool | true / false | | Notation: dot(".") notation is same as closure ("{}") notation ================================================ FILE: audio-echo/README.md ================================================ # Sample removed This sample has been removed because the API it demonstrated (OpenSLES) is deprecated. New apps should instead use [Oboe], which has its own samples. [Oboe]: https://github.com/google/oboe ================================================ FILE: base/.gitignore ================================================ /build ================================================ FILE: base/build.gradle.kts ================================================ plugins { id("ndksamples.android.library") } android { namespace = "com.android.ndk.samples.base" externalNativeBuild { cmake { path = file("src/main/cpp/CMakeLists.txt") } } buildFeatures { prefabPublishing = true } prefab { create("base") { headers = "src/main/cpp/include" } } } dependencies { implementation(libs.appcompat) implementation(libs.material) testImplementation(libs.junit) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.espresso.core) } ================================================ FILE: base/src/main/cpp/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.22.1) project(Base LANGUAGES CXX) include(AppLibrary) add_app_library(base STATIC logging.cpp ) target_compile_features(base PRIVATE cxx_std_23) target_compile_options(base PRIVATE -Wno-vla-cxx-extension) target_include_directories(base PUBLIC include) target_link_libraries(base PUBLIC log) ================================================ FILE: base/src/main/cpp/include/base/errno_restorer.h ================================================ /* * Copyright (C) 2020 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. */ #pragma once #include namespace ndksamples::base { class ErrnoRestorer { public: ErrnoRestorer() : saved_errno_(errno) {} ErrnoRestorer(const ErrnoRestorer&) = delete; ~ErrnoRestorer() { errno = saved_errno_; } ErrnoRestorer& operator=(const ErrnoRestorer&) = delete; // Allow this object to be used as part of && operation. explicit operator bool() const { return true; } private: const int saved_errno_; }; } // namespace ndksamples::base ================================================ FILE: base/src/main/cpp/include/base/logging.h ================================================ /* * Copyright (C) 2015 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. */ #pragma once /** * @file logging.h * @brief Logging and assertion utilities. * * This is a modified version of AOSP's android-base/logging.h: * https://cs.android.com/android/platform/superproject/main/+/main:system/libbase/include/android-base/logging.h * * The original file contained a lot of dependencies for things we don't need * (kernel logging, support for non-Android platforms, non-logd loggers, etc). * That's all been removed so we don't need to pull in those dependencies. * * If you copy from this sample, you may want to replace this with something * like absl, which provides a very similar (if not identical) interface for all * platforms. absl was not used here because we didn't need much, and it was * preferable to avoid an additional dependency. */ // // Google-style C++ logging. // // This header provides a C++ stream interface to logging. // // To log: // // LOG(INFO) << "Some text; " << some_value; // // Replace `INFO` with any severity from `enum LogSeverity`. // Most devices filter out VERBOSE logs by default, run // `adb shell setprop log.tag. V` to see them in adb logcat. // // To log the result of a failed function and include the string // representation of `errno` at the end: // // PLOG(ERROR) << "Write failed"; // // The output will be something like `Write failed: I/O error`. // Remember this as 'P' as in perror(3). // // To output your own types, simply implement operator<< as normal. // // By default, output goes to logcat on Android and stderr on the host. // A process can use `SetLogger` to decide where all logging goes. // Implementations are provided for logcat, stderr, and dmesg. // // By default, the process' name is used as the log tag. // Code can choose a specific log tag by defining LOG_TAG // before including this header. // This header also provides assertions: // // CHECK(must_be_true); // CHECK_EQ(a, b) << z_is_interesting_too; #include #include #include #include #include #include #include // Note: DO NOT USE DIRECTLY. Use LOG_TAG instead. #ifdef _LOG_TAG_INTERNAL #error "_LOG_TAG_INTERNAL must not be defined" #endif #ifdef LOG_TAG #define _LOG_TAG_INTERNAL LOG_TAG #else #define _LOG_TAG_INTERNAL nullptr #endif namespace ndksamples::base { enum LogSeverity { VERBOSE, DEBUG, INFO, WARNING, ERROR, FATAL_WITHOUT_ABORT, // For loggability tests, this is considered identical // to FATAL. FATAL, }; enum LogId { DEFAULT, MAIN, SYSTEM, RADIO, CRASH, }; using LogFunction = std::function; using AbortFunction = std::function; void DefaultAborter(const char* abort_message); void SetDefaultTag(const std::string& tag); // The LogdLogger sends chunks of up to ~4000 bytes at a time to logd. It does // not prevent other threads from writing to logd between sending each chunk, so // other threads may interleave their messages. If preventing interleaving is // required, then a custom logger that takes a lock before calling this logger // should be provided. class LogdLogger { public: explicit LogdLogger(LogId default_log_id = ndksamples::base::MAIN); void operator()(LogId, LogSeverity, const char* tag, const char* file, unsigned int line, const char* message); private: LogId default_log_id_; }; // Configure logging based on ANDROID_LOG_TAGS environment variable. // We need to parse a string that looks like // // *:v jdwp:d dalvikvm:d dalvikvm-gc:i dalvikvmi:i // // The tag (or '*' for the global level) comes first, followed by a colon and a // letter indicating the minimum priority level we're expected to log. This can // be used to reveal or conceal logs with specific tags. #define INIT_LOGGING_DEFAULT_LOGGER LogdLogger() void InitLogging(const std::optional default_tag = {}, std::optional log_level = {}, LogFunction&& logger = INIT_LOGGING_DEFAULT_LOGGER, AbortFunction&& aborter = DefaultAborter); #undef INIT_LOGGING_DEFAULT_LOGGER // Replace the current logger and return the old one. LogFunction SetLogger(LogFunction&& logger); // Replace the current aborter and return the old one. AbortFunction SetAborter(AbortFunction&& aborter); // A helper macro that produces an expression that accepts both a qualified name // and an unqualified name for a LogSeverity, and returns a LogSeverity value. // Note: DO NOT USE DIRECTLY. This is an implementation detail. #define SEVERITY_LAMBDA(severity) \ ([&]() { \ using ::ndksamples::base::VERBOSE; \ using ::ndksamples::base::DEBUG; \ using ::ndksamples::base::INFO; \ using ::ndksamples::base::WARNING; \ using ::ndksamples::base::ERROR; \ using ::ndksamples::base::FATAL_WITHOUT_ABORT; \ using ::ndksamples::base::FATAL; \ return (severity); \ }()) #define ABORT_AFTER_LOG_FATAL #define ABORT_AFTER_LOG_EXPR_IF(c, x) (x) #define MUST_LOG_MESSAGE(severity) false #define ABORT_AFTER_LOG_FATAL_EXPR(x) ABORT_AFTER_LOG_EXPR_IF(true, x) // Defines whether the given severity will be logged or silently swallowed. #define WOULD_LOG(severity) \ (UNLIKELY(::ndksamples::base::ShouldLog(SEVERITY_LAMBDA(severity), \ _LOG_TAG_INTERNAL)) || \ MUST_LOG_MESSAGE(severity)) // Get an ostream that can be used for logging at the given severity and to the // default destination. // // Notes: // 1) This will not check whether the severity is high enough. One should use // WOULD_LOG to filter // usage manually. // 2) This does not save and restore errno. #define LOG_STREAM(severity) \ ::ndksamples::base::LogMessage( \ __FILE__, __LINE__, SEVERITY_LAMBDA(severity), _LOG_TAG_INTERNAL, -1) \ .stream() // Logs a message to logcat on Android otherwise to stderr. If the severity is // FATAL it also causes an abort. For example: // // LOG(FATAL) << "We didn't expect to reach here"; #define LOG(severity) LOGGING_PREAMBLE(severity) && LOG_STREAM(severity) // Checks if we want to log something, and sets up appropriate RAII objects if // so. // Note: DO NOT USE DIRECTLY. This is an implementation detail. #define LOGGING_PREAMBLE(severity) \ (WOULD_LOG(severity) && \ ABORT_AFTER_LOG_EXPR_IF( \ (SEVERITY_LAMBDA(severity)) == ::ndksamples::base::FATAL, true) && \ ::ndksamples::base::ErrnoRestorer()) // A variant of LOG that also logs the current errno value. To be used when // library calls fail. #define PLOG(severity) \ LOGGING_PREAMBLE(severity) && \ ::ndksamples::base::LogMessage(__FILE__, __LINE__, \ SEVERITY_LAMBDA(severity), \ _LOG_TAG_INTERNAL, errno) \ .stream() // Marker that code is yet to be implemented. #define UNIMPLEMENTED(level) \ LOG(level) << __PRETTY_FUNCTION__ << " unimplemented " // Check whether condition x holds and LOG(FATAL) if not. The value of the // expression x is only evaluated once. Extra logging can be appended using << // after. For example: // // CHECK(false == true) results in a log message of // "Check failed: false == true". #define CHECK(x) \ LIKELY((x)) || ABORT_AFTER_LOG_FATAL_EXPR(false) || \ ::ndksamples::base::LogMessage(__FILE__, __LINE__, \ ::ndksamples::base::FATAL, \ _LOG_TAG_INTERNAL, -1) \ .stream() \ << "Check failed: " #x << " " // clang-format off // Helper for CHECK_xx(x,y) macros. #define CHECK_OP(LHS, RHS, OP) \ for (auto _values = ::ndksamples::base::MakeEagerEvaluator(LHS, RHS); \ UNLIKELY(!(_values.lhs.v OP _values.rhs.v)); \ /* empty */) \ ABORT_AFTER_LOG_FATAL \ ::ndksamples::base::LogMessage(__FILE__, __LINE__, ::ndksamples::base::FATAL, _LOG_TAG_INTERNAL, -1) \ .stream() \ << "Check failed: " << #LHS << " " << #OP << " " << #RHS << " (" #LHS "=" \ << ::ndksamples::base::LogNullGuard::Guard(_values.lhs.v) \ << ", " #RHS "=" \ << ::ndksamples::base::LogNullGuard::Guard(_values.rhs.v) \ << ") " // clang-format on // Check whether a condition holds between x and y, LOG(FATAL) if not. The value // of the expressions x and y is evaluated once. Extra logging can be appended // using << after. For example: // // CHECK_NE(0 == 1, false) results in // "Check failed: false != false (0==1=false, false=false) ". #define CHECK_EQ(x, y) CHECK_OP(x, y, ==) #define CHECK_NE(x, y) CHECK_OP(x, y, !=) #define CHECK_LE(x, y) CHECK_OP(x, y, <=) #define CHECK_LT(x, y) CHECK_OP(x, y, <) #define CHECK_GE(x, y) CHECK_OP(x, y, >=) #define CHECK_GT(x, y) CHECK_OP(x, y, >) // clang-format off // Helper for CHECK_STRxx(s1,s2) macros. #define CHECK_STROP(s1, s2, sense) \ while (UNLIKELY((strcmp(s1, s2) == 0) != (sense))) \ ABORT_AFTER_LOG_FATAL \ ::ndksamples::base::LogMessage(__FILE__, __LINE__, ::ndksamples::base::FATAL, \ _LOG_TAG_INTERNAL, -1) \ .stream() \ << "Check failed: " << "\"" << (s1) << "\"" \ << ((sense) ? " == " : " != ") << "\"" << (s2) << "\"" // clang-format on // Check for string (const char*) equality between s1 and s2, LOG(FATAL) if not. #define CHECK_STREQ(s1, s2) CHECK_STROP(s1, s2, true) #define CHECK_STRNE(s1, s2) CHECK_STROP(s1, s2, false) // Perform the pthread function call(args), LOG(FATAL) on error. #define CHECK_PTHREAD_CALL(call, args, what) \ do { \ int rc = call args; \ if (rc != 0) { \ errno = rc; \ ABORT_AFTER_LOG_FATAL \ PLOG(FATAL) << #call << " failed for " << (what); \ } \ } while (false) // DCHECKs are debug variants of CHECKs only enabled in debug builds. Generally // CHECK should be used unless profiling identifies a CHECK as being in // performance critical code. #if defined(NDEBUG) && !defined(__clang_analyzer__) static constexpr bool kEnableDChecks = false; #else static constexpr bool kEnableDChecks = true; #endif #define DCHECK(x) \ if (::ndksamples::base::kEnableDChecks) CHECK(x) #define DCHECK_EQ(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_EQ(x, y) #define DCHECK_NE(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_NE(x, y) #define DCHECK_LE(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_LE(x, y) #define DCHECK_LT(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_LT(x, y) #define DCHECK_GE(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_GE(x, y) #define DCHECK_GT(x, y) \ if (::ndksamples::base::kEnableDChecks) CHECK_GT(x, y) #define DCHECK_STREQ(s1, s2) \ if (::ndksamples::base::kEnableDChecks) CHECK_STREQ(s1, s2) #define DCHECK_STRNE(s1, s2) \ if (::ndksamples::base::kEnableDChecks) CHECK_STRNE(s1, s2) namespace log_detail { // Temporary storage for a single eagerly evaluated check expression operand. template struct Storage { template explicit constexpr Storage(U&& u) : v(std::forward(u)) {} explicit Storage(const Storage& t) = delete; explicit Storage(Storage&& t) = delete; T v; }; // Partial specialization for smart pointers to avoid copying. template struct Storage> { explicit constexpr Storage(const std::unique_ptr& ptr) : v(ptr.get()) {} const T* v; }; template struct Storage> { explicit constexpr Storage(const std::shared_ptr& ptr) : v(ptr.get()) {} const T* v; }; // Type trait that checks if a type is a (potentially const) char pointer. template struct IsCharPointer { using Pointee = std::remove_cv_t>; static constexpr bool value = std::is_pointer_v && (std::is_same_v || std::is_same_v || std::is_same_v); }; // Counterpart to Storage that depends on both operands. This is used to prevent // char pointers being treated as strings in the log output - they might point // to buffers of unprintable binary data. template struct StorageTypes { static constexpr bool voidptr = IsCharPointer::value && IsCharPointer::value; using LHSType = std::conditional_t; using RHSType = std::conditional_t; }; // Temporary class created to evaluate the LHS and RHS, used with // MakeEagerEvaluator to infer the types of LHS and RHS. template struct EagerEvaluator { template constexpr EagerEvaluator(A&& l, B&& r) : lhs(std::forward(l)), rhs(std::forward(r)) {} const Storage::LHSType> lhs; const Storage::RHSType> rhs; }; } // namespace log_detail // Converts std::nullptr_t and null char pointers to the string "null" // when writing the failure message. template struct LogNullGuard { static const T& Guard(const T& v) { return v; } }; template <> struct LogNullGuard { static const char* Guard(const std::nullptr_t&) { return "(null)"; } }; template <> struct LogNullGuard { static const char* Guard(const char* v) { return v ? v : "(null)"; } }; template <> struct LogNullGuard { static const char* Guard(const char* v) { return v ? v : "(null)"; } }; // Helper function for CHECK_xx. template constexpr auto MakeEagerEvaluator(LHS&& lhs, RHS&& rhs) { return log_detail::EagerEvaluator, std::decay_t>( std::forward(lhs), std::forward(rhs)); } // Data for the log message, not stored in LogMessage to avoid increasing the // stack size. class LogMessageData; // A LogMessage is a temporarily scoped object used by LOG and the unlikely part // of a CHECK. The destructor will abort if the severity is FATAL. class LogMessage { public: // LogId has been deprecated, but this constructor must exist for prebuilts. LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag, int error); LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error); DISALLOW_COPY_AND_ASSIGN(LogMessage); ~LogMessage(); // Returns the stream associated with the message, the LogMessage performs // output when it goes out of scope. std::ostream& stream(); // The routine that performs the actual logging. static void LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, const char* msg); private: const std::unique_ptr data_; }; // Get the minimum severity level for logging. LogSeverity GetMinimumLogSeverity(); // Set the minimum severity level for logging, returning the old severity. LogSeverity SetMinimumLogSeverity(LogSeverity new_severity); // Return whether or not a log message with the associated tag should be logged. bool ShouldLog(LogSeverity severity, const char* tag); // Allows to temporarily change the minimum severity level for logging. class ScopedLogSeverity { public: explicit ScopedLogSeverity(LogSeverity level); ~ScopedLogSeverity(); private: LogSeverity old_; }; } // namespace ndksamples::base namespace std { // NOLINT(cert-dcl58-cpp) // Emit a warning of ostream<< with std::string*. The intention was most likely // to print *string. // // Note: for this to work, we need to have this in a namespace. // Note: using a pragma because "-Wgcc-compat" (included in "-Weverything") // complains about // diagnose_if. // Note: to print the pointer, use "<< static_cast(string_pointer)" // instead. Note: a not-recommended alternative is to let Clang ignore the // warning by adding // -Wno-user-defined-warnings to CPPFLAGS. #pragma clang diagnostic push #pragma clang diagnostic ignored "-Wgcc-compat" #define OSTREAM_STRING_POINTER_USAGE_WARNING \ __attribute__(( \ diagnose_if(true, "Unexpected logging of string pointer", "warning"))) inline OSTREAM_STRING_POINTER_USAGE_WARNING std::ostream& operator<<( std::ostream& stream, const std::string* string_pointer) { return stream << static_cast(string_pointer); } #pragma clang diagnostic pop } // namespace std ================================================ FILE: base/src/main/cpp/include/base/macros.h ================================================ /* * Copyright (C) 2015 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. */ #pragma once #include // for size_t #include // A macro to disallow the copy constructor and operator= functions // This must be placed in the private: declarations for a class. // // For disallowing only assign or copy, delete the relevant operator or // constructor, for example: // void operator=(const TypeName&) = delete; // Note, that most uses of DISALLOW_ASSIGN and DISALLOW_COPY are broken // semantically, one should either use disallow both or neither. Try to // avoid these in new code. #define DISALLOW_COPY_AND_ASSIGN(TypeName) \ TypeName(const TypeName&) = delete; \ void operator=(const TypeName&) = delete // 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. #define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName) \ TypeName() = delete; \ DISALLOW_COPY_AND_ASSIGN(TypeName) // The arraysize(arr) macro returns the # of elements in an array arr. // The expression is a compile-time constant, and therefore can be // used in defining new arrays, for example. If you use arraysize on // a pointer by mistake, you will get a compile-time error. // // One caveat is that arraysize() doesn't accept any array of an // anonymous type or a type defined inside a function. In these rare // cases, you have to use the unsafe ARRAYSIZE_UNSAFE() macro below. This is // due to a limitation in C++'s template system. The limitation might // eventually be removed, but it hasn't happened yet. // This template function declaration is used in defining arraysize. // Note that the function doesn't need an implementation, as we only // use its type. template char (&ArraySizeHelper(T (&array)[N]))[N]; // NOLINT(readability/casting) #define arraysize(array) (sizeof(ArraySizeHelper(array))) #define SIZEOF_MEMBER(t, f) sizeof(std::declval().f) // Changing this definition will cause you a lot of pain. A majority of // vendor code defines LIKELY and UNLIKELY this way, and includes // this header through an indirect path. #define LIKELY(exp) (__builtin_expect((exp) != 0, true)) #define UNLIKELY(exp) (__builtin_expect((exp) != 0, false)) /// True if the (runtime) version of the OS is at least x. /// /// Clang is very particular about how __builtin_available is used. Logical /// operations (including negation) may not be combined with /// __builtin_available, so to negate this check you must do: /// /// if (API_AT_LEAST(x)) { /// } else { /// // do negated stuff /// } #define API_AT_LEAST(x) __builtin_available(android x, *) /// Marks a function as not callable on OS versions older than x. /// /// This is a minor abuse of Clang's __attribute__((availability)), so the /// diagnostic for this will be a little odd, but it allows us to extract /// functions from code that already has an API_AT_LEAST guard without rewriting /// the guard in every called function. #define REQUIRES_API(x) __INTRODUCED_IN(x) ================================================ FILE: base/src/main/cpp/logging.cpp ================================================ /* * Copyright (C) 2015 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. */ #include "base/logging.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "base/macros.h" #include "logging_splitters.h" namespace ndksamples::base { static const char* GetFileBasename(const char* file) { // We can't use basename(3) even on Unix because the Mac doesn't // have a non-modifying basename. const char* last_slash = strrchr(file, '/'); if (last_slash != nullptr) { return last_slash + 1; } return file; } static int32_t LogIdTolog_id_t(LogId log_id) { switch (log_id) { case MAIN: return LOG_ID_MAIN; case SYSTEM: return LOG_ID_SYSTEM; case RADIO: return LOG_ID_RADIO; case CRASH: return LOG_ID_CRASH; case DEFAULT: default: return LOG_ID_DEFAULT; } } static int32_t LogSeverityToPriority(LogSeverity severity) { switch (severity) { case VERBOSE: return ANDROID_LOG_VERBOSE; case DEBUG: return ANDROID_LOG_DEBUG; case INFO: return ANDROID_LOG_INFO; case WARNING: return ANDROID_LOG_WARN; case ERROR: return ANDROID_LOG_ERROR; case FATAL_WITHOUT_ABORT: case FATAL: default: return ANDROID_LOG_FATAL; } } static LogFunction& Logger() { static auto& logger = *new LogFunction(LogdLogger()); return logger; } static AbortFunction& Aborter() { static auto& aborter = *new AbortFunction(DefaultAborter); return aborter; } // Only used for Q fallback. static std::recursive_mutex& TagLock() { static auto& tag_lock = *new std::recursive_mutex(); return tag_lock; } static std::string* gDefaultTag; void SetDefaultTag(const std::string_view tag) { std::lock_guard lock(TagLock()); if (gDefaultTag != nullptr) { delete gDefaultTag; gDefaultTag = nullptr; } if (!tag.empty()) { gDefaultTag = new std::string(tag); } } static bool gInitialized = false; // Only used for Q fallback. static LogSeverity gMinimumLogSeverity = INFO; void DefaultAborter(const char* abort_message) { android_set_abort_message(abort_message); abort(); } static void LogdLogChunk(LogId id, LogSeverity severity, const char* tag, const char* message) { int32_t lg_id = LogIdTolog_id_t(id); int32_t priority = LogSeverityToPriority(severity); __android_log_buf_print(lg_id, priority, tag, "%s", message); } LogdLogger::LogdLogger(LogId default_log_id) : default_log_id_(default_log_id) {} void LogdLogger::operator()(LogId id, LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* message) { if (id == DEFAULT) { id = default_log_id_; } SplitByLogdChunks(id, severity, tag, file, line, message, LogdLogChunk); } void InitLogging(const std::optional default_tag, std::optional log_level, LogFunction&& logger, AbortFunction&& aborter) { SetLogger(std::forward(logger)); SetAborter(std::forward(aborter)); if (gInitialized) { return; } gInitialized = true; if (default_tag.has_value()) { SetDefaultTag(default_tag.value()); } const char* tags = getenv("ANDROID_LOG_TAGS"); if (tags == nullptr) { return; } if (log_level.has_value()) { SetMinimumLogSeverity(log_level.value()); } } LogFunction SetLogger(LogFunction&& logger) { LogFunction old_logger = std::move(Logger()); Logger() = std::move(logger); return old_logger; } AbortFunction SetAborter(AbortFunction&& aborter) { AbortFunction old_aborter = std::move(Aborter()); Aborter() = std::move(aborter); return old_aborter; } // This indirection greatly reduces the stack impact of having lots of // checks/logging in a function. class LogMessageData { public: LogMessageData(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error) : file_(GetFileBasename(file)), line_number_(line), severity_(severity), tag_(tag), error_(error) {} DISALLOW_COPY_AND_ASSIGN(LogMessageData); const char* GetFile() const { return file_; } unsigned int GetLineNumber() const { return line_number_; } LogSeverity GetSeverity() const { return severity_; } const char* GetTag() const { return tag_; } int GetError() const { return error_; } std::ostream& GetBuffer() { return buffer_; } std::string ToString() const { return buffer_.str(); } private: std::ostringstream buffer_; const char* const file_; const unsigned int line_number_; const LogSeverity severity_; const char* const tag_; const int error_; }; LogMessage::LogMessage(const char* file, unsigned int line, LogId, LogSeverity severity, const char* tag, int error) : LogMessage(file, line, severity, tag, error) {} LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, const char* tag, int error) : data_(new LogMessageData(file, line, severity, tag, error)) {} LogMessage::~LogMessage() { // Check severity again. This is duplicate work wrt/ LOG macros, but not // LOG_STREAM. if (!WOULD_LOG(data_->GetSeverity())) { return; } // Finish constructing the message. if (data_->GetError() != -1) { data_->GetBuffer() << ": " << strerror(data_->GetError()); } std::string msg(data_->ToString()); if (data_->GetSeverity() == FATAL) { // Set the bionic abort message early to avoid liblog doing it // with the individual lines, so that we get the whole message. android_set_abort_message(msg.c_str()); } LogLine(data_->GetFile(), data_->GetLineNumber(), data_->GetSeverity(), data_->GetTag(), msg.c_str()); // Abort if necessary. if (data_->GetSeverity() == FATAL) { Aborter()(msg.c_str()); } } std::ostream& LogMessage::stream() { return data_->GetBuffer(); } void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity severity, const char* tag, const char* message) { if (tag == nullptr) { std::lock_guard lock(TagLock()); if (gDefaultTag == nullptr) { gDefaultTag = new std::string(getprogname()); } Logger()(DEFAULT, severity, gDefaultTag->c_str(), file, line, message); } else { Logger()(DEFAULT, severity, tag, file, line, message); } } LogSeverity GetMinimumLogSeverity() { return gMinimumLogSeverity; } bool ShouldLog(LogSeverity severity, const char*) { return severity >= gMinimumLogSeverity; } LogSeverity SetMinimumLogSeverity(LogSeverity new_severity) { LogSeverity old_severity = gMinimumLogSeverity; gMinimumLogSeverity = new_severity; return old_severity; } ScopedLogSeverity::ScopedLogSeverity(LogSeverity new_severity) { old_ = SetMinimumLogSeverity(new_severity); } ScopedLogSeverity::~ScopedLogSeverity() { SetMinimumLogSeverity(old_); } } // namespace ndksamples::base ================================================ FILE: base/src/main/cpp/logging_splitters.h ================================================ /* * Copyright (C) 2020 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. */ #pragma once #include #include #include #include "base/logging.h" #define LOGGER_ENTRY_MAX_PAYLOAD 4068 // This constant is not in the NDK. namespace ndksamples::base { // This splits the message up line by line, by calling log_function with a // pointer to the start of each line and the size up to the newline character. // It sends size = -1 for the final line. template static void SplitByLines(const char* msg, const F& log_function, Args&&... args) { const char* newline = strchr(msg, '\n'); while (newline != nullptr) { log_function(msg, newline - msg, args...); msg = newline + 1; newline = strchr(msg, '\n'); } log_function(msg, -1, args...); } // This splits the message up into chunks that logs can process delimited by new // lines. It calls log_function with the exact null terminated message that // should be sent to logd. Note, despite the loops and snprintf's, if severity // is not fatal and there are no new lines, this function simply calls // log_function with msg without any extra overhead. template static void SplitByLogdChunks(LogId log_id, LogSeverity severity, const char* tag, const char* file, unsigned int line, const char* msg, const F& log_function) { // The maximum size of a payload, after the log header that logd will accept // is LOGGER_ENTRY_MAX_PAYLOAD, so subtract the other elements in the payload // to find the size of the string that we can log in each pass. The protocol // is documented in liblog/README.protocol.md. Specifically we subtract a byte // for the priority, the length of the tag + its null terminator, and an // additional byte for the null terminator on the payload. We subtract an // additional 32 bytes for slack, similar to java/android/util/Log.java. ptrdiff_t max_size = LOGGER_ENTRY_MAX_PAYLOAD - strlen(tag) - 35; if (max_size <= 0) { abort(); } // If we're logging a fatal message, we'll append the file and line numbers. bool add_file = file != nullptr && (severity == FATAL || severity == FATAL_WITHOUT_ABORT); std::string file_header; if (add_file) { file_header = std::format("{}:{}]", file, line); } int file_header_size = file_header.size(); __attribute__((uninitialized)) char logd_chunk[max_size + 1]; ptrdiff_t chunk_position = 0; auto call_log_function = [&]() { log_function(log_id, severity, tag, logd_chunk); chunk_position = 0; }; auto write_to_logd_chunk = [&](const char* message, int length) { int size_written = 0; const char* new_line = chunk_position > 0 ? "\n" : ""; if (add_file) { size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position, "%s%s%.*s", new_line, file_header.c_str(), length, message); } else { size_written = snprintf(logd_chunk + chunk_position, sizeof(logd_chunk) - chunk_position, "%s%.*s", new_line, length, message); } // This should never fail, if it does and we set size_written to 0, which // will skip this line and move to the next one. if (size_written < 0) { size_written = 0; } chunk_position += size_written; }; const char* newline = strchr(msg, '\n'); while (newline != nullptr) { // If we have data in the buffer and this next line doesn't fit, write the // buffer. if (chunk_position != 0 && chunk_position + (newline - msg) + 1 + file_header_size > max_size) { call_log_function(); } // Otherwise, either the next line fits or we have any empty buffer and too // large of a line to ever fit, in both cases, we add it to the buffer and // continue. write_to_logd_chunk(msg, newline - msg); msg = newline + 1; newline = strchr(msg, '\n'); } // If we have left over data in the buffer and we can fit the rest of msg, add // it to the buffer then write the buffer. if (chunk_position != 0 && chunk_position + static_cast(strlen(msg)) + 1 + file_header_size <= max_size) { write_to_logd_chunk(msg, -1); call_log_function(); } else { // If the buffer is not empty and we can't fit the rest of msg into it, // write its contents. if (chunk_position != 0) { call_log_function(); } // Then write the rest of the msg. if (add_file) { snprintf(logd_chunk, sizeof(logd_chunk), "%s%s", file_header.c_str(), msg); log_function(log_id, severity, tag, logd_chunk); } else { log_function(log_id, severity, tag, msg); } } } } // namespace ndksamples::base ================================================ FILE: bitmap-plasma/README.md ================================================ # Bitmap Plasma Bitmap Plasma is an Android sample that uses JNI to render a plasma effect in an Android [Bitmap](http://developer.android.com/reference/android/graphics/Bitmap.html) from C code. ## Screenshots ![screenshot](screenshot.png) ================================================ FILE: bitmap-plasma/app/build.gradle ================================================ plugins { id "ndksamples.android.application" } android { namespace 'com.example.plasma' defaultConfig { applicationId 'com.example.plasma' } externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' } } buildFeatures { prefab true } } dependencies { implementation project(":base") } ================================================ FILE: bitmap-plasma/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: bitmap-plasma/app/src/main/cpp/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.22.1) project(BitmapPlasma LANGUAGES CXX) include(AppLibrary) find_package(base CONFIG REQUIRED) add_app_library(plasma SHARED jni.cpp plasma.cpp) target_link_libraries(plasma base::base android jnigraphics log m ) ================================================ FILE: bitmap-plasma/app/src/main/cpp/jni.cpp ================================================ // Copyright (C) 2025 The Android Open Source Project // SPDX-License-Identifier: Apache-2.0 #include #include #include "plasma.h" extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } jclass c = env->FindClass("com/example/plasma/PlasmaView"); if (c == nullptr) return JNI_ERR; static const JNINativeMethod methods[] = { {"renderPlasma", "(Landroid/graphics/Bitmap;J)V", reinterpret_cast(RenderPlasma)}, }; int rc = env->RegisterNatives(c, methods, arraysize(methods)); if (rc != JNI_OK) return rc; return JNI_VERSION_1_6; } ================================================ FILE: bitmap-plasma/app/src/main/cpp/libplasma.map.txt ================================================ LIBPLASMA { global: JNI_OnLoad; local: *; }; ================================================ FILE: bitmap-plasma/app/src/main/cpp/plasma.cpp ================================================ /* * Copyright (C) 2010 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. */ #include #include #include #include #include #include #include #define LOG_TAG "libplasma" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) /* Set to 1 to enable debug log traces. */ #define DEBUG 0 /* Set to 1 to optimize memory stores when generating plasma. */ #define OPTIMIZE_WRITES 1 /* Return current time in milliseconds */ static double now_ms(void) { struct timeval tv; gettimeofday(&tv, NULL); return tv.tv_sec * 1000. + tv.tv_usec / 1000.; } /* We're going to perform computations for every pixel of the target * bitmap. floating-point operations are very slow on ARMv5, and not * too bad on ARMv7 with the exception of trigonometric functions. * * For better performance on all platforms, we're going to use fixed-point * arithmetic and all kinds of tricks */ typedef int32_t Fixed; #define FIXED_BITS 16 #define FIXED_ONE (1 << FIXED_BITS) #define FIXED_AVERAGE(x, y) (((x) + (y)) >> 1) #define FIXED_FROM_INT(x) ((x) << FIXED_BITS) #define FIXED_TO_INT(x) ((x) >> FIXED_BITS) #define FIXED_FROM_FLOAT(x) ((Fixed)((x) * FIXED_ONE)) #define FIXED_TO_FLOAT(x) ((x) / (1. * FIXED_ONE)) #define FIXED_MUL(x, y) (((int64_t)(x) * (y)) >> FIXED_BITS) #define FIXED_DIV(x, y) (((int64_t)(x) * FIXED_ONE) / (y)) #define FIXED_DIV2(x) ((x) >> 1) #define FIXED_AVERAGE(x, y) (((x) + (y)) >> 1) #define FIXED_FRAC(x) ((x) & ((1 << FIXED_BITS) - 1)) #define FIXED_TRUNC(x) ((x) & ~((1 << FIXED_BITS) - 1)) #define FIXED_FROM_INT_FLOAT(x, f) (Fixed)((x) * (FIXED_ONE * (f))) typedef int32_t Angle; #define ANGLE_BITS 9 #if ANGLE_BITS < 8 #error ANGLE_BITS must be at least 8 #endif #define ANGLE_2PI (1 << ANGLE_BITS) #define ANGLE_PI (1 << (ANGLE_BITS - 1)) #define ANGLE_PI2 (1 << (ANGLE_BITS - 2)) #define ANGLE_PI4 (1 << (ANGLE_BITS - 3)) #define ANGLE_FROM_FLOAT(x) (Angle)((x) * ANGLE_PI / M_PI) #define ANGLE_TO_FLOAT(x) ((x) * M_PI / ANGLE_PI) #if ANGLE_BITS <= FIXED_BITS #define ANGLE_FROM_FIXED(x) (Angle)((x) >> (FIXED_BITS - ANGLE_BITS)) #define ANGLE_TO_FIXED(x) (Fixed)((x) << (FIXED_BITS - ANGLE_BITS)) #else #define ANGLE_FROM_FIXED(x) (Angle)((x) << (ANGLE_BITS - FIXED_BITS)) #define ANGLE_TO_FIXED(x) (Fixed)((x) >> (ANGLE_BITS - FIXED_BITS)) #endif static Fixed angle_sin_tab[ANGLE_2PI + 1]; static void init_angles(void) { int nn; for (nn = 0; nn < ANGLE_2PI + 1; nn++) { double radians = nn * M_PI / ANGLE_PI; angle_sin_tab[nn] = FIXED_FROM_FLOAT(sin(radians)); } } static __inline__ Fixed angle_sin(Angle a) { return angle_sin_tab[(uint32_t)a & (ANGLE_2PI - 1)]; } static __inline__ Fixed fixed_sin(Fixed f) { return angle_sin(ANGLE_FROM_FIXED(f)); } /* Color palette used for rendering the plasma */ #define PALETTE_BITS 8 #define PALETTE_SIZE (1 << PALETTE_BITS) #if PALETTE_BITS > FIXED_BITS #error PALETTE_BITS must be smaller than FIXED_BITS #endif static uint16_t palette[PALETTE_SIZE]; static uint16_t make565(int red, int green, int blue) { return (uint16_t)(((red << 8) & 0xf800) | ((green << 3) & 0x07e0) | ((blue >> 3) & 0x001f)); } static void init_palette(void) { int nn, mm = 0; /* fun with colors */ for (nn = 0; nn < PALETTE_SIZE / 4; nn++) { int jj = (nn - mm) * 4 * 255 / PALETTE_SIZE; palette[nn] = make565(255, jj, 255 - jj); } for (mm = nn; nn < PALETTE_SIZE / 2; nn++) { int jj = (nn - mm) * 4 * 255 / PALETTE_SIZE; palette[nn] = make565(255 - jj, 255, jj); } for (mm = nn; nn < PALETTE_SIZE * 3 / 4; nn++) { int jj = (nn - mm) * 4 * 255 / PALETTE_SIZE; palette[nn] = make565(0, 255 - jj, 255); } for (mm = nn; nn < PALETTE_SIZE; nn++) { int jj = (nn - mm) * 4 * 255 / PALETTE_SIZE; palette[nn] = make565(jj, 0, 255); } } static __inline__ uint16_t palette_from_fixed(Fixed x) { if (x < 0) x = -x; if (x >= FIXED_ONE) x = FIXED_ONE - 1; int idx = FIXED_FRAC(x) >> (FIXED_BITS - PALETTE_BITS); return palette[idx & (PALETTE_SIZE - 1)]; } /* Angles expressed as fixed point radians */ static void init_tables(void) { init_palette(); init_angles(); } static void fill_plasma(AndroidBitmapInfo* info, void* pixels, double t) { Fixed yt1 = FIXED_FROM_FLOAT(t / 1230.); Fixed yt2 = yt1; Fixed xt10 = FIXED_FROM_FLOAT(t / 3000.); Fixed xt20 = xt10; #define YT1_INCR FIXED_FROM_FLOAT(1 / 100.) #define YT2_INCR FIXED_FROM_FLOAT(1 / 163.) for (uint32_t yy = 0; yy < info->height; yy++) { uint16_t* line = (uint16_t*)pixels; Fixed base = fixed_sin(yt1) + fixed_sin(yt2); Fixed xt1 = xt10; Fixed xt2 = xt20; yt1 += YT1_INCR; yt2 += YT2_INCR; #define XT1_INCR FIXED_FROM_FLOAT(1 / 173.) #define XT2_INCR FIXED_FROM_FLOAT(1 / 242.) #if OPTIMIZE_WRITES /* optimize memory writes by generating one aligned 32-bit store * for every pair of pixels. */ uint16_t* line_end = line + info->width; if (line < line_end) { if (((uint32_t)(uintptr_t)line & 3) != 0) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; line[0] = palette_from_fixed(ii >> 2); line++; } while (line + 2 <= line_end) { Fixed i1 = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; Fixed i2 = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; uint32_t pixel = ((uint32_t)palette_from_fixed(i1 >> 2) << 16) | (uint32_t)palette_from_fixed(i2 >> 2); ((uint32_t*)line)[0] = pixel; line += 2; } if (line < line_end) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); line[0] = palette_from_fixed(ii >> 2); line++; } } #else /* !OPTIMIZE_WRITES */ int xx; for (xx = 0; xx < info->width; xx++) { Fixed ii = base + fixed_sin(xt1) + fixed_sin(xt2); xt1 += XT1_INCR; xt2 += XT2_INCR; line[xx] = palette_from_fixed(ii / 4); } #endif /* !OPTIMIZE_WRITES */ // go to next line pixels = (char*)pixels + info->stride; } } /* simple stats management */ typedef struct { double renderTime; double frameTime; } FrameStats; #define MAX_FRAME_STATS 200 #define MAX_PERIOD_MS 1500 typedef struct { double firstTime; double lastTime; double frameTime; int firstFrame; int numFrames; FrameStats frames[MAX_FRAME_STATS]; } Stats; static void stats_init(Stats* s) { s->lastTime = now_ms(); s->firstTime = 0.; s->firstFrame = 0; s->numFrames = 0; } static void stats_startFrame(Stats* s) { s->frameTime = now_ms(); } static void stats_endFrame(Stats* s) { double now = now_ms(); double renderTime = now - s->frameTime; double frameTime = now - s->lastTime; int nn; if (now - s->firstTime >= MAX_PERIOD_MS) { if (s->numFrames > 0) { double minRender, maxRender, avgRender; double minFrame, maxFrame, avgFrame; int count; nn = s->firstFrame; minRender = maxRender = avgRender = s->frames[nn].renderTime; minFrame = maxFrame = avgFrame = s->frames[nn].frameTime; for (count = s->numFrames; count > 0; count--) { nn += 1; if (nn >= MAX_FRAME_STATS) nn -= MAX_FRAME_STATS; double render = s->frames[nn].renderTime; if (render < minRender) minRender = render; if (render > maxRender) maxRender = render; double frame = s->frames[nn].frameTime; if (frame < minFrame) minFrame = frame; if (frame > maxFrame) maxFrame = frame; avgRender += render; avgFrame += frame; } avgRender /= s->numFrames; avgFrame /= s->numFrames; LOGI( "frame/s (avg,min,max) = (%.1f,%.1f,%.1f) " "render time ms (avg,min,max) = (%.1f,%.1f,%.1f)\n", 1000. / avgFrame, 1000. / maxFrame, 1000. / minFrame, avgRender, minRender, maxRender); } s->numFrames = 0; s->firstFrame = 0; s->firstTime = now; } nn = s->firstFrame + s->numFrames; if (nn >= MAX_FRAME_STATS) nn -= MAX_FRAME_STATS; s->frames[nn].renderTime = renderTime; s->frames[nn].frameTime = frameTime; if (s->numFrames < MAX_FRAME_STATS) { s->numFrames += 1; } else { s->firstFrame += 1; if (s->firstFrame >= MAX_FRAME_STATS) s->firstFrame -= MAX_FRAME_STATS; } s->lastTime = now; } void RenderPlasma(JNIEnv* env, jclass, jobject bitmap, jlong time_ms) { AndroidBitmapInfo info; void* pixels; int ret; static Stats stats; static int init; if (!init) { init_tables(); stats_init(&stats); init = 1; } if ((ret = AndroidBitmap_getInfo(env, bitmap, &info)) < 0) { LOGE("AndroidBitmap_getInfo() failed ! error=%d", ret); return; } if (info.format != ANDROID_BITMAP_FORMAT_RGB_565) { LOGE("Bitmap format is not RGB_565 !"); return; } if ((ret = AndroidBitmap_lockPixels(env, bitmap, &pixels)) < 0) { LOGE("AndroidBitmap_lockPixels() failed ! error=%d", ret); } stats_startFrame(&stats); /* Now fill the values with a nice little plasma */ fill_plasma(&info, pixels, time_ms); AndroidBitmap_unlockPixels(env, bitmap); stats_endFrame(&stats); } ================================================ FILE: bitmap-plasma/app/src/main/cpp/plasma.h ================================================ // Copyright (C) 2025 The Android Open Source Project // SPDX-License-Identifier: Apache-2.0 #pragma once #include void RenderPlasma(JNIEnv* env, jclass, jobject bitmap, jlong time_ms); ================================================ FILE: bitmap-plasma/app/src/main/java/com/example/plasma/Plasma.java ================================================ /* * Copyright (C) 2010 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.example.plasma; import android.annotation.SuppressLint; import android.app.Activity; import android.graphics.Point; import android.os.Bundle; import android.content.Context; import android.view.View; import android.graphics.Bitmap; import android.graphics.Canvas; import android.view.Display; import android.view.WindowManager; public class Plasma extends Activity { // Called when the activity is first created. @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Display display = getWindowManager().getDefaultDisplay(); Point displaySize = new Point(); display.getSize(displaySize); setContentView(new PlasmaView(this, displaySize.x, displaySize.y)); } // load our native library static { System.loadLibrary("plasma"); } } // Custom view for rendering plasma. // // Note: suppressing lint wrarning for ViewConstructor since it is // manually set from the activity and not used in any layout. @SuppressLint("ViewConstructor") class PlasmaView extends View { private Bitmap mBitmap; private long mStartTime; // implementend by libplasma.so private static native void renderPlasma(Bitmap bitmap, long time_ms); public PlasmaView(Context context, int width, int height) { super(context); mBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.RGB_565); mStartTime = System.currentTimeMillis(); } @Override protected void onDraw(Canvas canvas) { renderPlasma(mBitmap, System.currentTimeMillis() - mStartTime); canvas.drawBitmap(mBitmap, 0, 0, null); // force a redraw, with a different time-based pattern. invalidate(); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { mBitmap = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565); } } ================================================ FILE: bitmap-plasma/app/src/main/res/values/strings.xml ================================================ Plasma ================================================ FILE: build-logic/.gitignore ================================================ /bin ================================================ FILE: build-logic/README.md ================================================ # Convention plugins This directory contains [convention plugins] used by the NDK samples. These are used to remove Gradle boiler plate from individual samples in favor of common configuration here. Using convention plugins for single module projects is overkill, but any non-trivial app will likely need their own eventually. See [Now In Android's build-logic][nia-build-logic] for a more thorough example of building convention plugins for Android projects. [convention plugins]: https://docs.gradle.org/current/samples/sample_convention_plugins.html [nia-build-logic]: https://github.com/android/nowinandroid/blob/main/build-logic/README.md ================================================ FILE: build-logic/build.gradle.kts ================================================ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { id("java-gradle-plugin") `kotlin-dsl` alias(libs.plugins.jetbrains.kotlin.jvm) } java { sourceCompatibility = JavaVersion.VERSION_17 targetCompatibility = JavaVersion.VERSION_17 } tasks.withType().configureEach { kotlinOptions { jvmTarget = JavaVersion.VERSION_17.toString() } } dependencies { compileOnly(libs.android.gradlePlugin) compileOnly(libs.kotlin.gradlePlugin) } gradlePlugin { plugins { register("androidApplication") { id = "ndksamples.android.application" implementationClass = "com.android.ndk.samples.buildlogic.AndroidApplicationConventionPlugin" } register("androidLibrary") { id = "ndksamples.android.library" implementationClass = "com.android.ndk.samples.buildlogic.AndroidLibraryConventionPlugin" } register("kotlinAndroid") { id = "ndksamples.android.kotlin" implementationClass = "com.android.ndk.samples.buildlogic.KotlinConventionPlugin" } } } ================================================ FILE: build-logic/settings.gradle.kts ================================================ dependencyResolutionManagement { repositories { google() mavenCentral() } versionCatalogs { create("libs") { from(files("../gradle/libs.versions.toml")) } } } rootProject.name = "build-logic" ================================================ FILE: build-logic/src/main/java/com/android/ndk/samples/buildlogic/AndroidApplicationConventionPlugin.kt ================================================ package com.android.ndk.samples.buildlogic import com.android.build.api.dsl.ApplicationExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure class AndroidApplicationConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { with(pluginManager) { apply("com.android.application") } extensions.configure { compileSdk = Versions.COMPILE_SDK ndkVersion = Versions.NDK externalNativeBuild { cmake { version = Versions.CMAKE } } defaultConfig { minSdk = Versions.MIN_SDK targetSdk = Versions.TARGET_SDK externalNativeBuild { cmake { arguments.add("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON") arguments.add("-DCMAKE_MODULE_PATH=${rootDir.resolve("cmake")}") } } ndk { // riscv64 isn't a supported Android ABI yet (August 2025), but we're // enabling it here as part of that experiment. Until it's a supported ABI, // don't include this in your app, as Play will block uploads of APKs which // contain riscv64 libraries. abiFilters.addAll( listOf( "arm64-v8a", "armeabi-v7a", "riscv64", "x86", "x86_64", ) ) } } compileOptions { sourceCompatibility = Versions.JAVA targetCompatibility = Versions.JAVA } // Studio will not automatically pass logcat through ndk-stack, so we need to avoid // stripping debug binaries if we want the crash trace to be readable. buildTypes { debug { packaging { jniLibs { keepDebugSymbols += "**/*.so" } } } } } } } } ================================================ FILE: build-logic/src/main/java/com/android/ndk/samples/buildlogic/AndroidLibraryConventionPlugin.kt ================================================ package com.android.ndk.samples.buildlogic import com.android.build.api.dsl.LibraryExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure class AndroidLibraryConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { with(pluginManager) { apply("com.android.library") } extensions.configure { compileSdk = Versions.COMPILE_SDK ndkVersion = Versions.NDK externalNativeBuild { cmake { version = Versions.CMAKE } } defaultConfig { minSdk = Versions.MIN_SDK lint { targetSdk = Versions.TARGET_SDK } testOptions { targetSdk = Versions.TARGET_SDK } externalNativeBuild { cmake { arguments.add("-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON") arguments.add("-DCMAKE_MODULE_PATH=${rootDir.resolve("cmake")}") } } ndk { // riscv64 isn't a supported Android ABI yet (August 2025), but we're // enabling it here as part of that experiment. Until it's a supported ABI, // don't include this in your app, as Play will block uploads of APKs which // contain riscv64 libraries. abiFilters.addAll( listOf( "arm64-v8a", "armeabi-v7a", "riscv64", "x86", "x86_64", ) ) } } compileOptions { sourceCompatibility = Versions.JAVA targetCompatibility = Versions.JAVA } // Studio will not automatically pass logcat through ndk-stack, so we need to avoid // stripping debug binaries if we want the crash trace to be readable. buildTypes { debug { packaging { jniLibs { keepDebugSymbols += "**/*.so" } } } } } } } } ================================================ FILE: build-logic/src/main/java/com/android/ndk/samples/buildlogic/KotlinConventionPlugin.kt ================================================ package com.android.ndk.samples.buildlogic import com.android.build.api.dsl.ApplicationExtension import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.kotlin.dsl.configure import org.gradle.kotlin.dsl.withType import org.jetbrains.kotlin.gradle.tasks.KotlinCompile class KotlinConventionPlugin : Plugin { override fun apply(target: Project) { with(target) { with(pluginManager) { apply("org.jetbrains.kotlin.android") } extensions.configure { tasks.withType().configureEach { kotlinOptions { jvmTarget = Versions.JAVA.toString() } } } } } } ================================================ FILE: build-logic/src/main/java/com/android/ndk/samples/buildlogic/Versions.kt ================================================ package com.android.ndk.samples.buildlogic import org.gradle.api.JavaVersion object Versions { const val COMPILE_SDK = 35 const val TARGET_SDK = 35 const val MIN_SDK = 21 const val NDK = "29.0.14206865" // r29 const val CMAKE = "4.1.0" val JAVA = JavaVersion.VERSION_1_8 } ================================================ FILE: build.gradle ================================================ // Top-level build file where you can add configuration options common to all sub-projects/modules. plugins { alias(libs.plugins.android.application) apply false alias(libs.plugins.android.library) apply false alias(libs.plugins.jetbrainsKotlinAndroid) apply false } ================================================ FILE: camera/README.md ================================================ # NdkCamera Sample Two API samples: - texture-view: Preview NDK camera image with [Android TextureView](https://developer.android.com/reference/android/view/TextureView.html) - basic: A basic NdkCamera sample to preview camera images with AReadImage and take jpeg photos. Exposure and sensitivity are adjustable for preview, however capturing photos is in auto mode (it could be adjustable with similar method as used for preview). ## Other Resources - Getting familiar with the 5 Camera2 objects ![Camera2 API Model](Camera2ProgrammingModel.png) - [Camera2 blogs](https://medium.com/androiddevelopers/camera-enumeration-on-android-9a053b910cb5) - [Camera2 Java documentation](https://developer.android.com/reference/android/hardware/camera2/package-summary) ## Screenshots ![screenshot](ndkCamera.png) ================================================ FILE: camera/basic/build.gradle ================================================ plugins { id "ndksamples.android.application" } android { namespace 'com.sample.camera.basic' defaultConfig { applicationId 'com.sample.camera.basic' minSdkVersion 24 externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_static' } } } externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' } } buildFeatures { prefab true } } dependencies { implementation project(":base") implementation libs.appcompat implementation project(":camera:camera-utils") } ================================================ FILE: camera/basic/src/main/AndroidManifest.xml ================================================ ================================================ FILE: camera/basic/src/main/cpp/CMakeLists.txt ================================================ # # Copyright (C) 2017 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. # cmake_minimum_required(VERSION 3.22.1) project(CameraBasic LANGUAGES C CXX) include(AppLibrary) include(AndroidNdkModules) find_package(base REQUIRED CONFIG) find_package(camera-utils REQUIRED CONFIG) android_ndk_import_module_native_app_glue() add_app_library(ndk_camera SHARED ${CMAKE_CURRENT_SOURCE_DIR}/android_main.cpp ${CMAKE_CURRENT_SOURCE_DIR}/camera_engine.cpp ${CMAKE_CURRENT_SOURCE_DIR}/camera_manager.cpp ${CMAKE_CURRENT_SOURCE_DIR}/camera_listeners.cpp ${CMAKE_CURRENT_SOURCE_DIR}/image_reader.cpp ${CMAKE_CURRENT_SOURCE_DIR}/camera_ui.cpp ) target_link_libraries(ndk_camera PRIVATE base::base camera-utils::camera-utils android log m $ camera2ndk mediandk ) ================================================ FILE: camera/basic/src/main/cpp/android_main.cpp ================================================ /* * Copyright (C) 2017 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. */ #include #include "camera_engine.h" /* * SampleEngine global object */ static CameraEngine* pEngineObj = nullptr; CameraEngine* GetAppEngine(void) { ASSERT(pEngineObj, "AppEngine has not initialized"); return pEngineObj; } /** * Teamplate function for NativeActivity derived applications * Create/Delete camera object with * INIT_WINDOW/TERM_WINDOW command, ignoring other event. */ static void ProcessAndroidCmd(struct android_app* app, int32_t cmd) { CameraEngine* engine = reinterpret_cast(app->userData); switch (cmd) { case APP_CMD_INIT_WINDOW: if (engine->AndroidApp()->window != NULL) { engine->SaveNativeWinRes(ANativeWindow_getWidth(app->window), ANativeWindow_getHeight(app->window), ANativeWindow_getFormat(app->window)); engine->OnAppInitWindow(); } break; case APP_CMD_TERM_WINDOW: engine->OnAppTermWindow(); ANativeWindow_setBuffersGeometry( app->window, engine->GetSavedNativeWinWidth(), engine->GetSavedNativeWinHeight(), engine->GetSavedNativeWinFormat()); break; case APP_CMD_CONFIG_CHANGED: engine->OnAppConfigChange(); break; case APP_CMD_LOST_FOCUS: break; } } extern "C" void android_main(struct android_app* state) { CameraEngine engine(state); pEngineObj = &engine; state->userData = reinterpret_cast(&engine); state->onAppCmd = ProcessAndroidCmd; // loop waiting for stuff to do. while (!state->destroyRequested) { struct android_poll_source* source = nullptr; auto result = ALooper_pollOnce(0, NULL, nullptr, (void**)&source); ASSERT(result != ALOOPER_POLL_ERROR, "ALooper_pollOnce returned an error"); if (source != NULL) { source->process(state, source); } pEngineObj->DrawFrame(); } LOGI("CameraEngine thread destroy requested!"); engine.DeleteCamera(); pEngineObj = nullptr; } /** * Handle Android System APP_CMD_INIT_WINDOW message * Request camera persmission from Java side * Create camera object if camera has been granted */ void CameraEngine::OnAppInitWindow(void) { if (!cameraGranted_) { // Not permitted to use camera yet, ask(again) and defer other events RequestCameraPermission(); return; } rotation_ = GetDisplayRotation(); CreateCamera(); ASSERT(camera_, "CameraCreation Failed"); EnableUI(); // NativeActivity end is ready to display, start pulling images cameraReady_ = true; camera_->StartPreview(true); } /** * Handle APP_CMD_TEMR_WINDOW */ void CameraEngine::OnAppTermWindow(void) { cameraReady_ = false; DeleteCamera(); } /** * Handle APP_CMD_CONFIG_CHANGED */ void CameraEngine::OnAppConfigChange(void) { int newRotation = GetDisplayRotation(); if (newRotation != rotation_) { OnAppTermWindow(); rotation_ = newRotation; OnAppInitWindow(); } } /** * Retrieve saved native window width. * @return width of native window */ int32_t CameraEngine::GetSavedNativeWinWidth(void) { return savedNativeWinRes_.width; } /** * Retrieve saved native window height. * @return height of native window */ int32_t CameraEngine::GetSavedNativeWinHeight(void) { return savedNativeWinRes_.height; } /** * Retrieve saved native window format * @return format of native window */ int32_t CameraEngine::GetSavedNativeWinFormat(void) { return savedNativeWinRes_.format; } /** * Save original NativeWindow Resolution * @param w width of native window in pixel * @param h height of native window in pixel * @param format */ void CameraEngine::SaveNativeWinRes(int32_t w, int32_t h, int32_t format) { savedNativeWinRes_.width = w; savedNativeWinRes_.height = h; savedNativeWinRes_.format = format; } ================================================ FILE: camera/basic/src/main/cpp/camera_engine.cpp ================================================ /** * Copyright (C) 2017 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. */ /** Description * Demonstrate NDK Camera interface added to android-24 */ #include "camera_engine.h" #include #include /** * constructor and destructor for main application class * @param app native_app_glue environment * @return none */ CameraEngine::CameraEngine(android_app* app) : app_(app), cameraGranted_(false), rotation_(0), cameraReady_(false), camera_(nullptr), yuvReader_(nullptr), jpgReader_(nullptr) { memset(&savedNativeWinRes_, 0, sizeof(savedNativeWinRes_)); } CameraEngine::~CameraEngine() { cameraReady_ = false; DeleteCamera(); } struct android_app* CameraEngine::AndroidApp(void) const { return app_; } /** * Create a camera object for onboard BACK_FACING camera */ void CameraEngine::CreateCamera(void) { // Camera needed to be requested at the run-time from Java SDK // if Not granted, do nothing. if (!cameraGranted_ || !app_->window) { LOGW("Camera Sample requires Full Camera access"); return; } int32_t displayRotation = GetDisplayRotation(); rotation_ = displayRotation; camera_ = new NDKCamera(); ASSERT(camera_, "Failed to Create CameraObject"); int32_t facing = 0, angle = 0, imageRotation = 0; if (camera_->GetSensorOrientation(&facing, &angle)) { if (facing == ACAMERA_LENS_FACING_FRONT) { imageRotation = (angle + rotation_) % 360; imageRotation = (360 - imageRotation) % 360; } else { imageRotation = (angle - rotation_ + 360) % 360; } } LOGI("Phone Rotation: %d, Present Rotation Angle: %d", rotation_, imageRotation); ImageFormat view{0, 0, 0}, capture{0, 0, 0}; camera_->MatchCaptureSizeRequest(app_->window, &view, &capture); ASSERT(view.width && view.height, "Could not find supportable resolution"); // Request the necessary nativeWindow to OS bool portraitNativeWindow = (savedNativeWinRes_.width < savedNativeWinRes_.height); ANativeWindow_setBuffersGeometry( app_->window, portraitNativeWindow ? view.height : view.width, portraitNativeWindow ? view.width : view.height, WINDOW_FORMAT_RGBA_8888); yuvReader_ = new ImageReader(&view, AIMAGE_FORMAT_YUV_420_888); yuvReader_->SetPresentRotation(imageRotation); jpgReader_ = new ImageReader(&capture, AIMAGE_FORMAT_JPEG); jpgReader_->SetPresentRotation(imageRotation); jpgReader_->RegisterCallback(this, [](void* ctx, const char* str) -> void { reinterpret_cast(ctx)->OnPhotoTaken(str); }); // now we could create session camera_->CreateSession(yuvReader_->GetNativeWindow(), jpgReader_->GetNativeWindow(), imageRotation); } void CameraEngine::DeleteCamera(void) { cameraReady_ = false; if (camera_) { delete camera_; camera_ = nullptr; } if (yuvReader_) { delete yuvReader_; yuvReader_ = nullptr; } if (jpgReader_) { delete jpgReader_; jpgReader_ = nullptr; } } /** * Initiate a Camera Run-time usage request to Java side implementation * [ The request result will be passed back in function * notifyCameraPermission()] */ void CameraEngine::RequestCameraPermission() { if (!app_) return; JNIEnv* env; ANativeActivity* activity = app_->activity; activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6); activity->vm->AttachCurrentThread(&env, NULL); jobject activityObj = env->NewGlobalRef(activity->clazz); jclass clz = env->GetObjectClass(activityObj); env->CallVoidMethod(activityObj, env->GetMethodID(clz, "RequestCamera", "()V")); env->DeleteGlobalRef(activityObj); activity->vm->DetachCurrentThread(); } /** * Process to user's sensitivity and exposure value change * all values are represented in int64_t even exposure is just int32_t * @param code ACAMERA_SENSOR_EXPOSURE_TIME or ACAMERA_SENSOR_SENSITIVITY * @param val corresponding value from user */ void CameraEngine::OnCameraParameterChanged(int32_t code, int64_t val) { camera_->UpdateCameraRequestParameter(code, val); } /** * The main function rendering a frame. In our case, it is yuv to RGBA8888 * converter */ void CameraEngine::DrawFrame(void) { if (!cameraReady_ || !yuvReader_) return; AImage* image = yuvReader_->GetNextImage(); if (!image) { return; } ANativeWindow_acquire(app_->window); ANativeWindow_Buffer buf; if (ANativeWindow_lock(app_->window, &buf, nullptr) < 0) { yuvReader_->DeleteImage(image); return; } yuvReader_->DisplayImage(&buf, image); ANativeWindow_unlockAndPost(app_->window); ANativeWindow_release(app_->window); } ================================================ FILE: camera/basic/src/main/cpp/camera_engine.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef __CAMERA_ENGINE_H__ #define __CAMERA_ENGINE_H__ #include #include #include #include #include "camera_manager.h" /** * basic CameraAppEngine */ class CameraEngine { public: explicit CameraEngine(android_app* app); ~CameraEngine(); // Interfaces to android application framework struct android_app* AndroidApp(void) const; void OnAppInitWindow(void); void DrawFrame(void); void OnAppConfigChange(void); void OnAppTermWindow(void); // Native Window handlers int32_t GetSavedNativeWinWidth(void); int32_t GetSavedNativeWinHeight(void); int32_t GetSavedNativeWinFormat(void); void SaveNativeWinRes(int32_t w, int32_t h, int32_t format); // UI handlers void RequestCameraPermission(); void OnCameraPermission(jboolean granted); void EnableUI(void); void OnTakePhoto(void); void OnCameraParameterChanged(int32_t code, int64_t val); // Manage NDKCamera Object void CreateCamera(void); void DeleteCamera(void); private: void OnPhotoTaken(const char* fileName); int GetDisplayRotation(void); struct android_app* app_; ImageFormat savedNativeWinRes_; bool cameraGranted_; int rotation_; volatile bool cameraReady_; NDKCamera* camera_; ImageReader* yuvReader_; ImageReader* jpgReader_; }; /** * retrieve global singleton CameraEngine instance * @return the only instance of CameraEngine in the app */ CameraEngine* GetAppEngine(void); #endif // __CAMERA_ENGINE_H__ ================================================ FILE: camera/basic/src/main/cpp/camera_listeners.cpp ================================================ /* * Copyright (C) 2017 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. */ #include #include #include #include #include #include #include #include "camera_manager.h" /* * Camera Manager Listener object */ void OnCameraAvailable(void* ctx, const char* id) { reinterpret_cast(ctx)->OnCameraStatusChanged(id, true); } void OnCameraUnavailable(void* ctx, const char* id) { reinterpret_cast(ctx)->OnCameraStatusChanged(id, false); } /** * OnCameraStatusChanged() * handles Callback from ACameraManager */ void NDKCamera::OnCameraStatusChanged(const char* id, bool available) { if (valid_) { cameras_[std::string(id)].available_ = available ? true : false; } } /** * Construct a camera manager listener on the fly and return to caller * * @return ACameraManager_AvailabilityCallback */ ACameraManager_AvailabilityCallbacks* NDKCamera::GetManagerListener() { static ACameraManager_AvailabilityCallbacks cameraMgrListener = { .context = this, .onCameraAvailable = ::OnCameraAvailable, .onCameraUnavailable = ::OnCameraUnavailable, }; return &cameraMgrListener; } /* * CameraDevice callbacks */ void OnDeviceStateChanges(void* ctx, ACameraDevice* dev) { reinterpret_cast(ctx)->OnDeviceState(dev); } void OnDeviceErrorChanges(void* ctx, ACameraDevice* dev, int err) { reinterpret_cast(ctx)->OnDeviceError(dev, err); } #if __NDK_MAJOR__ >= 30 void OnClientSharedAccessPriorityChanged(void*, ACameraDevice*, bool) { // TODO: Implement this. } #endif ACameraDevice_stateCallbacks* NDKCamera::GetDeviceListener() { static ACameraDevice_stateCallbacks cameraDeviceListener = { .context = this, .onDisconnected = ::OnDeviceStateChanges, .onError = ::OnDeviceErrorChanges, #if __NDK_MAJOR__ >= 30 .onClientSharedAccessPriorityChanged = ::OnClientSharedAccessPriorityChanged #endif }; return &cameraDeviceListener; } /** * Handle Camera DeviceStateChanges msg, notify device is disconnected * simply close the camera */ void NDKCamera::OnDeviceState(ACameraDevice* dev) { std::string id(ACameraDevice_getId(dev)); LOGW("device %s is disconnected", id.c_str()); cameras_[id].available_ = false; ACameraDevice_close(cameras_[id].device_); cameras_.erase(id); } /** * Handles Camera's deviceErrorChanges message, no action; * mainly debugging purpose * * */ void NDKCamera::OnDeviceError(ACameraDevice* dev, int err) { std::string id(ACameraDevice_getId(dev)); LOGI("CameraDevice %s is in error %#x", id.c_str(), err); PrintCameraDeviceError(err); CameraId& cam = cameras_[id]; switch (err) { case ERROR_CAMERA_IN_USE: cam.available_ = false; cam.owner_ = false; break; case ERROR_CAMERA_SERVICE: case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_DISABLED: case ERROR_MAX_CAMERAS_IN_USE: cam.available_ = false; cam.owner_ = false; break; default: LOGI("Unknown Camera Device Error: %#x", err); } } // CaptureSession state callbacks void OnSessionClosed(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p closed", ses); reinterpret_cast(ctx)->OnSessionState( ses, CaptureSessionState::CLOSED); } void OnSessionReady(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p ready", ses); reinterpret_cast(ctx)->OnSessionState(ses, CaptureSessionState::READY); } void OnSessionActive(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p active", ses); reinterpret_cast(ctx)->OnSessionState( ses, CaptureSessionState::ACTIVE); } ACameraCaptureSession_stateCallbacks* NDKCamera::GetSessionListener() { static ACameraCaptureSession_stateCallbacks sessionListener = { .context = this, .onClosed = ::OnSessionClosed, .onReady = ::OnSessionReady, .onActive = ::OnSessionActive, }; return &sessionListener; } /** * Handles capture session state changes. * Update into internal session state. */ void NDKCamera::OnSessionState(ACameraCaptureSession* ses, CaptureSessionState state) { if (!ses || ses != captureSession_) { LOGW("CaptureSession is %s", (ses ? "NOT our session" : "NULL")); return; } ASSERT(state < CaptureSessionState::MAX_STATE, "Wrong state %d", static_cast(state)); captureSessionState_ = state; } // Capture callbacks, mostly information purpose void SessionCaptureCallback_OnFailed(void* context, ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure) { std::thread captureFailedThread(&NDKCamera::OnCaptureFailed, static_cast(context), session, request, failure); captureFailedThread.detach(); } void SessionCaptureCallback_OnSequenceEnd(void* context, ACameraCaptureSession* session, int sequenceId, int64_t frameNumber) { std::thread sequenceThread(&NDKCamera::OnCaptureSequenceEnd, static_cast(context), session, sequenceId, frameNumber); sequenceThread.detach(); } void SessionCaptureCallback_OnSequenceAborted(void* context, ACameraCaptureSession* session, int sequenceId) { std::thread sequenceThread(&NDKCamera::OnCaptureSequenceEnd, static_cast(context), session, sequenceId, static_cast(-1)); sequenceThread.detach(); } ACameraCaptureSession_captureCallbacks* NDKCamera::GetCaptureCallback() { static ACameraCaptureSession_captureCallbacks captureListener{ .context = this, .onCaptureStarted = nullptr, .onCaptureProgressed = nullptr, .onCaptureCompleted = nullptr, .onCaptureFailed = SessionCaptureCallback_OnFailed, .onCaptureSequenceCompleted = SessionCaptureCallback_OnSequenceEnd, .onCaptureSequenceAborted = SessionCaptureCallback_OnSequenceAborted, .onCaptureBufferLost = nullptr, }; return &captureListener; } /** * Process JPG capture SessionCaptureCallback_OnFailed event * If this is current JPG capture session, simply resume preview * @param session the capture session that failed * @param request the capture request that failed * @param failure for additional fail info. */ void NDKCamera::OnCaptureFailed(ACameraCaptureSession*, ACaptureRequest* request, ACameraCaptureFailure* failure) { if (valid_ && request == requests_[JPG_CAPTURE_REQUEST_IDX].request_) { ASSERT(failure->sequenceId == requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_, "Error jpg sequence id") StartPreview(true); } } /** * Process event from JPEG capture * SessionCaptureCallback_OnSequenceEnd() * SessionCaptureCallback_OnSequenceAborted() * * If this is jpg capture, turn back on preview after a catpure. */ void NDKCamera::OnCaptureSequenceEnd(ACameraCaptureSession*, int sequenceId, int64_t) { if (sequenceId != requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_) return; // resume preview CALL_SESSION(setRepeatingRequest(captureSession_, nullptr, 1, &requests_[PREVIEW_REQUEST_IDX].request_, nullptr)); } ================================================ FILE: camera/basic/src/main/cpp/camera_manager.cpp ================================================ /* * Copyright (C) 2017 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. */ #include "camera_manager.h" #include #include #include #include #include #include #include /** * Range of Camera Exposure Time: * Camera's capability range have a very long range which may be disturbing * on camera. For this sample purpose, clamp to a range showing visible * video on preview: 100000ns ~ 250000000ns */ static const int64_t kMinExposureTime = 1000000; static const int64_t kMaxExposureTime = 250000000; NDKCamera::NDKCamera() : cameraMgr_(nullptr), activeCameraId_(""), cameraFacing_(ACAMERA_LENS_FACING_BACK), cameraOrientation_(0), outputContainer_(nullptr), captureSessionState_(CaptureSessionState::MAX_STATE), exposureTime_(static_cast(0)) { valid_ = false; requests_.resize(CAPTURE_REQUEST_COUNT); memset(requests_.data(), 0, requests_.size() * sizeof(requests_[0])); cameras_.clear(); cameraMgr_ = ACameraManager_create(); ASSERT(cameraMgr_, "Failed to create cameraManager"); // Pick up a back-facing camera to preview EnumerateCamera(); ASSERT(activeCameraId_.size(), "Unknown ActiveCameraIdx"); // Create back facing camera device CALL_MGR(openCamera(cameraMgr_, activeCameraId_.c_str(), GetDeviceListener(), &cameras_[activeCameraId_].device_)); CALL_MGR(registerAvailabilityCallback(cameraMgr_, GetManagerListener())); // Initialize camera controls(exposure time and sensitivity), pick // up value of 2% * range + min as starting value (just a number, no magic) ACameraMetadata* metadataObj; CALL_MGR(getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadataObj)); ACameraMetadata_const_entry val = {}; camera_status_t status = ACameraMetadata_getConstEntry( metadataObj, ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val); if (status == ACAMERA_OK) { exposureRange_.min_ = val.data.i64[0]; if (exposureRange_.min_ < kMinExposureTime) { exposureRange_.min_ = kMinExposureTime; } exposureRange_.max_ = val.data.i64[1]; if (exposureRange_.max_ > kMaxExposureTime) { exposureRange_.max_ = kMaxExposureTime; } exposureTime_ = exposureRange_.value(2); } else { LOGW("Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE"); exposureRange_.min_ = exposureRange_.max_ = 0l; exposureTime_ = 0l; } status = ACameraMetadata_getConstEntry( metadataObj, ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val); if (status == ACAMERA_OK) { sensitivityRange_.min_ = val.data.i32[0]; sensitivityRange_.max_ = val.data.i32[1]; sensitivity_ = sensitivityRange_.value(2); } else { LOGW("failed for ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE"); sensitivityRange_.min_ = sensitivityRange_.max_ = 0; sensitivity_ = 0; } valid_ = true; } /** * A helper class to assist image size comparison, by comparing the absolute * size * regardless of the portrait or landscape mode. */ class DisplayDimension { public: DisplayDimension(int32_t w, int32_t h) : w_(w), h_(h), portrait_(false) { if (h > w) { // make it landscape w_ = h; h_ = w; portrait_ = true; } } DisplayDimension(const DisplayDimension& other) { w_ = other.w_; h_ = other.h_; portrait_ = other.portrait_; } DisplayDimension(void) { w_ = 0; h_ = 0; portrait_ = false; } DisplayDimension& operator=(const DisplayDimension& other) { w_ = other.w_; h_ = other.h_; portrait_ = other.portrait_; return (*this); } bool IsSameRatio(DisplayDimension& other) { return (w_ * other.h_ == h_ * other.w_); } bool operator>(DisplayDimension& other) { return (w_ >= other.w_ & h_ >= other.h_); } bool operator==(DisplayDimension& other) { return (w_ == other.w_ && h_ == other.h_ && portrait_ == other.portrait_); } DisplayDimension operator-(DisplayDimension& other) { DisplayDimension delta(w_ - other.w_, h_ - other.h_); return delta; } void Flip(void) { portrait_ = !portrait_; } bool IsPortrait(void) { return portrait_; } int32_t width(void) { return w_; } int32_t height(void) { return h_; } int32_t org_width(void) { return (portrait_ ? h_ : w_); } int32_t org_height(void) { return (portrait_ ? w_ : h_); } private: int32_t w_, h_; bool portrait_; }; /** * Find a compatible camera modes: * 1) the same aspect ration as the native display window, which should be a * rotated version of the physical device * 2) the smallest resolution in the camera mode list * This is to minimize the later color space conversion workload. */ bool NDKCamera::MatchCaptureSizeRequest(ANativeWindow* display, ImageFormat* resView, ImageFormat* resCap) { DisplayDimension disp(ANativeWindow_getWidth(display), ANativeWindow_getHeight(display)); if (cameraOrientation_ == 90 || cameraOrientation_ == 270) { disp.Flip(); } ACameraMetadata* metadata; CALL_MGR( getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadata)); ACameraMetadata_const_entry entry; CALL_METADATA(getConstEntry( metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry)); // format of the data: format, width, height, input?, type int32 bool foundIt = false; DisplayDimension foundRes(4000, 4000); DisplayDimension maxJPG(0, 0); for (uint32_t i = 0; i < entry.count; i += 4) { int32_t input = entry.data.i32[i + 3]; int32_t format = entry.data.i32[i + 0]; if (input) continue; if (format == AIMAGE_FORMAT_YUV_420_888 || format == AIMAGE_FORMAT_JPEG) { DisplayDimension res(entry.data.i32[i + 1], entry.data.i32[i + 2]); if (!disp.IsSameRatio(res)) continue; if (format == AIMAGE_FORMAT_YUV_420_888 && foundRes > res) { foundIt = true; foundRes = res; } else if (format == AIMAGE_FORMAT_JPEG && res > maxJPG) { maxJPG = res; } } } if (foundIt) { resView->width = foundRes.org_width(); resView->height = foundRes.org_height(); resCap->width = maxJPG.org_width(); resCap->height = maxJPG.org_height(); } else { LOGW("Did not find any compatible camera resolution, taking 640x480"); if (disp.IsPortrait()) { resView->width = 480; resView->height = 640; } else { resView->width = 640; resView->height = 480; } *resCap = *resView; } resView->format = AIMAGE_FORMAT_YUV_420_888; resCap->format = AIMAGE_FORMAT_JPEG; return foundIt; } void NDKCamera::CreateSession(ANativeWindow* previewWindow, ANativeWindow* jpgWindow, int32_t imageRotation) { // Create output from this app's ANativeWindow, and add into output container requests_[PREVIEW_REQUEST_IDX].outputNativeWindow_ = previewWindow; requests_[PREVIEW_REQUEST_IDX].template_ = TEMPLATE_PREVIEW; requests_[JPG_CAPTURE_REQUEST_IDX].outputNativeWindow_ = jpgWindow; requests_[JPG_CAPTURE_REQUEST_IDX].template_ = TEMPLATE_STILL_CAPTURE; CALL_CONTAINER(create(&outputContainer_)); for (auto& req : requests_) { ANativeWindow_acquire(req.outputNativeWindow_); CALL_OUTPUT(create(req.outputNativeWindow_, &req.sessionOutput_)); CALL_CONTAINER(add(outputContainer_, req.sessionOutput_)); CALL_TARGET(create(req.outputNativeWindow_, &req.target_)); CALL_DEV(createCaptureRequest(cameras_[activeCameraId_].device_, req.template_, &req.request_)); CALL_REQUEST(addTarget(req.request_, req.target_)); } // Create a capture session for the given preview request captureSessionState_ = CaptureSessionState::READY; CALL_DEV(createCaptureSession(cameras_[activeCameraId_].device_, outputContainer_, GetSessionListener(), &captureSession_)); ACaptureRequest_setEntry_i32(requests_[JPG_CAPTURE_REQUEST_IDX].request_, ACAMERA_JPEG_ORIENTATION, 1, &imageRotation); /* * Only preview request is in manual mode, JPG is always in Auto mode * JPG capture mode could also be switch into manual mode and control * the capture parameters, this sample leaves JPG capture to be auto mode * (auto control has better effect than author's manual control) */ uint8_t aeModeOff = ACAMERA_CONTROL_AE_MODE_OFF; CALL_REQUEST(setEntry_u8(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_CONTROL_AE_MODE, 1, &aeModeOff)); CALL_REQUEST(setEntry_i32(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_)); CALL_REQUEST(setEntry_i64(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime_)); } NDKCamera::~NDKCamera() { valid_ = false; // stop session if it is on: if (captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } ACameraCaptureSession_close(captureSession_); for (auto& req : requests_) { CALL_REQUEST(removeTarget(req.request_, req.target_)); ACaptureRequest_free(req.request_); ACameraOutputTarget_free(req.target_); CALL_CONTAINER(remove(outputContainer_, req.sessionOutput_)); ACaptureSessionOutput_free(req.sessionOutput_); ANativeWindow_release(req.outputNativeWindow_); } requests_.resize(0); ACaptureSessionOutputContainer_free(outputContainer_); for (auto& cam : cameras_) { if (cam.second.device_) { CALL_DEV(close(cam.second.device_)); } } cameras_.clear(); if (cameraMgr_) { CALL_MGR(unregisterAvailabilityCallback(cameraMgr_, GetManagerListener())); ACameraManager_delete(cameraMgr_); cameraMgr_ = nullptr; } } /** * EnumerateCamera() * Loop through cameras on the system, pick up * 1) back facing one if available * 2) otherwise pick the first one reported to us */ void NDKCamera::EnumerateCamera() { ACameraIdList* cameraIds = nullptr; CALL_MGR(getCameraIdList(cameraMgr_, &cameraIds)); for (int i = 0; i < cameraIds->numCameras; ++i) { const char* id = cameraIds->cameraIds[i]; ACameraMetadata* metadataObj; CALL_MGR(getCameraCharacteristics(cameraMgr_, id, &metadataObj)); int32_t count = 0; const uint32_t* tags = nullptr; ACameraMetadata_getAllTags(metadataObj, &count, &tags); for (int tagIdx = 0; tagIdx < count; ++tagIdx) { if (ACAMERA_LENS_FACING == tags[tagIdx]) { ACameraMetadata_const_entry lensInfo = {}; CALL_METADATA(getConstEntry(metadataObj, tags[tagIdx], &lensInfo)); CameraId cam(id); cam.facing_ = static_cast( lensInfo.data.u8[0]); cam.owner_ = false; cam.device_ = nullptr; cameras_[cam.id_] = cam; if (cam.facing_ == ACAMERA_LENS_FACING_BACK) { activeCameraId_ = cam.id_; } break; } } ACameraMetadata_free(metadataObj); } ASSERT(cameras_.size(), "No Camera Available on the device"); if (activeCameraId_.length() == 0) { // if no back facing camera found, pick up the first one to use... activeCameraId_ = cameras_.begin()->second.id_; } ACameraManager_deleteCameraIdList(cameraIds); } /** * GetSensorOrientation() * Retrieve current sensor orientation regarding to the phone device * orientation * SensorOrientation is NOT settable. */ bool NDKCamera::GetSensorOrientation(int32_t* facing, int32_t* angle) { if (!cameraMgr_) { return false; } ACameraMetadata* metadataObj; ACameraMetadata_const_entry face, orientation; CALL_MGR(getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadataObj)); CALL_METADATA(getConstEntry(metadataObj, ACAMERA_LENS_FACING, &face)); cameraFacing_ = static_cast(face.data.u8[0]); CALL_METADATA( getConstEntry(metadataObj, ACAMERA_SENSOR_ORIENTATION, &orientation)); LOGI("====Current SENSOR_ORIENTATION: %8d", orientation.data.i32[0]); ACameraMetadata_free(metadataObj); cameraOrientation_ = orientation.data.i32[0]; if (facing) *facing = cameraFacing_; if (angle) *angle = cameraOrientation_; return true; } /** * StartPreview() * Toggle preview start/stop */ void NDKCamera::StartPreview(bool start) { if (start) { CALL_SESSION(setRepeatingRequest(captureSession_, nullptr, 1, &requests_[PREVIEW_REQUEST_IDX].request_, nullptr)); } else if (!start && captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } else { ASSERT(false, "Conflict states(%s, %d)", (start ? "true" : "false"), static_cast(captureSessionState_)); } } /** * Capture one jpg photo into * /sdcard/DCIM/Camera * refer to WriteFile() for details */ bool NDKCamera::TakePhoto(void) { if (captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } CALL_SESSION(capture(captureSession_, GetCaptureCallback(), 1, &requests_[JPG_CAPTURE_REQUEST_IDX].request_, &requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_)); return true; } void NDKCamera::UpdateCameraRequestParameter(int32_t code, int64_t val) { ACaptureRequest* request = requests_[PREVIEW_REQUEST_IDX].request_; switch (code) { case ACAMERA_SENSOR_EXPOSURE_TIME: if (exposureRange_.Supported()) { exposureTime_ = val; CALL_REQUEST(setEntry_i64(request, ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime_)); } break; case ACAMERA_SENSOR_SENSITIVITY: if (sensitivityRange_.Supported()) { sensitivity_ = val; CALL_REQUEST(setEntry_i32(request, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_)); } break; default: ASSERT(false, "==ERROR==: error code for CameraParameterChange: %d", code); return; } uint8_t aeModeOff = ACAMERA_CONTROL_AE_MODE_OFF; CALL_REQUEST(setEntry_u8(request, ACAMERA_CONTROL_AE_MODE, 1, &aeModeOff)); CALL_SESSION( setRepeatingRequest(captureSession_, nullptr, 1, &request, &requests_[PREVIEW_REQUEST_IDX].sessionSequenceId_)); } /** * Retrieve Camera Exposure adjustable range. * * @param min Camera minimium exposure time in nanoseconds * @param max Camera maximum exposure tiem in nanoseconds * * @return true min and max are loaded with the camera's exposure values * false camera has not initialized, no value available */ bool NDKCamera::GetExposureRange(int64_t* min, int64_t* max, int64_t* curVal) { if (!exposureRange_.Supported() || !exposureTime_ || !min || !max || !curVal) { return false; } *min = exposureRange_.min_; *max = exposureRange_.max_; *curVal = exposureTime_; return true; } /** * Retrieve Camera sensitivity range. * * @param min Camera minimium sensitivity * @param max Camera maximum sensitivity * * @return true min and max are loaded with the camera's sensitivity values * false camera has not initialized, no value available */ bool NDKCamera::GetSensitivityRange(int64_t* min, int64_t* max, int64_t* curVal) { if (!sensitivityRange_.Supported() || !sensitivity_ || !min || !max || !curVal) { return false; } *min = static_cast(sensitivityRange_.min_); *max = static_cast(sensitivityRange_.max_); *curVal = sensitivity_; return true; } ================================================ FILE: camera/basic/src/main/cpp/camera_manager.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef CAMERA_NATIVE_CAMERA_H #define CAMERA_NATIVE_CAMERA_H #include #include #include #include #include #include #include #include "image_reader.h" enum class CaptureSessionState : int32_t { READY = 0, // session is ready ACTIVE, // session is busy CLOSED, // session is closed(by itself or a new session evicts) MAX_STATE }; template class RangeValue { public: T min_, max_; /** * return absolute value from relative value * value: in percent (50 for 50%) */ T value(int percent) { return static_cast(min_ + (max_ - min_) * percent / 100); } RangeValue() { min_ = max_ = static_cast(0); } bool Supported(void) const { return (min_ != max_); } }; enum PREVIEW_INDICES { PREVIEW_REQUEST_IDX = 0, JPG_CAPTURE_REQUEST_IDX, CAPTURE_REQUEST_COUNT, }; struct CaptureRequestInfo { ANativeWindow* outputNativeWindow_; ACaptureSessionOutput* sessionOutput_; ACameraOutputTarget* target_; ACaptureRequest* request_; ACameraDevice_request_template template_; int sessionSequenceId_; }; class CameraId; class NDKCamera { private: ACameraManager* cameraMgr_; std::map cameras_; std::string activeCameraId_; uint32_t cameraFacing_; uint32_t cameraOrientation_; std::vector requests_; ACaptureSessionOutputContainer* outputContainer_; ACameraCaptureSession* captureSession_; CaptureSessionState captureSessionState_; // set up exposure control int64_t exposureTime_; RangeValue exposureRange_; int32_t sensitivity_; RangeValue sensitivityRange_; volatile bool valid_; ACameraManager_AvailabilityCallbacks* GetManagerListener(); ACameraDevice_stateCallbacks* GetDeviceListener(); ACameraCaptureSession_stateCallbacks* GetSessionListener(); ACameraCaptureSession_captureCallbacks* GetCaptureCallback(); public: NDKCamera(); ~NDKCamera(); void EnumerateCamera(void); bool MatchCaptureSizeRequest(ANativeWindow* display, ImageFormat* view, ImageFormat* capture); void CreateSession(ANativeWindow* previewWindow, ANativeWindow* jpgWindow, int32_t imageRotation); bool GetSensorOrientation(int32_t* facing, int32_t* angle); void OnCameraStatusChanged(const char* id, bool available); void OnDeviceState(ACameraDevice* dev); void OnDeviceError(ACameraDevice* dev, int err); void OnSessionState(ACameraCaptureSession* ses, CaptureSessionState state); void OnCaptureSequenceEnd(ACameraCaptureSession* session, int sequenceId, int64_t frameNumber); void OnCaptureFailed(ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure); void StartPreview(bool start); bool TakePhoto(void); bool GetExposureRange(int64_t* min, int64_t* max, int64_t* curVal); bool GetSensitivityRange(int64_t* min, int64_t* max, int64_t* curVal); void UpdateCameraRequestParameter(int32_t code, int64_t val); }; // helper classes to hold enumerated camera class CameraId { public: ACameraDevice* device_; std::string id_; acamera_metadata_enum_android_lens_facing_t facing_; bool available_; // free to use ( no other apps are using bool owner_; // we are the owner of the camera explicit CameraId(const char* id) : device_(nullptr), facing_(ACAMERA_LENS_FACING_FRONT), available_(false), owner_(false) { id_ = id; } explicit CameraId(void) { CameraId(""); } }; #endif // CAMERA_NATIVE_CAMERA_H ================================================ FILE: camera/basic/src/main/cpp/camera_ui.cpp ================================================ /* * Copyright (C) 2017 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. */ #include #include #include "camera_engine.h" /** * Retrieve current rotation from Java side * * @return current rotation angle */ int CameraEngine::GetDisplayRotation() { ASSERT(app_, "Application is not initialized"); JNIEnv* env; ANativeActivity* activity = app_->activity; activity->vm->GetEnv((void**)&env, JNI_VERSION_1_6); activity->vm->AttachCurrentThread(&env, NULL); jobject activityObj = env->NewGlobalRef(activity->clazz); jclass clz = env->GetObjectClass(activityObj); jint newOrientation = env->CallIntMethod( activityObj, env->GetMethodID(clz, "getRotationDegree", "()I")); env->DeleteGlobalRef(activityObj); activity->vm->DetachCurrentThread(); return newOrientation; } /** * Initializate UI on Java side. The 2 seekBars' values are passed in * array in the tuple of ( min, max, curVal ) * 0: exposure min * 1: exposure max * 2: exposure val * 3: sensitivity min * 4: sensitivity max * 5: sensitivity val */ const int kInitDataLen = 6; void CameraEngine::EnableUI(void) { JNIEnv* jni; app_->activity->vm->AttachCurrentThread(&jni, NULL); int64_t range[3]; // Default class retrieval jclass clazz = jni->GetObjectClass(app_->activity->clazz); jmethodID methodID = jni->GetMethodID(clazz, "EnableUI", "([J)V"); jlongArray initData = jni->NewLongArray(kInitDataLen); ASSERT(initData && methodID, "JavaUI interface Object failed(%p, %p)", methodID, initData); if (!camera_->GetExposureRange(&range[0], &range[1], &range[2])) { memset(range, 0, sizeof(int64_t) * 3); } jni->SetLongArrayRegion(initData, 0, 3, range); if (!camera_->GetSensitivityRange(&range[0], &range[1], &range[2])) { memset(range, 0, sizeof(int64_t) * 3); } jni->SetLongArrayRegion(initData, 3, 3, range); jni->CallVoidMethod(app_->activity->clazz, methodID, initData); app_->activity->vm->DetachCurrentThread(); } /** * Handles UI request to take a photo into * /sdcard/DCIM/Camera */ void CameraEngine::OnTakePhoto() { if (camera_) { camera_->TakePhoto(); } } void CameraEngine::OnPhotoTaken(const char* fileName) { JNIEnv* jni; app_->activity->vm->AttachCurrentThread(&jni, NULL); // Default class retrieval jclass clazz = jni->GetObjectClass(app_->activity->clazz); jmethodID methodID = jni->GetMethodID(clazz, "OnPhotoTaken", "(Ljava/lang/String;)V"); jstring javaName = jni->NewStringUTF(fileName); jni->CallVoidMethod(app_->activity->clazz, methodID, javaName); app_->activity->vm->DetachCurrentThread(); } /** * Process user camera and disk writing permission * Resume application initialization after user granted camera and disk usage * If user denied permission, do nothing: no camera * * @param granted user's authorization for camera and disk usage. * @return none */ void CameraEngine::OnCameraPermission(jboolean granted) { cameraGranted_ = (granted != JNI_FALSE); // TODO: Fail gracefully. ASSERT(cameraGranted_, "required app permissions were not granted"); OnAppInitWindow(); } /** * A couple UI handles ( from UI ) * user camera and disk permission * exposure and sensitivity SeekBars * takePhoto button */ void notifyCameraPermission(JNIEnv*, jclass, jboolean permission) { std::thread permissionHandler(&CameraEngine::OnCameraPermission, GetAppEngine(), permission); permissionHandler.detach(); } void TakePhoto(JNIEnv*, jclass) { std::thread takePhotoHandler(&CameraEngine::OnTakePhoto, GetAppEngine()); takePhotoHandler.detach(); } void OnExposureChanged(JNIEnv*, jobject, jlong exposurePercent) { GetAppEngine()->OnCameraParameterChanged(ACAMERA_SENSOR_EXPOSURE_TIME, exposurePercent); } void OnSensitivityChanged(JNIEnv*, jobject, jlong sensitivity) { GetAppEngine()->OnCameraParameterChanged(ACAMERA_SENSOR_SENSITIVITY, sensitivity); } extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } jclass c = env->FindClass("com/sample/camera/basic/CameraActivity"); if (c == nullptr) return JNI_ERR; static const JNINativeMethod methods[] = { {"notifyCameraPermission", "(Z)V", reinterpret_cast(notifyCameraPermission)}, {"TakePhoto", "()V", reinterpret_cast(TakePhoto)}, {"OnExposureChanged", "(J)V", reinterpret_cast(OnExposureChanged)}, {"OnSensitivityChanged", "(J)V", reinterpret_cast(OnSensitivityChanged)}, }; int rc = env->RegisterNatives(c, methods, arraysize(methods)); if (rc != JNI_OK) return rc; return JNI_VERSION_1_6; } ================================================ FILE: camera/basic/src/main/cpp/image_reader.cpp ================================================ /* * Copyright (C) 2017 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. */ #include "image_reader.h" #include #include #include #include #include #include #include /* * For JPEG capture, captured files are saved under * DirName * File names are incrementally appended an index number as * capture0.jpg, capture1.jpg, capture2.jpg */ static const char* kDirName = "/sdcard/DCIM/Camera/"; static const char* kFileName = "capture"; /** * MAX_BUF_COUNT: * Max buffers in this ImageReader. */ #define MAX_BUF_COUNT 4 /** * ImageReader listener: called by AImageReader for every frame captured * We pass the event to ImageReader class, so it could do some housekeeping * about * the loaded queue. For example, we could keep a counter to track how many * buffers are full and idle in the queue. If camera almost has no buffer to * capture * we could release ( skip ) some frames by AImageReader_getNextImage() and * AImageReader_delete(). */ void OnImageCallback(void* ctx, AImageReader* reader) { reinterpret_cast(ctx)->ImageCallback(reader); } /** * Constructor */ ImageReader::ImageReader(ImageFormat* res, enum AIMAGE_FORMATS format) : presentRotation_(0), reader_(nullptr) { callback_ = nullptr; callbackCtx_ = nullptr; media_status_t status = AImageReader_new(res->width, res->height, format, MAX_BUF_COUNT, &reader_); ASSERT(reader_ && status == AMEDIA_OK, "Failed to create AImageReader"); AImageReader_ImageListener listener{ .context = this, .onImageAvailable = OnImageCallback, }; AImageReader_setImageListener(reader_, &listener); } ImageReader::~ImageReader() { ASSERT(reader_, "NULL Pointer to %s", __FUNCTION__); AImageReader_delete(reader_); } void ImageReader::RegisterCallback( void* ctx, std::function func) { callbackCtx_ = ctx; callback_ = func; } void ImageReader::ImageCallback(AImageReader* reader) { int32_t format; media_status_t status = AImageReader_getFormat(reader, &format); ASSERT(status == AMEDIA_OK, "Failed to get the media format"); if (format == AIMAGE_FORMAT_JPEG) { AImage* image = nullptr; media_status_t status = AImageReader_acquireNextImage(reader, &image); ASSERT(status == AMEDIA_OK && image, "Image is not available"); // Create a thread and write out the jpeg files std::thread writeFileHandler(&ImageReader::WriteFile, this, image); writeFileHandler.detach(); } } ANativeWindow* ImageReader::GetNativeWindow(void) { if (!reader_) return nullptr; ANativeWindow* nativeWindow; media_status_t status = AImageReader_getWindow(reader_, &nativeWindow); ASSERT(status == AMEDIA_OK, "Could not get ANativeWindow"); return nativeWindow; } /** * GetNextImage() * Retrieve the next image in ImageReader's bufferQueue, NOT the last image so * no image is skipped. Recommended for batch/background processing. */ AImage* ImageReader::GetNextImage(void) { AImage* image; media_status_t status = AImageReader_acquireNextImage(reader_, &image); if (status != AMEDIA_OK) { return nullptr; } return image; } /** * GetLatestImage() * Retrieve the last image in ImageReader's bufferQueue, deleting images in * in front of it on the queue. Recommended for real-time processing. */ AImage* ImageReader::GetLatestImage(void) { AImage* image; media_status_t status = AImageReader_acquireLatestImage(reader_, &image); if (status != AMEDIA_OK) { return nullptr; } return image; } /** * Delete Image * @param image {@link AImage} instance to be deleted */ void ImageReader::DeleteImage(AImage* image) { if (image) AImage_delete(image); } /** * Helper function for YUV_420 to RGB conversion. Courtesy of Tensorflow * ImageClassifier Sample: * https://github.com/tensorflow/tensorflow/blob/master/tensorflow/examples/android/jni/yuv2rgb.cc * The difference is that here we have to swap UV plane when calling it. */ #ifndef MAX #define MAX(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a > _b ? _a : _b; \ }) #define MIN(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a < _b ? _a : _b; \ }) #endif // This value is 2 ^ 18 - 1, and is used to clamp the RGB values before their // ranges // are normalized to eight bits. static const int kMaxChannelValue = 262143; static inline uint32_t YUV2RGB(int nY, int nU, int nV) { nY -= 16; nU -= 128; nV -= 128; if (nY < 0) nY = 0; // This is the floating point equivalent. We do the conversion in integer // because some Android devices do not have floating point in hardware. // nR = (int)(1.164 * nY + 1.596 * nV); // nG = (int)(1.164 * nY - 0.813 * nV - 0.391 * nU); // nB = (int)(1.164 * nY + 2.018 * nU); int nR = (int)(1192 * nY + 1634 * nV); int nG = (int)(1192 * nY - 833 * nV - 400 * nU); int nB = (int)(1192 * nY + 2066 * nU); nR = MIN(kMaxChannelValue, MAX(0, nR)); nG = MIN(kMaxChannelValue, MAX(0, nG)); nB = MIN(kMaxChannelValue, MAX(0, nB)); nR = (nR >> 10) & 0xff; nG = (nG >> 10) & 0xff; nB = (nB >> 10) & 0xff; return 0xff000000 | (nB << 16) | (nG << 8) | nR; } /** * Convert yuv image inside AImage into ANativeWindow_Buffer * ANativeWindow_Buffer format is guaranteed to be * WINDOW_FORMAT_RGBX_8888 * WINDOW_FORMAT_RGBA_8888 * @param buf a {@link ANativeWindow_Buffer } instance, destination of * image conversion * @param image a {@link AImage} instance, source of image conversion. * it will be deleted via {@link AImage_delete} */ bool ImageReader::DisplayImage(ANativeWindow_Buffer* buf, AImage* image) { ASSERT(buf->format == WINDOW_FORMAT_RGBX_8888 || buf->format == WINDOW_FORMAT_RGBA_8888, "Not supported buffer format"); int32_t srcFormat = -1; AImage_getFormat(image, &srcFormat); ASSERT(AIMAGE_FORMAT_YUV_420_888 == srcFormat, "Failed to get format"); int32_t srcPlanes = 0; AImage_getNumberOfPlanes(image, &srcPlanes); ASSERT(srcPlanes == 3, "Is not 3 planes"); switch (presentRotation_) { case 0: PresentImage(buf, image); break; case 90: PresentImage90(buf, image); break; case 180: PresentImage180(buf, image); break; case 270: PresentImage270(buf, image); break; default: ASSERT(0, "NOT recognized display rotation: %d", presentRotation_); } AImage_delete(image); return true; } /* * PresentImage() * Converting yuv to RGB * No rotation: (x,y) --> (x, y) * Refer to: * https://mathbits.com/MathBits/TISection/Geometry/Transformations2.htm */ void ImageReader::PresentImage(ANativeWindow_Buffer* buf, AImage* image) { AImageCropRect srcRect; AImage_getCropRect(image, &srcRect); int32_t yStride, uvStride; uint8_t *yPixel, *uPixel, *vPixel; int32_t yLen, uLen, vLen; AImage_getPlaneRowStride(image, 0, &yStride); AImage_getPlaneRowStride(image, 1, &uvStride); AImage_getPlaneData(image, 0, &yPixel, &yLen); AImage_getPlaneData(image, 1, &uPixel, &uLen); AImage_getPlaneData(image, 2, &vPixel, &vLen); int32_t uvPixelStride; AImage_getPlanePixelStride(image, 1, &uvPixelStride); int32_t height = MIN(buf->height, (srcRect.bottom - srcRect.top)); int32_t width = MIN(buf->width, (srcRect.right - srcRect.left)); uint32_t* out = static_cast(buf->bits); for (int32_t y = 0; y < height; y++) { const uint8_t* pY = yPixel + yStride * (y + srcRect.top) + srcRect.left; int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1); const uint8_t* pU = uPixel + uv_row_start + (srcRect.left >> 1); const uint8_t* pV = vPixel + uv_row_start + (srcRect.left >> 1); for (int32_t x = 0; x < width; x++) { const int32_t uv_offset = (x >> 1) * uvPixelStride; out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]); } out += buf->stride; } } /* * PresentImage90() * Converting YUV to RGB * Rotation image anti-clockwise 90 degree -- (x, y) --> (-y, x) */ void ImageReader::PresentImage90(ANativeWindow_Buffer* buf, AImage* image) { AImageCropRect srcRect; AImage_getCropRect(image, &srcRect); int32_t yStride, uvStride; uint8_t *yPixel, *uPixel, *vPixel; int32_t yLen, uLen, vLen; AImage_getPlaneRowStride(image, 0, &yStride); AImage_getPlaneRowStride(image, 1, &uvStride); AImage_getPlaneData(image, 0, &yPixel, &yLen); AImage_getPlaneData(image, 1, &uPixel, &uLen); AImage_getPlaneData(image, 2, &vPixel, &vLen); int32_t uvPixelStride; AImage_getPlanePixelStride(image, 1, &uvPixelStride); int32_t height = MIN(buf->width, (srcRect.bottom - srcRect.top)); int32_t width = MIN(buf->height, (srcRect.right - srcRect.left)); uint32_t* out = static_cast(buf->bits); out += height - 1; for (int32_t y = 0; y < height; y++) { const uint8_t* pY = yPixel + yStride * (y + srcRect.top) + srcRect.left; int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1); const uint8_t* pU = uPixel + uv_row_start + (srcRect.left >> 1); const uint8_t* pV = vPixel + uv_row_start + (srcRect.left >> 1); for (int32_t x = 0; x < width; x++) { const int32_t uv_offset = (x >> 1) * uvPixelStride; // [x, y]--> [-y, x] out[x * buf->stride] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]); } out -= 1; // move to the next column } } /* * PresentImage180() * Converting yuv to RGB * Rotate image 180 degree: (x, y) --> (-x, -y) */ void ImageReader::PresentImage180(ANativeWindow_Buffer* buf, AImage* image) { AImageCropRect srcRect; AImage_getCropRect(image, &srcRect); int32_t yStride, uvStride; uint8_t *yPixel, *uPixel, *vPixel; int32_t yLen, uLen, vLen; AImage_getPlaneRowStride(image, 0, &yStride); AImage_getPlaneRowStride(image, 1, &uvStride); AImage_getPlaneData(image, 0, &yPixel, &yLen); AImage_getPlaneData(image, 1, &uPixel, &uLen); AImage_getPlaneData(image, 2, &vPixel, &vLen); int32_t uvPixelStride; AImage_getPlanePixelStride(image, 1, &uvPixelStride); int32_t height = MIN(buf->height, (srcRect.bottom - srcRect.top)); int32_t width = MIN(buf->width, (srcRect.right - srcRect.left)); uint32_t* out = static_cast(buf->bits); out += (height - 1) * buf->stride; for (int32_t y = 0; y < height; y++) { const uint8_t* pY = yPixel + yStride * (y + srcRect.top) + srcRect.left; int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1); const uint8_t* pU = uPixel + uv_row_start + (srcRect.left >> 1); const uint8_t* pV = vPixel + uv_row_start + (srcRect.left >> 1); for (int32_t x = 0; x < width; x++) { const int32_t uv_offset = (x >> 1) * uvPixelStride; // mirror image since we are using front camera out[width - 1 - x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]); // out[x] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]); } out -= buf->stride; } } /* * PresentImage270() * Converting image from YUV to RGB * Rotate Image counter-clockwise 270 degree: (x, y) --> (y, x) */ void ImageReader::PresentImage270(ANativeWindow_Buffer* buf, AImage* image) { AImageCropRect srcRect; AImage_getCropRect(image, &srcRect); int32_t yStride, uvStride; uint8_t *yPixel, *uPixel, *vPixel; int32_t yLen, uLen, vLen; AImage_getPlaneRowStride(image, 0, &yStride); AImage_getPlaneRowStride(image, 1, &uvStride); AImage_getPlaneData(image, 0, &yPixel, &yLen); AImage_getPlaneData(image, 1, &uPixel, &uLen); AImage_getPlaneData(image, 2, &vPixel, &vLen); int32_t uvPixelStride; AImage_getPlanePixelStride(image, 1, &uvPixelStride); int32_t height = MIN(buf->width, (srcRect.bottom - srcRect.top)); int32_t width = MIN(buf->height, (srcRect.right - srcRect.left)); uint32_t* out = static_cast(buf->bits); for (int32_t y = 0; y < height; y++) { const uint8_t* pY = yPixel + yStride * (y + srcRect.top) + srcRect.left; int32_t uv_row_start = uvStride * ((y + srcRect.top) >> 1); const uint8_t* pU = uPixel + uv_row_start + (srcRect.left >> 1); const uint8_t* pV = vPixel + uv_row_start + (srcRect.left >> 1); for (int32_t x = 0; x < width; x++) { const int32_t uv_offset = (x >> 1) * uvPixelStride; out[(width - 1 - x) * buf->stride] = YUV2RGB(pY[x], pU[uv_offset], pV[uv_offset]); } out += 1; // move to the next column } } void ImageReader::SetPresentRotation(int32_t angle) { presentRotation_ = angle; } /** * Write out jpeg files to kDirName directory * @param image point capture jpg image */ void ImageReader::WriteFile(AImage* image) { int planeCount; media_status_t status = AImage_getNumberOfPlanes(image, &planeCount); ASSERT(status == AMEDIA_OK && planeCount == 1, "Error: getNumberOfPlanes() planeCount = %d", planeCount); uint8_t* data = nullptr; int len = 0; AImage_getPlaneData(image, 0, &data, &len); DIR* dir = opendir(kDirName); if (dir) { closedir(dir); } else { std::string cmd = "mkdir -p "; cmd += kDirName; system(cmd.c_str()); } struct timespec ts { 0, 0 }; clock_gettime(CLOCK_REALTIME, &ts); struct tm localTime; localtime_r(&ts.tv_sec, &localTime); std::string fileName = kDirName; std::string dash("-"); fileName += kFileName + std::to_string(localTime.tm_mon) + std::to_string(localTime.tm_mday) + dash + std::to_string(localTime.tm_hour) + std::to_string(localTime.tm_min) + std::to_string(localTime.tm_sec) + ".jpg"; FILE* file = fopen(fileName.c_str(), "wb"); if (file && data && len) { fwrite(data, 1, len, file); fclose(file); if (callback_) { callback_(callbackCtx_, fileName.c_str()); } } else { if (file) fclose(file); } AImage_delete(image); } ================================================ FILE: camera/basic/src/main/cpp/image_reader.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef CAMERA_IMAGE_READER_H #define CAMERA_IMAGE_READER_H #include #include /* * ImageFormat: * A Data Structure to communicate resolution between camera and ImageReader */ struct ImageFormat { int32_t width; int32_t height; int32_t format; // Through out this demo, the format is fixed to // YUV_420 format }; class ImageReader { public: /** * Ctor and Dtor() */ explicit ImageReader(ImageFormat* res, enum AIMAGE_FORMATS format); ~ImageReader(); /** * Report cached ANativeWindow, which was used to create camera's capture * session output. */ ANativeWindow* GetNativeWindow(void); /** * Retrieve Image on the top of Reader's queue */ AImage* GetNextImage(void); /** * Retrieve Image on the back of Reader's queue, dropping older images */ AImage* GetLatestImage(void); /** * Delete Image * @param image {@link AImage} instance to be deleted */ void DeleteImage(AImage* image); /** * AImageReader callback handler. Called by AImageReader when a frame is * captured * (Internal function, not to be called by clients) */ void ImageCallback(AImageReader* reader); /** * DisplayImage() * Present camera image to the given display buffer. Avaliable image is * converted * to display buffer format. Supported display format: * WINDOW_FORMAT_RGBX_8888 * WINDOW_FORMAT_RGBA_8888 * @param buf {@link ANativeWindow_Buffer} for image to display to. * @param image a {@link AImage} instance, source of image conversion. * it will be deleted via {@link AImage_delete} * @return true on success, false on failure */ bool DisplayImage(ANativeWindow_Buffer* buf, AImage* image); /** * Configure the rotation angle necessary to apply to * Camera image when presenting: all rotations should be accumulated: * CameraSensorOrientation + Android Device Native Orientation + * Human Rotation (rotated degree related to Phone native orientation */ void SetPresentRotation(int32_t angle); /** * regsiter a callback function for client to be notified that jpeg already * written out. * @param ctx is client context when callback is invoked * @param callback is the actual callback function */ void RegisterCallback(void* ctx, std::function); private: int32_t presentRotation_; AImageReader* reader_; std::function callback_; void* callbackCtx_; void PresentImage(ANativeWindow_Buffer* buf, AImage* image); void PresentImage90(ANativeWindow_Buffer* buf, AImage* image); void PresentImage180(ANativeWindow_Buffer* buf, AImage* image); void PresentImage270(ANativeWindow_Buffer* buf, AImage* image); void WriteFile(AImage* image); }; #endif // CAMERA_IMAGE_READER_H ================================================ FILE: camera/basic/src/main/cpp/libndk_camera.map.txt ================================================ LIBNDK_CAMERA { global: ANativeActivity_onCreate; JNI_OnLoad; local: *; }; ================================================ FILE: camera/basic/src/main/java/com/sample/camera/basic/CameraActivity.java ================================================ /* * Copyright (C) 2017 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.sample.camera.basic; import android.Manifest; import android.annotation.SuppressLint; import android.app.NativeActivity; import android.content.Context; import android.content.pm.PackageManager; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import android.os.Bundle; import android.util.Log; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; import android.widget.ImageButton; import android.widget.PopupWindow; import android.widget.RelativeLayout; import android.widget.SeekBar; import android.widget.TextView; import android.widget.Toast; import static android.hardware.camera2.CameraMetadata.LENS_FACING_BACK; import java.util.Arrays; class CameraSeekBar { int _progress; long _min, _max, _absVal; SeekBar _seekBar; TextView _sliderPrompt; CameraSeekBar() { _progress = 0; _min = _max = _absVal = 0; } CameraSeekBar(SeekBar seekBar, TextView textView, long min, long max, long val) { _seekBar = seekBar; _sliderPrompt = textView; _min = min; _max = max; _absVal = val; if(_min != _max) { _progress = (int) ((_absVal - _min) * _seekBar.getMax() / (_max - _min)); seekBar.setProgress(_progress); updateProgress(_progress); } else { _progress = 0; seekBar.setEnabled(false); } } public boolean isSupported() { return (_min != _max); } public void updateProgress(int progress) { if (!isSupported()) return; _progress = progress; _absVal = (progress * ( _max - _min )) / _seekBar.getMax() + _min; int val = (progress * (_seekBar.getWidth() - 2 * _seekBar.getThumbOffset())) / _seekBar.getMax(); _sliderPrompt.setText("" + _absVal); _sliderPrompt.setX(_seekBar.getX() + val + _seekBar.getThumbOffset() / 2); } public int getProgress() { return _progress; } public void updateAbsProgress(long val) { if (!isSupported()) return; int progress = (int)((val - _min) * _seekBar.getMax() / (_max - _min)); updateProgress(progress); } public long getAbsProgress() { return _absVal; } } public class CameraActivity extends NativeActivity implements ActivityCompat.OnRequestPermissionsResultCallback { volatile CameraActivity _savedInstance; PopupWindow _popupWindow; ImageButton _takePhoto; CameraSeekBar _exposure, _sensitivity; long[] _initParams; private final String DBG_TAG = "NDK-CAMERA-BASIC"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Log.i(DBG_TAG, "OnCreate()"); // new initialization here... request for permission _savedInstance = this; setImmersiveSticky(); View decorView = getWindow().getDecorView(); decorView.setOnSystemUiVisibilityChangeListener (new View.OnSystemUiVisibilityChangeListener() { @Override public void onSystemUiVisibilityChange(int visibility) { setImmersiveSticky(); } }); } private boolean isCamera2Device() { CameraManager camMgr = (CameraManager)getSystemService(Context.CAMERA_SERVICE); boolean camera2Dev = true; try { String[] cameraIds = camMgr.getCameraIdList(); if (cameraIds.length != 0 ) { for (String id : cameraIds) { CameraCharacteristics characteristics = camMgr.getCameraCharacteristics(id); int deviceLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY && facing == LENS_FACING_BACK) { camera2Dev = false; } } } } catch (CameraAccessException e) { e.printStackTrace(); camera2Dev = false; } return camera2Dev; } // get current rotation method int getRotationDegree() { return 90 * ((WindowManager)(getSystemService(WINDOW_SERVICE))) .getDefaultDisplay() .getRotation(); } @Override protected void onResume() { super.onResume(); setImmersiveSticky(); } void setImmersiveSticky() { View decorView = getWindow().getDecorView(); decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_STABLE); } @Override protected void onPause() { if (_popupWindow != null && _popupWindow.isShowing()) { _popupWindow.dismiss(); _popupWindow = null; } super.onPause(); } @Override protected void onDestroy() { super.onDestroy(); } private static final int PERMISSION_REQUEST_CODE_CAMERA = 1; public void RequestCamera() { if(!isCamera2Device()) { Log.e(DBG_TAG, "Found legacy camera Device, this sample needs camera2 device"); return; } if (ActivityCompat.checkSelfPermission( this, Manifest.permission.CAMERA ) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE_CAMERA ); return; } notifyCameraPermission(true); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { if (requestCode != PERMISSION_REQUEST_CODE_CAMERA) { // The permissions request isn't ours. super.onRequestPermissionsResult(requestCode, permissions, grantResults); return; } if (permissions.length == 0) { // https://developer.android.com/reference/androidx/core/app/ActivityCompat.OnRequestPermissionsResultCallback#onRequestPermissionsResult(int,java.lang.String[],int[]) // // Note: It is possible that the permissions request interaction with the user is // interrupted. In this case you will receive empty permissions and results arrays which // should be treated as a cancellation. // // The docs aren't clear about *why* it might be canceled, so it's not clear what we // should do here other than restart the request. RequestCamera(); return; } boolean granted = Arrays.stream(grantResults) .allMatch(element -> element == PackageManager.PERMISSION_GRANTED); if (!granted) { logDeniedPermissions(permissions, grantResults); } notifyCameraPermission(granted); } private void logDeniedPermissions( @NonNull String[] requestedPermissions, @NonNull int[] grantResults ) { if (requestedPermissions.length != grantResults.length) { throw new IllegalArgumentException( String.format( "requestedPermissions.length (%d) != grantResults.length (%d)", requestedPermissions.length, grantResults.length ) ); } for (int i = 0; i < requestedPermissions.length; i++) { if (grantResults[i] != PackageManager.PERMISSION_GRANTED) { Log.i(DBG_TAG, requestedPermissions[i] + " DENIED"); } } } /** * params[] exposure and sensitivity init values in (min, max, curVa) tuple * 0: exposure min * 1: exposure max * 2: exposure val * 3: sensitivity min * 4: sensitivity max * 5: sensitivity val */ @SuppressLint("InflateParams") public void EnableUI(final long[] params) { // make our own copy _initParams = new long[params.length]; System.arraycopy(params, 0, _initParams, 0, params.length); runOnUiThread(new Runnable() { @Override public void run() { try { if (_popupWindow != null) { _popupWindow.dismiss(); } LayoutInflater layoutInflater = (LayoutInflater) getBaseContext() .getSystemService(LAYOUT_INFLATER_SERVICE); View popupView = layoutInflater.inflate(R.layout.widgets, null); _popupWindow = new PopupWindow( popupView, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT); RelativeLayout mainLayout = new RelativeLayout(_savedInstance); ViewGroup.MarginLayoutParams params = new ViewGroup.MarginLayoutParams( -1, -1); params.setMargins(0, 0, 0, 0); _savedInstance.setContentView(mainLayout, params); // Show our UI over NativeActivity window _popupWindow.showAtLocation(mainLayout, Gravity.BOTTOM | Gravity.START, 0, 0); _popupWindow.update(); _takePhoto = (ImageButton) popupView.findViewById(R.id.takePhoto); _takePhoto.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { TakePhoto(); } }); _takePhoto.setEnabled(true); (popupView.findViewById(R.id.exposureLabel)).setEnabled(true); (popupView.findViewById(R.id.sensitivityLabel)).setEnabled(true); SeekBar seekBar = (SeekBar) popupView.findViewById(R.id.exposure_seekbar); _exposure = new CameraSeekBar(seekBar, (TextView) popupView.findViewById(R.id.exposureVal), _initParams[0], _initParams[1], _initParams[2]); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { _exposure.updateProgress(progress); OnExposureChanged(_exposure.getAbsProgress()); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); seekBar = ((SeekBar) popupView.findViewById(R.id.sensitivity_seekbar)); _sensitivity = new CameraSeekBar(seekBar, (TextView) popupView.findViewById(R.id.sensitivityVal), _initParams[3], _initParams[4], _initParams[5]); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { _sensitivity.updateProgress(progress); OnSensitivityChanged(_sensitivity.getAbsProgress()); } @Override public void onStartTrackingTouch(SeekBar seekBar) { } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); } catch (WindowManager.BadTokenException e) { // UI error out, ignore and continue Log.e(DBG_TAG, "UI Exception Happened: " + e.getMessage()); } }}); } /** Called from Native side to notify that a photo is taken */ public void OnPhotoTaken(String fileName) { final String name = fileName; runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "Photo saved to " + name, Toast.LENGTH_SHORT).show(); } }); } native static void notifyCameraPermission(boolean granted); native static void TakePhoto(); native void OnExposureChanged(long exposure); native void OnSensitivityChanged(long sensitivity); static { System.loadLibrary("ndk_camera"); } } ================================================ FILE: camera/basic/src/main/res/layout/widgets.xml ================================================ ================================================ FILE: camera/basic/src/main/res/values/strings.xml ================================================ NDKCamera ================================================ FILE: camera/camera-utils/build.gradle.kts ================================================ plugins { id("ndksamples.android.library") } android { namespace = "com.android.ndk.samples.camera.utils" defaultConfig { minSdk = 24 } externalNativeBuild { cmake { path = file("src/main/cpp/CMakeLists.txt") } } buildFeatures { prefabPublishing = true } prefab { create("camera-utils") { headers = "src/main/cpp/include" } } } ================================================ FILE: camera/camera-utils/src/main/cpp/CMakeLists.txt ================================================ cmake_minimum_required(VERSION 3.22.1) project(CameraCommon LANGUAGES CXX) include(AppLibrary) add_app_library(camera-utils STATIC camera_utils.cpp ) target_include_directories(camera-utils PUBLIC include) target_link_libraries(camera-utils PUBLIC log) ================================================ FILE: camera/camera-utils/src/main/cpp/camera_utils.cpp ================================================ /* * Copyright (C) 2017 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. */ #include "ndksamples/camera/camera_utils.h" #include #include #include #include #include #include #include #include "ndksamples/camera/native_debug.h" #define UKNOWN_TAG "UNKNOW_TAG" #define MAKE_PAIR(val) std::make_pair(val, #val) template const char* GetPairStr(T key, std::vector>& store) { typedef typename std::vector>::iterator iterator; for (iterator it = store.begin(); it != store.end(); ++it) { if (it->first == key) { return it->second; } } LOGW("(%#08x) : UNKNOWN_TAG for %s", key, typeid(store[0].first).name()); return UKNOWN_TAG; } /* * camera_status_t error translation */ using ERROR_PAIR = std::pair; static std::vector errorInfo{ MAKE_PAIR(ACAMERA_OK), MAKE_PAIR(ACAMERA_ERROR_UNKNOWN), MAKE_PAIR(ACAMERA_ERROR_INVALID_PARAMETER), MAKE_PAIR(ACAMERA_ERROR_CAMERA_DISCONNECTED), MAKE_PAIR(ACAMERA_ERROR_NOT_ENOUGH_MEMORY), MAKE_PAIR(ACAMERA_ERROR_METADATA_NOT_FOUND), MAKE_PAIR(ACAMERA_ERROR_CAMERA_DEVICE), MAKE_PAIR(ACAMERA_ERROR_CAMERA_SERVICE), MAKE_PAIR(ACAMERA_ERROR_SESSION_CLOSED), MAKE_PAIR(ACAMERA_ERROR_INVALID_OPERATION), MAKE_PAIR(ACAMERA_ERROR_STREAM_CONFIGURE_FAIL), MAKE_PAIR(ACAMERA_ERROR_CAMERA_IN_USE), MAKE_PAIR(ACAMERA_ERROR_MAX_CAMERA_IN_USE), MAKE_PAIR(ACAMERA_ERROR_CAMERA_DISABLED), MAKE_PAIR(ACAMERA_ERROR_PERMISSION_DENIED), }; const char* GetErrorStr(camera_status_t err) { return GetPairStr(err, errorInfo); } /* * camera_metadata_tag_t translation. Useful to look at available tags * on the underneath platform */ using TAG_PAIR = std::pair; static std::vector tagInfo{ MAKE_PAIR(ACAMERA_COLOR_CORRECTION_MODE), MAKE_PAIR(ACAMERA_COLOR_CORRECTION_TRANSFORM), MAKE_PAIR(ACAMERA_COLOR_CORRECTION_GAINS), MAKE_PAIR(ACAMERA_COLOR_CORRECTION_ABERRATION_MODE), MAKE_PAIR(ACAMERA_COLOR_CORRECTION_AVAILABLE_ABERRATION_MODES), MAKE_PAIR(ACAMERA_COLOR_CORRECTION_END), MAKE_PAIR(ACAMERA_CONTROL_AE_ANTIBANDING_MODE), MAKE_PAIR(ACAMERA_CONTROL_AE_EXPOSURE_COMPENSATION), MAKE_PAIR(ACAMERA_CONTROL_AE_LOCK), MAKE_PAIR(ACAMERA_CONTROL_AE_MODE), MAKE_PAIR(ACAMERA_CONTROL_AE_REGIONS), MAKE_PAIR(ACAMERA_CONTROL_AE_TARGET_FPS_RANGE), MAKE_PAIR(ACAMERA_CONTROL_AE_PRECAPTURE_TRIGGER), MAKE_PAIR(ACAMERA_CONTROL_AF_MODE), MAKE_PAIR(ACAMERA_CONTROL_AF_REGIONS), MAKE_PAIR(ACAMERA_CONTROL_AF_TRIGGER), MAKE_PAIR(ACAMERA_CONTROL_AWB_LOCK), MAKE_PAIR(ACAMERA_CONTROL_AWB_MODE), MAKE_PAIR(ACAMERA_CONTROL_AWB_REGIONS), MAKE_PAIR(ACAMERA_CONTROL_CAPTURE_INTENT), MAKE_PAIR(ACAMERA_CONTROL_EFFECT_MODE), MAKE_PAIR(ACAMERA_CONTROL_MODE), MAKE_PAIR(ACAMERA_CONTROL_SCENE_MODE), MAKE_PAIR(ACAMERA_CONTROL_VIDEO_STABILIZATION_MODE), MAKE_PAIR(ACAMERA_CONTROL_AE_AVAILABLE_ANTIBANDING_MODES), MAKE_PAIR(ACAMERA_CONTROL_AE_AVAILABLE_MODES), MAKE_PAIR(ACAMERA_CONTROL_AE_AVAILABLE_TARGET_FPS_RANGES), MAKE_PAIR(ACAMERA_CONTROL_AE_COMPENSATION_RANGE), MAKE_PAIR(ACAMERA_CONTROL_AE_COMPENSATION_STEP), MAKE_PAIR(ACAMERA_CONTROL_AF_AVAILABLE_MODES), MAKE_PAIR(ACAMERA_CONTROL_AVAILABLE_EFFECTS), MAKE_PAIR(ACAMERA_CONTROL_AVAILABLE_SCENE_MODES), MAKE_PAIR(ACAMERA_CONTROL_AVAILABLE_VIDEO_STABILIZATION_MODES), MAKE_PAIR(ACAMERA_CONTROL_AWB_AVAILABLE_MODES), MAKE_PAIR(ACAMERA_CONTROL_MAX_REGIONS), MAKE_PAIR(ACAMERA_CONTROL_AE_STATE), MAKE_PAIR(ACAMERA_CONTROL_AF_STATE), MAKE_PAIR(ACAMERA_CONTROL_AWB_STATE), MAKE_PAIR(ACAMERA_CONTROL_AE_LOCK_AVAILABLE), MAKE_PAIR(ACAMERA_CONTROL_AWB_LOCK_AVAILABLE), MAKE_PAIR(ACAMERA_CONTROL_AVAILABLE_MODES), MAKE_PAIR(ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST_RANGE), MAKE_PAIR(ACAMERA_CONTROL_POST_RAW_SENSITIVITY_BOOST), MAKE_PAIR(ACAMERA_CONTROL_END), MAKE_PAIR(ACAMERA_EDGE_MODE), MAKE_PAIR(ACAMERA_EDGE_AVAILABLE_EDGE_MODES), MAKE_PAIR(ACAMERA_EDGE_END), MAKE_PAIR(ACAMERA_FLASH_MODE), MAKE_PAIR(ACAMERA_FLASH_STATE), MAKE_PAIR(ACAMERA_FLASH_END), MAKE_PAIR(ACAMERA_FLASH_INFO_AVAILABLE), MAKE_PAIR(ACAMERA_FLASH_INFO_END), MAKE_PAIR(ACAMERA_HOT_PIXEL_MODE), MAKE_PAIR(ACAMERA_HOT_PIXEL_AVAILABLE_HOT_PIXEL_MODES), MAKE_PAIR(ACAMERA_HOT_PIXEL_END), MAKE_PAIR(ACAMERA_JPEG_GPS_COORDINATES), MAKE_PAIR(ACAMERA_JPEG_GPS_PROCESSING_METHOD), MAKE_PAIR(ACAMERA_JPEG_GPS_TIMESTAMP), MAKE_PAIR(ACAMERA_JPEG_ORIENTATION), MAKE_PAIR(ACAMERA_JPEG_QUALITY), MAKE_PAIR(ACAMERA_JPEG_THUMBNAIL_QUALITY), MAKE_PAIR(ACAMERA_JPEG_THUMBNAIL_SIZE), MAKE_PAIR(ACAMERA_JPEG_AVAILABLE_THUMBNAIL_SIZES), MAKE_PAIR(ACAMERA_JPEG_END), MAKE_PAIR(ACAMERA_LENS_APERTURE), MAKE_PAIR(ACAMERA_LENS_FILTER_DENSITY), MAKE_PAIR(ACAMERA_LENS_FOCAL_LENGTH), MAKE_PAIR(ACAMERA_LENS_FOCUS_DISTANCE), MAKE_PAIR(ACAMERA_LENS_OPTICAL_STABILIZATION_MODE), MAKE_PAIR(ACAMERA_LENS_FACING), MAKE_PAIR(ACAMERA_LENS_POSE_ROTATION), MAKE_PAIR(ACAMERA_LENS_POSE_TRANSLATION), MAKE_PAIR(ACAMERA_LENS_FOCUS_RANGE), MAKE_PAIR(ACAMERA_LENS_STATE), MAKE_PAIR(ACAMERA_LENS_INTRINSIC_CALIBRATION), MAKE_PAIR(ACAMERA_LENS_RADIAL_DISTORTION), MAKE_PAIR(ACAMERA_LENS_END), MAKE_PAIR(ACAMERA_LENS_INFO_AVAILABLE_APERTURES), MAKE_PAIR(ACAMERA_LENS_INFO_AVAILABLE_FILTER_DENSITIES), MAKE_PAIR(ACAMERA_LENS_INFO_AVAILABLE_FOCAL_LENGTHS), MAKE_PAIR(ACAMERA_LENS_INFO_AVAILABLE_OPTICAL_STABILIZATION), MAKE_PAIR(ACAMERA_LENS_INFO_HYPERFOCAL_DISTANCE), MAKE_PAIR(ACAMERA_LENS_INFO_MINIMUM_FOCUS_DISTANCE), MAKE_PAIR(ACAMERA_LENS_INFO_SHADING_MAP_SIZE), MAKE_PAIR(ACAMERA_LENS_INFO_FOCUS_DISTANCE_CALIBRATION), MAKE_PAIR(ACAMERA_LENS_INFO_END), MAKE_PAIR(ACAMERA_NOISE_REDUCTION_MODE), MAKE_PAIR(ACAMERA_NOISE_REDUCTION_AVAILABLE_NOISE_REDUCTION_MODES), MAKE_PAIR(ACAMERA_NOISE_REDUCTION_END), MAKE_PAIR(ACAMERA_REQUEST_MAX_NUM_OUTPUT_STREAMS), MAKE_PAIR(ACAMERA_REQUEST_PIPELINE_DEPTH), MAKE_PAIR(ACAMERA_REQUEST_PIPELINE_MAX_DEPTH), MAKE_PAIR(ACAMERA_REQUEST_PARTIAL_RESULT_COUNT), MAKE_PAIR(ACAMERA_REQUEST_AVAILABLE_CAPABILITIES), MAKE_PAIR(ACAMERA_REQUEST_AVAILABLE_REQUEST_KEYS), MAKE_PAIR(ACAMERA_REQUEST_AVAILABLE_RESULT_KEYS), MAKE_PAIR(ACAMERA_REQUEST_AVAILABLE_CHARACTERISTICS_KEYS), MAKE_PAIR(ACAMERA_REQUEST_END), MAKE_PAIR(ACAMERA_SCALER_CROP_REGION), MAKE_PAIR(ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM), MAKE_PAIR(ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS), MAKE_PAIR(ACAMERA_SCALER_AVAILABLE_MIN_FRAME_DURATIONS), MAKE_PAIR(ACAMERA_SCALER_AVAILABLE_STALL_DURATIONS), MAKE_PAIR(ACAMERA_SCALER_CROPPING_TYPE), MAKE_PAIR(ACAMERA_SCALER_END), MAKE_PAIR(ACAMERA_SENSOR_EXPOSURE_TIME), MAKE_PAIR(ACAMERA_SENSOR_FRAME_DURATION), MAKE_PAIR(ACAMERA_SENSOR_SENSITIVITY), MAKE_PAIR(ACAMERA_SENSOR_REFERENCE_ILLUMINANT1), MAKE_PAIR(ACAMERA_SENSOR_REFERENCE_ILLUMINANT2), MAKE_PAIR(ACAMERA_SENSOR_CALIBRATION_TRANSFORM1), MAKE_PAIR(ACAMERA_SENSOR_CALIBRATION_TRANSFORM2), MAKE_PAIR(ACAMERA_SENSOR_COLOR_TRANSFORM1), MAKE_PAIR(ACAMERA_SENSOR_COLOR_TRANSFORM2), MAKE_PAIR(ACAMERA_SENSOR_FORWARD_MATRIX1), MAKE_PAIR(ACAMERA_SENSOR_FORWARD_MATRIX2), MAKE_PAIR(ACAMERA_SENSOR_BLACK_LEVEL_PATTERN), MAKE_PAIR(ACAMERA_SENSOR_MAX_ANALOG_SENSITIVITY), MAKE_PAIR(ACAMERA_SENSOR_ORIENTATION), MAKE_PAIR(ACAMERA_SENSOR_TIMESTAMP), MAKE_PAIR(ACAMERA_SENSOR_NEUTRAL_COLOR_POINT), MAKE_PAIR(ACAMERA_SENSOR_NOISE_PROFILE), MAKE_PAIR(ACAMERA_SENSOR_GREEN_SPLIT), MAKE_PAIR(ACAMERA_SENSOR_TEST_PATTERN_DATA), MAKE_PAIR(ACAMERA_SENSOR_TEST_PATTERN_MODE), MAKE_PAIR(ACAMERA_SENSOR_AVAILABLE_TEST_PATTERN_MODES), MAKE_PAIR(ACAMERA_SENSOR_ROLLING_SHUTTER_SKEW), MAKE_PAIR(ACAMERA_SENSOR_OPTICAL_BLACK_REGIONS), MAKE_PAIR(ACAMERA_SENSOR_DYNAMIC_BLACK_LEVEL), MAKE_PAIR(ACAMERA_SENSOR_DYNAMIC_WHITE_LEVEL), MAKE_PAIR(ACAMERA_SENSOR_END), MAKE_PAIR(ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE), MAKE_PAIR(ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE), MAKE_PAIR(ACAMERA_SENSOR_INFO_COLOR_FILTER_ARRANGEMENT), MAKE_PAIR(ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE), MAKE_PAIR(ACAMERA_SENSOR_INFO_MAX_FRAME_DURATION), MAKE_PAIR(ACAMERA_SENSOR_INFO_PHYSICAL_SIZE), MAKE_PAIR(ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE), MAKE_PAIR(ACAMERA_SENSOR_INFO_WHITE_LEVEL), MAKE_PAIR(ACAMERA_SENSOR_INFO_TIMESTAMP_SOURCE), MAKE_PAIR(ACAMERA_SENSOR_INFO_LENS_SHADING_APPLIED), MAKE_PAIR(ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE), MAKE_PAIR(ACAMERA_SENSOR_INFO_END), MAKE_PAIR(ACAMERA_SHADING_MODE), MAKE_PAIR(ACAMERA_SHADING_AVAILABLE_MODES), MAKE_PAIR(ACAMERA_SHADING_END), MAKE_PAIR(ACAMERA_STATISTICS_FACE_DETECT_MODE), MAKE_PAIR(ACAMERA_STATISTICS_HOT_PIXEL_MAP_MODE), MAKE_PAIR(ACAMERA_STATISTICS_FACE_IDS), MAKE_PAIR(ACAMERA_STATISTICS_FACE_LANDMARKS), MAKE_PAIR(ACAMERA_STATISTICS_FACE_RECTANGLES), MAKE_PAIR(ACAMERA_STATISTICS_FACE_SCORES), MAKE_PAIR(ACAMERA_STATISTICS_LENS_SHADING_MAP), MAKE_PAIR(ACAMERA_STATISTICS_SCENE_FLICKER), MAKE_PAIR(ACAMERA_STATISTICS_HOT_PIXEL_MAP), MAKE_PAIR(ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE), MAKE_PAIR(ACAMERA_STATISTICS_END), MAKE_PAIR(ACAMERA_STATISTICS_INFO_AVAILABLE_FACE_DETECT_MODES), MAKE_PAIR(ACAMERA_STATISTICS_INFO_MAX_FACE_COUNT), MAKE_PAIR(ACAMERA_STATISTICS_INFO_AVAILABLE_HOT_PIXEL_MAP_MODES), MAKE_PAIR(ACAMERA_STATISTICS_INFO_AVAILABLE_LENS_SHADING_MAP_MODES), MAKE_PAIR(ACAMERA_STATISTICS_INFO_END), MAKE_PAIR(ACAMERA_TONEMAP_CURVE_BLUE), MAKE_PAIR(ACAMERA_TONEMAP_CURVE_GREEN), MAKE_PAIR(ACAMERA_TONEMAP_CURVE_RED), MAKE_PAIR(ACAMERA_TONEMAP_MODE), MAKE_PAIR(ACAMERA_TONEMAP_MAX_CURVE_POINTS), MAKE_PAIR(ACAMERA_TONEMAP_AVAILABLE_TONE_MAP_MODES), MAKE_PAIR(ACAMERA_TONEMAP_GAMMA), MAKE_PAIR(ACAMERA_TONEMAP_PRESET_CURVE), MAKE_PAIR(ACAMERA_TONEMAP_END), MAKE_PAIR(ACAMERA_INFO_SUPPORTED_HARDWARE_LEVEL), MAKE_PAIR(ACAMERA_INFO_END), MAKE_PAIR(ACAMERA_BLACK_LEVEL_LOCK), MAKE_PAIR(ACAMERA_BLACK_LEVEL_END), MAKE_PAIR(ACAMERA_SYNC_FRAME_NUMBER), MAKE_PAIR(ACAMERA_SYNC_MAX_LATENCY), MAKE_PAIR(ACAMERA_SYNC_END), MAKE_PAIR(ACAMERA_DEPTH_AVAILABLE_DEPTH_STREAM_CONFIGURATIONS), MAKE_PAIR(ACAMERA_DEPTH_AVAILABLE_DEPTH_MIN_FRAME_DURATIONS), MAKE_PAIR(ACAMERA_DEPTH_AVAILABLE_DEPTH_STALL_DURATIONS), MAKE_PAIR(ACAMERA_DEPTH_DEPTH_IS_EXCLUSIVE), MAKE_PAIR(ACAMERA_DEPTH_END), }; const char* GetTagStr(acamera_metadata_tag_t tag) { return GetPairStr(tag, tagInfo); } using FORMAT_PAIR = std::pair; static std::vector formatInfo{ MAKE_PAIR(AIMAGE_FORMAT_YUV_420_888), MAKE_PAIR(AIMAGE_FORMAT_JPEG), MAKE_PAIR(AIMAGE_FORMAT_RAW16), MAKE_PAIR(AIMAGE_FORMAT_RAW_PRIVATE), MAKE_PAIR(AIMAGE_FORMAT_RAW10), MAKE_PAIR(AIMAGE_FORMAT_RAW12), MAKE_PAIR(AIMAGE_FORMAT_DEPTH16), MAKE_PAIR(AIMAGE_FORMAT_DEPTH_POINT_CLOUD), MAKE_PAIR(AIMAGE_FORMAT_PRIVATE), }; const char* GetFormatStr(int fmt) { return GetPairStr(fmt, formatInfo); } void PrintMetadataTags(int32_t entries, const uint32_t* pTags) { LOGI("MetadataTag (start):"); for (int32_t idx = 0; idx < entries; ++idx) { const char* name = GetTagStr(static_cast(pTags[idx])); LOGI("(%#08x) : %s", pTags[idx], name); } LOGI("MetadataTag (end)"); } void PrintLensFacing(ACameraMetadata_const_entry& lens) { ASSERT(lens.tag == ACAMERA_LENS_FACING, "Wrong tag(%#x) of %s to %s", lens.tag, GetTagStr((acamera_metadata_tag_t)lens.tag), __FUNCTION__); LOGI("LensFacing: tag(%#x), type(%d), count(%d), val(%#x)", lens.tag, lens.type, lens.count, lens.data.u8[0]); } /* * Stream_Configuration is in format of: * format, width, height, input? * ACAMERA_TYPE_INT32 type */ void PrintStreamConfigurations(ACameraMetadata_const_entry& val) { #define MODE_LABLE "ModeInfo:" const char* tagName = GetTagStr(static_cast(val.tag)); ASSERT(!(val.count & 0x3), "STREAM_CONFIGURATION (%d) should multiple of 4", val.count); ASSERT(val.type == ACAMERA_TYPE_INT32, "STREAM_CONFIGURATION TYPE(%d) is not ACAMERA_TYPE_INT32(1)", val.type); LOGI("%s -- %s:", tagName, MODE_LABLE); for (uint32_t i = 0; i < val.count; i += 4) { LOGI("%s: %08d x %08d %s", GetFormatStr(val.data.i32[i]), val.data.i32[i + 1], val.data.i32[i + 2], val.data.i32[i + 3] ? "INPUT" : "OUTPUT"); } #undef MODE_LABLE } void PrintTagVal(const char* printLabel, ACameraMetadata_const_entry& val) { if (val.tag == ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS) { PrintStreamConfigurations(val); return; } const char* name = GetTagStr(static_cast(val.tag)); for (uint32_t i = 0; i < val.count; ++i) { switch (val.type) { case ACAMERA_TYPE_INT32: LOGI("%s %s: %08d", printLabel, name, val.data.i32[i]); break; case ACAMERA_TYPE_BYTE: LOGI("%s %s: %#02x", printLabel, name, val.data.u8[i]); break; case ACAMERA_TYPE_INT64: LOGI("%s %s: %" PRIu64, printLabel, name, (int64_t)val.data.i64[i]); break; case ACAMERA_TYPE_FLOAT: LOGI("%s %s: %f", printLabel, name, val.data.f[i]); break; case ACAMERA_TYPE_DOUBLE: LOGI("%s %s: %" PRIx64, printLabel, name, val.data.i64[i]); break; case ACAMERA_TYPE_RATIONAL: LOGI("%s %s: %08x, %08x", printLabel, name, val.data.r[i].numerator, val.data.r[i].denominator); break; default: ASSERT(false, "Unknown tag value type: %d", val.type); } } } /* * PrintCamera(): * Enumerate existing camera and its metadata. */ void PrintCameras(ACameraManager* cmrMgr) { if (!cmrMgr) return; ACameraIdList* cameraIds = nullptr; camera_status_t status = ACameraManager_getCameraIdList(cmrMgr, &cameraIds); LOGI("camera Status = %d, %s", status, GetErrorStr(status)); for (int i = 0; i < cameraIds->numCameras; ++i) { const char* id = cameraIds->cameraIds[i]; LOGI("=====cameraId = %d, cameraName = %s=====", i, id); ACameraMetadata* metadataObj; CALL_MGR(getCameraCharacteristics(cmrMgr, id, &metadataObj)); int32_t count = 0; const uint32_t* tags = nullptr; ACameraMetadata_getAllTags(metadataObj, &count, &tags); for (int tagIdx = 0; tagIdx < count; ++tagIdx) { ACameraMetadata_const_entry val = {}; camera_status_t status = ACameraMetadata_getConstEntry(metadataObj, tags[tagIdx], &val); if (status != ACAMERA_OK) { LOGW("Unsupported Tag: %s", GetTagStr(static_cast(tags[tagIdx]))); continue; } PrintTagVal("Camera Tag:", val); if (ACAMERA_LENS_FACING == tags[tagIdx]) { PrintLensFacing(val); } } ACameraMetadata_free(metadataObj); } ACameraManager_deleteCameraIdList(cameraIds); } void PrintRequestMetadata(ACaptureRequest* req) { if (!req) return; int32_t count; const uint32_t* tags; CALL_REQUEST(getAllTags(req, &count, &tags)); for (int32_t idx = 0; idx < count; ++idx) { ACameraMetadata_const_entry val; CALL_REQUEST(getConstEntry(req, tags[idx], &val)); const char* name = GetTagStr(static_cast(tags[idx])); for (uint32_t i = 0; i < val.count; ++i) { switch (val.type) { case ACAMERA_TYPE_INT32: LOGI("Capture Tag %s: %08d", name, val.data.i32[i]); break; case ACAMERA_TYPE_BYTE: LOGI("Capture Tag %s: %#08x", name, val.data.u8[i]); break; case ACAMERA_TYPE_INT64: LOGI("Capture Tag %s: %" PRIu64, name, (int64_t)val.data.i64[i]); break; case ACAMERA_TYPE_FLOAT: LOGI("Capture Tag %s: %f", name, val.data.f[i]); break; case ACAMERA_TYPE_DOUBLE: LOGI("Capture Tag %s: %" PRIx64, name, val.data.i64[i]); break; case ACAMERA_TYPE_RATIONAL: LOGI("Capture Tag %s: %08x, %08x", name, val.data.r[i].numerator, val.data.r[i].denominator); break; default: ASSERT(false, "Unknown tag value type: %d", val.type); } } } } /* * CameraDevice error state translation, used in * ACameraDevice_ErrorStateCallback */ using DEV_ERROR_PAIR = std::pair; static std::vector devErrors{ MAKE_PAIR(ERROR_CAMERA_IN_USE), MAKE_PAIR(ERROR_MAX_CAMERAS_IN_USE), MAKE_PAIR(ERROR_CAMERA_DISABLED), MAKE_PAIR(ERROR_CAMERA_DEVICE), MAKE_PAIR(ERROR_CAMERA_SERVICE), }; const char* GetCameraDeviceErrorStr(int err) { return GetPairStr(err, devErrors); } void PrintCameraDeviceError(int err) { LOGI("CameraDeviceError(%#x): %s", err, GetCameraDeviceErrorStr(err)); } ================================================ FILE: camera/camera-utils/src/main/cpp/include/ndksamples/camera/camera_utils.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef __CAMERA_CAMERA_UTILS_H__ #define __CAMERA_CAMERA_UTILS_H__ #include #include /* * A set of macros to call into Camera APIs. The API is grouped with a few * objects, with object name as the prefix of function names. */ #define CALL_CAMERA(func) \ { \ camera_status_t status = func; \ ASSERT(status == ACAMERA_OK, "%s call failed with code: %#x, %s", \ __FUNCTION__, status, GetErrorStr(status)); \ } #define CALL_MGR(func) CALL_CAMERA(ACameraManager_##func) #define CALL_DEV(func) CALL_CAMERA(ACameraDevice_##func) #define CALL_METADATA(func) CALL_CAMERA(ACameraMetadata_##func) #define CALL_CONTAINER(func) CALL_CAMERA(ACaptureSessionOutputContainer_##func) #define CALL_OUTPUT(func) CALL_CAMERA(ACaptureSessionOutput_##func) #define CALL_TARGET(func) CALL_CAMERA(ACameraOutputTarget_##func) #define CALL_REQUEST(func) CALL_CAMERA(ACaptureRequest_##func) #define CALL_SESSION(func) CALL_CAMERA(ACameraCaptureSession_##func) /* * A few debugging functions for error code strings etc */ const char* GetErrorStr(camera_status_t err); const char* GetTagStr(acamera_metadata_tag_t tag); void PrintMetadataTags(int32_t entries, const uint32_t* pTags); void PrintLensFacing(ACameraMetadata_const_entry& lensData); void PrintCameras(ACameraManager* cameraMgr); void PrintCameraDeviceError(int err); void PrintRequestMetadata(ACaptureRequest* req); #endif // __CAMERA_CAMERA_UTILS_H__ ================================================ FILE: camera/camera-utils/src/main/cpp/include/ndksamples/camera/native_debug.h ================================================ #include #define LOG_TAG "CAMERA-SAMPLE" #define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) #define ASSERT(cond, fmt, ...) \ if (!(cond)) { \ __android_log_assert(#cond, LOG_TAG, fmt, ##__VA_ARGS__); \ } ================================================ FILE: camera/texture-view/build.gradle ================================================ plugins { id "ndksamples.android.application" } android { namespace 'com.sample.textureview' defaultConfig { applicationId "com.sample.textureview" minSdkVersion 24 externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_static' } } } externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' } } buildFeatures { prefab true } } dependencies { implementation libs.androidx.core implementation project(":base") implementation project(":camera:camera-utils") } ================================================ FILE: camera/texture-view/src/main/AndroidManifest.xml ================================================ ================================================ FILE: camera/texture-view/src/main/cpp/CMakeLists.txt ================================================ # # Copyright (C) 2017 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. # cmake_minimum_required(VERSION 3.22.1) project(CameraTextureView LANGUAGES CXX) include(AppLibrary) find_package(base REQUIRED CONFIG) find_package(camera-utils REQUIRED CONFIG) add_app_library(camera_textureview SHARED android_main.cpp camera_manager.cpp camera_engine.cpp camera_listeners.cpp ) target_link_libraries(camera_textureview PRIVATE base::base camera-utils::camera-utils dl android log m camera2ndk ) ================================================ FILE: camera/texture-view/src/main/cpp/android_main.cpp ================================================ /** * Copyright (C) 2017 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. */ /* Description * Demonstrate NDKCamera's PREVIEW mode -- hooks camera directly into * display. * Control: * Double-Tap on Android device's screen to toggle start/stop preview * Tested: * Google Pixel and Nexus 6 phones */ #include #include #include #include #include "camera_engine.h" #include "camera_manager.h" /** * Application object: * the top level camera application object, maintained by native code only */ CameraAppEngine* pEngineObj = nullptr; /** * createCamera() Create application instance and NDK camera object * @param width is the texture view window width * @param height is the texture view window height * In this sample, it takes the simplest approach in that: * the android system display size is used to view full screen * preview camera images. Onboard Camera most likely to * support the onboard panel size on that device. Camera is most likely * to be oriented as landscape mode, the input width/height is in * landscape mode. TextureView on Java side handles rotation for * portrait mode. * @return application object instance ( not used in this sample ) */ jlong CreateCamera(JNIEnv* env, jobject, jint width, jint height) { pEngineObj = new CameraAppEngine(env, width, height); return reinterpret_cast(pEngineObj); } /** * deleteCamera(): * releases native application object, which * triggers native camera object be released */ void DeleteCamera(JNIEnv*, jobject, jlong ndkCameraObj) { if (!pEngineObj || !ndkCameraObj) { return; } CameraAppEngine* pApp = reinterpret_cast(ndkCameraObj); ASSERT(pApp == pEngineObj, "NdkCamera Obj mismatch"); delete pApp; // also reset the private global object pEngineObj = nullptr; } /** * getCameraCompatibleSize() * @returns minimium camera preview window size for the given * requested camera size in CreateCamera() function, with the same * ascpect ratio. essentially, * 1) Display device size decides NDKCamera object preview size * 2) Chosen NDKCamera preview size passed to TextView to * reset textureView size * 3) textureView size is stretched when previewing image * on display device */ jobject GetMinimumCompatiblePreviewSize(JNIEnv* env, jobject, jlong ndkCameraObj) { if (!ndkCameraObj) { return nullptr; } CameraAppEngine* pApp = reinterpret_cast(ndkCameraObj); jclass cls = env->FindClass("android/util/Size"); jobject previewSize = env->NewObject(cls, env->GetMethodID(cls, "", "(II)V"), pApp->GetCompatibleCameraRes().width, pApp->GetCompatibleCameraRes().height); return previewSize; } /** * OnPreviewSurfaceCreated() * Notification to native camera that java TextureView is ready * to preview video. Simply create cameraSession and * start camera preview */ void OnPreviewSurfaceCreated(JNIEnv*, jobject, jlong ndkCameraObj, jobject surface) { ASSERT(ndkCameraObj && (jlong)pEngineObj == ndkCameraObj, "NativeObject should not be null Pointer"); CameraAppEngine* pApp = reinterpret_cast(ndkCameraObj); pApp->CreateCameraSession(surface); pApp->StartPreview(true); } /** * OnPreviewSurfaceDestroyed() * Notification to native camera that java TextureView is destroyed * Native camera would: * * stop preview */ void OnPreviewSurfaceDestroyed(JNIEnv* env, jobject, jlong ndkCameraObj, jobject surface) { CameraAppEngine* pApp = reinterpret_cast(ndkCameraObj); ASSERT(ndkCameraObj && pEngineObj == pApp, "NativeObject should not be null Pointer"); jclass cls = env->FindClass("android/view/Surface"); jmethodID toString = env->GetMethodID(cls, "toString", "()Ljava/lang/String;"); jstring destroyObjStr = reinterpret_cast(env->CallObjectMethod(surface, toString)); const char* destroyObjName = env->GetStringUTFChars(destroyObjStr, nullptr); jstring appObjStr = reinterpret_cast( env->CallObjectMethod(pApp->GetSurfaceObject(), toString)); const char* appObjName = env->GetStringUTFChars(appObjStr, nullptr); ASSERT(!strcmp(destroyObjName, appObjName), "object Name MisMatch"); env->ReleaseStringUTFChars(destroyObjStr, destroyObjName); env->ReleaseStringUTFChars(appObjStr, appObjName); pApp->StartPreview(false); } extern "C" JNIEXPORT jint JNI_OnLoad(JavaVM* _Nonnull vm, void* _Nullable) { JNIEnv* env; if (vm->GetEnv(reinterpret_cast(&env), JNI_VERSION_1_6) != JNI_OK) { return JNI_ERR; } jclass c = env->FindClass("com/sample/textureview/ViewActivity"); if (c == nullptr) return JNI_ERR; static const JNINativeMethod methods[] = { {"createCamera", "(II)J", reinterpret_cast(CreateCamera)}, {"deleteCamera", "(JLandroid/view/Surface;)V", reinterpret_cast(DeleteCamera)}, {"getMinimumCompatiblePreviewSize", "(J)Landroid/util/Size;", reinterpret_cast(GetMinimumCompatiblePreviewSize)}, {"onPreviewSurfaceCreated", "(JLandroid/view/Surface;)V", reinterpret_cast(OnPreviewSurfaceCreated)}, {"onPreviewSurfaceDestroyed", "(JLandroid/view/Surface;)V", reinterpret_cast(OnPreviewSurfaceDestroyed)}, }; int rc = env->RegisterNatives(c, methods, arraysize(methods)); if (rc != JNI_OK) return rc; return JNI_VERSION_1_6; } ================================================ FILE: camera/texture-view/src/main/cpp/camera_engine.cpp ================================================ /** * Copyright (C) 2017 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. */ /** Description * Demonstrate NDK Camera interface added to android-24 */ #include "camera_engine.h" #include #include #include CameraAppEngine::CameraAppEngine(JNIEnv* env, jint w, jint h) : env_(env), requestWidth_(w), requestHeight_(h), surface_(nullptr), camera_(nullptr) { memset(&compatibleCameraRes_, 0, sizeof(compatibleCameraRes_)); camera_ = new NDKCamera(); ASSERT(camera_, "Failed to Create CameraObject"); camera_->MatchCaptureSizeRequest(requestWidth_, requestHeight_, &compatibleCameraRes_); } CameraAppEngine::~CameraAppEngine() { if (camera_) { delete camera_; camera_ = nullptr; } if (surface_) { env_->DeleteGlobalRef(surface_); surface_ = nullptr; } } /** * Create a capture session with given Java Surface Object * @param surface a {@link Surface} object. */ void CameraAppEngine::CreateCameraSession(jobject surface) { surface_ = env_->NewGlobalRef(surface); camera_->CreateSession(ANativeWindow_fromSurface(env_, surface)); } /** * @return cached {@link Surface} object */ jobject CameraAppEngine::GetSurfaceObject() { return surface_; } /** * * @return saved camera preview resolution for this session */ const ImageFormat& CameraAppEngine::GetCompatibleCameraRes() const { return compatibleCameraRes_; } int CameraAppEngine::GetCameraSensorOrientation(int32_t requestFacing) { ASSERT(requestFacing == ACAMERA_LENS_FACING_BACK, "Only support rear facing camera"); int32_t facing = 0, angle = 0; if (camera_->GetSensorOrientation(&facing, &angle) || facing == requestFacing) { return angle; } ASSERT(false, "Failed for GetSensorOrientation()"); return 0; } /** * * @param start is true to start preview, false to stop preview * @return true if preview started, false when error happened */ void CameraAppEngine::StartPreview(bool start) { camera_->StartPreview(start); } ================================================ FILE: camera/texture-view/src/main/cpp/camera_engine.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef __CAMERA_ENGINE_H__ #define __CAMERA_ENGINE_H__ #include #include #include #include #include #include #include "camera_manager.h" /** * CameraAppEngine */ class CameraAppEngine { public: explicit CameraAppEngine(JNIEnv* env, jint w, jint h); ~CameraAppEngine(); // Manage NDKCamera Object void CreateCameraSession(jobject surface); void StartPreview(bool start); const ImageFormat& GetCompatibleCameraRes() const; int32_t GetCameraSensorOrientation(int32_t facing); jobject GetSurfaceObject(); private: JNIEnv* env_; int32_t requestWidth_; int32_t requestHeight_; jobject surface_; NDKCamera* camera_; ImageFormat compatibleCameraRes_; }; #endif // __CAMERA_ENGINE_H__ ================================================ FILE: camera/texture-view/src/main/cpp/camera_listeners.cpp ================================================ /* * Copyright (C) 2017 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. */ #include #include #include #include #include #include #include #include "camera_manager.h" /* * Camera Manager Listener object */ void OnCameraAvailable(void* ctx, const char* id) { reinterpret_cast(ctx)->OnCameraStatusChanged(id, true); } void OnCameraUnavailable(void* ctx, const char* id) { reinterpret_cast(ctx)->OnCameraStatusChanged(id, false); } /** * OnCameraStatusChanged() * handles Callback from ACameraManager */ void NDKCamera::OnCameraStatusChanged(const char* id, bool available) { if (valid_) { cameras_[std::string(id)].available_ = available ? true : false; } } /** * Construct a camera manager listener on the fly and return to caller * * @return ACameraManager_AvailabilityCallback */ ACameraManager_AvailabilityCallbacks* NDKCamera::GetManagerListener() { static ACameraManager_AvailabilityCallbacks cameraMgrListener = { .context = this, .onCameraAvailable = ::OnCameraAvailable, .onCameraUnavailable = ::OnCameraUnavailable, }; return &cameraMgrListener; } /* * CameraDevice callbacks */ void OnDeviceStateChanges(void* ctx, ACameraDevice* dev) { reinterpret_cast(ctx)->OnDeviceState(dev); } void OnDeviceErrorChanges(void* ctx, ACameraDevice* dev, int err) { reinterpret_cast(ctx)->OnDeviceError(dev, err); } #if __NDK_MAJOR__ >= 30 void OnClientSharedAccessPriorityChanged(void*, ACameraDevice*, bool) { // TODO: Implement this. } #endif ACameraDevice_stateCallbacks* NDKCamera::GetDeviceListener() { static ACameraDevice_stateCallbacks cameraDeviceListener = { .context = this, .onDisconnected = ::OnDeviceStateChanges, .onError = ::OnDeviceErrorChanges, #if __NDK_MAJOR__ >= 30 .onClientSharedAccessPriorityChanged = ::OnClientSharedAccessPriorityChanged #endif }; return &cameraDeviceListener; } /** * Handle Camera DeviceStateChanges msg, notify device is disconnected * simply close the camera */ void NDKCamera::OnDeviceState(ACameraDevice* dev) { std::string id(ACameraDevice_getId(dev)); LOGW("device %s is disconnected", id.c_str()); cameras_[id].available_ = false; ACameraDevice_close(cameras_[id].device_); cameras_.erase(id); } /** * Handles Camera's deviceErrorChanges message, no action; * mainly debugging purpose * * */ void NDKCamera::OnDeviceError(ACameraDevice* dev, int err) { std::string id(ACameraDevice_getId(dev)); LOGI("CameraDevice %s is in error %#x", id.c_str(), err); PrintCameraDeviceError(err); CameraId& cam = cameras_[id]; switch (err) { case ERROR_CAMERA_IN_USE: cam.available_ = false; cam.owner_ = false; break; case ERROR_CAMERA_SERVICE: case ERROR_CAMERA_DEVICE: case ERROR_CAMERA_DISABLED: case ERROR_MAX_CAMERAS_IN_USE: cam.available_ = false; cam.owner_ = false; break; default: LOGI("Unknown Camera Device Error: %#x", err); } } // CaptureSession state callbacks void OnSessionClosed(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p closed", ses); reinterpret_cast(ctx)->OnSessionState( ses, CaptureSessionState::CLOSED); } void OnSessionReady(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p ready", ses); reinterpret_cast(ctx)->OnSessionState(ses, CaptureSessionState::READY); } void OnSessionActive(void* ctx, ACameraCaptureSession* ses) { LOGW("session %p active", ses); reinterpret_cast(ctx)->OnSessionState( ses, CaptureSessionState::ACTIVE); } ACameraCaptureSession_stateCallbacks* NDKCamera::GetSessionListener() { static ACameraCaptureSession_stateCallbacks sessionListener = { .context = this, .onClosed = ::OnSessionClosed, .onReady = ::OnSessionReady, .onActive = ::OnSessionActive, }; return &sessionListener; } /** * Handles capture session state changes. * Update into internal session state. */ void NDKCamera::OnSessionState(ACameraCaptureSession* ses, CaptureSessionState state) { if (!ses || ses != captureSession_) { LOGW("CaptureSession is %s", (ses ? "NOT our session" : "NULL")); return; } ASSERT(state < CaptureSessionState::MAX_STATE, "Wrong state %d", static_cast(state)); captureSessionState_ = state; } // Capture callbacks, mostly information purpose void SessionCaptureCallback_OnFailed(void* context, ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure) { std::thread captureFailedThread(&NDKCamera::OnCaptureFailed, static_cast(context), session, request, failure); captureFailedThread.detach(); } void SessionCaptureCallback_OnSequenceEnd(void* context, ACameraCaptureSession* session, int sequenceId, int64_t frameNumber) { std::thread sequenceThread(&NDKCamera::OnCaptureSequenceEnd, static_cast(context), session, sequenceId, frameNumber); sequenceThread.detach(); } void SessionCaptureCallback_OnSequenceAborted(void* context, ACameraCaptureSession* session, int sequenceId) { std::thread sequenceThread(&NDKCamera::OnCaptureSequenceEnd, static_cast(context), session, sequenceId, static_cast(-1)); sequenceThread.detach(); } ACameraCaptureSession_captureCallbacks* NDKCamera::GetCaptureCallback() { static ACameraCaptureSession_captureCallbacks captureListener{ .context = this, .onCaptureStarted = nullptr, .onCaptureProgressed = nullptr, .onCaptureCompleted = nullptr, .onCaptureFailed = SessionCaptureCallback_OnFailed, .onCaptureSequenceCompleted = SessionCaptureCallback_OnSequenceEnd, .onCaptureSequenceAborted = SessionCaptureCallback_OnSequenceAborted, .onCaptureBufferLost = nullptr, }; return &captureListener; } /** * Process JPG capture SessionCaptureCallback_OnFailed event * If this is current JPG capture session, simply resume preview * @param session the capture session that failed * @param request the capture request that failed * @param failure for additional fail info. */ void NDKCamera::OnCaptureFailed(ACameraCaptureSession*, ACaptureRequest* request, ACameraCaptureFailure* failure) { if (valid_ && request == requests_[JPG_CAPTURE_REQUEST_IDX].request_) { ASSERT(failure->sequenceId == requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_, "Error jpg sequence id") StartPreview(true); } } /** * Process event from JPEG capture * SessionCaptureCallback_OnSequenceEnd() * SessionCaptureCallback_OnSequenceAborted() * * If this is jpg capture, turn back on preview after a catpure. */ void NDKCamera::OnCaptureSequenceEnd(ACameraCaptureSession*, int sequenceId, int64_t) { if (sequenceId != requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_) return; // resume preview CALL_SESSION(setRepeatingRequest(captureSession_, nullptr, 1, &requests_[PREVIEW_REQUEST_IDX].request_, nullptr)); } ================================================ FILE: camera/texture-view/src/main/cpp/camera_manager.cpp ================================================ /* * Copyright (C) 2017 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. */ #include "camera_manager.h" #include #include #include #include #include #include #include #include #include /** * Range of Camera Exposure Time: * Camera's capability range have a very long range which may be disturbing * on camera. For this sample purpose, clamp to a range showing visible * video on preview: 100000ns ~ 250000000ns */ static const uint64_t kMinExposureTime = static_cast(1000000); static const uint64_t kMaxExposureTime = static_cast(250000000); NDKCamera::NDKCamera() : cameraMgr_(nullptr), activeCameraId_(""), cameraFacing_(ACAMERA_LENS_FACING_BACK), cameraOrientation_(0), outputContainer_(nullptr), captureSessionState_(CaptureSessionState::MAX_STATE), exposureTime_(static_cast(0)) { valid_ = false; requests_.resize(CAPTURE_REQUEST_COUNT); memset(requests_.data(), 0, requests_.size() * sizeof(requests_[0])); cameras_.clear(); cameraMgr_ = ACameraManager_create(); ASSERT(cameraMgr_, "Failed to create cameraManager"); // Pick up a back-facing camera to preview EnumerateCamera(); ASSERT(activeCameraId_.size(), "Unknown ActiveCameraIdx"); // Create back facing camera device CALL_MGR(openCamera(cameraMgr_, activeCameraId_.c_str(), GetDeviceListener(), &cameras_[activeCameraId_].device_)); CALL_MGR(registerAvailabilityCallback(cameraMgr_, GetManagerListener())); // Initialize camera controls(exposure time and sensitivity), pick // up value of 2% * range + min as starting value (just a number, no magic) ACameraMetadata* metadataObj; CALL_MGR(getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadataObj)); ACameraMetadata_const_entry val = {}; camera_status_t status = ACameraMetadata_getConstEntry( metadataObj, ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE, &val); if (status == ACAMERA_OK) { exposureRange_.min_ = val.data.i64[0]; if (exposureRange_.min_ < kMinExposureTime) { exposureRange_.min_ = kMinExposureTime; } exposureRange_.max_ = val.data.i64[1]; if (exposureRange_.max_ > kMaxExposureTime) { exposureRange_.max_ = kMaxExposureTime; } exposureTime_ = exposureRange_.value(2); } else { LOGW("Unsupported ACAMERA_SENSOR_INFO_EXPOSURE_TIME_RANGE"); exposureRange_.min_ = exposureRange_.max_ = 0l; exposureTime_ = 0l; } status = ACameraMetadata_getConstEntry( metadataObj, ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE, &val); if (status == ACAMERA_OK) { sensitivityRange_.min_ = val.data.i32[0]; sensitivityRange_.max_ = val.data.i32[1]; sensitivity_ = sensitivityRange_.value(2); } else { LOGW("failed for ACAMERA_SENSOR_INFO_SENSITIVITY_RANGE"); sensitivityRange_.min_ = sensitivityRange_.max_ = 0; sensitivity_ = 0; } valid_ = true; } /** * A helper class to assist image size comparison, by comparing the absolute * size * regardless of the portrait or landscape mode. */ class DisplayDimension { public: DisplayDimension(int32_t w, int32_t h) : w_(w), h_(h), portrait_(false) { if (h > w) { // make it landscape w_ = h; h_ = w; portrait_ = true; } } DisplayDimension(const DisplayDimension& other) { w_ = other.w_; h_ = other.h_; portrait_ = other.portrait_; } DisplayDimension(void) { w_ = 0; h_ = 0; portrait_ = false; } DisplayDimension& operator=(const DisplayDimension& other) { w_ = other.w_; h_ = other.h_; portrait_ = other.portrait_; return (*this); } bool IsSameRatio(DisplayDimension& other) { return (w_ * other.h_ == h_ * other.w_); } bool operator>(DisplayDimension& other) { return (w_ >= other.w_ & h_ >= other.h_); } bool operator==(DisplayDimension& other) { return (w_ == other.w_ && h_ == other.h_ && portrait_ == other.portrait_); } DisplayDimension operator-(DisplayDimension& other) { DisplayDimension delta(w_ - other.w_, h_ - other.h_); return delta; } void Flip(void) { portrait_ = !portrait_; } bool IsPortrait(void) { return portrait_; } int32_t width(void) { return w_; } int32_t height(void) { return h_; } int32_t org_width(void) { return (portrait_ ? h_ : w_); } int32_t org_height(void) { return (portrait_ ? w_ : h_); } private: int32_t w_, h_; bool portrait_; }; /** * Find a compatible camera modes: * 1) the same aspect ration as the native display window, which should be a * rotated version of the physical device * 2) the smallest resolution in the camera mode list * This is to minimize the later color space conversion workload. */ bool NDKCamera::MatchCaptureSizeRequest(int32_t requestWidth, int32_t requestHeight, ImageFormat* view) { return MatchCaptureSizeRequest(requestWidth, requestHeight, view, nullptr); } bool NDKCamera::MatchCaptureSizeRequest(int32_t requestWidth, int32_t requestHeight, ImageFormat* resView, ImageFormat* resCap) { DisplayDimension disp(requestWidth, requestHeight); if (cameraOrientation_ == 90 || cameraOrientation_ == 270) { disp.Flip(); } ACameraMetadata* metadata; CALL_MGR( getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadata)); ACameraMetadata_const_entry entry; CALL_METADATA(getConstEntry( metadata, ACAMERA_SCALER_AVAILABLE_STREAM_CONFIGURATIONS, &entry)); // format of the data: format, width, height, input?, type int32 bool foundIt = false; DisplayDimension foundRes(4000, 4000); DisplayDimension maxJPG(0, 0); for (uint32_t i = 0; i < entry.count; i += 4) { int32_t input = entry.data.i32[i + 3]; int32_t format = entry.data.i32[i + 0]; if (input) continue; if (format == AIMAGE_FORMAT_YUV_420_888 || format == AIMAGE_FORMAT_JPEG) { DisplayDimension res(entry.data.i32[i + 1], entry.data.i32[i + 2]); if (!disp.IsSameRatio(res)) continue; if (format == AIMAGE_FORMAT_YUV_420_888 && foundRes > res) { foundIt = true; foundRes = res; } else if (format == AIMAGE_FORMAT_JPEG && res > maxJPG) { maxJPG = res; } } } if (foundIt) { resView->width = foundRes.org_width(); resView->height = foundRes.org_height(); if (resCap) { resCap->width = maxJPG.org_width(); resCap->height = maxJPG.org_height(); } } else { LOGW("Did not find any compatible camera resolution, taking 640x480"); if (disp.IsPortrait()) { resView->width = 480; resView->height = 640; } else { resView->width = 640; resView->height = 480; } if (resCap) *resCap = *resView; } resView->format = AIMAGE_FORMAT_YUV_420_888; if (resCap) resCap->format = AIMAGE_FORMAT_JPEG; return foundIt; } void NDKCamera::CreateSession(ANativeWindow* previewWindow, ANativeWindow* jpgWindow, bool manualPreview, int32_t imageRotation) { // Create output from this app's ANativeWindow, and add into output container requests_[PREVIEW_REQUEST_IDX].outputNativeWindow_ = previewWindow; requests_[PREVIEW_REQUEST_IDX].template_ = TEMPLATE_PREVIEW; requests_[JPG_CAPTURE_REQUEST_IDX].outputNativeWindow_ = jpgWindow; requests_[JPG_CAPTURE_REQUEST_IDX].template_ = TEMPLATE_STILL_CAPTURE; CALL_CONTAINER(create(&outputContainer_)); for (auto& req : requests_) { if (!req.outputNativeWindow_) continue; ANativeWindow_acquire(req.outputNativeWindow_); CALL_OUTPUT(create(req.outputNativeWindow_, &req.sessionOutput_)); CALL_CONTAINER(add(outputContainer_, req.sessionOutput_)); CALL_TARGET(create(req.outputNativeWindow_, &req.target_)); CALL_DEV(createCaptureRequest(cameras_[activeCameraId_].device_, req.template_, &req.request_)); CALL_REQUEST(addTarget(req.request_, req.target_)); } // Create a capture session for the given preview request captureSessionState_ = CaptureSessionState::READY; CALL_DEV(createCaptureSession(cameras_[activeCameraId_].device_, outputContainer_, GetSessionListener(), &captureSession_)); if (jpgWindow) { ACaptureRequest_setEntry_i32(requests_[JPG_CAPTURE_REQUEST_IDX].request_, ACAMERA_JPEG_ORIENTATION, 1, &imageRotation); } if (!manualPreview) { return; } /* * Only preview request is in manual mode, JPG is always in Auto mode * JPG capture mode could also be switch into manual mode and control * the capture parameters, this sample leaves JPG capture to be auto mode * (auto control has better effect than author's manual control) */ uint8_t aeModeOff = ACAMERA_CONTROL_AE_MODE_OFF; CALL_REQUEST(setEntry_u8(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_CONTROL_AE_MODE, 1, &aeModeOff)); CALL_REQUEST(setEntry_i32(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_)); CALL_REQUEST(setEntry_i64(requests_[PREVIEW_REQUEST_IDX].request_, ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime_)); } void NDKCamera::CreateSession(ANativeWindow* previewWindow) { CreateSession(previewWindow, nullptr, false, 0); } NDKCamera::~NDKCamera() { valid_ = false; // stop session if it is on: if (captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } ACameraCaptureSession_close(captureSession_); for (auto& req : requests_) { if (!req.outputNativeWindow_) continue; CALL_REQUEST(removeTarget(req.request_, req.target_)); ACaptureRequest_free(req.request_); ACameraOutputTarget_free(req.target_); CALL_CONTAINER(remove(outputContainer_, req.sessionOutput_)); ACaptureSessionOutput_free(req.sessionOutput_); ANativeWindow_release(req.outputNativeWindow_); } requests_.resize(0); ACaptureSessionOutputContainer_free(outputContainer_); for (auto& cam : cameras_) { if (cam.second.device_) { CALL_DEV(close(cam.second.device_)); } } cameras_.clear(); if (cameraMgr_) { CALL_MGR(unregisterAvailabilityCallback(cameraMgr_, GetManagerListener())); ACameraManager_delete(cameraMgr_); cameraMgr_ = nullptr; } } /** * EnumerateCamera() * Loop through cameras on the system, pick up * 1) back facing one if available * 2) otherwise pick the first one reported to us */ void NDKCamera::EnumerateCamera() { ACameraIdList* cameraIds = nullptr; CALL_MGR(getCameraIdList(cameraMgr_, &cameraIds)); for (int i = 0; i < cameraIds->numCameras; ++i) { const char* id = cameraIds->cameraIds[i]; ACameraMetadata* metadataObj; CALL_MGR(getCameraCharacteristics(cameraMgr_, id, &metadataObj)); int32_t count = 0; const uint32_t* tags = nullptr; ACameraMetadata_getAllTags(metadataObj, &count, &tags); for (int tagIdx = 0; tagIdx < count; ++tagIdx) { if (ACAMERA_LENS_FACING == tags[tagIdx]) { ACameraMetadata_const_entry lensInfo = {}; CALL_METADATA(getConstEntry(metadataObj, tags[tagIdx], &lensInfo)); CameraId cam(id); cam.facing_ = static_cast( lensInfo.data.u8[0]); cam.owner_ = false; cam.device_ = nullptr; cameras_[cam.id_] = cam; if (cam.facing_ == ACAMERA_LENS_FACING_BACK) { activeCameraId_ = cam.id_; } break; } } ACameraMetadata_free(metadataObj); } ASSERT(cameras_.size(), "No Camera Available on the device"); if (activeCameraId_.length() == 0) { // if no back facing camera found, pick up the first one to use... activeCameraId_ = cameras_.begin()->second.id_; } ACameraManager_deleteCameraIdList(cameraIds); } /** * GetSensorOrientation() * Retrieve current sensor orientation regarding to the phone device * orientation * SensorOrientation is NOT settable. */ bool NDKCamera::GetSensorOrientation(int32_t* facing, int32_t* angle) { if (!cameraMgr_) { return false; } ACameraMetadata* metadataObj; ACameraMetadata_const_entry face, orientation; CALL_MGR(getCameraCharacteristics(cameraMgr_, activeCameraId_.c_str(), &metadataObj)); CALL_METADATA(getConstEntry(metadataObj, ACAMERA_LENS_FACING, &face)); cameraFacing_ = static_cast(face.data.u8[0]); CALL_METADATA( getConstEntry(metadataObj, ACAMERA_SENSOR_ORIENTATION, &orientation)); LOGI("====Current SENSOR_ORIENTATION: %8d", orientation.data.i32[0]); ACameraMetadata_free(metadataObj); cameraOrientation_ = orientation.data.i32[0]; if (facing) *facing = cameraFacing_; if (angle) *angle = cameraOrientation_; return true; } /** * StartPreview() * Toggle preview start/stop */ void NDKCamera::StartPreview(bool start) { if (start) { CALL_SESSION(setRepeatingRequest(captureSession_, nullptr, 1, &requests_[PREVIEW_REQUEST_IDX].request_, nullptr)); } else if (!start && captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } } /** * Capture one jpg photo into * /sdcard/DCIM/Camera * refer to WriteFile() for details */ bool NDKCamera::TakePhoto(void) { if (captureSessionState_ == CaptureSessionState::ACTIVE) { ACameraCaptureSession_stopRepeating(captureSession_); } CALL_SESSION(capture(captureSession_, GetCaptureCallback(), 1, &requests_[JPG_CAPTURE_REQUEST_IDX].request_, &requests_[JPG_CAPTURE_REQUEST_IDX].sessionSequenceId_)); return true; } void NDKCamera::UpdateCameraRequestParameter(int32_t code, int64_t val) { ACaptureRequest* request = requests_[PREVIEW_REQUEST_IDX].request_; switch (code) { case ACAMERA_SENSOR_EXPOSURE_TIME: exposureTime_ = val; CALL_REQUEST(setEntry_i64(request, ACAMERA_SENSOR_EXPOSURE_TIME, 1, &exposureTime_)); break; case ACAMERA_SENSOR_SENSITIVITY: sensitivity_ = val; CALL_REQUEST( setEntry_i32(request, ACAMERA_SENSOR_SENSITIVITY, 1, &sensitivity_)); break; default: ASSERT(false, "==ERROR==: error code for CameraParameterChange: %d", code); return; } uint8_t aeModeOff = ACAMERA_CONTROL_AE_MODE_OFF; CALL_REQUEST(setEntry_u8(request, ACAMERA_CONTROL_AE_MODE, 1, &aeModeOff)); CALL_SESSION( setRepeatingRequest(captureSession_, nullptr, 1, &request, &requests_[PREVIEW_REQUEST_IDX].sessionSequenceId_)); } /** * Retrieve Camera Exposure adjustable range. * * @param min Camera minimium exposure time in nanoseconds * @param max Camera maximum exposure tiem in nanoseconds * * @return true min and max are loaded with the camera's exposure values * false camera has not initialized, no value available */ bool NDKCamera::GetExposureRange(int64_t* min, int64_t* max, int64_t* curVal) { if (!exposureTime_ || !min || !max || !curVal) { return false; } *min = exposureRange_.min_; *max = exposureRange_.max_; *curVal = exposureTime_; return true; } /** * Retrieve Camera sensitivity range. * * @param min Camera minimium sensitivity * @param max Camera maximum sensitivity * * @return true min and max are loaded with the camera's sensitivity values * false camera has not initialized, no value available */ bool NDKCamera::GetSensitivityRange(int64_t* min, int64_t* max, int64_t* curVal) { if (!sensitivity_ || !min || !max || !curVal) { return false; } *min = static_cast(sensitivityRange_.min_); *max = static_cast(sensitivityRange_.max_); *curVal = sensitivity_; return true; } ================================================ FILE: camera/texture-view/src/main/cpp/camera_manager.h ================================================ /* * Copyright (C) 2017 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. */ #ifndef CAMERA_NATIVE_CAMERA_H #define CAMERA_NATIVE_CAMERA_H #include #include #include #include #include #include #include enum class CaptureSessionState : int32_t { READY = 0, // session is ready ACTIVE, // session is busy CLOSED, // session is closed(by itself or a new session evicts) MAX_STATE }; /* * ImageFormat: * A Data Structure to communicate resolution between camera and ImageReader */ struct ImageFormat { int32_t width; int32_t height; int32_t format; // Through out this demo, the format is fixed to // YUV_420 format }; template class RangeValue { public: T min_, max_; /** * return absolute value from relative value * value: in percent (50 for 50%) */ T value(int percent) { return static_cast(min_ + (max_ - min_) * percent / 100); } RangeValue() { min_ = max_ = static_cast(0); } bool Supported(void) const { return (min_ != max_); } }; enum PREVIEW_INDICES { PREVIEW_REQUEST_IDX = 0, JPG_CAPTURE_REQUEST_IDX, CAPTURE_REQUEST_COUNT, }; struct CaptureRequestInfo { ANativeWindow* outputNativeWindow_; ACaptureSessionOutput* sessionOutput_; ACameraOutputTarget* target_; ACaptureRequest* request_; ACameraDevice_request_template template_; int sessionSequenceId_; }; class CameraId; class NDKCamera { private: ACameraManager* cameraMgr_; std::map cameras_; std::string activeCameraId_; uint32_t cameraFacing_; uint32_t cameraOrientation_; std::vector requests_; ACaptureSessionOutputContainer* outputContainer_; ACameraCaptureSession* captureSession_; CaptureSessionState captureSessionState_; // set up exposure control int64_t exposureTime_; RangeValue exposureRange_; int32_t sensitivity_; RangeValue sensitivityRange_; volatile bool valid_; ACameraManager_AvailabilityCallbacks* GetManagerListener(); ACameraDevice_stateCallbacks* GetDeviceListener(); ACameraCaptureSession_stateCallbacks* GetSessionListener(); ACameraCaptureSession_captureCallbacks* GetCaptureCallback(); public: NDKCamera(); ~NDKCamera(); void EnumerateCamera(void); bool MatchCaptureSizeRequest(int32_t requestWidth, int32_t requestHeight, ImageFormat* view); bool MatchCaptureSizeRequest(int32_t requestWidth, int32_t requestHeight, ImageFormat* view, ImageFormat* capture); void CreateSession(ANativeWindow* previewWindow, ANativeWindow* jpgWindow, bool manaulPreview, int32_t imageRotation); void CreateSession(ANativeWindow* previewWindow); bool GetSensorOrientation(int32_t* facing, int32_t* angle); void OnCameraStatusChanged(const char* id, bool available); void OnDeviceState(ACameraDevice* dev); void OnDeviceError(ACameraDevice* dev, int err); void OnSessionState(ACameraCaptureSession* ses, CaptureSessionState state); void OnCaptureSequenceEnd(ACameraCaptureSession* session, int sequenceId, int64_t frameNumber); void OnCaptureFailed(ACameraCaptureSession* session, ACaptureRequest* request, ACameraCaptureFailure* failure); void StartPreview(bool start); bool TakePhoto(void); bool GetExposureRange(int64_t* min, int64_t* max, int64_t* curVal); bool GetSensitivityRange(int64_t* min, int64_t* max, int64_t* curVal); void UpdateCameraRequestParameter(int32_t code, int64_t val); }; // helper classes to hold enumerated camera class CameraId { public: ACameraDevice* device_; std::string id_; acamera_metadata_enum_android_lens_facing_t facing_; bool available_; // free to use ( no other apps are using bool owner_; // we are the owner of the camera explicit CameraId(const char* id) : device_(nullptr), facing_(ACAMERA_LENS_FACING_FRONT), available_(false), owner_(false) { id_ = id; } explicit CameraId(void) { CameraId(""); } }; #endif // CAMERA_NATIVE_CAMERA_H ================================================ FILE: camera/texture-view/src/main/cpp/libcamera_textureview.map.txt ================================================ LIBCAMERA_TEXTUREVIEW { global: JNI_OnLoad; local: *; }; ================================================ FILE: camera/texture-view/src/main/java/com/sample/textureview/ViewActivity.java ================================================ /* * Copyright (C) 2017 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.sample.textureview; import android.Manifest; import android.app.Activity; import android.content.Context; import android.content.pm.PackageManager; import android.graphics.Matrix; import android.graphics.SurfaceTexture; import android.hardware.camera2.CameraAccessException; import android.hardware.camera2.CameraCharacteristics; import android.hardware.camera2.CameraManager; import android.os.Bundle; import androidx.annotation.NonNull; import androidx.core.app.ActivityCompat; import android.util.Log; import android.view.Display; import android.view.Gravity; import android.view.Surface; import android.view.TextureView; import android.view.View; import android.util.Size; import android.widget.FrameLayout; import static android.hardware.camera2.CameraMetadata.LENS_FACING_BACK; public class ViewActivity extends Activity implements TextureView.SurfaceTextureListener, ActivityCompat.OnRequestPermissionsResultCallback { long ndkCamera_; private TextureView textureView_; Surface surface_ = null; private Size cameraPreviewSize_; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); onWindowFocusChanged(true); setContentView(R.layout.activity_main); if (isCamera2Device()) { RequestCamera(); } else { Log.e("CameraSample", "Found legacy camera device, this sample needs camera2 device"); } } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { getWindow().getDecorView().setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); } } private boolean isCamera2Device() { CameraManager camMgr = (CameraManager)getSystemService(Context.CAMERA_SERVICE); boolean camera2Dev = true; try { String[] cameraIds = camMgr.getCameraIdList(); if (cameraIds.length != 0 ) { for (String id : cameraIds) { CameraCharacteristics characteristics = camMgr.getCameraCharacteristics(id); int deviceLevel = characteristics.get(CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL); int facing = characteristics.get(CameraCharacteristics.LENS_FACING); if (deviceLevel == CameraCharacteristics.INFO_SUPPORTED_HARDWARE_LEVEL_LEGACY && facing == LENS_FACING_BACK) { camera2Dev = false; } } } } catch (CameraAccessException e) { e.printStackTrace(); camera2Dev = false; } return camera2Dev; } private void createTextureView() { textureView_ = (TextureView) findViewById(R.id.texturePreview); textureView_.setSurfaceTextureListener(this); if (textureView_.isAvailable()) { onSurfaceTextureAvailable(textureView_.getSurfaceTexture(), textureView_.getWidth(), textureView_.getHeight()); } } public void onSurfaceTextureAvailable(SurfaceTexture surface, int width, int height) { createNativeCamera(); resizeTextureView(width, height); surface.setDefaultBufferSize(cameraPreviewSize_.getWidth(), cameraPreviewSize_.getHeight()); surface_ = new Surface(surface); onPreviewSurfaceCreated(ndkCamera_, surface_); } private void resizeTextureView(int textureWidth, int textureHeight) { int rotation = getWindowManager().getDefaultDisplay().getRotation(); int newWidth = textureWidth; int newHeight = textureWidth * cameraPreviewSize_.getWidth() / cameraPreviewSize_.getHeight(); if (Surface.ROTATION_90 == rotation || Surface.ROTATION_270 == rotation) { newHeight = (textureWidth * cameraPreviewSize_.getHeight()) / cameraPreviewSize_.getWidth(); } textureView_.setLayoutParams( new FrameLayout.LayoutParams(newWidth, newHeight, Gravity.CENTER)); configureTransform(newWidth, newHeight); } /** * configureTransform() * Courtesy to https://github.com/google/cameraview/blob/master/library/src/main/api14/com/google/android/cameraview/TextureViewPreview.java#L108 * * @param width TextureView width * @param height is TextureView height */ void configureTransform(int width, int height) { int mDisplayOrientation = getWindowManager().getDefaultDisplay().getRotation() * 90; Matrix matrix = new Matrix(); if (mDisplayOrientation % 180 == 90) { //final int width = getWidth(); //final int height = getHeight(); // Rotate the camera preview when the screen is landscape. matrix.setPolyToPoly( new float[]{ 0.f, 0.f, // top left width, 0.f, // top right 0.f, height, // bottom left width, height, // bottom right }, 0, mDisplayOrientation == 90 ? // Clockwise new float[]{ 0.f, height, // top left 0.f, 0.f, // top right width, height, // bottom left width, 0.f, // bottom right } : // mDisplayOrientation == 270 // Counter-clockwise new float[]{ width, 0.f, // top left width, height, // top right 0.f, 0.f, // bottom left 0.f, height, // bottom right }, 0, 4); } else if (mDisplayOrientation == 180) { matrix.postRotate(180, width / 2, height / 2); } textureView_.setTransform(matrix); } public void onSurfaceTextureSizeChanged(SurfaceTexture surface, int width, int height) { } public boolean onSurfaceTextureDestroyed(SurfaceTexture surface) { onPreviewSurfaceDestroyed(ndkCamera_, surface_); deleteCamera(ndkCamera_, surface_); ndkCamera_ = 0; surface_ = null; return true; } public void onSurfaceTextureUpdated(SurfaceTexture surface) { } private static final int PERMISSION_REQUEST_CODE_CAMERA = 1; public void RequestCamera() { if (ActivityCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) { ActivityCompat.requestPermissions( this, new String[]{Manifest.permission.CAMERA}, PERMISSION_REQUEST_CODE_CAMERA); return; } createTextureView(); } @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { /* * if any permission failed, the sample could not play */ if (PERMISSION_REQUEST_CODE_CAMERA != requestCode) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); return; } if (grantResults.length == 1 && grantResults[0] == PackageManager.PERMISSION_GRANTED) { Thread initCamera = new Thread(new Runnable() { public void run() { runOnUiThread(new Runnable() { @Override public void run() { createTextureView(); } }); } }); initCamera.start(); } } private void createNativeCamera() { Display display = getWindowManager().getDefaultDisplay(); int height = display.getMode().getPhysicalHeight(); int width = display.getMode().getPhysicalWidth(); ndkCamera_ = createCamera(width, height); cameraPreviewSize_ = getMinimumCompatiblePreviewSize(ndkCamera_); } /* * Functions calling into NDKCamera side to: * CreateCamera / DeleteCamera object * Start/Stop Preview * Pulling Camera Parameters */ private native long createCamera(int width, int height); private native Size getMinimumCompatiblePreviewSize(long ndkCamera); private native void onPreviewSurfaceCreated(long ndkCamera, Surface surface); private native void onPreviewSurfaceDestroyed(long ndkCamera, Surface surface); private native void deleteCamera(long ndkCamera, Surface surface); static { System.loadLibrary("camera_textureview"); } } ================================================ FILE: camera/texture-view/src/main/res/layout/activity_main.xml ================================================ ================================================ FILE: camera/texture-view/src/main/res/values/strings.xml ================================================ texture-view ================================================ FILE: cmake/AppLibrary.cmake ================================================ include_guard() # Wrapper for add_library which enables common options we want for all # libraries. function(add_app_library name) cmake_parse_arguments(PARSE_ARGV 1 arg "NO_VERSION_SCRIPT" "" "") add_library(${name} ${arg_UNPARSED_ARGUMENTS}) target_compile_options(${name} PRIVATE -Wall -Wextra -Werror ) if(NOT arg_NO_VERSION_SCRIPT) target_link_options(${name} PRIVATE -Wl,--no-undefined-version -Wl,--version-script,${CMAKE_SOURCE_DIR}/lib${name}.map.txt ) set_target_properties(${name} PROPERTIES LINK_DEPENDS ${CMAKE_SOURCE_DIR}/lib${name}.map.txt ) endif() endfunction() ================================================ FILE: endless-tunnel/README.md ================================================ # Endless Tunnel Endless Tunnel is a sample game that shows how to: - use the Android Studio C++ support - implement a game using Android native glue - implement joystick support, including robust DPAD navigation for non-touch screens It is NOT the goal of this sample to show the best way to write the game logic, load resources, etc. The game itself was intentionally kept rudimentary in order to keep the focus on the Android Studio C++ integration. For example, this game contains textures and geometry hard-coded in code, which works for small demo games like this one, but doesn't scale well to real games. ## Screenshots ![screenshot](screenshot.png) ## Dependencies ### GLM LIBRARY This project uses the OpenGL Mathematics (GLM) library, available at: ``` https://github.com/g-truc/glm ``` For more information about this library and its license, please see [readme.md](https://github.com/g-truc/glm/blob/master/readme.md) and [copying](https://github.com/g-truc/glm/blob/master/copying.txt). ## Walkthrough Source code is under app, it only contains C++ code, which is sitting at its default location (same as for other samples) at app/cpp. The game starts at the android_main function, defined in android_main.cpp, like any standard NDK game. ### Scenes And The Scene Manager We have a singleton class called SceneManager. As the name says, it's the class that manages scenes. There's always an active Scene, and the scene determines what's visible onscreen and how the game reacts to input. The main menu is a scene, the gameplay is another scene. As the game runs, the display might be initialized and terminated multiple times, corresponding, for example, to the app losing focus and being brought back into focus. This is why the SceneManager (and the Scene's) have the notion of StartGraphics() and KillGraphics(). These two methods may be called multiple times along the lifetime of a scene. So everything that has to do with graphics context (like shaders, textures, etc) has to be initialized in StartGraphics(), and has to be torn down in KillGraphics(). The NativeEngine::InitDisplay function is where we set up OpenGL for our game, and call StartGraphics() on the active scene. The NativeEngine::KillGLObjects is where we call KillGraphics() on the active scene. Input arrives by way of the NativeEngine::HandleInput function, which does some basic input classification and delivers the input to the scene manager. Incidentally, here we also synthesise DPAD events based on the joystick hat axes (many game controllers generate hat events when you press the directional pad), because that way we can use that directional pad to drive UI navigation in the main screen. Take a look at scene_manager.cpp, scene.cpp, etc to familiarize yourself with them. ### Geometry And Rendering The game's geometry is represented by VBOs and IBOs. A VBO is represented by the VertexBuf class, and an IBO is represented by an IndexBuf. A shader is represented by the Shader class, of which TrivialShader is a concrete example. Now, onto rendering. Everything in the game is rendered by a Shader. Normally, to use a Shader, you call BeginRender() and give it a VertexBuf. This means you will be rendering one or more subsets of that geometry. After that, call Render(ibuf, mat) where ibuf is the IndexBuffer that represents the part of the geometry you want to render, and mat is the transformation matrix. You can call Render() multiple times to render different subsets of the geometry with different matrices. When you're done, you call the shader's EndRender() method. As a simpler alternative when you only want to render a single copy of an object that's defined by a VertexBuffer and IndexBuffer pair, just call RenderSimpleGeom(), which takes a matrix and a SimpleGeom object (which, in turn, is just a pair of VertexBuffer and IndexBuffer). The shader subclass is responsible for knowing what to do to render a geometry. For example, if the shader needs texture coordinates, it will query the geometry for texture coordinates as necessary -- if it doesn't have them, it will throw an error (that being just an euphemism for an ugly native crash). So, yes, you have to be careful that the geometry you're feeding to a shader has the data that's needed by that shader. Particularly, TrivialShader only needs position and color info for each vertex. The more complex OurShader class (in jni/our_shader.cpp) needs texture coordinates. ### The Normalized 2d Coord System For all 2D rendering, we use a normalized coordinate system where the bottom-left of the screen is (0,0), the X coordinate increases to the right and the Y coordinate increases upwards. The Y coordinate of the top of the screen is defined to be 1.0. The X coordinate of the right side of the screen is the screen's aspect ratio. So, on a 4:3 screen, these are the coordinates of the four corners of the screen: ``` (0.000,1.000) (1.333,1.000) +--------------+ | | | | | | | | +--------------+ (0.000,0.000) (1.333,0.000) ``` What this means is that Y=0.5 is always the vertical center of the screen regardless of the screen size, and that X=aspect/2 is always the horizontal center of the screen, regardless of physical screen size. This coordinate system is set up like this: ``` glm::mat4 modelMat, mat; // set up projection matrix float aspect = SceneManager::GetInstance()->GetScreenAspect(); glm::mat4 orthoMat = glm::ortho(0.0f, aspect, 0.0f, 1.0f); // ... (set up modelMat as needed) // determine final matrix for rendering mat = orthoMat * modelMat; // render something mShader->RenderSimpleGeom(&mat, mGeom); ``` ### The Main Menu The game's main menu scene is in welcome_scene.cpp. It renders all the buttons on the interface and manages the navigation. It can also show popups ("About", "Story", "Play"). ### Game Logic The whole game logic is contained in play_scene.cpp. We won't dive into a full discussion of it, but start reading from the PlayScene::DoFrame() method and it should become clear. It's a standard game loop that handles input, updates the world, checks for collisions and renders. ================================================ FILE: endless-tunnel/app/build.gradle ================================================ /* * Copyright (C) 2015 Google Inc. * * 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. */ plugins { id "ndksamples.android.application" } android { namespace 'com.google.sample.tunnel' defaultConfig { applicationId 'com.google.sample.tunnel' versionCode 1 versionName '1.0' externalNativeBuild { cmake { arguments '-DANDROID_STL=c++_static' } } } externalNativeBuild { cmake { path 'src/main/cpp/CMakeLists.txt' } } } ================================================ FILE: endless-tunnel/app/src/main/AndroidManifest.xml ================================================ ================================================ FILE: endless-tunnel/app/src/main/cpp/CMakeLists.txt ================================================ # # Copyright (C) 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. # cmake_minimum_required(VERSION 3.22.1) project(EndlessTunnel LANGUAGES C CXX) include(AppLibrary) include(AndroidNdkModules) android_ndk_import_module_native_app_glue() # Set common compiler options add_definitions("-DGLM_FORCE_SIZE_T_LENGTH -DGLM_FORCE_RADIANS") # Import the CMakeLists.txt for the glm library add_subdirectory(glm) # now build app's shared lib add_app_library(game SHARED android_main.cpp anim.cpp ascii_to_geom.cpp dialog_scene.cpp indexbuf.cpp input_util.cpp jni_util.cpp native_engine.cpp obstacle.cpp obstacle_generator.cpp our_shader.cpp play_scene.cpp scene.cpp scene_manager.cpp sfxman.cpp shader.cpp shape_renderer.cpp tex_quad.cpp text_renderer.cpp texture.cpp ui_scene.cpp util.cpp vertexbuf.cpp welcome_scene.cpp ) if(ANDROID_ABI STREQUAL riscv64) # This sample uses OpenSLES, which was deprecated in API 26. Our # minSdkVersion is 21, but we also build for riscv64, which isn't a # supported ABI yet and so that configuration is built for the latest API # level supported by the NDK. # # Longer term, this sample should migrate to Oboe. target_compile_options(game PRIVATE -Wno-deprecated-declarations) endif() target_include_directories(game PRIVATE ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/data ) # add lib dependencies target_link_libraries(game android $ atomic EGL GLESv2 glm log OpenSLES ) ================================================ FILE: endless-tunnel/app/src/main/cpp/android_main.cpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #include "native_engine.hpp" extern "C" { void android_main(struct android_app* state); }; void android_main(struct android_app* app) { NativeEngine* engine = new NativeEngine(app); engine->GameLoop(); delete engine; } ================================================ FILE: endless-tunnel/app/src/main/cpp/anim.cpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #include "anim.hpp" #include "util.hpp" void RenderBackgroundAnimation(ShapeRenderer* r) { float aspect = SceneManager::GetInstance()->GetScreenAspect(); static const int BG_RECTS = 50; static const float RECT_W = 0.3f; static const float RECT_H = 0.1f; static float rectX[BG_RECTS]; static float rectY[BG_RECTS]; static bool rectsInitted = false; int i; if (!rectsInitted) { for (i = 0; i < BG_RECTS; i++) { rectX[i] = aspect * (Random(100) / 100.0f); rectY[i] = Random(100) / 100.0f; } rectsInitted = true; } glClear(GL_COLOR_BUFFER_BIT); for (i = 0; i < BG_RECTS; i++) { float c = 0.1f + 0.1f * (i % 4); r->SetColor(c, c, c); r->RenderRect(rectX[i], rectY[i], RECT_W, RECT_H); rectX[i] -= (0.01f + 0.01f * (i % 4)); if (rectX[i] < -RECT_W * 0.5f) { rectX[i] = aspect + RECT_W * 0.5f; rectY[i] = Random(100) / 100.0f; } } } ================================================ FILE: endless-tunnel/app/src/main/cpp/anim.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_anim_hpp #define endlesstunnel_anim_hpp #include "shape_renderer.hpp" /* Renders a the background animation seen on the main screen and menus (the * parallax rectangles scrolling by). */ void RenderBackgroundAnimation(ShapeRenderer *r); #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/ascii_to_geom.cpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #include "ascii_to_geom.hpp" #define GEOM_DEBUG LOGD // #define GEOM_DEBUG SimpleGeom* AsciiArtToGeom(const char* art, float scale) { // figure out width and height LOGD("Creating geometry from ASCII art."); GEOM_DEBUG("Ascii art source:\n%s", art); int rows = 1; int curCols = 0, cols = 0; int r, c; const char* p; for (p = art; *p; ++p) { if (*p == '\n') { rows++; curCols = 0; } else { curCols++; cols = curCols > cols ? curCols : cols; } } GEOM_DEBUG("Ascii art has %d rows, %d cols.", rows, cols); GEOM_DEBUG("Making working array."); // allocate a rows x cols array that we will use as working space unsigned int** v = new unsigned int*[rows]; for (r = 0; r < rows; r++) { v[r] = new unsigned int[cols]; memset(v[r], 0, cols * sizeof(unsigned int)); } // copy the input into the array r = c = 0; for (p = art; *p; ++p) { if (*p == '\n') { r++, c = 0; } else { MY_ASSERT(r >= 0 && r < rows); MY_ASSERT(c >= 0 && c < cols); v[r][c++] = static_cast(*p); } } GEOM_DEBUG("Removing redundant line markers."); // remove redundant line markers for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { if (c + 1 < cols && v[r][c] == '-' && v[r][c + 1] == '-') { v[r][c] = ' '; } if (r + 1 < rows && v[r][c] == '|' && v[r + 1][c] == '|') { v[r][c] = ' '; } if (r + 1 < rows && c + 1 < cols && v[r][c] == '`' && v[r + 1][c + 1] == '`') { v[r][c] = ' '; } if (r + 1 < rows && c > 0 && v[r][c] == '/' && v[r + 1][c - 1] == '/') { v[r][c] = ' '; } } } // count how many vertices and indices we will have int vertices = 0, indices = 0; for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { char t = static_cast(v[r][c]); if (t == '+') { vertices++; } else if (t == '-' || t == '|' || t == '`' || t == '/') { indices += 2; // each line requires 2 indices } } } GEOM_DEBUG("Total vertices: %d, total indices %d", vertices, indices); // allocate arrays for the vertices and lines const int VERTICES_STRIDE = sizeof(GLfloat) * 7; const int VERTICES_COLOR_OFFSET = sizeof(GLfloat) * 3; GLfloat* verticesArray = new GLfloat[vertices * VERTICES_STRIDE]; GLushort* indicesArray = new GLushort[indices]; vertices = indices = 0; // current count of vertices and lines float left = (-cols / 2) * scale; if (cols % 2 == 0) left += scale * 0.5f; float top = (rows / 2) * scale; if (rows % 2 == 0) top += scale * 0.5f; const int VERTEX_BIT = 0x1000; const int VERTEX_INDEX_MASK = 0x0fff; // process vertices for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { unsigned t = v[r][c]; if (t == '+') { GEOM_DEBUG("Found vertex at %d,%d, index %d", r, c, vertices); verticesArray[vertices * 7] = left + c * scale; verticesArray[vertices * 7 + 1] = top - r * scale; verticesArray[vertices * 7 + 2] = 0.0f; // z coord is always 0 verticesArray[vertices * 7 + 3] = 1.0f; // red verticesArray[vertices * 7 + 4] = 1.0f; // green verticesArray[vertices * 7 + 5] = 1.0f; // blue verticesArray[vertices * 7 + 6] = 1.0f; // alpha // mark which vertex this is v[r][c] = static_cast(VERTEX_BIT | vertices); vertices++; } } } // process lines int col_dir, row_dir; int start_c, start_r, end_c, end_r; GEOM_DEBUG("Now processing lines."); for (r = 0; r < rows; r++) { for (c = 0; c < cols; c++) { int t = v[r][c]; if (t == '-') { // horizontal line GEOM_DEBUG("Horizontal line found at %d,%d", r, c); col_dir = -1, row_dir = 0; } else if (t == '|') { // vertical line GEOM_DEBUG("Vertical line found at %d,%d", r, c); col_dir = 0, row_dir = -1; } else if (t == '`') { // horizontal line, slanting down GEOM_DEBUG("Downward diagonal line found at %d,%d", r, c); col_dir = -1, row_dir = -1; } else if (t == '/') { // horizontal line, slanting down GEOM_DEBUG("Upward diagonal line found at %d,%d", r, c); col_dir = -1, row_dir = 1; } else { continue; } // look for the vertex that starts the line: start_c = c; start_r = r; while (!(v[start_r][start_c] & VERTEX_BIT)) { start_c += col_dir; start_r += row_dir; if (start_c < 0 || start_r < 0 || start_c >= cols || start_r >= rows) { LOGE("Invalid line in ascii-art: no start. At position %d,%d", r, c); ABORT_GAME; } } GEOM_DEBUG("Start vertex is at %d,%d, index %d", start_r, start_c, v[start_r][start_c] & VERTEX_INDEX_MASK); // look for the vertex that ends the line end_c = c; end_r = r; while (!(v[end_r][end_c] & VERTEX_BIT)) { end_c -= col_dir; end_r -= row_dir; if (end_c < 0 || end_r < 0 || end_c >= cols || end_r >= rows) { LOGE("Invalid line in ascii-art: no end. At position %d,%d", r, c); ABORT_GAME; } } GEOM_DEBUG("End vertex is at %d,%d, index %d", end_r, end_c, v[end_r][end_c] & VERTEX_INDEX_MASK); indicesArray[indices] = static_cast(v[start_r][start_c] & VERTEX_INDEX_MASK); indicesArray[indices + 1] = static_cast(v[end_r][end_c] & VERTEX_INDEX_MASK); indices += 2; GEOM_DEBUG("We now have %d indices.", indices); } } GEOM_DEBUG("Deallocating working space."); // get rid of the working arrays for (r = 0; r < rows; r++) { delete v[r]; } delete[] v; for (int i = 0; i < indices; i++) { GEOM_DEBUG("indices[%d] = %d\n", i, indicesArray[i]); } for (int i = 0; i < vertices; i++) { GEOM_DEBUG("vertices[%d]", i * 7); for (int j = 0; j < 7; j++) { GEOM_DEBUG("vertices[%d+%d=%d] = %f\n", i * 7, j, i * 7 + j, verticesArray[i * 7 + j]); } } // create the buffers GEOM_DEBUG("Creating output VBO (%d vertices) and IBO (%d indices).", vertices, indices); SimpleGeom* out = new SimpleGeom( new VertexBuf(verticesArray, vertices * sizeof(GLfloat) * VERTICES_STRIDE, VERTICES_STRIDE), new IndexBuf(indicesArray, indices * sizeof(GLushort))); out->vbuf->SetPrimitive(GL_LINES); // draw as lines out->vbuf->SetColorsOffset(VERTICES_COLOR_OFFSET); // clean up our work buffers delete[] verticesArray; verticesArray = NULL; delete[] indicesArray; indicesArray = NULL; LOGD("Created geometry from ascii art: %d vertices, %d indices", vertices, indices); return out; } ================================================ FILE: endless-tunnel/app/src/main/cpp/ascii_to_geom.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_ascii_to_geom_hpp #define endlesstunnel_ascii_to_geom_hpp #include "engine.hpp" /* Converts ASCII art into a Vbo/Ibo pair. Useful for retro-looking * drawings/text! scale is the size of each character. The center of the * rendering will be 0,0. * * Examples: * * Square: * +---+ * | | * +---+ * * Triangle: * +-----+ * ` / * ` / * + * * The + sign represents a vertex; lines are represented by -, /, ` and |. */ SimpleGeom* AsciiArtToGeom(const char* art, float scale); #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/common.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_common_hpp #define endlesstunnel_common_hpp extern "C" { #include #include #include #include #include #include #include #include #include } #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #define DEBUG_TAG "EndlessTunnel:Native" #define LOGD(...) \ ((void)__android_log_print(ANDROID_LOG_DEBUG, DEBUG_TAG, __VA_ARGS__)) #define LOGI(...) \ ((void)__android_log_print(ANDROID_LOG_INFO, DEBUG_TAG, __VA_ARGS__)) #define LOGW(...) \ ((void)__android_log_print(ANDROID_LOG_WARN, DEBUG_TAG, __VA_ARGS__)) #define LOGE(...) \ ((void)__android_log_print(ANDROID_LOG_ERROR, DEBUG_TAG, __VA_ARGS__)) #define ABORT_GAME \ { \ LOGE("*** GAME ABORTING."); \ *((volatile char*)0) = 'a'; \ } #define DEBUG_BLIP LOGD("[ BLIP ]: %s:%d", __FILE__, __LINE__) #define MY_ASSERT(cond) \ { \ if (!(cond)) { \ LOGE("ASSERTION FAILED: %s", #cond); \ ABORT_GAME; \ } \ } #include "our_key_codes.hpp" #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/alphabet.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_alphabet_inl #define _mygame_alphabet_inl #define ALPHABET_GLYPH_COLS 5 #define ALPHABET_GLYPH_ROWS 9 static const char *ALPHABET_ART[] = { NULL, // chr 0 NULL, // chr 1 NULL, // chr 2 NULL, // chr 3 NULL, // chr 4 NULL, // chr 5 NULL, // chr 6 NULL, // chr 7 NULL, // chr 8 NULL, // chr 9 NULL, // chr 10 NULL, // chr 11 NULL, // chr 12 NULL, // chr 13 NULL, // chr 14 NULL, // chr 15 NULL, // chr 16 NULL, // chr 17 NULL, // chr 18 NULL, // chr 19 NULL, // chr 20 NULL, // chr 21 NULL, // chr 22 NULL, // chr 23 NULL, // chr 24 NULL, // chr 25 NULL, // chr 26 NULL, // chr 27 NULL, // chr 28 NULL, // chr 29 NULL, // chr 30 NULL, // chr 31 NULL, // chr 32 "+---+\n" // chr 33, ! "| |\n" "+ +\n" " ` / \n" " + \n" " +-+ \n" " | | \n" " +-+ \n" " \n", NULL, // chr 34, " NULL, // chr 35, # NULL, // chr 36, $ NULL, // chr 37, % NULL, // chr 38, & " + \n" // chr 39, ' " | \n" " + \n" " \n" " \n" " \n" " \n" " \n" " \n", NULL, // chr 40, ( NULL, // chr 41, ) NULL, // chr 42, * " \n" // chr 43, + " + \n" " | \n" "+-+-+\n" " | \n" " + \n" " \n" " \n" " \n", " \n" // chr 44, , " \n" " \n" " \n" " \n" " + \n" " / \n" " + \n" " \n", " \n" // chr 45, - " \n" " \n" "+---+\n" " \n" " \n" " \n" " \n" " \n", " \n" // chr 46, . " \n" " \n" " \n" " \n" " +-+ \n" " | | \n" " +-+ \n" " \n", " \n" // chr 47, / " \n" " +\n" " / \n" " / \n" " / \n" "+ \n" " \n" " \n", "+---+\n" // chr 48, 0 "| |\n" "| |\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", " + \n" // chr 49, 1 " | \n" " | \n" " | \n" " | \n" " | \n" " + \n" " \n" " \n", "+---+\n" // chr 50, 2 " |\n" " |\n" "+---+\n" "| \n" "| \n" "+---+\n" " \n" " \n", "+---+\n" // chr 51, 3 " |\n" " |\n" "+---+\n" " |\n" " |\n" "+---+\n" " \n" " \n", "+ +\n" // chr 52, 4 "| |\n" "| |\n" "+---+\n" " |\n" " |\n" " +\n" " \n" " \n", "+---+\n" // chr 53, 5 "| \n" "| \n" "+---+\n" " |\n" " |\n" "+---+\n" " \n" " \n", "+---+\n" // chr 54, 6 "| \n" "| \n" "+---+\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+---+\n" // chr 55, 7 " |\n" " |\n" " |\n" " |\n" " |\n" " +\n" " \n" " \n", "+---+\n" // chr 56, 8 "| |\n" "| |\n" "+---+\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+---+\n" // chr 57, 9 "| |\n" "| |\n" "+---+\n" " |\n" " |\n" "+---+\n" " \n" " \n", " +-+ \n" // chr 58, : " | | \n" " +-+ \n" " \n" " +-+ \n" " | | \n" " +-+ \n" " \n" " \n", NULL, // chr 59, ; NULL, // chr 60, < NULL, // chr 61, = NULL, // chr 62, > "+---+\n" // chr 63, ? " |\n" " +-+\n" " | \n" " + \n" " +-+ \n" " | | \n" " +-+ \n" " \n", NULL, // chr 64, @ "+---+\n" // chr 65, A "| |\n" "| |\n" "+---+\n" "| |\n" "| |\n" "+ +\n" " \n" " \n", "+---+\n" // chr 66, B "| |\n" "| |\n" "+---+\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+---+\n" // chr 67, C "| \n" "| \n" "| \n" "| \n" "| \n" "+---+\n" " \n" " \n", "+-+ \n" // chr 68, D "| ` \n" "| +\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+---+\n" // chr 69, E "| \n" "| \n" "+--+ \n" "| \n" "| \n" "+---+\n" " \n" " \n", "+---+\n" // chr 70, F "| \n" "| \n" "+--+ \n" "| \n" "| \n" "+ \n" " \n" " \n", "+---+\n" // chr 71, G "| \n" "| \n" "| +-+\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+ +\n" // chr 72, H "| |\n" "| |\n" "+---+\n" "| |\n" "| |\n" "+ +\n" " \n" " \n", "+-+-+\n" // chr 73, I " | \n" " | \n" " | \n" " | \n" " | \n" "+-+-+\n" " \n" " \n", "+-+-+\n" // chr 74, J " | \n" " | \n" " | \n" "+ | \n" "| | \n" "+-+ \n" " \n" " \n", "+ + \n" // chr 75, K "| / \n" "|/ \n" "+ \n" "|` \n" "| ` \n" "+ + \n" " \n" " \n", "+ \n" // chr 76, L "| \n" "| \n" "| \n" "| \n" "| \n" "+---+\n" " \n" " \n", "+-+-+\n" // chr 77, M "| | |\n" "| | |\n" "| | |\n" "| + |\n" "| |\n" "+ +\n" " \n" " \n", "+-+ \n" // chr 78, N "| ` \n" "| +\n" "| |\n" "| |\n" "| |\n" "+ +\n" " \n" " \n", " + \n" // chr 79, O " / ` \n" "+ +\n" "| |\n" "+ +\n" " ` / \n" " + \n" " \n" " \n", "+---+\n" // chr 80, P "| |\n" "| |\n" "+---+\n" "| \n" "| \n" "+ \n" " \n" " \n", "+---+\n" // chr 81, Q "| |\n" "| |\n" "| |\n" "| + |\n" "| `|\n" "+---+\n" " \n" " \n", "+---+\n" // chr 82, R "| |\n" "| |\n" "+---+\n" "|` \n" "| ` \n" "+ + \n" " \n" " \n", "+---+\n" // chr 83, S "| \n" "| \n" "+---+\n" " |\n" " |\n" "+---+\n" " \n" " \n", "+-+-+\n" // chr 84, T " | \n" " | \n" " | \n" " | \n" " | \n" " + \n" " \n" " \n", "+ +\n" // chr 85, U "| |\n" "| |\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", "+ +\n" // chr 86, V "| |\n" "| |\n" "| |\n" "+ +\n" " ` / \n" " + \n" " \n" " \n", "+ +\n" // chr 87, W "| |\n" "| |\n" "| + |\n" "| | |\n" "| | |\n" "+-+-+\n" " \n" " \n", "+ +\n" // chr 88, X " ` / \n" " + \n" " | \n" " + \n" " / ` \n" "+ +\n" " \n" " \n", "+ +\n" // chr 89, Y "| |\n" "| |\n" "+-+-+\n" " | \n" " | \n" " + \n" " \n" " \n", "+---+\n" // chr 90, Z " / \n" " / \n" " / \n" "+ \n" "| \n" "+---+\n" " \n" " \n", "+-+ \n" // chr 91, [ "| \n" "| \n" "| \n" "| \n" "| \n" "+-+ \n" " \n" " \n", " \n" // chr 92, backslash "+ \n" " ` \n" " ` \n" " ` \n" " +\n" " \n" " \n" " \n", " +-+\n" // chr 93, ] " |\n" " |\n" " |\n" " |\n" " |\n" " +-+\n" " \n" " \n", " + \n" // chr 94, ^ " / ` \n" "+ +\n" " \n" " \n" " \n" " \n" " \n" " \n", " \n" // chr 95, _ " \n" " \n" " \n" " \n" " \n" "+---+\n" " \n" " \n", NULL, // chr 96, ` " \n" // chr 97, a " \n" "+---+\n" " |\n" "+---+\n" "| |\n" "+---+\n" " \n" " \n", "+ \n" // chr 98, b "| \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", " \n" // chr 99, c " \n" "+---+\n" "| \n" "| \n" "| \n" "+---+\n" " \n" " \n", " +\n" // chr 100, d " |\n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", " \n" // chr 101, e " \n" "+---+\n" "| |\n" "+---+\n" "| \n" "+---+\n" " \n" " \n", "+--+ \n" // chr 102, f "| \n" "| \n" "+-+ \n" "| \n" "| \n" "+ \n" " \n" " \n", " \n" // chr 103, g " \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" " |\n" "+---+\n", "+ \n" // chr 104, h "| \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+ +\n" " \n" " \n", " \n" // chr 105, i " \n" " + \n" " | \n" " | \n" " | \n" " + \n" " \n" " \n", " \n" // chr 106, j " \n" " + \n" " | \n" " | \n" " | \n" "+ | \n" "| | \n" "+-+ \n", " + \n" // chr 107, k " | \n" " | + \n" " |/ \n" " + \n" " |` \n" " + + \n" " \n" " \n", " + \n" // chr 108, l " | \n" " | \n" " | \n" " | \n" " | \n" " + \n" " \n" " \n", " \n" // chr 109, m " \n" "+-+-+\n" "| | |\n" "| | |\n" "| | |\n" "+ + +\n" " \n" " \n", " \n" // chr 110, n " \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+ +\n" " \n" " \n", " \n" // chr 111, o " \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", " \n" // chr 112, p " \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" "| \n" "+ \n", " \n" // chr 113, q " \n" "+---+\n" "| |\n" "| |\n" "| |\n" "+---+\n" " |\n" " +\n", " \n" // chr 114, r " \n" "+---+\n" "| \n" "| \n" "| \n" "+ \n" " \n" " \n", " \n" // chr 115, s " \n" "+---+\n" "| \n" "+---+\n" " |\n" "+---+\n" " \n" " \n", "+ \n" // chr 116, t "| \n" "+--+ \n" "| \n" "| \n" "| \n" "+---+\n" " \n" " \n", " \n" // chr 117, u " \n" "+ +\n" "| |\n" "| |\n" "| |\n" "+---+\n" " \n" " \n", " \n" // chr 118, v " \n" "+ +\n" "| |\n" "+ +\n" " ` / \n" " + \n" " \n" " \n", " \n" // chr 119, w " \n" "+ +\n" "| + |\n" "+ | +\n" "| | |\n" "+-+-+\n" " \n" " \n", " \n" // chr 120, x " \n" "+ +\n" " ` / \n" " \n" " / ` \n" "+ +\n" " \n" " \n", " \n" // chr 121, y " \n" "+ +\n" "| |\n" "| |\n" "| |\n" "+---+\n" " |\n" "+---+\n", " \n" // chr 122, z " \n" "+---+\n" " / \n" " / \n" " / \n" "+---+\n" " \n" " \n", NULL, // chr 123, { NULL, // chr 124, | NULL, // chr 125, } NULL, // chr 126, ~ NULL // chr 127, weird DEL thing }; #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/ascii_art.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_ascii_art_inl #define _mygame_ascii_art_inl #define ART_LIFE \ " +-+ +-+ \n" \ " / ` / ` \n" \ " + + +\n" \ " ` / \n" \ " ` / \n" \ " ` / \n" \ " ` / \n" \ " ` / \n" \ " + \n" #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/blurb.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #define BLURB_ABOUT \ "ABOUT THIS GAME\n\n" \ "This game is written in C++\n" \ "to showcase Android Studio NDK support, \n" \ "Find out more about the Android Studio at:\n" \ "http://tools.android.com" #define BLURB_STORY \ "STORY\n\n" \ "A messenger from the king rushes\n" \ "into the tavern and asks for the\n" \ "highest level character. That's\n" \ "you so he gives you a quest: fly\n" \ "to the end of that endless tunnel\n" \ "collecting white cubes. At the end\n" \ "you will receive cake." ================================================ FILE: endless-tunnel/app/src/main/cpp/data/cube_geom.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_obstacle_geom_hpp #define _mygame_obstacle_geom_hpp #include "engine.hpp" /* H+-------+G /. /| D / . C/ | +-------+..+F | /E | / |/ |/ A+-------+B */ #define V_A -0.5f, -0.5f, 0.5f #define V_B 0.5f, -0.5f, 0.5f #define V_C 0.5f, 0.5f, 0.5f #define V_D -0.5f, 0.5f, 0.5f #define V_E -0.5f, -0.5f, -0.5f #define V_F 0.5f, -0.5f, -0.5f #define V_G 0.5f, 0.5f, -0.5f #define V_H -0.5f, 0.5f, -0.5f #define COLOR_1 1.0f, 1.0f, 1.0f, 1.0f #define COLOR_2 0.8f, 0.8f, 0.8f, 1.0f #define COLOR_3 0.6f, 0.6f, 0.6f, 1.0f // max tex coordinate (i.e. texture repeats across cube) #define TC_R 3.0f static GLfloat CUBE_GEOM[] = { // front face of cube: V_A, COLOR_2, 0.0f, 0.0f, V_B, COLOR_2, TC_R, 0.0f, V_D, COLOR_2, 0.0f, TC_R, V_D, COLOR_2, 0.0f, TC_R, V_B, COLOR_2, TC_R, 0.0f, V_C, COLOR_2, TC_R, TC_R, // right face of cube: V_B, COLOR_3, 0.0f, 0.0f, V_F, COLOR_3, TC_R, 0.0f, V_C, COLOR_3, 0.0f, TC_R, V_C, COLOR_3, 0.0f, TC_R, V_F, COLOR_3, TC_R, 0.0f, V_G, COLOR_3, TC_R, TC_R, // left face of cube V_A, COLOR_3, 0.0f, TC_R, V_D, COLOR_3, TC_R, TC_R, V_E, COLOR_3, 0.0f, 0.0f, V_E, COLOR_3, 0.0f, 0.0f, V_D, COLOR_3, TC_R, TC_R, V_H, COLOR_3, 0.0f, TC_R, // back face of cube V_E, COLOR_2, TC_R, 0.0f, V_H, COLOR_2, TC_R, TC_R, V_F, COLOR_2, 0.0f, 0.0f, V_F, COLOR_2, 0.0f, 0.0f, V_H, COLOR_2, TC_R, TC_R, V_G, COLOR_2, 0.0f, TC_R, // bottom of cube V_A, COLOR_1, 0.0f, TC_R, V_E, COLOR_1, 0.0f, 0.0f, V_B, COLOR_1, TC_R, TC_R, V_B, COLOR_1, TC_R, TC_R, V_E, COLOR_1, 0.0f, 0.0f, V_F, COLOR_1, TC_R, 0.0f, // top of cube V_D, COLOR_1, 0.0f, 0.0f, V_C, COLOR_1, TC_R, 0.0f, V_H, COLOR_1, 0.0f, TC_R, V_H, COLOR_1, 0.0f, TC_R, V_C, COLOR_1, TC_R, 0.0f, V_G, COLOR_1, TC_R, TC_R}; static const int CUBE_GEOM_COLOR_OFFSET = 3 * sizeof(GLfloat); static const int CUBE_GEOM_TEXCOORD_OFFSET = 7 * sizeof(GLfloat); static const int CUBE_GEOM_STRIDE = 9 * sizeof(GLfloat); /* this is something of a trivial index buffer (and could just as well be replaced by an array), but we have it here for demonstration purposes: static unsigned short CUBE_GEOM_INDICES[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 }; */ #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/our_shader.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_our_shader_inl #define _mygame_our_shader_inl #define OUR_VERTEX_SHADER_SOURCE \ "uniform mat4 u_MVP; \n" \ "uniform vec4 u_PointLightPos; \n" \ "uniform mediump vec4 u_PointLightColor; \n" \ "attribute vec4 a_Position; \n" \ "attribute vec4 a_Color; \n" \ "attribute vec2 a_TexCoord; \n" \ "varying vec4 v_Color; \n" \ "varying vec4 v_Pos; \n" \ "varying float v_FogFactor; \n" \ "varying vec2 v_TexCoord; \n" \ "float FOG_START = 100.0; \n" \ "float FOG_END = 200.0; \n" \ "varying vec4 v_PointLightPos; \n" \ "void main() \n" \ "{ \n" \ " v_Color = a_Color; \n" \ " gl_Position = u_MVP \n" \ " * a_Position; \n" \ " v_Pos = u_MVP * a_Position; \n" \ " v_PointLightPos = u_MVP * u_PointLightPos; \n" \ " v_TexCoord = a_TexCoord; \n" \ " v_FogFactor = clamp((v_Pos.z - FOG_START) / (FOG_END - FOG_START), " \ "0.0, 1.0); \n" \ "} \n"; #define OUR_FRAG_SHADER_SOURCE \ "precision mediump float; \n" \ "varying vec4 v_Color; \n" \ "varying vec4 v_Pos; \n" \ "varying vec2 v_TexCoord; \n" \ "varying float v_FogFactor; \n" \ "uniform vec4 u_Tint; \n" \ "uniform sampler2D u_Sampler; \n" \ "uniform vec4 u_PointLightColor; \n" \ "varying vec4 v_PointLightPos; \n" \ "float ATT_FACT_2 = 0.005; \n" \ "float ATT_FACT_1 = 0.00; \n" \ "void main() \n" \ "{ \n" \ " float d = distance(v_PointLightPos, v_Pos);\n" \ " float att = 1.0/(ATT_FACT_1 * d + ATT_FACT_2 * d * d);\n" \ " gl_FragColor = mix(v_Color * u_Tint * texture2D(u_Sampler, v_TexCoord) " \ "+ u_PointLightColor * att, vec4(0), v_FogFactor);\n" \ "}"; #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/strings.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_strings_inl #define _mygame_strings_inl #define S_HOWTO_WITHOUT_JOY "Drag to steer" #define S_GOT_BONUS "+ 50" #define S_GAME_OVER "Game Over" #define S_OUCH "Ouch" #define S_CHECKPOINT_SAVED "Checkpoint saved" #define S_UNPAUSE "Resume" #define S_QUIT "Quit" #define S_START_OVER "Start Over" #define S_RESUME "Start from checkpoint" #define S_TITLE "Endless Tunnel" #define S_PLAY "Play!" #define S_PLEASE_WAIT "Please wait..." #define S_STORY "Story" #define S_ABOUT "About" #define S_OK "OK" #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/data/tunnel_geom.inl ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef _mygame_tunnel_geom_hpp #define _mygame_tunnel_geom_hpp #include "engine.hpp" #include "game_consts.hpp" // shorthand to make it simpler to hand-code the geometry below: // (first char is the coord, second is 'B'ottom, 'R'ight, 'L'eft or 'T'op, // 'N'ear or 'F'ar) // and third is whether this accounts for the 'S'pacing or 'N'ot. #define ZB -TUNNEL_HALF_H #define ZT TUNNEL_HALF_H #define XL -TUNNEL_HALF_W #define XR TUNNEL_HALF_W #define YN (TUNNEL_SECTION_LENGTH * -0.5f) #define YF (TUNNEL_SECTION_LENGTH * 0.5f) #define TCOLOR_M 0.10f, 0.10f, 0.10f, 1.0f #define TCOLOR_D 0.07f, 0.07f, 0.07f, 1.0f // max texture coord along X and Z axis (i.e. repetitions) #define REPN 10.0f // max texture coord along Y axis (i.e. repetitions) #define REPF (REPN * TUNNEL_SECTION_LENGTH / (2 * TUNNEL_HALF_W)) // note: the color data is temporary (will be replaced with texture once texture // is implemented) static GLfloat TUNNEL_GEOM[] = { /* vert 0: x,y,z:*/ XL, YN, ZB, /*tex u,v*/ 0.0f, 0.0f, /*color:*/ TCOLOR_M, /* vert 1: x,y,z:*/ XR, YN, ZB, /*tex u,v*/ REPN, 0.0f, /*color:*/ TCOLOR_M, /* vert 2: x,y,z:*/ XR, YF, ZB, /*tex u,v*/ REPN, REPF, /*color:*/ TCOLOR_M, /* vert 3: x,y,z:*/ XL, YF, ZB, /*tex u,v*/ 0.0f, REPF, /*color:*/ TCOLOR_M, /* vert 4: x,y,z:*/ XL, YN, ZB, /*tex u,v*/ 0.0f, 0.0f, /*color:*/ TCOLOR_D, /* vert 5: x,y,z:*/ XL, YF, ZB, /*tex u,v*/ REPF, 0.0f, /*color:*/ TCOLOR_D, /* vert 6: x,y,z:*/ XL, YF, ZT, /*tex u,v*/ REPF, REPN, /*color:*/ TCOLOR_D, /* vert 7: x,y,z:*/ XL, YN, ZT, /*tex u,v*/ 0.0f, REPN, /*color:*/ TCOLOR_D, /* vert 8: x,y,z:*/ XR, YN, ZB, /*tex u,v*/ REPF, 0.0f, /*color:*/ TCOLOR_D, /* vert 9: x,y,z:*/ XR, YN, ZT, /*tex u,v*/ REPF, REPN, /*color:*/ TCOLOR_D, /* vert 10: x,y,z:*/ XR, YF, ZT, /*tex u,v*/ 0.0f, REPN, /*color:*/ TCOLOR_D, /* vert 11: x,y,z:*/ XR, YF, ZB, /*tex u,v*/ 0.0f, 0.0f, /*color:*/ TCOLOR_D, /* vert 12: x,y,z:*/ XL, YF, ZT, /*tex u,v*/ 0.0f, 0.0f, /*color:*/ TCOLOR_M, /* vert 13: x,y,z:*/ XR, YF, ZT, /*tex u,v*/ REPN, 0.0f, /*color:*/ TCOLOR_M, /* vert 14: x,y,z:*/ XR, YN, ZT, /*tex u,v*/ REPN, REPF, /*color:*/ TCOLOR_M, /* vert 15: x,y,z:*/ XL, YN, ZT, /*tex u,v*/ 0.0f, REPF, /*color:*/ TCOLOR_M, }; static GLushort TUNNEL_GEOM_INDICES[] = { 0, 1, 2, 0, 2, 3, // floor 8, 9, 11, 11, 9, 10, // right wall 4, 5, 7, 7, 5, 6, // left wall 12, 13, 15, 15, 13, 14 // ceiling }; #define TUNNEL_GEOM_STRIDE (9 * sizeof(GLfloat)) #define TUNNEL_GEOM_TEXCOORD_OFFSET (3 * sizeof(GLfloat)) #define TUNNEL_GEOM_COLOR_OFFSET (5 * sizeof(GLfloat)) #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/dialog_scene.cpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #include "dialog_scene.hpp" #include "anim.hpp" #include "play_scene.hpp" #define BUTTON_FONT_SCALE 0.6f #define TEXT_FONT_SCALE 0.6f #define BUTTON_MARGIN 0.1f #define BUTTON_WIDTH 0.4f #define BUTTON_HEIGHT 0.15f #define BUTTON_SIZE BUTTON_WIDTH, BUTTON_HEIGHT #define BUTTON_COLOR 0.0f, 1.0f, 0.0f #define BUTTON_DISCOURAGE_COLOR 0.0f, 0.4f, 0.0f #define LEFT_X center * 2 * 0.33f #define RIGHT_X center * 2 * 0.67f #define TEXT_Y 0.6f DialogScene::DialogScene() { mLeftButtonId = mRightButtonId = -1; mTextBoxId = -1; mLeftButtonAction = mRightButtonAction = ACTION_RETURN; mButtonY = 0.5f; mText = mLeftButtonText = mRightButtonText = NULL; } DialogScene::~DialogScene() {} void DialogScene::CreateWidgetsSetText() { const char* text = mText; float center = 0.5f * SceneManager::GetInstance()->GetScreenAspect(); if (mTextBoxId < 0) { mTextBoxId = NewWidget()->SetTransition(UiWidget::TRANS_FROM_TOP)->GetId(); } GetWidgetById(mTextBoxId) ->SetText(text) ->SetFontScale(TEXT_FONT_SCALE) ->SetCenter(center, TEXT_Y); float height = TextRenderer::MeasureTextHeight(text, TEXT_FONT_SCALE); mButtonY = TEXT_Y - height * 0.5f - BUTTON_MARGIN - 0.5f * BUTTON_HEIGHT; } void DialogScene::CreateWidgetsSingleButton() { const char* text = mLeftButtonText; int action = mLeftButtonAction; float center = 0.5f * SceneManager::GetInstance()->GetScreenAspect(); mLeftButtonId = NewWidget() ->SetText(text) ->SetIsButton(true) ->SetCenter(center, mButtonY) ->SetSize(BUTTON_SIZE) ->SetTextColor(BUTTON_COLOR) ->SetFontScale(BUTTON_FONT_SCALE) ->SetTransition(UiWidget::TRANS_FROM_BOTTOM) ->GetId(); mLeftButtonAction = action; SetDefaultButton(mLeftButtonId); } void DialogScene::CreateWidgetsTwoButtons() { const char* leftText = mLeftButtonText; int leftAction = mLeftButtonAction; const char* rightText = mRightButtonText; int rightAction = mRightButtonAction; float center = 0.5f * SceneManager::GetInstance()->GetScreenAspect(); mLeftButtonId = NewWidget() ->SetText(leftText) ->SetIsButton(true) ->SetCenter(LEFT_X, mButtonY) ->SetSize(BUTTON_SIZE) ->SetTextColor(BUTTON_COLOR) ->SetTransition(UiWidget::TRANS_FROM_LEFT) ->GetId(); mLeftButtonAction = leftAction; mRightButtonId = NewWidget() ->SetText(rightText) ->SetIsButton(true) ->SetCenter(RIGHT_X, mButtonY) ->SetSize(BUTTON_SIZE) ->SetTransition(UiWidget::TRANS_FROM_RIGHT) ->SetTextColor(BUTTON_COLOR) ->GetId(); mRightButtonAction = rightAction; if (leftAction == ACTION_SIGN_OUT || leftAction == ACTION_PLAY_WITHOUT_SIGNIN) { GetWidgetById(mLeftButtonId)->SetTextColor(BUTTON_DISCOURAGE_COLOR); } if (rightAction == ACTION_SIGN_OUT || rightAction == ACTION_PLAY_WITHOUT_SIGNIN) { GetWidgetById(mRightButtonId)->SetTextColor(BUTTON_DISCOURAGE_COLOR); } // set up navigation between the buttons AddNav(mLeftButtonId, UI_DIR_RIGHT, mRightButtonId); AddNav(mRightButtonId, UI_DIR_LEFT, mLeftButtonId); } void DialogScene::OnCreateWidgets() { if (mRightButtonText) { CreateWidgetsSetText(); CreateWidgetsTwoButtons(); } else { CreateWidgetsSetText(); CreateWidgetsSingleButton(); } } void DialogScene::RenderBackground() { RenderBackgroundAnimation(mShapeRenderer); } bool DialogScene::OnBackKeyPressed() { SceneManager* mgr = SceneManager::GetInstance(); mgr->RequestNewScene(new WelcomeScene()); return true; } void DialogScene::OnButtonClicked(int id) { SceneManager* mgr = SceneManager::GetInstance(); int action; if (id == mLeftButtonId) { action = mLeftButtonAction; } else if (id == mRightButtonId) { action = mRightButtonAction; } else { return; } switch (action) { case ACTION_RETURN: mgr->RequestNewScene(new WelcomeScene()); break; case ACTION_SIGN_IN: // note: we can't start playing directly because PlayScene expects the // cloud results to be ready when it constructs itself; therefore, // WelcomeScene has to make sure of that. So we can't jump directly to // PlayScene from here. mgr->RequestNewScene(new WelcomeScene()); break; case ACTION_PLAY_WITHOUT_SIGNIN: mgr->RequestNewScene(new PlayScene()); break; case ACTION_SIGN_OUT: mgr->RequestNewScene(new WelcomeScene()); break; default: // do nothing. break; } } ================================================ FILE: endless-tunnel/app/src/main/cpp/dialog_scene.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_dialog_scene_hpp #define endlesstunnel_dialog_scene_hpp #include "engine.hpp" #include "ui_scene.hpp" #include "welcome_scene.hpp" /* Dialog Scene. Shows a message and buttons. When a button is clicked, performs * a given action. */ class DialogScene : public UiScene { protected: // text to be shown const char *mText; const char *mLeftButtonText; const char *mRightButtonText; // IDs for buttons int mLeftButtonId; int mRightButtonId; // ID for the text box int mTextBoxId; // action for left button and right button int mLeftButtonAction, mRightButtonAction; // y position of buttons float mButtonY; virtual void OnCreateWidgets(); virtual void RenderBackground(); virtual void OnButtonClicked(int id); virtual bool OnBackKeyPressed(); public: // (action) return to main screen static const int ACTION_RETURN = 1000; // (action) sign in with Google static const int ACTION_SIGN_IN = 1001; // (action) play without signing in static const int ACTION_PLAY_WITHOUT_SIGNIN = 1002; // (action) sign out static const int ACTION_SIGN_OUT = 1003; DialogScene(); ~DialogScene(); DialogScene *SetText(const char *text) { mText = text; return this; } DialogScene *SetSingleButton(const char *text, int action) { mLeftButtonText = text; mLeftButtonAction = action; mRightButtonText = NULL; return this; } private: void CreateWidgetsSetText(); void CreateWidgetsSingleButton(); void CreateWidgetsTwoButtons(); }; #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/engine.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_engine_hpp #define endlesstunnel_engine_hpp // These are the include files that comprise the "engine" part of the game -- // that is, the parts of it that are not game-specific. #include "common.hpp" #include "indexbuf.hpp" #include "joystick-support.hpp" #include "native_engine.hpp" #include "our_key_codes.hpp" #include "scene.hpp" #include "scene_manager.hpp" #include "shader.hpp" #include "simplegeom.hpp" #include "texture.hpp" #include "vertexbuf.hpp" #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/game_consts.hpp ================================================ /* * Copyright (C) Google Inc. * * 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. */ #ifndef endlesstunnel_game_consts_h #define endlesstunnel_game_consts_h // Render settings #define RENDER_FOV 45.0f #define RENDER_NEAR_CLIP 0.1f #define RENDER_FAR_CLIP 200.0f // Size of the tunnel #define TUNNEL_HALF_W 10.0f #define TUNNEL_HALF_H 10.0f // length of each tunnel section #define TUNNEL_SECTION_LENGTH 150.0f // number of tunnel sections to render ahead #define RENDER_TUNNEL_SECTION_COUNT 4 // An obstacle is a grid of boxes. This indicates how many boxes by how many // boxes this grid is. #define OBS_GRID_SIZE 5 // This is how wide each of the grid cells are #define OBS_CELL_SIZE ((2 * TUNNEL_HALF_W) / (float)OBS_GRID_SIZE) // size of each obstacle box #define OBS_BOX_SIZE (0.8f * OBS_CELL_SIZE) // size of bonus box #define OBS_BONUS_SIZE (0.3f * OBS_CELL_SIZE) // at what distance (in tunnel sections) from the start position do obstacles // start to appear? #define OBS_START_SECTION 4 // once a tunnel section is this far behind the player, delete it #define SHIFT_THRESH 20.0f // maximum delta T between two frames #define MAX_DELTA_T 0.05f // player's speed #define PLAYER_SPEED 80.0f // how much the player's speed increases when we go up one difficulty level #define PLAYER_SPEED_INC_PER_LEVEL 10.0f // player's lateral speed #define PLAYER_MAX_LAT_SPEED 40.0f // bounds on player's movement #define PLAYER_MAX_X TUNNEL_HALF_W - 1.0f #define PLAYER_MIN_X -(PLAYER_MAX_X) #define PLAYER_MAX_Z TUNNEL_HALF_H - 1.0f #define PLAYER_MIN_Z -(PLAYER_MAX_Z) // touch control sensivity (ship displacement caused by dragging the screen by a // length equivalent to its height). #define TOUCH_CONTROL_SENSIVITY (TUNNEL_HALF_W * 5) // joystick control sensivity (maximum velocity attained per axis) #define JOYSTICK_CONTROL_SENSIVITY 20.0f // how many points equal a raise in difficulty level? #define SCORE_PER_LEVEL 500 // settings for rendering the score to the screen #define SCORE_POS_X 0.15f #define SCORE_POS_Y 0.92f #define SCORE_FONT_SCALE 0.8f // scale of the signs that appear onscreen #define SIGN_FONT_SCALE 0.9f // scale of menu items #define MENUITEM_FONT_SCALE 0.8f // how long do signs stay onscreen #define SIGN_DURATION 2.0f #define SIGN_DURATION_BONUS 1.0f #define SIGN_DURATION_GAME_OVER 5.0f // duration of a text sign's zoom-in animation #define SIGN_ANIM_DUR 0.2f // how big the life symbol (heart) is #define LIFE_ICON_SCALE 0.004f #define LIFE_LINE_WIDTH 3 // where do we start drawing the life icons? (negative to mean counting from // right side of screen) #define LIFE_POS_X -0.4f #define LIFE_POS_Y SCORE_POS_Y #define LIFE_SPACING_X 0.08f #define LIFE_SCALE_Y 1.5f // how many lives the player has #define PLAYER_LIVES 4 // how many points player gets for picking up a bonus #define BONUS_POINTS 50 // roll speeds for each level (how fast the chamber turns) #define ROLL_SPEEDS \ { 0.0f, 0.1f, 0.0f, -0.1f, 0.0f, 0.2f, 0.0f, -0.2f } // recipes for synthesizing our very advanced sound effects: #define TONE_LEVEL_UP "d100 f500. f600. f700. f600. f700. f800." #define TONE_CRASHED \ "a100 d15 f0. a40 d75 f0. a30 f0. a20 f0. a70 d100 f400. a0. a70. a0. a70." #define TONE_GAME_OVER \ "a100 d15 f0. a40 d75 f0. a30 f0. a20 f0. a70 d200 f400. a0. f350 a70. " \ "a0. f300 a70. a0. f250 a70. a0. f200 a70." #define TONE_AMBIENT_0 "d100 f300." #define TONE_AMBIENT_1 "d100 f200." // player's acceleration, in units per second squared #define PLAYER_ACCELERATION_NEGATIVE_SPEED 10.0f // used when speed is negative #define PLAYER_ACCELERATION_POSITIVE_SPEED 40.0f // used when speed is positive // the speed after colliding with an obstacle #define PLAYER_SPEED_AFTER_COLLISION -20.0f // how far beind the obstacle the player is placed upon collision #define PLAYER_RECEDE_AFTER_COLLISION 2.0f // how long the heart meter blinks for when you've just lost a life #define BLINKING_HEART_DURATION 2.0f // how long does the game take to end after we show Game Over #define GAME_OVER_EXPIRE 5.0f // UI transition animation duration #define TRANSITION_DURATION 0.25f // for the purposes of testing for close calls with obstacles, by how much do we // move the player to test for collisions? #define CLOSE_CALL_CALC_DELTA (OBS_CELL_SIZE * 0.2f) // menu item pulse animation settings #define MENUITEM_PULSE_AMOUNT 1.1f #define MENUITEM_PULSE_PERIOD 0.5f // save file name #define SAVE_FILE_NAME "tunnel.dat" // checkpoint (save progress) every how many levels? #define LEVELS_PER_CHECKPOINT 4 #endif ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/CMakeLists.txt ================================================ # # Copyright (C) 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. # add_library(glm STATIC detail/glm.cpp) target_include_directories(glm PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/..) ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/common.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/common.hpp /// @date 2013-12-24 / 2013-12-24 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef GLM_COMMON_INCLUDED #define GLM_COMMON_INCLUDED #include "detail/func_common.hpp" #endif // GLM_COMMON_INCLUDED ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_features.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_features.hpp /// @date 2013-02-20 / 2013-02-20 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef glm_core_features #define glm_core_features // #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) #endif // glm_core_features ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_fixes.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_fixes.hpp /// @date 2011-02-21 / 2011-11-22 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #include //! 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 ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_literals.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_literals.hpp /// @date 2013-05-06 / 2013-05-06 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef glm_core_literals #define glm_core_literals namespace glm { #define GLM_CXX11_USER_LITERALS #ifdef GLM_CXX11_USER_LITERALS /* GLM_FUNC_QUALIFIER detail::half operator "" _h(long double const s) { return detail::half(s); } GLM_FUNC_QUALIFIER float operator "" _f(long double const s) { return static_cast(s); } */ #endif // GLM_CXX11_USER_LITERALS } // namespace glm #endif // glm_core_literals ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_noise.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/detail/_noise.hpp /// @date 2013-12-24 / 2013-12-24 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef GLM_DETAIL_NOISE_INCLUDED #define GLM_DETAIL_NOISE_INCLUDED namespace glm { namespace detail { template GLM_FUNC_QUALIFIER T mod289(T const& x) { return x - floor(x * static_cast(1.0) / static_cast(289.0)) * static_cast(289.0); } template GLM_FUNC_QUALIFIER T permute(T const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER tvec2 permute(tvec2 const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER tvec3 permute(tvec3 const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } template GLM_FUNC_QUALIFIER tvec4 permute(tvec4 const& x) { return mod289(((x * static_cast(34)) + static_cast(1)) * x); } /* template class vecType> GLM_FUNC_QUALIFIER vecType permute(vecType const & x) { return mod289(((x * T(34)) + T(1)) * x); } */ template GLM_FUNC_QUALIFIER T taylorInvSqrt(T const& r) { return T(1.79284291400159) - T(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER detail::tvec2 taylorInvSqrt( detail::tvec2 const& r) { return T(1.79284291400159) - T(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER detail::tvec3 taylorInvSqrt( detail::tvec3 const& r) { return T(1.79284291400159) - T(0.85373472095314) * r; } template GLM_FUNC_QUALIFIER detail::tvec4 taylorInvSqrt( detail::tvec4 const& r) { return T(1.79284291400159) - T(0.85373472095314) * r; } /* template class vecType> GLM_FUNC_QUALIFIER vecType taylorInvSqrt(vecType const & r) { return T(1.79284291400159) - T(0.85373472095314) * r; } */ template GLM_FUNC_QUALIFIER detail::tvec2 fade(detail::tvec2 const& t) { return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); } template GLM_FUNC_QUALIFIER detail::tvec3 fade(detail::tvec3 const& t) { return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); } template GLM_FUNC_QUALIFIER detail::tvec4 fade(detail::tvec4 const& t) { return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); } /* template class vecType> GLM_FUNC_QUALIFIER vecType fade(vecType const & t) { return (t * t * t) * (t * (t * T(6) - T(15)) + T(10)); } */ } // namespace detail } // namespace glm #endif // GLM_DETAIL_NOISE_INCLUDED ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_swizzle.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_swizzle.hpp /// @date 2006-04-20 / 2011-02-16 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef glm_core_swizzle #define glm_core_swizzle namespace glm { namespace detail { // Internal class for implementing swizzle operators template struct _swizzle_base0 { typedef T value_type; protected: GLM_FUNC_QUALIFIER value_type& elem(size_t i) { return (reinterpret_cast(_buffer))[i]; } GLM_FUNC_QUALIFIER const value_type& elem(size_t i) const { return (reinterpret_cast(_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 struct _swizzle_base1 : public _swizzle_base0 {}; template struct _swizzle_base1 : public _swizzle_base0 { GLM_FUNC_QUALIFIER V operator()() const { return V(this->elem(E0), this->elem(E1)); } }; template struct _swizzle_base1 : public _swizzle_base0 { GLM_FUNC_QUALIFIER V operator()() const { return V(this->elem(E0), this->elem(E1), this->elem(E2)); } }; template struct _swizzle_base1 : public _swizzle_base0 { GLM_FUNC_QUALIFIER V operator()() const { return V(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) 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 struct _swizzle_base2 : public _swizzle_base1 { typedef VecType vec_type; typedef ValueType value_type; GLM_FUNC_QUALIFIER _swizzle_base2& operator=(const ValueType& t) { for (int i = 0; i < N; ++i) (*this)[i] = t; return *this; } GLM_FUNC_QUALIFIER _swizzle_base2& operator=(const VecType& that) { struct op { GLM_FUNC_QUALIFIER void operator()(value_type& e, value_type& t) { e = t; } }; _apply_op(that, op()); return *this; } GLM_FUNC_QUALIFIER void operator-=(const VecType& that) { struct op { GLM_FUNC_QUALIFIER void operator()(value_type& e, value_type& t) { e -= t; } }; _apply_op(that, op()); } GLM_FUNC_QUALIFIER void operator+=(const VecType& that) { struct op { GLM_FUNC_QUALIFIER void operator()(value_type& e, value_type& t) { e += t; } }; _apply_op(that, op()); } GLM_FUNC_QUALIFIER void operator*=(const VecType& that) { struct op { GLM_FUNC_QUALIFIER void operator()(value_type& e, value_type& t) { e *= t; } }; _apply_op(that, op()); } GLM_FUNC_QUALIFIER void operator/=(const VecType& that) { struct op { GLM_FUNC_QUALIFIER void operator()(value_type& e, value_type& t) { e /= t; } }; _apply_op(that, op()); } GLM_FUNC_QUALIFIER value_type& operator[](size_t i) { #ifndef __CUDA_ARCH__ static #endif const int offset_dst[4] = {E0, E1, E2, E3}; return this->elem(offset_dst[i]); } GLM_FUNC_QUALIFIER value_type operator[](size_t i) const { #ifndef __CUDA_ARCH__ static #endif const int offset_dst[4] = {E0, E1, E2, E3}; return this->elem(offset_dst[i]); } protected: template GLM_FUNC_QUALIFIER void _apply_op(const VecType& that, T 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. ValueType 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 struct _swizzle_base2 : public _swizzle_base1 { typedef VecType vec_type; typedef ValueType value_type; struct Stub {}; GLM_FUNC_QUALIFIER _swizzle_base2& operator=(Stub const&) { return *this; } GLM_FUNC_QUALIFIER value_type operator[](size_t i) const { #ifndef __CUDA_ARCH__ static #endif const int offset_dst[4] = {E0, E1, E2, E3}; return this->elem(offset_dst[i]); } }; template struct _swizzle : public _swizzle_base2 { typedef _swizzle_base2 base_type; using base_type::operator=; GLM_FUNC_QUALIFIER operator VecType() const { return (*this)(); } }; // // To prevent the C++ syntax from getting entirely overwhelming, define some // alias macros // #define _GLM_SWIZZLE_TEMPLATE1 \ template #define _GLM_SWIZZLE_TEMPLATE2 \ template #define _GLM_SWIZZLE_TYPE1 _swizzle #define _GLM_SWIZZLE_TYPE2 _swizzle // // 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 V operator OPERAND(const _GLM_SWIZZLE_TYPE1& a, \ const _GLM_SWIZZLE_TYPE2& b) { \ return a() OPERAND b(); \ } \ _GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER V operator OPERAND(const _GLM_SWIZZLE_TYPE1& a, \ const V& b) { \ return a() OPERAND b; \ } \ _GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER V operator OPERAND(const V& 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 V operator OPERAND(const _GLM_SWIZZLE_TYPE1& a, \ const T& b) { \ return a() OPERAND b; \ } \ _GLM_SWIZZLE_TEMPLATE1 \ GLM_FUNC_QUALIFIER V 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(/) } // namespace detail // // 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); } // namespace glm #define _GLM_SWIZZLE2_2_MEMBERS(T, P, V, E0, E1) \ struct { \ _swizzle<2, T, P, V, 0, 0, -1, -2> E0##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 1, -1, -2> E0##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 0, -1, -2> E1##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 1, -1, -2> E1##E1; \ }; #define _GLM_SWIZZLE2_3_MEMBERS(T, P, V, E0, E1) \ struct { \ _swizzle<3, T, P, V, 0, 0, 0, -1> E0##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 1, -1> E0##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 0, -1> E0##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 1, -1> E0##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 0, -1> E1##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 1, -1> E1##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 0, -1> E1##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 1, -1> E1##E1##E1; \ }; #define _GLM_SWIZZLE2_4_MEMBERS(T, P, V, E0, E1) \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 0> E0##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 1> E0##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 0> E0##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 1> E0##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 0> E0##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 1> E0##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 0> E0##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 1> E0##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 0> E1##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 1> E1##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 0> E1##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 1> E1##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 0> E1##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 1> E1##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 0> E1##E1##E1##E0; \ }; \ struct { \ _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 { \ _swizzle<2, T, P, V, 0, 0, -1, -2> E0##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 1, -1, -2> E0##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 2, -1, -2> E0##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 0, -1, -2> E1##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 1, -1, -2> E1##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 2, -1, -2> E1##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 0, -1, -2> E2##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 1, -1, -2> E2##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 2, -1, -2> E2##E2; \ }; #define _GLM_SWIZZLE3_3_MEMBERS(T, P, V, E0, E1, E2) \ struct { \ _swizzle<3, T, P, V, 0, 0, 0, -1> E0##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 1, -1> E0##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 2, -1> E0##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 0, -1> E0##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 1, -1> E0##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 2, -1> E0##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 0, -1> E0##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 1, -1> E0##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 2, -1> E0##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 0, -1> E1##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 1, -1> E1##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 2, -1> E1##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 0, -1> E1##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 1, -1> E1##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 2, -1> E1##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 0, -1> E1##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 1, -1> E1##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 2, -1> E1##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 0, -1> E2##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 1, -1> E2##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 2, -1> E2##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 0, -1> E2##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 1, -1> E2##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 2, -1> E2##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 0, -1> E2##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 1, -1> E2##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 2, -1> E2##E2##E2; \ }; #define _GLM_SWIZZLE3_4_MEMBERS(T, P, V, E0, E1, E2) \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 0> E0##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 1> E0##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 2> E0##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 0> E0##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 1> E0##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 2> E0##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 0> E0##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 1> E0##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 2> E0##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 0> E0##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 1> E0##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 2> E0##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 0> E0##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 1> E0##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 2> E0##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 0> E0##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 1> E0##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 2> E0##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 0> E0##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 1> E0##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 2> E0##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 0> E0##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 1> E0##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 2> E0##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 0> E0##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 1> E0##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 2> E0##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 0> E1##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 1> E1##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 2> E1##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 0> E1##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 1> E1##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 2> E1##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 0> E1##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 1> E1##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 2> E1##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 0> E1##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 1> E1##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 2> E1##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 0> E1##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 1> E1##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 2> E1##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 0> E1##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 1> E1##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 2> E1##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 0> E1##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 1> E1##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 2> E1##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 0> E1##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 1> E1##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 2> E1##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 0> E1##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 1> E1##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 2> E1##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 0> E2##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 1> E2##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 2> E2##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 0> E2##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 1> E2##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 2> E2##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 0> E2##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 1> E2##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 2> E2##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 0> E2##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 1> E2##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 2> E2##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 0> E2##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 1> E2##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 2> E2##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 0> E2##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 1> E2##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 2> E2##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 0> E2##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 1> E2##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 2> E2##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 0> E2##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 1> E2##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 2> E2##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 0> E2##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 1> E2##E2##E2##E1; \ }; \ struct { \ _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 { \ _swizzle<2, T, P, V, 0, 0, -1, -2> E0##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 1, -1, -2> E0##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 2, -1, -2> E0##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 0, 3, -1, -2> E0##E3; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 0, -1, -2> E1##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 1, -1, -2> E1##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 2, -1, -2> E1##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 1, 3, -1, -2> E1##E3; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 0, -1, -2> E2##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 1, -1, -2> E2##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 2, -1, -2> E2##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 2, 3, -1, -2> E2##E3; \ }; \ struct { \ _swizzle<2, T, P, V, 3, 0, -1, -2> E3##E0; \ }; \ struct { \ _swizzle<2, T, P, V, 3, 1, -1, -2> E3##E1; \ }; \ struct { \ _swizzle<2, T, P, V, 3, 2, -1, -2> E3##E2; \ }; \ struct { \ _swizzle<2, T, P, V, 3, 3, -1, -2> E3##E3; \ }; #define _GLM_SWIZZLE4_3_MEMBERS(T, P, V, E0, E1, E2, E3) \ struct { \ _swizzle<3, T, P, V, 0, 0, 0, -1> E0##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 1, -1> E0##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 2, -1> E0##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 0, 3, -1> E0##E0##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 0, -1> E0##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 1, -1> E0##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 2, -1> E0##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 1, 3, -1> E0##E1##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 0, -1> E0##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 1, -1> E0##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 2, -1> E0##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 2, 3, -1> E0##E2##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 3, 0, -1> E0##E3##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 3, 1, -1> E0##E3##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 3, 2, -1> E0##E3##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 0, 3, 3, -1> E0##E3##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 0, -1> E1##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 1, -1> E1##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 2, -1> E1##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 0, 3, -1> E1##E0##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 0, -1> E1##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 1, -1> E1##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 2, -1> E1##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 1, 3, -1> E1##E1##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 0, -1> E1##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 1, -1> E1##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 2, -1> E1##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 2, 3, -1> E1##E2##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 3, 0, -1> E1##E3##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 3, 1, -1> E1##E3##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 3, 2, -1> E1##E3##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 1, 3, 3, -1> E1##E3##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 0, -1> E2##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 1, -1> E2##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 2, -1> E2##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 0, 3, -1> E2##E0##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 0, -1> E2##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 1, -1> E2##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 2, -1> E2##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 1, 3, -1> E2##E1##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 0, -1> E2##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 1, -1> E2##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 2, -1> E2##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 2, 3, -1> E2##E2##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 3, 0, -1> E2##E3##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 3, 1, -1> E2##E3##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 3, 2, -1> E2##E3##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 2, 3, 3, -1> E2##E3##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 0, 0, -1> E3##E0##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 0, 1, -1> E3##E0##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 0, 2, -1> E3##E0##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 0, 3, -1> E3##E0##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 1, 0, -1> E3##E1##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 1, 1, -1> E3##E1##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 1, 2, -1> E3##E1##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 1, 3, -1> E3##E1##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 2, 0, -1> E3##E2##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 2, 1, -1> E3##E2##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 2, 2, -1> E3##E2##E2; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 2, 3, -1> E3##E2##E3; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 3, 0, -1> E3##E3##E0; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 3, 1, -1> E3##E3##E1; \ }; \ struct { \ _swizzle<3, T, P, V, 3, 3, 2, -1> E3##E3##E2; \ }; \ struct { \ _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 { \ _swizzle<4, T, P, V, 0, 0, 0, 0> E0##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 1> E0##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 2> E0##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 0, 3> E0##E0##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 0> E0##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 1> E0##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 2> E0##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 1, 3> E0##E0##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 0> E0##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 1> E0##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 2> E0##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 2, 3> E0##E0##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 3, 0> E0##E0##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 3, 1> E0##E0##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 3, 2> E0##E0##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 0, 3, 3> E0##E0##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 0> E0##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 1> E0##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 2> E0##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 0, 3> E0##E1##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 0> E0##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 1> E0##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 2> E0##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 1, 3> E0##E1##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 0> E0##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 1> E0##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 2> E0##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 2, 3> E0##E1##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 3, 0> E0##E1##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 3, 1> E0##E1##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 3, 2> E0##E1##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 1, 3, 3> E0##E1##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 0> E0##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 1> E0##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 2> E0##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 0, 3> E0##E2##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 0> E0##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 1> E0##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 2> E0##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 1, 3> E0##E2##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 0> E0##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 1> E0##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 2> E0##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 2, 3> E0##E2##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 3, 0> E0##E2##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 3, 1> E0##E2##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 3, 2> E0##E2##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 2, 3, 3> E0##E2##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 0, 0> E0##E3##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 0, 1> E0##E3##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 0, 2> E0##E3##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 0, 3> E0##E3##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 1, 0> E0##E3##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 1, 1> E0##E3##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 1, 2> E0##E3##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 1, 3> E0##E3##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 2, 0> E0##E3##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 2, 1> E0##E3##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 2, 2> E0##E3##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 2, 3> E0##E3##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 3, 0> E0##E3##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 3, 1> E0##E3##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 3, 2> E0##E3##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 0, 3, 3, 3> E0##E3##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 0> E1##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 1> E1##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 2> E1##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 0, 3> E1##E0##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 0> E1##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 1> E1##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 2> E1##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 1, 3> E1##E0##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 0> E1##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 1> E1##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 2> E1##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 2, 3> E1##E0##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 3, 0> E1##E0##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 3, 1> E1##E0##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 3, 2> E1##E0##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 0, 3, 3> E1##E0##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 0> E1##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 1> E1##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 2> E1##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 0, 3> E1##E1##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 0> E1##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 1> E1##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 2> E1##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 1, 3> E1##E1##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 0> E1##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 1> E1##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 2> E1##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 2, 3> E1##E1##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 3, 0> E1##E1##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 3, 1> E1##E1##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 3, 2> E1##E1##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 1, 3, 3> E1##E1##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 0> E1##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 1> E1##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 2> E1##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 0, 3> E1##E2##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 0> E1##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 1> E1##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 2> E1##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 1, 3> E1##E2##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 0> E1##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 1> E1##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 2> E1##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 2, 3> E1##E2##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 3, 0> E1##E2##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 3, 1> E1##E2##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 3, 2> E1##E2##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 2, 3, 3> E1##E2##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 0, 0> E1##E3##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 0, 1> E1##E3##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 0, 2> E1##E3##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 0, 3> E1##E3##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 1, 0> E1##E3##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 1, 1> E1##E3##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 1, 2> E1##E3##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 1, 3> E1##E3##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 2, 0> E1##E3##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 2, 1> E1##E3##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 2, 2> E1##E3##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 2, 3> E1##E3##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 3, 0> E1##E3##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 3, 1> E1##E3##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 3, 2> E1##E3##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 1, 3, 3, 3> E1##E3##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 0> E2##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 1> E2##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 2> E2##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 0, 3> E2##E0##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 0> E2##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 1> E2##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 2> E2##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 1, 3> E2##E0##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 0> E2##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 1> E2##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 2> E2##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 2, 3> E2##E0##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 3, 0> E2##E0##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 3, 1> E2##E0##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 3, 2> E2##E0##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 0, 3, 3> E2##E0##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 0> E2##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 1> E2##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 2> E2##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 0, 3> E2##E1##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 0> E2##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 1> E2##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 2> E2##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 1, 3> E2##E1##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 0> E2##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 1> E2##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 2> E2##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 2, 3> E2##E1##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 3, 0> E2##E1##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 3, 1> E2##E1##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 3, 2> E2##E1##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 1, 3, 3> E2##E1##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 0> E2##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 1> E2##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 2> E2##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 0, 3> E2##E2##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 0> E2##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 1> E2##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 2> E2##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 1, 3> E2##E2##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 0> E2##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 1> E2##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 2> E2##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 2, 3> E2##E2##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 3, 0> E2##E2##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 3, 1> E2##E2##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 3, 2> E2##E2##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 2, 3, 3> E2##E2##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 0, 0> E2##E3##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 0, 1> E2##E3##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 0, 2> E2##E3##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 0, 3> E2##E3##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 1, 0> E2##E3##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 1, 1> E2##E3##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 1, 2> E2##E3##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 1, 3> E2##E3##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 2, 0> E2##E3##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 2, 1> E2##E3##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 2, 2> E2##E3##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 2, 3> E2##E3##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 3, 0> E2##E3##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 3, 1> E2##E3##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 3, 2> E2##E3##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 2, 3, 3, 3> E2##E3##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 0, 0> E3##E0##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 0, 1> E3##E0##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 0, 2> E3##E0##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 0, 3> E3##E0##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 1, 0> E3##E0##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 1, 1> E3##E0##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 1, 2> E3##E0##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 1, 3> E3##E0##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 2, 0> E3##E0##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 2, 1> E3##E0##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 2, 2> E3##E0##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 2, 3> E3##E0##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 3, 0> E3##E0##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 3, 1> E3##E0##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 3, 2> E3##E0##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 0, 3, 3> E3##E0##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 0, 0> E3##E1##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 0, 1> E3##E1##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 0, 2> E3##E1##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 0, 3> E3##E1##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 1, 0> E3##E1##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 1, 1> E3##E1##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 1, 2> E3##E1##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 1, 3> E3##E1##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 2, 0> E3##E1##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 2, 1> E3##E1##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 2, 2> E3##E1##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 2, 3> E3##E1##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 3, 0> E3##E1##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 3, 1> E3##E1##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 3, 2> E3##E1##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 1, 3, 3> E3##E1##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 0, 0> E3##E2##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 0, 1> E3##E2##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 0, 2> E3##E2##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 0, 3> E3##E2##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 1, 0> E3##E2##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 1, 1> E3##E2##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 1, 2> E3##E2##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 1, 3> E3##E2##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 2, 0> E3##E2##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 2, 1> E3##E2##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 2, 2> E3##E2##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 2, 3> E3##E2##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 3, 0> E3##E2##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 3, 1> E3##E2##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 3, 2> E3##E2##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 2, 3, 3> E3##E2##E3##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 0, 0> E3##E3##E0##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 0, 1> E3##E3##E0##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 0, 2> E3##E3##E0##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 0, 3> E3##E3##E0##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 1, 0> E3##E3##E1##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 1, 1> E3##E3##E1##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 1, 2> E3##E3##E1##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 1, 3> E3##E3##E1##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 2, 0> E3##E3##E2##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 2, 1> E3##E3##E2##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 2, 2> E3##E3##E2##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 2, 3> E3##E3##E2##E3; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 3, 0> E3##E3##E3##E0; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 3, 1> E3##E3##E3##E1; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 3, 2> E3##E3##E3##E2; \ }; \ struct { \ _swizzle<4, T, P, V, 3, 3, 3, 3> E3##E3##E3##E3; \ }; #endif // glm_core_swizzle ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_swizzle_func.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_swizzle_func.hpp /// @date 2011-10-16 / 2011-10-16 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef glm_core_swizzle_func #define glm_core_swizzle_func #define GLM_SWIZZLE_GEN_VEC2_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, \ SWIZZLED_TYPE, CONST, A, B) \ SWIZZLED_TYPE A##B() CONST { \ return SWIZZLED_TYPE(this->A, this->B); \ } #define GLM_SWIZZLE_GEN_VEC3_ENTRY(TMPL_TYPE, PRECISION, CLASS_TYPE, \ SWIZZLED_TYPE, CONST, A, B, C) \ SWIZZLED_TYPE A##B##C() CONST { \ return SWIZZLED_TYPE(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 A##B##C##D() CONST { \ return SWIZZLED_TYPE(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 \ SWIZZLED_TYPE CLASS_TYPE::A##B() CONST { \ return SWIZZLED_TYPE(this->A, this->B); \ } #define GLM_SWIZZLE_GEN_VEC3_ENTRY_DEF(TMPL_TYPE, PRECISION, CLASS_TYPE, \ SWIZZLED_TYPE, CONST, A, B, C) \ template \ SWIZZLED_TYPE CLASS_TYPE::A##B##C() CONST { \ return SWIZZLED_TYPE(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 \ SWIZZLED_TYPE CLASS_TYPE::A##B##C##D() \ CONST { \ return SWIZZLED_TYPE(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) #endif // glm_core_swizzle_func ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/_vectorize.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/_vectorize.hpp /// @date 2011-10-14 / 2011-10-14 /// @author Christophe Riccio /////////////////////////////////////////////////////////////////////////////////// #ifndef GLM_CORE_DETAIL_INCLUDED #define GLM_CORE_DETAIL_INCLUDED #include "type_vec1.hpp" #include "type_vec2.hpp" #include "type_vec3.hpp" #include "type_vec4.hpp" #define VECTORIZE1_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec1 func(detail::tvec1 const& v) { \ return detail::tvec1(func(v.x)); \ } #define VECTORIZE2_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec2 func(detail::tvec2 const& v) { \ return detail::tvec2(func(v.x), func(v.y)); \ } #define VECTORIZE3_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec3 func(detail::tvec3 const& v) { \ return detail::tvec3(func(v.x), func(v.y), func(v.z)); \ } #define VECTORIZE4_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec4 func(detail::tvec4 const& v) { \ return detail::tvec4(func(v.x), func(v.y), func(v.z), func(v.w)); \ } #define VECTORIZE_VEC(func) \ VECTORIZE1_VEC(func) \ VECTORIZE2_VEC(func) \ VECTORIZE3_VEC(func) \ VECTORIZE4_VEC(func) #define VECTORIZE1_VEC_SCA(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec1 func(detail::tvec1 const& x, \ T const& y) { \ return detail::tvec1(func(x.x, y)); \ } #define VECTORIZE2_VEC_SCA(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec2 func(detail::tvec2 const& x, \ T const& y) { \ return detail::tvec2(func(x.x, y), func(x.y, y)); \ } #define VECTORIZE3_VEC_SCA(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec3 func(detail::tvec3 const& x, \ T const& y) { \ return detail::tvec3(func(x.x, y), func(x.y, y), func(x.z, y)); \ } #define VECTORIZE4_VEC_SCA(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec4 func(detail::tvec4 const& x, \ T const& y) { \ return detail::tvec4(func(x.x, y), func(x.y, y), func(x.z, y), \ func(x.w, y)); \ } #define VECTORIZE_VEC_SCA(func) \ VECTORIZE1_VEC_SCA(func) \ VECTORIZE2_VEC_SCA(func) \ VECTORIZE3_VEC_SCA(func) \ VECTORIZE4_VEC_SCA(func) #define VECTORIZE2_VEC_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec2 func(detail::tvec2 const& x, \ detail::tvec2 const& y) { \ return detail::tvec2(func(x.x, y.x), func(x.y, y.y)); \ } #define VECTORIZE3_VEC_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec3 func(detail::tvec3 const& x, \ detail::tvec3 const& y) { \ return detail::tvec3(func(x.x, y.x), func(x.y, y.y), \ func(x.z, y.z)); \ } #define VECTORIZE4_VEC_VEC(func) \ template \ GLM_FUNC_QUALIFIER detail::tvec4 func(detail::tvec4 const& x, \ detail::tvec4 const& y) { \ return detail::tvec4(func(x.x, y.x), func(x.y, y.y), func(x.z, y.z), \ func(x.w, y.w)); \ } #define VECTORIZE_VEC_VEC(func) \ VECTORIZE2_VEC_VEC(func) \ VECTORIZE3_VEC_VEC(func) \ VECTORIZE4_VEC_VEC(func) namespace glm { namespace detail { template struct If { template static GLM_FUNC_QUALIFIER T apply(F functor, const T& val) { return functor(val); } }; template <> struct If { template static GLM_FUNC_QUALIFIER T apply(F, const T& val) { return val; } }; } // namespace detail } // namespace glm #endif // GLM_CORE_DETAIL_INCLUDED ================================================ FILE: endless-tunnel/app/src/main/cpp/glm/detail/func_common.hpp ================================================ /////////////////////////////////////////////////////////////////////////////////// /// OpenGL Mathematics (glm.g-truc.net) /// /// Copyright (c) 2005 - 2014 G-Truc Creation (www.g-truc.net) /// 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. /// /// @ref core /// @file glm/core/func_common.hpp /// @date 2008-03-08 / 2010-01-26 /// @author Christophe Riccio /// /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions /// /// @defgroup core_func_common Common functions /// @ingroup core /// /// These all operate component-wise. The description is per component. /////////////////////////////////////////////////////////////////////////////////// #ifndef GLM_FUNC_COMMON_INCLUDED #define GLM_FUNC_COMMON_INCLUDED #include "_fixes.hpp" #include "precision.hpp" #include "setup.hpp" #include "type_int.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 GLSL abs /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType abs(genType 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 GLSL /// sign man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType sign(genType 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 GLSL /// floor man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType floor(genType 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 GLSL /// trunc man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType trunc(genType 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 GLSL /// round man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType round(genType 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 GLSL /// roundEven man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions /// @see New /// round to even technique template GLM_FUNC_DECL genType roundEven(genType 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 GLSL /// ceil man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType ceil(genType const& x); /// Return x - floor(x). /// /// @tparam genType Floating-point scalar or vector types. /// /// @see GLSL /// fract man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType fract(genType 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 GLSL mod /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType mod(genType const& x, genType const& y); /// 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 GLSL mod /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType mod(genType const& x, typename genType::value_type 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 GLSL /// modf man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType modf(genType const& x, genType& i); /// Returns y if y < x; otherwise, it returns x. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see GLSL min /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions<<<<<<< HEAD template GLM_FUNC_DECL genType min(genType const& x, genType const& y); template GLM_FUNC_DECL genType min(genType const& x, typename genType::value_type const& y); /// Returns y if x < y; otherwise, it returns x. /// /// @tparam genType Floating-point or integer; scalar or vector types. /// /// @see GLSL max /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType max(genType const& x, genType const& y); template GLM_FUNC_DECL genType max(genType const& x, typename genType::value_type 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 GLSL /// clamp man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType clamp(genType const& x, genType const& minVal, genType const& maxVal); template GLM_FUNC_DECL genType clamp(genType const& x, typename genType::value_type const& minVal, typename genType::value_type 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 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 GLSL mix /// man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions /// /// @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 /// ... /// 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 class vecType> GLM_FUNC_DECL vecType mix(vecType const& x, vecType const& y, vecType const& a); template class vecType> GLM_FUNC_DECL vecType mix(vecType const& x, vecType const& y, U const& a); template GLM_FUNC_DECL genTypeT mix(genTypeT const& x, genTypeT const& y, genTypeU const& a); /// Returns 0.0 if x < edge, otherwise it returns 1.0 for each component of a /// genType. /// /// @see GLSL /// step man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template GLM_FUNC_DECL genType step(genType const& edge, genType const& x); /// Returns 0.0 if x < edge, otherwise it returns 1.0. /// /// @see GLSL /// step man page /// @see GLSL 4.20.8 /// specification, section 8.3 Common Functions template