#[cfg(target_os = "android")]
pub mod android;
mod assets;
mod audio;
mod context;
mod context_3d;
mod controls;
mod drawable;
mod drawable_3d;
#[cfg(feature = "effects")]
mod fog;
mod glyph_cache;
mod graphics;
pub mod image;
mod image_raw;
mod input;
mod key;
mod launch;
pub mod math;
#[cfg(feature = "model-3d")]
pub mod model;
mod mouse;
mod packer;
mod platform;
mod platform_events;
mod pt;
mod scenes;
mod shader_opts;
mod sound;
mod splash;
pub mod text;
mod texture;
mod touch;
#[cfg(any(feature = "utils", feature = "model-3d", feature = "gltf"))]
pub mod utils;
mod window;
#[cfg(target_os = "android")]
pub use android_activity::AndroidApp;
pub use assets::*;
pub use context::Context;
pub(crate) use context::DrawState;
pub use controls::*;
pub use drawable::DrawOption;
#[cfg(feature = "model-3d")]
pub use drawable_3d::DrawOption3D;
#[cfg(feature = "effects")]
pub use fog::{FogBackgroundSettings, FogSamplingSettings, FogSettings};
pub use image::{Bounds, Image};
pub use input::InputManager;
pub use key::Key;
pub use launch::{WindowConfig, run};
#[cfg(feature = "model-3d")]
pub use model::Model;
pub use mouse::MouseButton;
pub use platform_events::PlatformEvent;
pub use pt::Pt;
pub use scenes::{Spot, quit, switch_scene, switch_scene_with};
pub use shader_opts::ShaderOpts;
pub use sound::*;
pub use splash::OneShotSplash;
pub use text::Text;
pub use touch::{TouchInfo, TouchPhase};
pub fn register_font(ctx: &mut Context, font_data: Vec<u8>) -> u32 {
ctx.register_font(font_data)
}
pub fn register_shader(ctx: &mut Context, user_functions: &str) -> u32 {
ctx.register_image_shader(user_functions)
}
pub fn pt(x: f32) -> Pt {
Pt::from(x)
}
pub fn unregister_font(ctx: &mut Context, font_id: u32) {
assets::unregister_font(ctx, font_id);
}
pub fn register_sound(ctx: &mut Context, bytes: Vec<u8>) -> Option<u32> {
sound::register_sound(ctx, bytes)
}
pub fn unregister_sound(ctx: &mut Context, sound_id: u32) {
sound::unregister_sound(ctx, sound_id)
}
pub fn compress_assets(ctx: &mut Context) {
assets::compress_assets(ctx);
}
#[cfg(feature = "model-3d")]
pub fn set_camera(ctx: &mut Context, eye: [f32; 3], target: [f32; 3], up: [f32; 3]) {
ctx.set_camera(eye, target, up);
}
#[cfg(feature = "model-3d")]
pub fn camera_position(ctx: &Context) -> [f32; 3] {
ctx.camera_position()
}
#[cfg(feature = "model-3d")]
pub fn set_camera_pos(ctx: &mut Context, pos: [f32; 3]) {
ctx.set_camera_pos(pos);
}
#[cfg(feature = "model-3d")]
pub fn set_camera_target(ctx: &mut Context, x: f32, y: f32, z: f32) {
ctx.set_camera_target(x, y, z);
}
#[cfg(feature = "model-3d")]
pub fn set_camera_up(ctx: &mut Context, x: f32, y: f32, z: f32) {
ctx.set_camera_up(x, y, z);
}
#[cfg(feature = "model-3d")]
pub fn set_camera_fovy(ctx: &mut Context, fovy_degrees: f32) {
ctx.set_camera_fovy(fovy_degrees);
}
#[cfg(feature = "model-3d")]
pub fn set_ambient(ctx: &mut Context, color: [f32; 4]) {
ctx.set_ambient(color);
}
#[cfg(feature = "model-3d")]
pub fn set_light(ctx: &mut Context, index: usize, position: [f32; 4], color: [f32; 4]) {
ctx.set_light(index, position, color);
}
#[cfg(all(feature = "model-3d", feature = "effects"))]
pub fn set_fog(ctx: &mut Context, settings: FogSettings) {
ctx.set_fog(settings);
}
#[cfg(all(feature = "model-3d", feature = "effects"))]
pub fn clear_fog(ctx: &mut Context) {
ctx.clear_fog();
}
#[cfg(feature = "model-3d")]
pub fn set_ambient_light(ctx: &mut Context, color: [f32; 4]) {
ctx.set_ambient_light(color);
}
pub fn set_window_size(ctx: &mut Context, width: Pt, height: Pt) {
ctx.set_window_logical_size(width, height);
}
pub fn window_size(ctx: &Context) -> (Pt, Pt) {
ctx.window_logical_size()
}
pub fn insert_resource<T: std::any::Any>(ctx: &mut Context, value: std::rc::Rc<T>) {
ctx.insert_resource(value)
}
pub fn get_resource<T: std::any::Any>(ctx: &Context) -> Option<std::rc::Rc<T>> {
ctx.get_resource::<T>()
}
pub fn take_resource<T: std::any::Any>(ctx: &mut Context) -> Option<std::rc::Rc<T>> {
ctx.take_resource::<T>()
}
pub fn scale_factor(ctx: &Context) -> f64 {
ctx.scale_factor()
}
pub fn vw(ctx: &Context, percent: f32) -> Pt {
ctx.vw(percent)
}
pub fn vh(ctx: &Context, percent: f32) -> Pt {
ctx.vh(percent)
}
pub fn key_down(ctx: &Context, key: Key) -> bool {
ctx.input().key_down(key)
}
pub fn key_pressed(ctx: &Context, key: Key) -> bool {
ctx.input().key_pressed(key)
}
pub fn mouse_down(ctx: &Context, btn: MouseButton) -> bool {
ctx.input().mouse_down(btn)
}
pub fn mouse_pressed(ctx: &Context, btn: MouseButton) -> bool {
ctx.input().mouse_pressed(btn)
}
pub fn mouse_pos(ctx: &Context) -> Option<(Pt, Pt)> {
ctx.input().cursor_position()
}
pub fn cursor_position(ctx: &Context) -> Option<(Pt, Pt)> {
mouse_pos(ctx)
}
pub fn touches(ctx: &Context) -> &[TouchInfo] {
ctx.input().touches()
}
pub fn set_window_title(ctx: &mut Context, title: impl Into<String>) {
ctx.set_window_title(title);
}
pub fn set_cursor_visible(ctx: &mut Context, visible: bool) {
ctx.set_cursor_visible(visible);
}
pub fn set_fullscreen(ctx: &mut Context, enabled: bool) {
ctx.set_fullscreen(enabled);
}
pub fn switch_scene_ctx<T: Spot + 'static>(_ctx: &mut Context) {
switch_scene::<T>();
}
pub fn switch_scene_with_ctx<T: Spot + 'static, P: std::any::Any>(_ctx: &mut Context, payload: P) {
switch_scene_with::<T, P>(payload);
}
pub fn quit_ctx(_ctx: &mut Context) {
quit();
}
pub fn delta_time(ctx: &Context) -> std::time::Duration {
ctx.delta_time()
}
pub fn dt(ctx: &Context) -> f32 {
ctx.delta_time().as_secs_f32()
}
pub fn total_elapsed(ctx: &Context) -> std::time::Duration {
ctx.total_elapsed()
}
#[cfg(test)]
mod tests {
use super::*;
use crate::drawable::{DrawCommand, ImageCommand};
#[test]
fn test_image_culling_flip() {
let mut ctx = Context::new();
ctx.set_window_logical_size(Pt::from(800.0), Pt::from(600.0));
let img_id = 1u32;
let img_size = [Pt::from(100.0), Pt::from(100.0)];
let opts = DrawOption::default().with_position([Pt::from(100.0), Pt::from(100.0)]);
ctx.push(DrawCommand::Image(Box::new(ImageCommand {
id: img_id,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
size: img_size,
})));
assert_eq!(
ctx.runtime.draw_list.len(),
1,
"Normal image should be visible"
);
ctx.runtime.draw_list.clear();
let opts = DrawOption::default()
.with_position([Pt::from(100.0), Pt::from(100.0)])
.with_scale([-1.0, 1.0]);
ctx.push(DrawCommand::Image(Box::new(ImageCommand {
id: img_id,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
size: img_size,
})));
assert_eq!(
ctx.runtime.draw_list.len(),
1,
"Flipped H image at 100 should be visible (covers 0-100)"
);
ctx.runtime.draw_list.clear();
let opts = DrawOption::default()
.with_position([Pt::from(-0.1), Pt::from(100.0)])
.with_scale([-1.0, 1.0]);
ctx.push(DrawCommand::Image(Box::new(ImageCommand {
id: img_id,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
size: img_size,
})));
assert_eq!(
ctx.runtime.draw_list.len(),
0,
"Flipped H image at -0.1 should be culled (covers -100 to -0.1)"
);
ctx.runtime.draw_list.clear();
let opts = DrawOption::default()
.with_position([Pt::from(100.0), Pt::from(100.0)])
.with_scale([1.0, -1.0]);
ctx.push(DrawCommand::Image(Box::new(ImageCommand {
id: img_id,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
size: img_size,
})));
assert_eq!(
ctx.runtime.draw_list.len(),
1,
"Flipped V image at 100 should be visible (covers 0-100 in Y)"
);
ctx.runtime.draw_list.clear();
let opts = DrawOption::default()
.with_position([Pt::from(100.0), Pt::from(100.0)])
.with_scale([-1.0, -1.0]);
ctx.push(DrawCommand::Image(Box::new(ImageCommand {
id: img_id,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
size: img_size,
})));
assert_eq!(
ctx.runtime.draw_list.len(),
1,
"Both-flipped image at 100,100 should be visible"
);
ctx.runtime.draw_list.clear();
}
}