diff --git a/Cargo.toml b/Cargo.toml index 77d1402..f2f2a8d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ bevy_xr.path = "./crates/bevy_xr" bevy = "0.13.0" [workspace] -members = ["crates/*"] +members = ["crates/*", "crates/bevy_openxr/examples/android"] [workspace.dependencies] bevy = "0.13.0" diff --git a/crates/bevy_openxr/Cargo.toml b/crates/bevy_openxr/Cargo.toml index 350f251..6093bfc 100644 --- a/crates/bevy_openxr/Cargo.toml +++ b/crates/bevy_openxr/Cargo.toml @@ -14,6 +14,7 @@ bevy.workspace = true # all other dependencies are placed under this since on wasm, this crate is completely empty [target.'cfg(not(target_family = "wasm"))'.dependencies] +openxr = "0.18.0" thiserror = "1.0.57" wgpu = "0.19.3" wgpu-hal = "0.19.3" diff --git a/crates/bevy_openxr/examples/android/.gitignore b/crates/bevy_openxr/examples/android/.gitignore new file mode 100644 index 0000000..d83bd60 --- /dev/null +++ b/crates/bevy_openxr/examples/android/.gitignore @@ -0,0 +1 @@ +/runtime_libs \ No newline at end of file diff --git a/crates/bevy_openxr/examples/android/Cargo.toml b/crates/bevy_openxr/examples/android/Cargo.toml new file mode 100644 index 0000000..10e5235 --- /dev/null +++ b/crates/bevy_openxr/examples/android/Cargo.toml @@ -0,0 +1,63 @@ +[package] +name = "bevy_openxr_android" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +bevy_openxr.path = "../.." +bevy.workspace = true + + +[lib] +name = "bevy_openxr_android" +crate-type = ["rlib", "cdylib"] + + +# This metadata is used by `cargo-apk` - `xbuild` uses the `manifest.yaml` instead. +[package.metadata.android] +package = "org.bevyengine.example_openxr_android" +build_targets = ["aarch64-linux-android"] +runtime_libs = "runtime_libs" +apk_name = "bevyopenxr" +# assets = "assets" +# res = "assets/android-res" +icon = "@mipmap/ic_launcher" +label = "Bevy Openxr Android" +strip = "strip" + +# [package.metadata.android.application] +# icon = "@mipmap/ic_launcher" +# label = "Bevy Example" + +[package.metadata.android.sdk] +target_sdk_version = 32 + +[package.metadata.android.application.activity] +theme = "@android:style/Theme.Black.NoTitleBar.Fullscreen" +config_changes = "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode" +launch_mode = "singleTask" +orientation = "landscape" +resizeable_activity = false + +[[package.metadata.android.application.activity.intent_filter]] +actions = ["android.intent.action.MAIN"] +categories = [ + "com.oculus.intent.category.VR", + "android.intent.category.LAUNCHER", +] + +# !! IMPORTANT !! +# +# When creating your own apps, make sure to generate your own keystore, rather than using our example one! +# You can use `keytool` like so: +# keytool -genkey -v -keystore my-release-key.keystore -keyalg RSA -keysize 2048 -validity 10000 +# +# For more information on key signing and why it's so important, check out this article: +# https://developer.android.com/studio/publish/app-signing +# +# !! IMPORTANT !! +[package.metadata.android.signing.release] +path = "./hotham_examples.keystore" +keystore_password = "chomsky-vigilant-spa" diff --git a/crates/bevy_openxr/examples/android/hotham_examples.keystore b/crates/bevy_openxr/examples/android/hotham_examples.keystore new file mode 100644 index 0000000..62623c4 Binary files /dev/null and b/crates/bevy_openxr/examples/android/hotham_examples.keystore differ diff --git a/crates/bevy_openxr/examples/android/manifest.yaml b/crates/bevy_openxr/examples/android/manifest.yaml new file mode 100644 index 0000000..55b45d9 --- /dev/null +++ b/crates/bevy_openxr/examples/android/manifest.yaml @@ -0,0 +1,39 @@ +android: + runtime_libs: + - "runtime_libs" + manifest: + package: "org.bevyengine.example_openxr_android" + uses_feature: + - name: "android.hardware.vr.headtracking" + required: true + - name: "oculus.software.handtracking" + required: true + - name: "com.oculus.feature.PASSTHROUGH" + required: true + - name: "com.oculus.experimental.enabled" + required: true + uses_permission: + - name: "com.oculus.permission.HAND_TRACKING" + application: + label: "Bevy Openxr Android" + theme: "@android:style/Theme.DeviceDefault.NoActionBar.Fullscreen" + meta_data: + - name: "com.oculus.intent.category.VR" + value: "vr_only" + - name: "com.samsung.android.vr.application.mode" + value: "vr_only" + - name: "com.oculus.supportedDevices" + value: "quest|quest2|quest3|questpro" + activities: + - config_changes: "density|keyboard|keyboardHidden|navigation|orientation|screenLayout|screenSize|uiMode|screenLayout" + launch_mode: "singleTask" + orientation: "landscape" + intent_filters: + - actions: + - "android.intent.action.MAIN" + categories: + - "com.oculus.intent.category.VR" + - "android.intent.category.LAUNCHER" + - "org.khronos.openxr.intent.category.IMMERSIVE_HMD" + sdk: + target_sdk_version: 32 \ No newline at end of file diff --git a/crates/bevy_openxr/examples/android/src/lib.rs b/crates/bevy_openxr/examples/android/src/lib.rs new file mode 100644 index 0000000..c9a7190 --- /dev/null +++ b/crates/bevy_openxr/examples/android/src/lib.rs @@ -0,0 +1,43 @@ +//! A simple 3D scene with light shining over a cube sitting on a plane. + +use bevy::prelude::*; +use bevy_openxr::add_xr_plugins; + +#[bevy_main] +fn main() { + App::new() + .add_plugins(add_xr_plugins(DefaultPlugins)) + .add_systems(Startup, setup) + .run(); +} + +/// set up a simple 3D scene +fn setup( + mut commands: Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // circular base + commands.spawn(PbrBundle { + mesh: meshes.add(Circle::new(4.0)), + material: materials.add(Color::WHITE), + transform: Transform::from_rotation(Quat::from_rotation_x(-std::f32::consts::FRAC_PI_2)), + ..default() + }); + // cube + commands.spawn(PbrBundle { + mesh: meshes.add(Cuboid::new(1.0, 1.0, 1.0)), + material: materials.add(Color::rgb_u8(124, 144, 255)), + transform: Transform::from_xyz(0.0, 0.5, 0.0), + ..default() + }); + // light + commands.spawn(PointLightBundle { + point_light: PointLight { + shadows_enabled: true, + ..default() + }, + transform: Transform::from_xyz(4.0, 8.0, 4.0), + ..default() + }); +} diff --git a/flake.lock b/flake.lock index 05fdd44..21ef2ee 100644 --- a/flake.lock +++ b/flake.lock @@ -2,15 +2,17 @@ "nodes": { "fenix": { "inputs": { - "nixpkgs": "nixpkgs", + "nixpkgs": [ + "nixpkgs" + ], "rust-analyzer-src": "rust-analyzer-src" }, "locked": { - "lastModified": 1711088506, - "narHash": "sha256-USdlY7Tx2oJWqFBpp10+03+h7eVhpkQ4s9t1ERjeIJE=", + "lastModified": 1714631076, + "narHash": "sha256-at4+1R9gx3CGvX0ZJo9GwDZyt3RzOft7qDCTsYHjI4M=", "owner": "nix-community", "repo": "fenix", - "rev": "85f4139f3c092cf4afd9f9906d7ed218ef262c97", + "rev": "22a9eb3f20dd340d084cee4426f386a90b1351ca", "type": "github" }, "original": { @@ -37,59 +39,13 @@ "type": "github" } }, - "naersk": { - "inputs": { - "nixpkgs": "nixpkgs_2" - }, - "locked": { - "lastModified": 1698420672, - "narHash": "sha256-/TdeHMPRjjdJub7p7+w55vyABrsJlt5QkznPYy55vKA=", - "owner": "nix-community", - "repo": "naersk", - "rev": "aeb58d5e8faead8980a807c840232697982d47b9", - "type": "github" - }, - "original": { - "owner": "nix-community", - "repo": "naersk", - "type": "github" - } - }, "nixpkgs": { "locked": { - "lastModified": 1712963716, - "narHash": "sha256-WKm9CvgCldeIVvRz87iOMi8CFVB1apJlkUT4GGvA0iM=", - "owner": "nixos", - "repo": "nixpkgs", - "rev": "cfd6b5fc90b15709b780a5a1619695a88505a176", - "type": "github" - }, - "original": { - "owner": "nixos", - "ref": "nixos-unstable", - "repo": "nixpkgs", - "type": "github" - } - }, - "nixpkgs_2": { - "locked": { - "lastModified": 0, - "narHash": "sha256-vMZ5603yU0wxgyQeHJryOI+O61yrX2AHwY6LOFyV1gM=", - "path": "/nix/store/450afzqlzzgw6wnyc3dwysf3i5yxyqkr-source", - "type": "path" - }, - "original": { - "id": "nixpkgs", - "type": "indirect" - } - }, - "nixpkgs_3": { - "locked": { - "lastModified": 1713128889, - "narHash": "sha256-aB90ZqzosyRDpBh+rILIcyP5lao8SKz8Sr2PSWvZrzk=", + "lastModified": 1714656196, + "narHash": "sha256-kjQkA98lMcsom6Gbhw8SYzmwrSo+2nruiTcTZp5jK7o=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2748d22b45a99fb2deafa5f11c7531c212b2cefa", + "rev": "94035b482d181af0a0f8f77823a790b256b7c3cc", "type": "github" }, "original": { @@ -103,18 +59,17 @@ "inputs": { "fenix": "fenix", "flake-utils": "flake-utils", - "naersk": "naersk", - "nixpkgs": "nixpkgs_3" + "nixpkgs": "nixpkgs" } }, "rust-analyzer-src": { "flake": false, "locked": { - "lastModified": 1711052942, - "narHash": "sha256-lLsAhLgm/Nbin41wdfGKU7Rgd6ONBxYCUAMv53NXPjo=", + "lastModified": 1714572655, + "narHash": "sha256-xjD8vmit0Nz1qaSSSpeXOK3saSvAZtOGHS2SHZE75Ek=", "owner": "rust-lang", "repo": "rust-analyzer", - "rev": "7ef7f442fc34b5eadb1c6ad6433bd6d0c51b056b", + "rev": "cfce2bb46da62950a8b70ddb0b2a12332da1b1e1", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 58749d8..ddf372a 100644 --- a/flake.nix +++ b/flake.nix @@ -1,21 +1,31 @@ { inputs = { - fenix.url = "github:nix-community/fenix"; - flake-utils.url = "github:numtide/flake-utils"; - naersk.url = "github:nix-community/naersk"; nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; + fenix = { + url = "github:nix-community/fenix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; + flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, + nixpkgs, fenix, flake-utils, - naersk, - nixpkgs, }: flake-utils.lib.eachDefaultSystem ( system: let - pkgs = nixpkgs.legacyPackages.${system}; + # setup pkgs + pkgs = import nixpkgs { + inherit system; + overlays = [fenix.overlays.default]; + config = { + android_sdk.accept_license = true; + allowUnfree = true; + }; + }; + # the entire rust toolchain with required targets rustToolchain = with fenix.packages.${system}; combine [ (stable.withComponents [ @@ -27,15 +37,23 @@ ]) targets.wasm32-unknown-unknown.stable.rust-std + targets.aarch64-linux-android.stable.rust-std ]; - rustPlatform = pkgs.makeRustPlatform { - inherit (rustToolchain) cargo rustc; + androidComposition = pkgs.androidenv.composeAndroidPackages { + abiVersions = ["arm64-v8a"]; + includeNDK = true; + platformVersions = ["32"]; }; in { devShells.default = pkgs.mkShell rec { # build dependencies nativeBuildInputs = with pkgs; [ + # the entire rust toolchain rustToolchain + # tool for cross compiling + cargo-apk + # xbuild + pkg-config # Common cargo tools we often use @@ -51,6 +69,7 @@ buildInputs = [ pkgs.zstd + pkgs.libxml2 ] ++ pkgs.lib.optionals pkgs.stdenv.isLinux (with pkgs; [ # bevy dependencies @@ -75,12 +94,15 @@ ]) ++ pkgs.lib.optionals pkgs.stdenv.isDarwin [ pkgs.darwin.apple_sdk.frameworks.Cocoa - rustPlatform.bindgenHook # # This is missing on mac m1 nix, for some reason. # # see https://stackoverflow.com/a/69732679 pkgs.libiconv ]; + # android vars + ANDROID_SDK_ROOT = "${androidComposition.androidsdk}/libexec/android-sdk"; + ANDROID_NDK_ROOT = "${ANDROID_SDK_ROOT}/ndk-bundle"; + LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath buildInputs; # this is most likely not needed. for some reason shadows flicker without it. AMD_VULKAN_ICD = "RADV";