#[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 gamepad;
mod glyph_cache;
mod graphics;
pub mod image;
mod image_raw;
mod image_shader;
mod input;
#[cfg(target_os = "ios")]
pub mod ios;
mod key;
mod launch;
pub mod math;
#[cfg(feature = "model-3d")]
pub mod model;
mod mouse;
mod platform;
mod platform_events;
mod pt;
mod scenes;
mod shader_opts;
mod shader_templates;
mod sound;
mod splash;
pub mod text;
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 use controls::*;
pub use drawable::{DrawOption, Drawable, ImageRepeat};
#[cfg(feature = "model-3d")]
pub use drawable_3d::DrawOption3D;
#[cfg(feature = "effects")]
pub use fog::{FogBackgroundSettings, FogSamplingSettings, FogSettings};
pub use gamepad::{GamepadAxis, GamepadButton, GamepadId, GamepadInfo};
pub use graphics::texture::Texture;
pub use image::{Bounds, Image};
pub use image_shader::{
ImageShaderBindings, ImageShaderBlendMode, ImageShaderDesc, ImageShaderInput,
};
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 shader_templates::{
ImageShaderTemplate, ModelShaderTemplate, image_shader_template, model_shader_template,
};
pub type ImageShaderTemplateBuilder = shader_templates::ImageShaderTemplate;
pub type ModelShaderTemplateBuilder = shader_templates::ModelShaderTemplate;
#[cfg(test)]
mod export_smoke_tests {
#[test]
fn image_template_exports_exist() {
let _ = super::image_shader_template();
let _ = super::ImageShaderTemplate::new();
let _fn_ptr: fn(&mut super::Context, super::ImageShaderTemplate) -> u32 =
super::register_image_shader_template;
}
}
pub use sound::*;
pub use splash::OneShotSplash;
pub use text::Text;
pub use touch::{TouchInfo, TouchPhase};
#[cfg(feature = "utils")]
pub use utils::image::{AsyncImageLoader, LoadingImage, load_image_async};
pub fn register_font(ctx: &mut Context, font_data: Vec<u8>) -> u32 {
ctx.register_font(font_data)
}
pub fn register_image_shader_desc(ctx: &mut Context, desc: ImageShaderDesc) -> u32 {
ctx.register_image_shader_desc(desc)
}
pub fn register_image_shader_template(ctx: &mut Context, template: ImageShaderTemplate) -> u32 {
ctx.register_image_shader_desc(template.build_desc())
}
#[cfg(feature = "model-3d")]
pub fn register_model_shader_template(ctx: &mut Context, template: ModelShaderTemplate) -> u32 {
ctx.register_model_shader(&template.build())
}
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)
}
#[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_released(ctx: &Context, btn: MouseButton) -> bool {
ctx.input().mouse_released(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 gamepads(ctx: &Context) -> Vec<GamepadInfo> {
ctx.input().gamepads()
}
pub fn gamepad_connected(ctx: &Context, id: GamepadId) -> bool {
ctx.input().gamepad_connected(id)
}
pub fn gamepad_button_down(ctx: &Context, id: GamepadId, button: GamepadButton) -> bool {
ctx.input().gamepad_button_down(id, button)
}
pub fn gamepad_button_pressed(ctx: &Context, id: GamepadId, button: GamepadButton) -> bool {
ctx.input().gamepad_button_pressed(id, button)
}
pub fn gamepad_button_released(ctx: &Context, id: GamepadId, button: GamepadButton) -> bool {
ctx.input().gamepad_button_released(id, button)
}
pub fn gamepad_axis(ctx: &Context, id: GamepadId, axis: GamepadAxis) -> f32 {
ctx.input().gamepad_axis(id, axis)
}
pub fn scroll_delta(ctx: &Context) -> (f32, f32) {
ctx.input().scroll_delta()
}
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,
target_texture_id: 0,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
shader_bindings: ImageShaderBindings::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,
target_texture_id: 0,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
shader_bindings: ImageShaderBindings::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,
target_texture_id: 0,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
shader_bindings: ImageShaderBindings::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,
target_texture_id: 0,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
shader_bindings: ImageShaderBindings::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,
target_texture_id: 0,
opts,
shader_id: 0,
shader_opts: ShaderOpts::default(),
shader_bindings: ImageShaderBindings::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();
}
#[test]
fn test_render_target_registration() {
let mut ctx = Context::new();
let texture = Texture::new_render_target(&mut ctx, Pt::from(100.0), Pt::from(200.0));
let image = texture.view();
assert_eq!(texture.width(), Pt::from(100.0));
assert_eq!(texture.height(), Pt::from(200.0));
assert_eq!(image.width(), Pt::from(100.0));
assert_eq!(image.height(), Pt::from(200.0));
let texture_entry = ctx
.registry
.textures
.get(texture.id() as usize)
.unwrap()
.as_ref()
.unwrap();
assert!(texture_entry.is_render_target());
assert_eq!(texture_entry.pixel_width, 100);
assert_eq!(texture_entry.pixel_height, 200);
}
}