From 3ad7f9a58429b02b11b18f6a70ac011f698b6f4b Mon Sep 17 00:00:00 2001 From: Pierre Krieger Date: Fri, 24 Apr 2015 09:51:23 +0200 Subject: Create reorganization --- src/api/android/mod.rs | 405 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 405 insertions(+) create mode 100644 src/api/android/mod.rs (limited to 'src/api/android/mod.rs') diff --git a/src/api/android/mod.rs b/src/api/android/mod.rs new file mode 100644 index 0000000..c769fc8 --- /dev/null +++ b/src/api/android/mod.rs @@ -0,0 +1,405 @@ +#![cfg(target_os = "android")] + +extern crate android_glue; + +use libc; +use std::ffi::{CString}; +use std::sync::mpsc::{Receiver, channel}; +use {CreationError, Event, MouseCursor}; +use CreationError::OsError; +use events::ElementState::{Pressed, Released}; +use events::Event::{MouseInput, MouseMoved}; +use events::MouseButton; + +use std::collections::VecDeque; + +use Api; +use BuilderAttribs; +use CursorState; +use GlRequest; +use PixelFormat; +use native_monitor::NativeMonitorId; + +pub struct Window { + display: ffi::egl::types::EGLDisplay, + context: ffi::egl::types::EGLContext, + surface: ffi::egl::types::EGLSurface, + event_rx: Receiver, +} + +pub struct MonitorID; + +mod ffi; + +pub fn get_available_monitors() -> VecDeque { + let mut rb = VecDeque::new(); + rb.push_back(MonitorID); + rb +} + +pub fn get_primary_monitor() -> MonitorID { + MonitorID +} + +impl MonitorID { + pub fn get_name(&self) -> Option { + Some("Primary".to_string()) + } + + pub fn get_native_identifier(&self) -> NativeMonitorId { + NativeMonitorId::Unavailable + } + + pub fn get_dimensions(&self) -> (u32, u32) { + unimplemented!() + } +} + +#[cfg(feature = "headless")] +pub struct HeadlessContext(i32); + +#[cfg(feature = "headless")] +impl HeadlessContext { + /// See the docs in the crate root file. + pub fn new(_builder: BuilderAttribs) -> Result { + unimplemented!() + } + + /// See the docs in the crate root file. + pub unsafe fn make_current(&self) { + unimplemented!() + } + + /// See the docs in the crate root file. + pub fn is_current(&self) -> bool { + unimplemented!() + } + + /// See the docs in the crate root file. + pub fn get_proc_address(&self, _addr: &str) -> *const () { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGlEs + } +} + +#[cfg(feature = "headless")] +unsafe impl Send for HeadlessContext {} +#[cfg(feature = "headless")] +unsafe impl Sync for HeadlessContext {} + +pub struct PollEventsIterator<'a> { + window: &'a Window, +} + +impl<'a> Iterator for PollEventsIterator<'a> { + type Item = Event; + + fn next(&mut self) -> Option { + match self.window.event_rx.try_recv() { + Ok(event) => { + match event { + android_glue::Event::EventDown => Some(MouseInput(Pressed, MouseButton::Left)), + android_glue::Event::EventUp => Some(MouseInput(Released, MouseButton::Left)), + android_glue::Event::EventMove(x, y) => Some(MouseMoved((x as i32, y as i32))), + _ => None, + } + } + Err(_) => { + None + } + } + } +} + +pub struct WaitEventsIterator<'a> { + window: &'a Window, +} + +impl<'a> Iterator for WaitEventsIterator<'a> { + type Item = Event; + + fn next(&mut self) -> Option { + loop { + // calling poll_events() + if let Some(ev) = self.window.poll_events().next() { + return Some(ev); + } + + // TODO: Implement a proper way of sleeping on the event queue + // timer::sleep(Duration::milliseconds(16)); + } + } +} + +impl Window { + pub fn new(builder: BuilderAttribs) -> Result { + use std::{mem, ptr}; + + if builder.sharing.is_some() { + unimplemented!() + } + + let native_window = unsafe { android_glue::get_native_window() }; + if native_window.is_null() { + return Err(OsError(format!("Android's native window is null"))); + } + + let display = unsafe { + let display = ffi::egl::GetDisplay(mem::transmute(ffi::egl::DEFAULT_DISPLAY)); + if display.is_null() { + return Err(OsError("No EGL display connection available".to_string())); + } + display + }; + + android_glue::write_log("eglGetDisplay succeeded"); + + let (_major, _minor) = unsafe { + let mut major: ffi::egl::types::EGLint = mem::uninitialized(); + let mut minor: ffi::egl::types::EGLint = mem::uninitialized(); + + if ffi::egl::Initialize(display, &mut major, &mut minor) == 0 { + return Err(OsError(format!("eglInitialize failed"))) + } + + (major, minor) + }; + + android_glue::write_log("eglInitialize succeeded"); + + let use_gles2 = match builder.gl_version { + GlRequest::Specific(Api::OpenGlEs, (2, _)) => true, + GlRequest::Specific(Api::OpenGlEs, _) => false, + GlRequest::Specific(_, _) => panic!("Only OpenGL ES is supported"), // FIXME: return a result + GlRequest::GlThenGles { opengles_version: (2, _), .. } => true, + _ => false, + }; + + let mut attribute_list = vec!(); + + if use_gles2 { + attribute_list.push(ffi::egl::RENDERABLE_TYPE as i32); + attribute_list.push(ffi::egl::OPENGL_ES2_BIT as i32); + } + + { + let (red, green, blue) = match builder.color_bits.unwrap_or(24) { + 24 => (8, 8, 8), + 16 => (6, 5, 6), + _ => panic!("Bad color_bits"), + }; + attribute_list.push(ffi::egl::RED_SIZE as i32); + attribute_list.push(red); + attribute_list.push(ffi::egl::GREEN_SIZE as i32); + attribute_list.push(green); + attribute_list.push(ffi::egl::BLUE_SIZE as i32); + attribute_list.push(blue); + } + + attribute_list.push(ffi::egl::DEPTH_SIZE as i32); + attribute_list.push(builder.depth_bits.unwrap_or(8) as i32); + + attribute_list.push(ffi::egl::NONE as i32); + + let config = unsafe { + let mut num_config: ffi::egl::types::EGLint = mem::uninitialized(); + let mut config: ffi::egl::types::EGLConfig = mem::uninitialized(); + if ffi::egl::ChooseConfig(display, attribute_list.as_ptr(), &mut config, 1, + &mut num_config) == 0 + { + return Err(OsError(format!("eglChooseConfig failed"))) + } + + if num_config <= 0 { + return Err(OsError(format!("eglChooseConfig returned no available config"))) + } + + config + }; + + android_glue::write_log("eglChooseConfig succeeded"); + + let context = unsafe { + let mut context_attributes = vec!(); + if use_gles2 { + context_attributes.push(ffi::egl::CONTEXT_CLIENT_VERSION as i32); + context_attributes.push(2); + } + context_attributes.push(ffi::egl::NONE as i32); + + let context = ffi::egl::CreateContext(display, config, ptr::null(), + context_attributes.as_ptr()); + if context.is_null() { + return Err(OsError(format!("eglCreateContext failed"))) + } + context + }; + + android_glue::write_log("eglCreateContext succeeded"); + + let surface = unsafe { + let surface = ffi::egl::CreateWindowSurface(display, config, native_window, ptr::null()); + if surface.is_null() { + return Err(OsError(format!("eglCreateWindowSurface failed"))) + } + surface + }; + + android_glue::write_log("eglCreateWindowSurface succeeded"); + + let (tx, rx) = channel(); + android_glue::add_sender(tx); + + Ok(Window { + display: display, + context: context, + surface: surface, + event_rx: rx, + }) + } + + pub fn is_closed(&self) -> bool { + false + } + + pub fn set_title(&self, _: &str) { + } + + pub fn show(&self) { + } + + pub fn hide(&self) { + } + + pub fn get_position(&self) -> Option<(i32, i32)> { + None + } + + pub fn set_position(&self, _x: i32, _y: i32) { + } + + pub fn get_inner_size(&self) -> Option<(u32, u32)> { + let native_window = unsafe { android_glue::get_native_window() }; + + if native_window.is_null() { + None + } else { + Some(( + unsafe { ffi::ANativeWindow_getWidth(native_window) } as u32, + unsafe { ffi::ANativeWindow_getHeight(native_window) } as u32 + )) + } + } + + pub fn get_outer_size(&self) -> Option<(u32, u32)> { + self.get_inner_size() + } + + pub fn set_inner_size(&self, _x: u32, _y: u32) { + } + + pub fn create_window_proxy(&self) -> WindowProxy { + WindowProxy + } + + pub fn poll_events(&self) -> PollEventsIterator { + PollEventsIterator { + window: self + } + } + + pub fn wait_events(&self) -> WaitEventsIterator { + WaitEventsIterator { + window: self + } + } + + pub fn make_current(&self) { + unsafe { + ffi::egl::MakeCurrent(self.display, self.surface, self.surface, self.context); + } + } + + pub fn is_current(&self) -> bool { + unsafe { ffi::egl::GetCurrentContext() == self.context } + } + + pub fn get_proc_address(&self, addr: &str) -> *const () { + let addr = CString::new(addr.as_bytes()).unwrap(); + let addr = addr.as_ptr(); + unsafe { + ffi::egl::GetProcAddress(addr) as *const () + } + } + + pub fn swap_buffers(&self) { + unsafe { + ffi::egl::SwapBuffers(self.display, self.surface); + } + } + + pub fn platform_display(&self) -> *mut libc::c_void { + self.display as *mut libc::c_void + } + + pub fn platform_window(&self) -> *mut libc::c_void { + unimplemented!() + } + + pub fn get_api(&self) -> ::Api { + ::Api::OpenGlEs + } + + pub fn get_pixel_format(&self) -> PixelFormat { + unimplemented!(); + } + + pub fn set_window_resize_callback(&mut self, _: Option) { + } + + pub fn set_cursor(&self, _: MouseCursor) { + } + + pub fn set_cursor_state(&self, state: CursorState) -> Result<(), String> { + Ok(()) + } + + pub fn hidpi_factor(&self) -> f32 { + 1.0 + } + + pub fn set_cursor_position(&self, x: i32, y: i32) -> Result<(), ()> { + unimplemented!(); + } +} + +unsafe impl Send for Window {} +unsafe impl Sync for Window {} + +#[cfg(feature = "window")] +#[derive(Clone)] +pub struct WindowProxy; + +impl WindowProxy { + pub fn wakeup_event_loop(&self) { + unimplemented!() + } +} + +impl Drop for Window { + fn drop(&mut self) { + use std::ptr; + + unsafe { + // we don't call MakeCurrent(0, 0) because we are not sure that the context + // is still the current one + android_glue::write_log("Destroying gl-init window"); + ffi::egl::DestroySurface(self.display, self.surface); + ffi::egl::DestroyContext(self.display, self.context); + ffi::egl::Terminate(self.display); + } + } +} -- cgit v1.2.3