feat/jni: Add rustboyadvance-jni crate to export some simple JNI bindings
Former-commit-id: d4e7a622a97215a8c1b7b50bb7f08d18cb9c5716
This commit is contained in:
parent
778274b5ae
commit
d938767430
|
@ -8,6 +8,7 @@ edition = "2018"
|
||||||
members = [
|
members = [
|
||||||
"rustboyadvance-sdl2",
|
"rustboyadvance-sdl2",
|
||||||
"rustboyadvance-minifb",
|
"rustboyadvance-minifb",
|
||||||
|
"rustboyadvance-jni",
|
||||||
]
|
]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
@ -24,7 +25,7 @@ hexdump = "0.1.0"
|
||||||
time = "0.2.6"
|
time = "0.2.6"
|
||||||
bitfield = "0.13.1"
|
bitfield = "0.13.1"
|
||||||
bitflags = "1.2.1"
|
bitflags = "1.2.1"
|
||||||
zip = "0.5.4"
|
zip = {version = "0.5.4", default-features = false, features = ["deflate", "time"]}
|
||||||
ctrlc = "3.1.3"
|
ctrlc = "3.1.3"
|
||||||
bit-set = "0.5.1"
|
bit-set = "0.5.1"
|
||||||
debug_stub_derive = "0.3.0"
|
debug_stub_derive = "0.3.0"
|
||||||
|
|
16
rustboyadvance-jni/Cargo.toml
Normal file
16
rustboyadvance-jni/Cargo.toml
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
[package]
|
||||||
|
name = "rustboyadvance-jni"
|
||||||
|
version = "0.1.0"
|
||||||
|
authors = ["Michel Heily <michelheily@gmail.com>"]
|
||||||
|
edition = "2018"
|
||||||
|
description = "JNI bindings for rustboyadvance core"
|
||||||
|
publish = false
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
crate-type = ["staticlib", "cdylib"]
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
rustboyadvance-ng = {path = "../"}
|
||||||
|
jni = { version = "0.14", default-features = false }
|
||||||
|
log = "0.4.8"
|
||||||
|
env_logger = "0.7.1"
|
159
rustboyadvance-jni/src/lib.rs
Normal file
159
rustboyadvance-jni/src/lib.rs
Normal file
|
@ -0,0 +1,159 @@
|
||||||
|
/// JNI Bindings to rustboyadvance
|
||||||
|
/// For use with the following java class
|
||||||
|
///
|
||||||
|
/// package com.mrmichel.rustboyadvance;
|
||||||
|
////
|
||||||
|
/// public class EmulatorInterface {
|
||||||
|
///
|
||||||
|
/// public static native int loadRom(String romPath);
|
||||||
|
///
|
||||||
|
/// public static native int openEmulator(String biosPath);
|
||||||
|
///
|
||||||
|
/// public static native void closeEmulator();
|
||||||
|
///
|
||||||
|
/// public static native int runFrame(int[] frame_buffer);
|
||||||
|
///
|
||||||
|
/// static {
|
||||||
|
/// System.loadLibrary("rustboyadvance_jni");
|
||||||
|
/// }
|
||||||
|
/// }
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::os::raw::c_void;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
#[macro_use]
|
||||||
|
extern crate log;
|
||||||
|
|
||||||
|
use env_logger;
|
||||||
|
|
||||||
|
use rustboyadvance_ng::prelude::*;
|
||||||
|
|
||||||
|
struct Hardware {
|
||||||
|
frame_buffer: [u32; DISPLAY_WIDTH * DISPLAY_HEIGHT],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Hardware {
|
||||||
|
fn new() -> Hardware {
|
||||||
|
Hardware {
|
||||||
|
frame_buffer: [0; DISPLAY_WIDTH * DISPLAY_HEIGHT],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl VideoInterface for Hardware {
|
||||||
|
fn render(&mut self, buffer: &[u32]) {
|
||||||
|
self.frame_buffer[..].clone_from_slice(buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AudioInterface for Hardware {}
|
||||||
|
impl InputInterface for Hardware {}
|
||||||
|
|
||||||
|
struct Emulator {
|
||||||
|
hwif: Rc<RefCell<Hardware>>,
|
||||||
|
gba: GameBoyAdvance,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(non_snake_case)]
|
||||||
|
pub mod android {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
use std::path::Path;
|
||||||
|
|
||||||
|
use jni;
|
||||||
|
|
||||||
|
use jni::objects::{JClass, JString};
|
||||||
|
use jni::sys::{jint, jintArray, JNI_VERSION_1_6};
|
||||||
|
use jni::{JNIEnv, JavaVM};
|
||||||
|
|
||||||
|
static mut EMULATOR: Option<Emulator> = None;
|
||||||
|
static mut ROM: Option<Cartridge> = None;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn JNI_OnLoad(_vm: *mut JavaVM, _reserved: *mut c_void) -> jint {
|
||||||
|
env_logger::init();
|
||||||
|
debug!("library loaded!");
|
||||||
|
|
||||||
|
JNI_VERSION_1_6
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_com_mrmichel_rustboyadvance_EmulatorInterface_loadRom(
|
||||||
|
env: JNIEnv,
|
||||||
|
_: JClass,
|
||||||
|
rom_path: JString,
|
||||||
|
) -> jint {
|
||||||
|
if EMULATOR.is_some() {
|
||||||
|
error!("can't load rom while emulator is running");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
let rom_path: String = env
|
||||||
|
.get_string(rom_path)
|
||||||
|
.expect("invalid rom path object")
|
||||||
|
.into();
|
||||||
|
let gamepak = GamepakBuilder::new()
|
||||||
|
.file(&Path::new(&rom_path))
|
||||||
|
.build()
|
||||||
|
.expect("failed to load rom");
|
||||||
|
|
||||||
|
info!("Loaded ROM file {:?}", gamepak.header);
|
||||||
|
ROM = Some(gamepak);
|
||||||
|
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_com_mrmichel_rustboyadvance_EmulatorInterface_openEmulator(
|
||||||
|
env: JNIEnv,
|
||||||
|
_: JClass,
|
||||||
|
bios_path: JString,
|
||||||
|
) -> jint {
|
||||||
|
if let Some(cartridge) = ROM.clone() {
|
||||||
|
let bios_path: String = env
|
||||||
|
.get_string(bios_path)
|
||||||
|
.expect("invalid bios path object")
|
||||||
|
.into();
|
||||||
|
let hw = Rc::new(RefCell::new(Hardware::new()));
|
||||||
|
|
||||||
|
let bios_rom = read_bin_file(&Path::new(&bios_path)).expect("failed to load bios file");
|
||||||
|
|
||||||
|
EMULATOR = Some(Emulator {
|
||||||
|
hwif: hw.clone(),
|
||||||
|
gba: GameBoyAdvance::new(bios_rom, cartridge, hw.clone(), hw.clone(), hw.clone()),
|
||||||
|
});
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
error!("please call loadRom first");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_com_mrmichel_rustboyadvance_EmulatorInterface_closeEmulator(
|
||||||
|
env: JNIEnv,
|
||||||
|
_: JClass,
|
||||||
|
) {
|
||||||
|
EMULATOR = None;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub unsafe extern "C" fn Java_com_mrmichel_rustboyadvance_EmulatorInterface_runFrame(
|
||||||
|
env: JNIEnv,
|
||||||
|
_: JClass,
|
||||||
|
frame_buffer: jintArray,
|
||||||
|
) -> jint {
|
||||||
|
if let Some(emu) = &mut EMULATOR {
|
||||||
|
emu.gba.frame();
|
||||||
|
let our_buffer =
|
||||||
|
std::mem::transmute::<&[u32], &[i32]>(&emu.hwif.borrow().frame_buffer as &[u32]);
|
||||||
|
env.set_int_array_region(frame_buffer, 0, our_buffer)
|
||||||
|
.expect("failed to copy frame buffer to java");
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
error!("emulator is not initalized");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
|
@ -58,7 +58,8 @@ pub trait InputInterface {
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::core::arm7tdmi;
|
pub use super::core::arm7tdmi;
|
||||||
pub use super::core::cartridge::GamepakBuilder;
|
pub use super::core::cartridge::{Cartridge, GamepakBuilder};
|
||||||
|
pub use super::core::gpu::{DISPLAY_HEIGHT, DISPLAY_WIDTH};
|
||||||
pub use super::core::Bus;
|
pub use super::core::Bus;
|
||||||
pub use super::core::{GBAError, GBAResult, GameBoyAdvance};
|
pub use super::core::{GBAError, GBAResult, GameBoyAdvance};
|
||||||
#[cfg(feature = "debugger")]
|
#[cfg(feature = "debugger")]
|
||||||
|
|
Reference in a new issue