diff --git a/Cargo.toml b/Cargo.toml index f38963f5a3a390..4776c6fc6d007d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -82,11 +82,6 @@ tracing = "0.1.21" tracing-chrome = "0.2.0" tracing-subscriber = "0.2.15" -# bevy (Android) -[target.'cfg(target_os = "android")'.dependencies] -android_logger = "0.9" -ndk-glue = {version = "0.2", features = ["logger"]} - [target.'cfg(target_arch = "wasm32")'.dev-dependencies] console_error_panic_hook = "0.1.6" console_log = {version = "0.2", features = ["color"]} diff --git a/crates/bevy_derive/src/bevy_main.rs b/crates/bevy_derive/src/bevy_main.rs new file mode 100644 index 00000000000000..bd7023ca6e20ae --- /dev/null +++ b/crates/bevy_derive/src/bevy_main.rs @@ -0,0 +1,36 @@ +use proc_macro::TokenStream; +use quote::quote; +use syn::{parse_macro_input, ItemFn}; + +pub fn bevy_main(_attr: TokenStream, item: TokenStream) -> TokenStream { + let input = parse_macro_input!(item as ItemFn); + if input.sig.ident.to_string() != "main" { + panic!("bevy_main can only be used on a function called 'main'") + } + + TokenStream::from(quote! { + #[no_mangle] + #[cfg(target_os = "android")] + unsafe extern "C" fn ANativeActivity_onCreate( + activity: *mut std::os::raw::c_void, + saved_state: *mut std::os::raw::c_void, + saved_state_size: usize, + ) { + bevy::ndk_glue::init( + activity as _, + saved_state as _, + saved_state_size as _, + main, + ); + } + + #[no_mangle] + #[cfg(target_os = "ios")] + extern "C" fn main_rs() { + main(); + } + + #[allow(unused)] + #input + }) +} diff --git a/crates/bevy_derive/src/lib.rs b/crates/bevy_derive/src/lib.rs index 0de7392d4626f4..76c0bdf76f4e6a 100644 --- a/crates/bevy_derive/src/lib.rs +++ b/crates/bevy_derive/src/lib.rs @@ -1,6 +1,7 @@ extern crate proc_macro; mod app_plugin; +mod bevy_main; mod bytes; mod modules; mod render_resource; @@ -60,3 +61,8 @@ pub fn type_uuid_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStre pub fn external_type_uuid(tokens: proc_macro::TokenStream) -> proc_macro::TokenStream { type_uuid::external_type_uuid(tokens) } + +#[proc_macro_attribute] +pub fn bevy_main(attr: TokenStream, item: TokenStream) -> TokenStream { + bevy_main::bevy_main(attr, item) +} diff --git a/crates/bevy_internal/Cargo.toml b/crates/bevy_internal/Cargo.toml index 23fdc7de6151f1..005d9873d42950 100644 --- a/crates/bevy_internal/Cargo.toml +++ b/crates/bevy_internal/Cargo.toml @@ -40,6 +40,7 @@ bevy_app = { path = "../bevy_app", version = "0.3.0" } bevy_asset = { path = "../bevy_asset", version = "0.3.0" } bevy_type_registry = { path = "../bevy_type_registry", version = "0.3.0" } bevy_core = { path = "../bevy_core", version = "0.3.0" } +bevy_derive = { path = "../bevy_derive", version = "0.3.0" } bevy_diagnostic = { path = "../bevy_diagnostic", version = "0.3.0" } bevy_ecs = { path = "../bevy_ecs", version = "0.3.0" } bevy_input = { path = "../bevy_input", version = "0.3.0" } @@ -63,3 +64,5 @@ bevy_wgpu = { path = "../bevy_wgpu", optional = true, version = "0.3.0" } bevy_winit = { path = "../bevy_winit", optional = true, version = "0.3.0" } bevy_gilrs = { path = "../bevy_gilrs", optional = true, version = "0.3.0" } +[target.'cfg(target_os = "android")'.dependencies] +ndk-glue = {version = "0.2", features = ["logger"]} diff --git a/crates/bevy_internal/src/lib.rs b/crates/bevy_internal/src/lib.rs index 0872432f551259..80717f366bafc9 100644 --- a/crates/bevy_internal/src/lib.rs +++ b/crates/bevy_internal/src/lib.rs @@ -131,3 +131,6 @@ pub mod wgpu { pub mod dynamic_plugin { pub use bevy_dynamic_plugin::*; } + +#[cfg(target_os = "android")] +pub use ndk_glue; diff --git a/crates/bevy_internal/src/prelude.rs b/crates/bevy_internal/src/prelude.rs index 4e2b911232435a..c18564e9e00eb1 100644 --- a/crates/bevy_internal/src/prelude.rs +++ b/crates/bevy_internal/src/prelude.rs @@ -4,6 +4,8 @@ pub use crate::{ type_registry::RegisterType, window::prelude::*, DefaultPlugins, MinimalPlugins, }; +pub use bevy_derive::bevy_main; + #[cfg(feature = "bevy_audio")] pub use crate::audio::prelude::*; diff --git a/examples/android/android.rs b/examples/android/android.rs index 57d422627cbee0..242c16c6987c30 100644 --- a/examples/android/android.rs +++ b/examples/android/android.rs @@ -1,10 +1,45 @@ -// Edit to run any single file example from Bevy. -include!("../3d/3d_scene.rs"); +use bevy::prelude::*; -#[cfg_attr( - target_os = "android", - ndk_glue::main(logger(level = "debug", tag = "android"), backtrace = "full") -)] -pub fn android_main() { - main(); +// the `bevy_main` proc_macro generates the required android boilerplate +#[bevy_main] +fn main() { + App::build() + .add_resource(Msaa { samples: 2 }) + .add_plugins(DefaultPlugins) + .add_startup_system(setup.system()) + .run(); +} + +/// set up a simple 3D scene +fn setup( + commands: &mut Commands, + mut meshes: ResMut>, + mut materials: ResMut>, +) { + // add entities to the world + commands + // plane + .spawn(PbrComponents { + mesh: meshes.add(Mesh::from(shape::Plane { size: 10.0 })), + material: materials.add(Color::rgb(0.3, 0.5, 0.3).into()), + ..Default::default() + }) + // cube + .spawn(PbrComponents { + mesh: meshes.add(Mesh::from(shape::Cube { size: 1.0 })), + material: materials.add(Color::rgb(0.8, 0.7, 0.6).into()), + transform: Transform::from_translation(Vec3::new(0.0, 1.0, 0.0)), + ..Default::default() + }) + // light + .spawn(LightComponents { + transform: Transform::from_translation(Vec3::new(4.0, 8.0, 4.0)), + ..Default::default() + }) + // camera + .spawn(Camera3dComponents { + transform: Transform::from_translation(Vec3::new(-3.0, 5.0, 8.0)) + .looking_at(Vec3::default(), Vec3::unit_y()), + ..Default::default() + }); } diff --git a/examples/ios/src/lib.rs b/examples/ios/src/lib.rs index 529c20da66d0a8..7822af3d4453d1 100644 --- a/examples/ios/src/lib.rs +++ b/examples/ios/src/lib.rs @@ -1,14 +1,8 @@ -use bevy::{ - prelude::{ - shape, App, Assets, Camera3dComponents, Color, Commands, DefaultPlugins, IntoSystem, - LightComponents, Mesh, Msaa, PbrComponents, ResMut, StandardMaterial, Transform, Vec3, - WindowDescriptor, - }, - window::WindowMode, -}; +use bevy::{prelude::*, window::WindowMode}; -#[no_mangle] -extern "C" fn main_rs() { +// the `bevy_main` proc_macro generates the required ios boilerplate +#[bevy_main] +fn main() { App::build() .add_resource(WindowDescriptor { vsync: true,