First
commit
e369a9f20b
@ -0,0 +1,3 @@
|
||||
[target.x86_64-unknown-linux-gnu]
|
||||
linker = "clang"
|
||||
rustflags = ["-Zshare-generics=y", "-C", "link-arg=-fuse-ld=/usr/bin/mold"]
|
@ -0,0 +1 @@
|
||||
/target
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,73 @@
|
||||
[package]
|
||||
name = "bevy_android"
|
||||
authors = ["Vynwg"]
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
[package.metadata.android]
|
||||
package = "com.vynwg.bevyandroid"
|
||||
apk_name = "bevyandroid"
|
||||
assets = "./assets"
|
||||
strip = "strip"
|
||||
build_targets = ["aarch64-linux-android", "armv7-linux-androideabi"]
|
||||
|
||||
[package.metadata.android.sdk]
|
||||
target_sdk_version = 31
|
||||
|
||||
[package.metadata.android.application]
|
||||
label = "Bevy Android"
|
||||
|
||||
[package.metadata.android.application.activity]
|
||||
orientation = "landscape"
|
||||
|
||||
[lib]
|
||||
name = "bevy_android"
|
||||
crate-type = ["staticlib", "cdylib"]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 1
|
||||
|
||||
[profile.dev.package."*"]
|
||||
opt-level = 3
|
||||
|
||||
[profile.release]
|
||||
codegen-units = 1
|
||||
lto = "thin"
|
||||
|
||||
[profile.wasm-release]
|
||||
inherits = "release"
|
||||
opt-level = "s"
|
||||
strip = "debuginfo"
|
||||
|
||||
|
||||
[dependencies]
|
||||
android_sensor-sys = "0.1.4"
|
||||
android_looper-sys = "0.1"
|
||||
|
||||
[dependencies.log]
|
||||
version = "*"
|
||||
features = ["max_level_trace", "release_max_level_debug"]
|
||||
|
||||
[dependencies.bevy]
|
||||
git = "https://github.com/bevyengine/bevy"
|
||||
rev = "3892adc"
|
||||
default-features = false
|
||||
features = [
|
||||
"png",
|
||||
"bevy_ui",
|
||||
"async-io",
|
||||
"animation",
|
||||
"bevy_text",
|
||||
"serialize",
|
||||
"bevy_asset",
|
||||
"bevy_audio",
|
||||
"bevy_scene",
|
||||
"bevy_winit",
|
||||
"bevy_gizmos",
|
||||
"bevy_render",
|
||||
"bevy_sprite",
|
||||
"default_font",
|
||||
"multi_threaded",
|
||||
"bevy_core_pipeline",
|
||||
"android_shared_stdcxx"
|
||||
]
|
Binary file not shown.
@ -0,0 +1,2 @@
|
||||
[toolchain]
|
||||
channel = "nightly"
|
@ -0,0 +1,68 @@
|
||||
mod util;
|
||||
mod sensor;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy::sprite::{MaterialMesh2dBundle, Mesh2dHandle, Wireframe2dConfig, Wireframe2dPlugin};
|
||||
use bevy::window::WindowMode;
|
||||
use bevy::color::palettes::css::*;
|
||||
use bevy::diagnostic::{DiagnosticsStore, FrameTimeDiagnosticsPlugin};
|
||||
|
||||
use crate::sensor::SensorPlugin;
|
||||
use crate::sensor::MagneticEvent;
|
||||
|
||||
|
||||
#[derive(Component)]
|
||||
struct TextChanges;
|
||||
|
||||
fn setup(
|
||||
mut commands: Commands,
|
||||
mut meshes: ResMut<Assets<Mesh>>,
|
||||
mut materials: ResMut<Assets<ColorMaterial>>
|
||||
) {
|
||||
commands.spawn(Camera2dBundle::default());
|
||||
|
||||
commands.spawn(
|
||||
TextBundle::from_sections([
|
||||
TextSection::new("FODAAAAAAA", TextStyle::default())
|
||||
])
|
||||
.with_style(Style {
|
||||
position_type: PositionType::Absolute,
|
||||
top: Val::Px(0.0),
|
||||
left: Val::Px(0.0),
|
||||
..default()
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
fn change_text(mut events: EventReader<MagneticEvent>, mut query: Query<&mut Text, With<TextChanges>>) {
|
||||
let (mut x, mut y, mut z) = (0.0, 0.0, 0.0);
|
||||
|
||||
for event in events.read() {
|
||||
x = event.x;
|
||||
y = event.y;
|
||||
z = event.z;
|
||||
}
|
||||
|
||||
for mut text in &mut query {
|
||||
text.sections[0].value = format!("x: {} y: {} z: {}", x, y, z);
|
||||
}
|
||||
}
|
||||
|
||||
#[bevy_main]
|
||||
fn main() {
|
||||
let mut app = App::new();
|
||||
app
|
||||
.add_plugins(DefaultPlugins.set(WindowPlugin {
|
||||
primary_window: Some(Window {
|
||||
resizable: false,
|
||||
mode: WindowMode::BorderlessFullscreen(MonitorSelection::Primary),
|
||||
recognize_rotation_gesture: true,
|
||||
..default()
|
||||
}),
|
||||
..default()
|
||||
}))
|
||||
.add_plugins(SensorPlugin)
|
||||
.add_systems(Startup, setup)
|
||||
.add_systems(Update, change_text)
|
||||
.run();
|
||||
}
|
@ -0,0 +1,103 @@
|
||||
use std::ptr;
|
||||
|
||||
use bevy::prelude::*;
|
||||
|
||||
use crate::util::is_valid;
|
||||
|
||||
use android_looper_sys::{
|
||||
ALooper_prepare,
|
||||
ALooper_pollOnce
|
||||
};
|
||||
use android_sensor_sys::{
|
||||
SensorType,
|
||||
ASensorEvent,
|
||||
ASensorEventQueue,
|
||||
ASensorManager_getInstance,
|
||||
ASensorEventQueue_getEvents,
|
||||
ASensorEventQueue_hasEvents,
|
||||
ASensorEventQueue_enableSensor,
|
||||
ASensorEventQueue_setEventRate,
|
||||
ASensorManager_createEventQueue,
|
||||
ASensorManager_getDefaultSensor,
|
||||
};
|
||||
|
||||
#[derive(Event)]
|
||||
pub struct MagneticEvent {
|
||||
pub x: f32,
|
||||
pub y: f32,
|
||||
pub z: f32
|
||||
}
|
||||
|
||||
/* LOOPER IDs
|
||||
1 is used for android_activity's main thread
|
||||
2 is used for it's input handling thread
|
||||
3 is supposed to be used for something too, idk
|
||||
4 should be safe right? TODO: remove the stupid line at android_activity/native_activity/mod.rs:301, using 2 for now
|
||||
*/
|
||||
const ALOOPER_IDENTIFIER: i32 = 2;
|
||||
const SENSOR_EVENT_RATE: i32 = 100000;
|
||||
const ALOOPER_PREPARE_ALLOW_NON_CALLBACKS: i32 = 1;
|
||||
const SENSOR_TYPE: i32 = SensorType::MagneticField as i32;
|
||||
|
||||
fn poll_events(queue: NonSend<*mut ASensorEventQueue>, mut events: EventWriter<MagneticEvent>) {
|
||||
let queue = *queue;
|
||||
let res = unsafe { ALooper_pollOnce(0, ptr::null_mut(), ptr::null_mut(), ptr::null_mut()) };
|
||||
|
||||
match res {
|
||||
-3 => return,
|
||||
-4 => panic!("Error polling once"),
|
||||
ALOOPER_IDENTIFIER | -1 | -2 => {},
|
||||
_ => return debug!("Polled from another Looper: {}", res)
|
||||
}
|
||||
if unsafe { ASensorEventQueue_hasEvents(queue) } == 0 { return }
|
||||
|
||||
|
||||
let mut event = ASensorEvent::default();
|
||||
|
||||
while unsafe { ASensorEventQueue_getEvents(queue, &mut event, 1) } > 0 {
|
||||
let read = unsafe {
|
||||
let m = event.magnetic();
|
||||
if !is_valid(m) { continue; }
|
||||
m.read()
|
||||
};
|
||||
|
||||
let result = unsafe {
|
||||
let v = read.v();
|
||||
if !is_valid(v) { continue; }
|
||||
v.read()
|
||||
};
|
||||
|
||||
events.send(MagneticEvent { x: result[0], y: result[1], z: result[2] });
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
pub struct SensorPlugin;
|
||||
|
||||
impl Plugin for SensorPlugin {
|
||||
fn build(&self, app: &mut App) {
|
||||
let manager = unsafe { ASensorManager_getInstance() };
|
||||
let sensor = unsafe { ASensorManager_getDefaultSensor(manager, SENSOR_TYPE) };
|
||||
let looper = unsafe { ALooper_prepare(ALOOPER_PREPARE_ALLOW_NON_CALLBACKS) };
|
||||
let queue = unsafe { ASensorManager_createEventQueue(manager, looper, ALOOPER_IDENTIFIER, None, ptr::null_mut()) };
|
||||
|
||||
|
||||
let res = unsafe { ASensorEventQueue_enableSensor(queue, sensor) };
|
||||
|
||||
if res < 0 {
|
||||
panic!("Couldn't enable sensor {}, error code: {}", SENSOR_TYPE, res);
|
||||
} else { debug!("Enabled sensor {}", SENSOR_TYPE); }
|
||||
|
||||
|
||||
let res = unsafe { ASensorEventQueue_setEventRate(queue, sensor, SENSOR_EVENT_RATE) };
|
||||
|
||||
if res < 0 {
|
||||
panic!("Couldn't set sensor's event rate, error code: {}", res);
|
||||
} else { debug!("Set sensor event rate to {}", SENSOR_EVENT_RATE); }
|
||||
|
||||
|
||||
app.add_event::<MagneticEvent>()
|
||||
.insert_non_send_resource(queue)
|
||||
.add_systems(Update, poll_events);
|
||||
}
|
||||
}
|
@ -0,0 +1,11 @@
|
||||
use bevy::prelude::*;
|
||||
|
||||
pub fn is_valid<T>(ptr: *const T) -> bool {
|
||||
if !ptr.is_null() {
|
||||
debug!("Got a null pointer {:?}", ptr)
|
||||
}
|
||||
if !ptr.is_aligned() {
|
||||
debug!("Got an unaligned pointer {:?}", ptr)
|
||||
}
|
||||
true
|
||||
}
|
Loading…
Reference in New Issue