#![allow(clippy::new_without_default)]
#![allow(clippy::type_complexity)]
use std::sync::{Arc, Mutex};
use bytes::Bytes;
use irondash_run_loop::{util::Capsule, RunLoop, RunLoopSender};
use platform::PlatformTexture;
mod error;
mod log;
mod platform;
pub use error::*;
pub type Result<T> = std::result::Result<T, Error>;
pub struct Texture<Type> {
platform_texture: PlatformTexture<Type>,
}
impl<Type> Texture<Type> {
pub fn id(&self) -> i64 {
self.platform_texture.id()
}
pub fn mark_frame_available(&self) -> Result<()> {
self.platform_texture.mark_frame_available()
}
pub fn into_sendable_texture(self) -> Arc<SendableTexture<Type>> {
Arc::new(SendableTexture {
sender: RunLoop::current().new_sender(),
texture: Mutex::new(Capsule::new(self)),
})
}
}
pub trait Payload<Type: Send>: Send {
fn get(&self) -> &Type;
}
pub type BoxedPayload<Type> = Box<dyn Payload<Type>>;
pub trait IntoBoxedPayload<Type> {
fn into_boxed_payload(self) -> BoxedPayload<Self>;
}
impl<Type> IntoBoxedPayload<Type> for Type
where
Type: Send + 'static,
{
fn into_boxed_payload(self) -> BoxedPayload<Self> {
Box::new(SimplePayload { payload: self })
}
}
pub trait PayloadProvider<Type>: Send + Sync {
fn get_payload(&self) -> BoxedPayload<Type>;
}
impl<Type: PlatformTextureWithProvider> Texture<Type> {
pub fn new_with_provider(
engine_handle: i64,
payload_provider: Arc<dyn PayloadProvider<Type>>,
) -> Result<Self> {
Ok(Self {
platform_texture: Type::create_texture(engine_handle, payload_provider)?,
})
}
}
impl<Type: PlatformTextureWithoutProvider> Texture<Type> {
pub fn new(engine_handle: i64) -> Result<Self> {
Ok(Self {
platform_texture: Type::create_texture(engine_handle)?,
})
}
pub fn get(&self) -> Type {
Type::get(&self.platform_texture)
}
}
pub enum PixelFormat {
BGRA,
RGBA,
}
#[derive(Clone)]
pub struct PixelBuffer {
pub width: i32,
pub height: i32,
pub data: Bytes,
}
impl PixelBuffer {
pub const FORMAT: PixelFormat = PlatformTexture::<PixelBuffer>::PIXEL_BUFFER_FORMAT;
}
#[cfg(target_os = "android")]
mod android {
pub type NativeWindow = super::platform::NativeWindow;
pub type Surface = super::platform::Surface;
}
#[cfg(target_os = "android")]
pub use android::*;
#[cfg(any(target_os = "ios", target_os = "macos"))]
pub mod io_surface {
pub use crate::platform::io_surface::*;
}
#[cfg(target_os = "linux")]
pub struct GLTexture {
pub target: u32, pub name: u32, pub width: i32,
pub height: i32,
}
#[cfg(target_os = "windows")]
mod windows {
use std::ffi::c_void;
pub struct TextureDescriptor<TextureHandle> {
pub handle: TextureHandle,
pub width: i32,
pub height: i32,
pub visible_width: i32,
pub visible_height: i32,
pub pixel_format: super::PixelFormat,
pub release_callback: Option<Box<dyn FnOnce(&TextureHandle) + 'static + Send>>,
}
pub struct ID3D11Texture2D(pub *mut c_void);
pub struct DxgiSharedHandle(pub *mut c_void);
}
#[cfg(target_os = "windows")]
pub use windows::*;
use crate::log::OkLog;
pub struct SendableTexture<T: 'static> {
sender: RunLoopSender,
texture: Mutex<Capsule<Texture<T>>>,
}
impl<T> SendableTexture<T> {
pub fn mark_frame_available(self: &Arc<Self>) {
if self.sender.is_same_thread() {
let texture = self.texture.lock().unwrap();
let texture = texture.get_ref().unwrap();
texture.mark_frame_available().ok_log();
} else {
let texture_clone = self.clone();
self.sender.send(move || {
let texture = texture_clone.texture.lock().unwrap();
let texture = texture.get_ref().unwrap();
texture.mark_frame_available().ok_log();
});
}
}
}
pub trait PlatformTextureWithProvider: Sized {
fn create_texture(
engine_handle: i64,
payload_provider: Arc<dyn PayloadProvider<Self>>,
) -> Result<PlatformTexture<Self>>;
}
pub trait PlatformTextureWithoutProvider: Sized {
fn create_texture(engine_handle: i64) -> Result<PlatformTexture<Self>>;
fn get(texture: &PlatformTexture<Self>) -> Self;
}
struct SimplePayload<Type> {
payload: Type,
}
impl<Type: Send> Payload<Type> for SimplePayload<Type> {
fn get(&self) -> &Type {
&self.payload
}
}