use alloc::format;
use core::ptr::NonNull;
use super::unowned_bitmap::UnownedBitmapRef;
use crate::capi_state::CApiState;
use crate::ctypes::*;
use crate::error::Error;
use crate::null_terminated::ToNullTerminatedString;
#[derive(Debug)]
pub struct Font {
font_ptr: NonNull<CFont>,
}
impl Font {
pub(crate) fn from_ptr(font_ptr: *mut CFont) -> Self {
Font {
font_ptr: unsafe { NonNull::new_unchecked(font_ptr) },
}
}
pub fn from_file(path: &str) -> Result<Font, Error> {
let mut out_err: *const u8 = core::ptr::null_mut();
let font_ptr = unsafe {
Self::fns().loadFont.unwrap()(path.to_null_terminated_utf8().as_ptr(), &mut out_err)
};
if !out_err.is_null() {
let result = unsafe { crate::null_terminated::parse_null_terminated_utf8(out_err) };
match result {
Ok(err) => Err(format!("load_font: {}", err).into()),
Err(err) => Err(format!("load_font: unknown error ({})", err).into()),
}
} else {
assert!(!font_ptr.is_null());
Ok(Font::from_ptr(font_ptr))
}
}
pub fn measure_text_width(&self, text: &str, tracking: i32) -> i32 {
let utf = text.to_null_terminated_utf8();
unsafe {
Self::fns().getTextWidth.unwrap()(
self.cptr() as *mut _,
utf.as_ptr() as *const core::ffi::c_void,
utf.len() as u64 - 1, CStringEncoding::kUTF8Encoding,
tracking,
)
}
}
pub fn font_height(&self) -> u8 {
unsafe { Self::fns().getFontHeight.unwrap()(self.cptr() as *mut _) }
}
pub fn font_page(&self, c: char) -> FontPage {
let page_ptr = unsafe { Self::fns().getFontPage.unwrap()(self.cptr() as *mut _, c as u32) };
FontPage {
page_ptr: unsafe { NonNull::new_unchecked(page_ptr) },
page_test: c as u32 & 0xffffff00,
}
}
pub(crate) fn cptr(&self) -> *const CFont {
self.font_ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_graphics {
CApiState::get().cgraphics
}
}
pub struct FontPage {
page_ptr: NonNull<CFontPage>,
page_test: u32,
}
impl FontPage {
pub fn contains(&self, c: char) -> bool {
c as u32 & 0xffffff00 == self.page_test
}
pub fn glyph(&self, c: char) -> Option<FontGlyph> {
if !self.contains(c) {
None
} else {
let mut bitmap_ptr: *mut CBitmap = core::ptr::null_mut();
let mut advance = 0;
let glyph_ptr = unsafe {
Self::fns().getPageGlyph.unwrap()(
self.cptr() as *mut _,
c as u32,
&mut bitmap_ptr,
&mut advance,
)
};
Some(FontGlyph {
glyph_ptr: NonNull::new(glyph_ptr).unwrap(),
advance,
glyph_char: c,
bitmap: UnownedBitmapRef::<'static>::from_ptr(NonNull::new(bitmap_ptr).unwrap()),
})
}
}
pub(crate) fn cptr(&self) -> *const CFontPage {
self.page_ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_graphics {
CApiState::get().cgraphics
}
}
pub struct FontGlyph {
glyph_ptr: NonNull<CFontGlyph>,
advance: i32,
glyph_char: char,
bitmap: UnownedBitmapRef<'static>,
}
impl FontGlyph {
pub fn advance(&self) -> i32 {
self.advance
}
pub fn kerning(&self, next_char: char) -> i32 {
unsafe {
Self::fns().getGlyphKerning.unwrap()(
self.cptr() as *mut _,
self.glyph_char as u32,
next_char as u32,
)
}
}
pub fn bitmap(&self) -> UnownedBitmapRef<'static> {
self.bitmap.clone()
}
pub(crate) fn cptr(&self) -> *const CFontGlyph {
self.glyph_ptr.as_ptr()
}
pub(crate) fn fns() -> &'static craydate_sys::playdate_graphics {
CApiState::get().cgraphics
}
}