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;
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
use jni::{JNIEnv, JavaVM};
|
2019-03-18 21:13:13 -04:00
|
|
|
use jni::objects::{GlobalRef, JByteBuffer, JClass, JObject, JString, JValue};
|
2019-03-08 19:52:47 -05:00
|
|
|
use pathfinder_demo::DemoApp;
|
2019-03-18 21:13:13 -04:00
|
|
|
use pathfinder_demo::window::{Event, SVGPath, Window, WindowSize};
|
2019-03-08 19:52:47 -05:00
|
|
|
use pathfinder_geometry::basic::point::Point2DI32;
|
|
|
|
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);
|
2019-03-18 21:13:13 -04:00
|
|
|
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]
|
|
|
|
pub unsafe extern "system" fn
|
|
|
|
Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_init(env: JNIEnv,
|
|
|
|
class: JClass,
|
2019-03-18 21:13:13 -04:00
|
|
|
activity: JObject,
|
2019-03-14 22:13:27 -04:00
|
|
|
loader: JObject,
|
|
|
|
width: i32,
|
|
|
|
height: i32) {
|
|
|
|
let logical_size = Point2DI32::new(width, height);
|
|
|
|
let window_size = WindowSize { logical_size, backing_scale_factor: 1.0 };
|
|
|
|
|
2019-03-18 21:13:13 -04:00
|
|
|
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| {
|
2019-03-14 22:13:27 -04:00
|
|
|
*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(WindowImpl, window_size));
|
2019-03-08 19:52:47 -05:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "system" fn
|
2019-03-14 23:15:48 -04:00
|
|
|
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();
|
2019-03-14 23:15:48 -04:00
|
|
|
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]
|
|
|
|
pub unsafe extern "system" fn
|
|
|
|
Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_drawScene(
|
|
|
|
env: JNIEnv,
|
|
|
|
class: JClass,
|
|
|
|
scene_index: i32) {
|
|
|
|
DEMO_APP.with(|demo_app| {
|
2019-03-08 19:52:47 -05:00
|
|
|
if let Some(ref mut demo_app) = *demo_app.borrow_mut() {
|
2019-03-14 23:15:48 -04:00
|
|
|
demo_app.draw_scene(scene_index as u32)
|
2019-03-08 19:52:47 -05:00
|
|
|
}
|
2019-03-14 23:15:48 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
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
|
|
|
}
|
|
|
|
|
2019-03-14 22:13:27 -04:00
|
|
|
#[no_mangle]
|
|
|
|
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: Point2DI32::new(width, height),
|
|
|
|
backing_scale_factor: 1.0,
|
|
|
|
}))
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "system" fn
|
2019-03-13 19:32:39 -04:00
|
|
|
Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDownEvent(
|
2019-03-14 18:29:56 -04:00
|
|
|
_: JNIEnv,
|
|
|
|
_: JClass,
|
2019-03-13 19:32:39 -04:00
|
|
|
x: i32,
|
|
|
|
y: i32) {
|
|
|
|
EVENT_QUEUE.lock().unwrap().push(Event::MouseDown(Point2DI32::new(x, y)))
|
|
|
|
}
|
|
|
|
|
|
|
|
#[no_mangle]
|
|
|
|
pub unsafe extern "system" fn
|
|
|
|
Java_graphics_pathfinder_pathfinderdemo_PathfinderDemoRenderer_pushMouseDraggedEvent(
|
2019-03-14 18:29:56 -04:00
|
|
|
_: JNIEnv,
|
|
|
|
_: JClass,
|
2019-03-13 19:32:39 -04:00
|
|
|
x: i32,
|
|
|
|
y: i32) {
|
|
|
|
EVENT_QUEUE.lock().unwrap().push(Event::MouseDragged(Point2DI32::new(x, y)))
|
2019-03-08 19:52:47 -05:00
|
|
|
}
|
|
|
|
|
2019-03-14 18:29:56 -04:00
|
|
|
#[no_mangle]
|
|
|
|
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 })
|
|
|
|
}
|
|
|
|
|
2019-03-18 21:13:13 -04:00
|
|
|
#[no_mangle]
|
|
|
|
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();
|
|
|
|
EVENT_QUEUE.lock().unwrap().push(Event::OpenSVG(SVGPath::Resource(string)))
|
|
|
|
}
|
|
|
|
|
2019-03-08 19:52:47 -05:00
|
|
|
struct WindowImpl;
|
|
|
|
|
|
|
|
impl Window for WindowImpl {
|
|
|
|
fn gl_version(&self) -> GLVersion {
|
|
|
|
GLVersion::GLES3
|
|
|
|
}
|
|
|
|
|
|
|
|
fn mouse_position(&self) -> Point2DI32 {
|
|
|
|
Point2DI32::new(0, 0)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn present(&self) {}
|
|
|
|
|
|
|
|
fn resource_loader(&self) -> &dyn ResourceLoader {
|
|
|
|
&RESOURCE_LOADER
|
|
|
|
}
|
|
|
|
|
|
|
|
fn create_user_event_id(&self) -> u32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_user_event(message_type: u32, message_data: u32) {
|
|
|
|
}
|
|
|
|
|
2019-03-18 21:13:13 -04: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();
|
|
|
|
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();
|
|
|
|
match env.call_method(loader,
|
|
|
|
"slurp",
|
|
|
|
"(Ljava/lang/String;)Ljava/nio/ByteBuffer;",
|
|
|
|
&[JValue::Object(*env.new_string(path).unwrap())]).unwrap() {
|
|
|
|
JValue::Object(object) => {
|
|
|
|
let byte_buffer = JByteBuffer::from(object);
|
|
|
|
Ok(Vec::from(env.get_direct_buffer_address(byte_buffer).unwrap()))
|
|
|
|
}
|
|
|
|
_ => panic!("Unexpected return value!"),
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-03-18 21:13:13 -04:00
|
|
|
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(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|