use super::*;
fn rgba_len(rgba: *const u8, w: u32, h: u32) -> Option<usize> {
if rgba.is_null() || w == 0 || h == 0 {
return None;
}
(w as usize)
.checked_mul(h as usize)?
.checked_mul(4)
.filter(|&n| n <= isize::MAX as usize)
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_image_add(ptr: *mut KuiCtx, w: u32, h: u32, rgba: *const u8) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let Some(len) = rgba_len(rgba, w, h) else {
return 0;
};
let data = unsafe { std::slice::from_raw_parts(rgba, len) }.to_vec();
c.core().resources.add_image(w, h, data).to_ffi()
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_image_update(ptr: *mut KuiCtx, id: u64, w: u32, h: u32, rgba: *const u8) {
guard((), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return;
};
let Some(len) = rgba_len(rgba, w, h) else {
return;
};
let data = unsafe { std::slice::from_raw_parts(rgba, len) };
c.core()
.update_image_with(kui_core::ImageId::from_ffi(id), w, h, |px| {
px.copy_from_slice(data)
});
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_image_pixels(
ptr: *mut KuiCtx,
id: u64,
w: *mut u32,
h: *mut u32,
rgba: *mut *const u8,
) -> bool {
guard(false, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return false;
};
if w.is_null() || h.is_null() || rgba.is_null() {
return false;
}
let Some((iw, ih, px)) = c.core().image_pixels(kui_core::ImageId::from_ffi(id)) else {
return false;
};
c.image_pixels = Some(px);
unsafe {
*w = iw;
*h = ih;
*rgba = c.image_pixels.as_ref().unwrap().as_ptr();
}
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_add(ptr: *mut KuiCtx, data: *const u8, len: usize) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
if data.is_null() || len == 0 {
return 0;
}
let bytes = unsafe { std::slice::from_raw_parts(data, len) }.to_vec();
c.core().add_font_data(bytes).map_or(0, |id| id.to_ffi())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_add_system(ptr: *mut KuiCtx, name: KuiStr) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
c.core()
.add_system_font(&kstr(name))
.map_or(0, |id| id.to_ffi())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_families(ptr: *mut KuiCtx, out: *mut KuiStr, cap: usize) -> usize {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
c.font_families = c.core().system_font_families();
let n = c.font_families.len();
if out.is_null() {
return n;
}
for (i, name) in c.font_families.iter().take(cap).enumerate() {
unsafe {
out.add(i).write(KuiStr {
ptr: name.as_ptr(),
len: name.len(),
})
};
}
n
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_system_fonts(ptr: *mut KuiCtx, out: *mut KuiSystemFont, cap: usize) -> usize {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
c.system_fonts = c.core().system_fonts();
let n = c.system_fonts.len();
if out.is_null() {
return n;
}
for (i, font) in c.system_fonts.iter().take(cap).enumerate() {
unsafe {
out.add(i).write(KuiSystemFont {
family: KuiStr {
ptr: font.family.as_ptr(),
len: font.family.len(),
},
weights: font.weights.as_ptr(),
weight_count: font.weights.len() as u32,
monospaced: u32::from(font.monospaced),
italic: u32::from(font.italic),
})
};
}
n
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_fragment_add(ptr: *mut KuiCtx, wgsl: KuiStr) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
c.core()
.add_fragment(&kstr(wgsl))
.map_or(0, |id| id.to_ffi())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_fragment_remove(ptr: *mut KuiCtx, id: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().remove_fragment(kui_core::FragmentId::from_ffi(id));
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_fragment_source(ptr: *mut KuiCtx, id: u64, out: *mut KuiStr) -> bool {
guard(false, || {
let (Some(c), false) = (unsafe { ctx(ptr) }, out.is_null()) else {
return false;
};
let Some(src) = c
.core()
.fragment_module_source(kui_core::FragmentId::from_ffi(id))
else {
return false;
};
c.fragment_source = src;
unsafe {
*out = KuiStr {
ptr: c.fragment_source.as_ptr(),
len: c.fragment_source.len(),
}
};
true
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_load_file(ptr: *mut KuiCtx, path: KuiStr) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let path = kstr(path).into_owned();
c.core().load_font_file(path).map_or(0, |id| id.to_ffi())
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_load_dir(ptr: *mut KuiCtx, dir: KuiStr) -> usize {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let dir = kstr(dir).into_owned();
c.core().load_fonts_dir(dir)
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_reload_system(ptr: *mut KuiCtx) -> usize {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
c.core().reload_system_fonts()
})
}
#[unsafe(no_mangle)]
pub unsafe extern "C" fn kui_font_set_fallback(ptr: *mut KuiCtx, ids: *const u64, len: usize) {
guard((), || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return;
};
let ids: Vec<kui_core::FontId> = if ids.is_null() {
Vec::new()
} else {
unsafe { std::slice::from_raw_parts(ids, len) }
.iter()
.map(|&id| kui_core::FontId::from_ffi(id))
.collect()
};
c.core().set_fallback_fonts(&ids);
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_font_remove(ptr: *mut KuiCtx, id: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().remove_font(kui_core::FontId::from_ffi(id));
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_sound_add(ptr: *mut KuiCtx, data: *const u8, len: usize) -> u64 {
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
if data.is_null() || len == 0 {
return 0;
}
let bytes = unsafe { std::slice::from_raw_parts(data, len) }.to_vec();
c.core().add_sound(bytes).to_ffi()
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_sound_remove(ptr: *mut KuiCtx, id: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().remove_sound(kui_core::SoundId::from_ffi(id));
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_play(
ptr: *mut KuiCtx,
sound: u64,
opts: *const KuiPlay,
tag: *mut KuiValue,
) -> u64 {
guard(0, || {
let tag = take_msg(tag);
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
let mut po = kui_core::PlayOptions::default();
if let Some(o) = unsafe { opts.as_ref() } {
po.volume = o.volume;
po.looped = o.looped != 0;
po.fade_in_ms = o.fade_in_ms;
}
po.tag = tag;
c.core().play(kui_core::SoundId::from_ffi(sound), po).0
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_stop(ptr: *mut KuiCtx, playback: u64, fade_ms: f32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().stop(kui_core::PlaybackId(playback), fade_ms);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_volume(ptr: *mut KuiCtx, playback: u64, volume: f32, tween_ms: f32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core()
.set_volume(kui_core::PlaybackId(playback), volume, tween_ms);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_pause(ptr: *mut KuiCtx, playback: u64, fade_ms: f32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().pause(kui_core::PlaybackId(playback), fade_ms);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_resume(ptr: *mut KuiCtx, playback: u64, fade_ms: f32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().resume(kui_core::PlaybackId(playback), fade_ms);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_set_master_volume(ptr: *mut KuiCtx, volume: f32, tween_ms: f32) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().set_master_volume(volume, tween_ms);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_audio(
ptr: *mut KuiCtx,
label: KuiStr,
spec: *const KuiAudio,
tag: *mut KuiValue,
) -> u64 {
guard(0, || {
let tag = take_msg(tag);
let (Some(c), Some(a)) = (unsafe { ctx(ptr) }, unsafe { spec.as_ref() }) else {
return 0;
};
let mut s = kui_core::AudioSpec::new(kui_core::SoundId::from_ffi(a.src))
.volume(a.volume)
.paused(a.paused != 0);
if a.looped != 0 {
s = s.looped();
}
if a.finish != 0 {
s = s.finish();
}
s.tag = tag;
let core = c.core();
if label.ptr.is_null() || label.len == 0 {
core.audio_node(s).0
} else {
core.audio_node_keyed(&kstr(label), s).0
}
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_take_audio_commands(
ptr: *mut KuiCtx,
out: *mut KuiAudioCommand,
cap: usize,
) -> usize {
use kui_core::AudioCommand as A;
guard(0, || {
let Some(c) = (unsafe { ctx(ptr) }) else {
return 0;
};
if out.is_null() || cap == 0 {
return 0;
}
let cmds = c.core().take_audio_commands();
let n = cmds.len().min(cap);
for (i, cmd) in cmds.into_iter().take(n).enumerate() {
let mut o = KuiAudioCommand::default();
match cmd {
A::Play {
playback,
sound,
volume,
looped,
fade_in_ms,
} => {
o.kind = KUI_AUDIO_PLAY;
o.playback = playback.0;
o.sound = sound.to_ffi();
o.volume = volume;
o.ms = fade_in_ms;
o.looped = looped as u32;
}
A::Stop { playback, fade_ms } => {
o.kind = KUI_AUDIO_STOP;
o.playback = playback.0;
o.ms = fade_ms;
}
A::SetVolume {
playback,
volume,
tween_ms,
} => {
o.kind = KUI_AUDIO_SET_VOLUME;
o.playback = playback.0;
o.volume = volume;
o.ms = tween_ms;
}
A::Pause { playback, fade_ms } => {
o.kind = KUI_AUDIO_PAUSE;
o.playback = playback.0;
o.ms = fade_ms;
}
A::Resume { playback, fade_ms } => {
o.kind = KUI_AUDIO_RESUME;
o.playback = playback.0;
o.ms = fade_ms;
}
A::MasterVolume { volume, tween_ms } => {
o.kind = KUI_AUDIO_MASTER_VOLUME;
o.volume = volume;
o.ms = tween_ms;
}
A::Unload { sound } => {
o.kind = KUI_AUDIO_UNLOAD;
o.sound = sound.to_ffi();
}
}
unsafe { out.add(i).write(o) };
}
n
})
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_audio_ended(ptr: *mut KuiCtx, playback: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().audio_ended(kui_core::PlaybackId(playback));
let pending = c.core().take_pending_events();
c.absorb(pending);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_audio_truncated(ptr: *mut KuiCtx, playback: u64, at: f64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().audio_truncated(kui_core::PlaybackId(playback), at);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_audio_refused(ptr: *mut KuiCtx, playback: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().audio_refused(kui_core::PlaybackId(playback));
let pending = c.core().take_pending_events();
c.absorb(pending);
}
});
}
#[unsafe(no_mangle)]
pub extern "C" fn kui_image_remove(ptr: *mut KuiCtx, id: u64) {
guard((), || {
if let Some(c) = unsafe { ctx(ptr) } {
c.core().remove_image(kui_core::ImageId::from_ffi(id));
}
});
}