diff --git a/Cargo.lock b/Cargo.lock index ba470f1..7fbd4b4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -88,6 +88,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" +[[package]] +name = "android_log-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85965b6739a430150bdd138e2374a98af0c3ee0d030b3bb7fc3bddff58d0102e" + +[[package]] +name = "android_logger" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8619b80c242aa7bd638b5c7ddd952addeecb71f69c75e33f1d47b2804f8f883a" +dependencies = [ + "android_log-sys", + "env_logger", + "log", + "once_cell", +] + [[package]] name = "android_system_properties" version = "0.1.5" @@ -1921,6 +1939,17 @@ dependencies = [ "winit_input_helper 0.14.1", ] +[[package]] +name = "minimal-winit-android" +version = "0.1.0" +dependencies = [ + "android_logger", + "env_logger", + "log", + "pixels", + "winit 0.28.6", +] + [[package]] name = "miniz_oxide" version = "0.6.2" diff --git a/examples/minimal-winit-android/Cargo.toml b/examples/minimal-winit-android/Cargo.toml new file mode 100644 index 0000000..39dddec --- /dev/null +++ b/examples/minimal-winit-android/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "minimal-winit-android" +version = "0.1.0" +authors = ["Randommist "] +edition = "2021" +publish = false + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +log = "0.4.19" +pixels = { path = "../.." } +winit = { version = "0.28.6", features = ["android-native-activity"] } + +[target.'cfg(not(target_os = "android"))'.dependencies] +env_logger = "0.10.0" + +[target.'cfg(target_os = "android")'.dependencies] +android_logger = "0.11.0" + +[lib] +crate_type = ["cdylib"] + + +[package.metadata.android.signing.release] +path = "./path/to/KeyStoreFile.jks" +keystore_password = "password" diff --git a/examples/minimal-winit-android/README.md b/examples/minimal-winit-android/README.md new file mode 100644 index 0000000..75f7928 --- /dev/null +++ b/examples/minimal-winit-android/README.md @@ -0,0 +1,18 @@ +# Hello Android + +![Hello Android](../../img/minimal-winit-android.png) + +Minimal example to run on android using `winit` with `android-native-activity` feature + +## Running +``` +export ANDROID_HOME="path/to/sdk" +export ANDROID_NDK_HOME="path/to/ndk" + +rustup target add aarch64-linux-android +cargo install cargo-apk +``` +Connect your Android device via USB cable to your computer in debug mode and run the following command +``` +cargo apk run +``` diff --git a/examples/minimal-winit-android/src/lib.rs b/examples/minimal-winit-android/src/lib.rs new file mode 100644 index 0000000..8284928 --- /dev/null +++ b/examples/minimal-winit-android/src/lib.rs @@ -0,0 +1,130 @@ +#[cfg(target_os = "android")] +use winit::platform::android::activity::AndroidApp; + +use pixels::{Pixels, SurfaceTexture}; +use winit::event::Event; +use winit::event_loop::{ControlFlow, EventLoop, EventLoopBuilder}; +use winit::window::Window; + +const WIDTH: u32 = 320; +const HEIGHT: u32 = 240; +const BOX_SIZE: i16 = 64; + +/// Representation of the application state. In this example, a box will bounce around the screen. +struct World { + box_x: i16, + box_y: i16, + velocity_x: i16, + velocity_y: i16, +} + +fn _main(event_loop: EventLoop<()>) { + let mut window: Option = None; + let mut pixels: Option = None; + + let mut world = World::new(); + + event_loop.run(move |event, event_loop, control_flow| { + *control_flow = ControlFlow::Wait; + match event { + Event::Resumed => { + let _window = Window::new(event_loop).unwrap(); + let _pixels = { + let window_size = _window.inner_size(); + let surface_texture = + SurfaceTexture::new(window_size.width, window_size.height, &_window); + Pixels::new(WIDTH, HEIGHT, surface_texture).unwrap() + }; + _window.request_redraw(); + window = Some(_window); + pixels = Some(_pixels); + } + Event::Suspended => { + pixels = None; + window = None; + } + Event::RedrawRequested(_) => { + if let (Some(pixels), Some(window)) = (&mut pixels, &window) { + world.draw(pixels.frame_mut()); + pixels.render().unwrap(); + window.request_redraw(); + } + } + _ => {} + } + if window.is_some() { + world.update(); + } + }); +} + +impl World { + /// Create a new `World` instance that can draw a moving box. + fn new() -> Self { + Self { + box_x: 24, + box_y: 16, + velocity_x: 1, + velocity_y: 1, + } + } + + /// Update the `World` internal state; bounce the box around the screen. + fn update(&mut self) { + if self.box_x <= 0 || self.box_x + BOX_SIZE > WIDTH as i16 { + self.velocity_x *= -1; + } + if self.box_y <= 0 || self.box_y + BOX_SIZE > HEIGHT as i16 { + self.velocity_y *= -1; + } + + self.box_x += self.velocity_x; + self.box_y += self.velocity_y; + } + + /// Draw the `World` state to the frame buffer. + /// + /// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb` + fn draw(&self, frame: &mut [u8]) { + for (i, pixel) in frame.chunks_exact_mut(4).enumerate() { + let x = (i % WIDTH as usize) as i16; + let y = (i / WIDTH as usize) as i16; + + let inside_the_box = x >= self.box_x + && x < self.box_x + BOX_SIZE + && y >= self.box_y + && y < self.box_y + BOX_SIZE; + + let rgba = if inside_the_box { + [0x5e, 0x48, 0xe8, 0xff] + } else { + [0x48, 0xb2, 0xe8, 0xff] + }; + + pixel.copy_from_slice(&rgba); + } + } +} + +#[allow(dead_code)] +#[cfg(target_os = "android")] +#[no_mangle] +fn android_main(app: AndroidApp) { + use winit::platform::android::EventLoopBuilderExtAndroid; + android_logger::init_once(android_logger::Config::default().with_min_level(log::Level::Info)); + let event_loop = EventLoopBuilder::new().with_android_app(app).build(); + log::info!("Hello from android!"); + _main(event_loop); +} + +#[allow(dead_code)] +#[cfg(not(target_os = "android"))] +fn main() { + env_logger::builder() + .filter_level(log::LevelFilter::Info) // Default Log Level + .parse_default_env() + .init(); + let event_loop = EventLoopBuilder::new().build(); + log::info!("Hello from desktop!"); + _main(event_loop); +} diff --git a/img/minimal-winit-android.png b/img/minimal-winit-android.png new file mode 100644 index 0000000..e682aa3 Binary files /dev/null and b/img/minimal-winit-android.png differ