pathfinder/demo/android/rust/src/lib.rs

304 lines
8.5 KiB
Rust
Raw Normal View History

2019-03-08 19:52:47 -05:00
// pathfinder/demo/android/rust/src/main.rs
//
// Copyright © 2019 The Pathfinder Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
2019-03-13 19:32:39 -04:00
#[macro_use]
extern crate lazy_static;
use jni::objects::{GlobalRef, JByteBuffer, JClass, JObject, JString, JValue};
2019-04-29 19:52:37 -04:00
use jni::{JNIEnv, JavaVM};
use pathfinder_demo::window::{Event, SVGPath, View, Window, WindowSize};
2019-03-08 19:52:47 -05:00
use pathfinder_demo::DemoApp;
use pathfinder_demo::Options;
use pathfinder_geometry::basic::vector::Vector2I;
use pathfinder_geometry::basic::rect::RectI;
2019-03-08 19:52:47 -05:00
use pathfinder_gl::GLVersion;
use pathfinder_gpu::resources::ResourceLoader;
use std::cell::RefCell;
use std::io::Error as IOError;
2019-03-13 19:32:39 -04:00
use std::mem;
2019-03-08 19:52:47 -05:00
use std::os::raw::c_void;
use std::path::PathBuf;
2019-03-13 19:32:39 -04:00
use std::sync::Mutex;
lazy_static! {
static ref EVENT_QUEUE: Mutex<Vec<Event>> = Mutex::new(vec![]);
}
2019-03-08 19:52:47 -05:00
thread_local! {
static DEMO_APP: RefCell<Option<DemoApp<WindowImpl>>> = RefCell::new(None);
static JAVA_ACTIVITY: RefCell<Option<JavaActivity>> = RefCell::new(None);
2019-03-08 19:52:47 -05:00
static JAVA_RESOURCE_LOADER: RefCell<Option<JavaResourceLoader>> = RefCell::new(None);
}
static RESOURCE_LOADER: AndroidResourceLoader = AndroidResourceLoader;
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_init(
env: JNIEnv,
class: JClass,
activity: JObject,
loader: JObject,
width: i32,
height: i32,
) {
let logical_size = Vector2I::new(width, height);
2019-04-29 19:52:37 -04:00
let window_size = WindowSize {
logical_size,
backing_scale_factor: 1.0,
};
let window = WindowImpl { size: logical_size };
2019-04-12 12:30:00 -04:00
let options = Options::default();
JAVA_ACTIVITY.with(|java_activity| {
*java_activity.borrow_mut() = Some(JavaActivity::new(env.clone(), activity));
});
2019-03-08 19:52:47 -05:00
JAVA_RESOURCE_LOADER.with(|java_resource_loader| {
*java_resource_loader.borrow_mut() = Some(JavaResourceLoader::new(env, loader));
});
DEMO_APP.with(|demo_app| {
gl::load_with(|name| egl::get_proc_address(name) as *const c_void);
*demo_app.borrow_mut() = Some(DemoApp::new(window, window_size, options));
2019-03-08 19:52:47 -05:00
});
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_prepareFrame(
env: JNIEnv,
class: JClass,
) -> i32 {
2019-03-08 19:52:47 -05:00
DEMO_APP.with(|demo_app| {
2019-03-13 19:32:39 -04:00
let mut event_queue = EVENT_QUEUE.lock().unwrap();
match *demo_app.borrow_mut() {
Some(ref mut demo_app) => {
demo_app.prepare_frame(mem::replace(&mut *event_queue, vec![])) as i32
}
None => 0,
}
})
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_drawScene(
env: JNIEnv,
class: JClass,
) {
DEMO_APP.with(|demo_app| {
2019-03-08 19:52:47 -05:00
if let Some(ref mut demo_app) = *demo_app.borrow_mut() {
demo_app.draw_scene()
2019-03-08 19:52:47 -05:00
}
})
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_finishDrawingFrame(
env: JNIEnv,
class: JClass,
) {
DEMO_APP.with(|demo_app| {
if let Some(ref mut demo_app) = *demo_app.borrow_mut() {
demo_app.finish_drawing_frame()
}
})
2019-03-08 19:52:47 -05:00
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushWindowResizedEvent(
env: JNIEnv,
class: JClass,
width: i32,
height: i32,
) {
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::WindowResized(WindowSize {
logical_size: Vector2I::new(width, height),
2019-04-29 19:52:37 -04:00
backing_scale_factor: 1.0,
}))
}
2019-03-08 19:52:47 -05:00
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDownEvent(
_: JNIEnv,
_: JClass,
x: i32,
y: i32,
) {
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::MouseDown(Vector2I::new(x, y)))
2019-03-13 19:32:39 -04:00
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDraggedEvent(
_: JNIEnv,
_: JClass,
x: i32,
y: i32,
) {
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::MouseDragged(Vector2I::new(x, y)))
2019-03-08 19:52:47 -05:00
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushZoomEvent(
_: JNIEnv,
_: JClass,
factor: f32,
center_x: i32,
center_y: i32,
) {
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::Zoom(factor, Vector2I::new(center_x, center_y)))
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushLookEvent(
_: JNIEnv,
_: JClass,
pitch: f32,
yaw: f32,
) {
EVENT_QUEUE.lock().unwrap().push(Event::Look { pitch, yaw })
}
#[no_mangle]
2019-04-29 19:52:37 -04:00
pub unsafe extern "system" fn Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushOpenSVGEvent(
env: JNIEnv,
_: JClass,
string: JObject,
) {
let string: String = env.get_string(JString::from(string)).unwrap().into();
2019-04-29 19:52:37 -04:00
EVENT_QUEUE
.lock()
.unwrap()
.push(Event::OpenSVG(SVGPath::Resource(string)))
}
struct WindowImpl {
size: Vector2I,
}
2019-03-08 19:52:47 -05:00
impl Window for WindowImpl {
fn gl_version(&self) -> GLVersion {
GLVersion::GLES3
}
fn viewport(&self, view: View) -> RectI {
let mut width = self.size.x();
let mut offset_x = 0;
let height = self.size.y();
2019-04-12 12:30:00 -04:00
if let View::Stereo(index) = view {
width = width / 2;
offset_x = (index as i32) * width;
}
let size = Vector2I::new(width, height);
let offset = Vector2I::new(offset_x, 0);
RectI::new(offset, size)
}
2019-04-12 12:30:00 -04:00
fn make_current(&mut self, _view: View) {}
fn present(&mut self) {}
2019-03-08 19:52:47 -05:00
fn resource_loader(&self) -> &dyn ResourceLoader {
&RESOURCE_LOADER
}
fn create_user_event_id(&self) -> u32 {
0
}
2019-04-29 19:52:37 -04:00
fn push_user_event(message_type: u32, message_data: u32) {}
2019-03-08 19:52:47 -05:00
fn present_open_svg_dialog(&mut self) {
JAVA_ACTIVITY.with(|java_activity| {
let mut java_activity = java_activity.borrow_mut();
let java_activity = java_activity.as_mut().unwrap();
let env = java_activity.vm.get_env().unwrap();
2019-04-29 19:52:37 -04:00
env.call_method(
java_activity.activity.as_obj(),
"presentOpenSVGDialog",
"()V",
&[],
)
.unwrap();
});
2019-03-08 19:52:47 -05:00
}
fn run_save_dialog(&self, extension: &str) -> Result<PathBuf, ()> {
// TODO(pcwalton)
Err(())
}
}
struct AndroidResourceLoader;
impl ResourceLoader for AndroidResourceLoader {
fn slurp(&self, path: &str) -> Result<Vec<u8>, IOError> {
JAVA_RESOURCE_LOADER.with(|java_resource_loader| {
let java_resource_loader = java_resource_loader.borrow();
let java_resource_loader = java_resource_loader.as_ref().unwrap();
let loader = java_resource_loader.loader.as_obj();
let env = java_resource_loader.vm.get_env().unwrap();
2019-04-29 19:52:37 -04:00
match env
.call_method(
loader,
"slurp",
"(Ljava/lang/String;)Ljava/nio/ByteBuffer;",
&[JValue::Object(*env.new_string(path).unwrap())],
)
.unwrap()
{
2019-03-08 19:52:47 -05:00
JValue::Object(object) => {
let byte_buffer = JByteBuffer::from(object);
2019-04-29 19:52:37 -04:00
Ok(Vec::from(
env.get_direct_buffer_address(byte_buffer).unwrap(),
))
2019-03-08 19:52:47 -05:00
}
_ => panic!("Unexpected return value!"),
}
})
}
}
struct JavaActivity {
activity: GlobalRef,
vm: JavaVM,
}
impl JavaActivity {
fn new(env: JNIEnv, activity: JObject) -> JavaActivity {
JavaActivity {
activity: env.new_global_ref(activity).unwrap(),
vm: env.get_java_vm().unwrap(),
}
}
}
2019-03-08 19:52:47 -05:00
struct JavaResourceLoader {
loader: GlobalRef,
vm: JavaVM,
}
impl JavaResourceLoader {
fn new(env: JNIEnv, loader: JObject) -> JavaResourceLoader {
JavaResourceLoader {
loader: env.new_global_ref(loader).unwrap(),
vm: env.get_java_vm().unwrap(),
}
}
}