1#[cfg(target_os = "android")]
55pub mod android;
56mod assets;
57mod audio;
58mod context;
59mod context_3d;
60mod controls;
61mod drawable;
62mod drawable_3d;
63#[cfg(feature = "effects")]
64mod fog;
65mod glyph_cache;
66mod graphics;
67pub mod image;
68mod image_raw;
69mod input;
70mod key;
71mod launch;
72pub mod math;
73#[cfg(feature = "model-3d")]
74pub mod model;
75mod mouse;
76mod platform;
77mod platform_events;
78mod pt;
79mod scenes;
80mod shader_opts;
81mod sound;
82mod splash;
83pub mod text;
84
85mod touch;
86#[cfg(any(feature = "utils", feature = "model-3d", feature = "gltf"))]
87pub mod utils;
88mod window;
89
90#[cfg(target_os = "android")]
91pub use android_activity::AndroidApp;
92pub use assets::*;
93pub use context::Context;
94pub use controls::*;
95pub use drawable::{DrawOption, Drawable};
96#[cfg(feature = "model-3d")]
97pub use drawable_3d::DrawOption3D;
98#[cfg(feature = "effects")]
99pub use fog::{FogBackgroundSettings, FogSamplingSettings, FogSettings};
100
101pub use image::{Bounds, Image};
102pub use input::InputManager;
103pub use key::Key;
104pub use launch::{WindowConfig, run};
105#[cfg(feature = "model-3d")]
106pub use model::Model;
107pub use mouse::MouseButton;
108pub use platform_events::PlatformEvent;
109pub use pt::Pt;
110pub use scenes::{Spot, quit, switch_scene, switch_scene_with};
111pub use shader_opts::ShaderOpts;
112pub use sound::*;
113pub use splash::OneShotSplash;
114pub use text::Text;
115pub use graphics::texture::Texture;
116pub use touch::{TouchInfo, TouchPhase};
117
118pub fn register_font(ctx: &mut Context, font_data: Vec<u8>) -> u32 {
122 ctx.register_font(font_data)
123}
124
125pub fn register_shader(ctx: &mut Context, user_functions: &str) -> u32 {
129 ctx.register_image_shader(user_functions)
130}
131
132pub fn pt(x: f32) -> Pt {
134 Pt::from(x)
135}
136
137pub fn unregister_font(ctx: &mut Context, font_id: u32) {
138 assets::unregister_font(ctx, font_id);
139}
140
141pub fn register_sound(ctx: &mut Context, bytes: Vec<u8>) -> Option<u32> {
143 sound::register_sound(ctx, bytes)
144}
145
146pub fn unregister_sound(ctx: &mut Context, sound_id: u32) {
148 sound::unregister_sound(ctx, sound_id)
149}
150
151#[cfg(feature = "model-3d")]
155pub fn set_camera(ctx: &mut Context, eye: [f32; 3], target: [f32; 3], up: [f32; 3]) {
157 ctx.set_camera(eye, target, up);
158}
159
160#[cfg(feature = "model-3d")]
161pub fn camera_position(ctx: &Context) -> [f32; 3] {
163 ctx.camera_position()
164}
165
166#[cfg(feature = "model-3d")]
167pub fn set_camera_pos(ctx: &mut Context, pos: [f32; 3]) {
169 ctx.set_camera_pos(pos);
170}
171
172#[cfg(feature = "model-3d")]
173pub fn set_camera_target(ctx: &mut Context, x: f32, y: f32, z: f32) {
175 ctx.set_camera_target(x, y, z);
176}
177
178#[cfg(feature = "model-3d")]
179pub fn set_camera_up(ctx: &mut Context, x: f32, y: f32, z: f32) {
181 ctx.set_camera_up(x, y, z);
182}
183
184#[cfg(feature = "model-3d")]
185pub fn set_camera_fovy(ctx: &mut Context, fovy_degrees: f32) {
187 ctx.set_camera_fovy(fovy_degrees);
188}
189
190#[cfg(feature = "model-3d")]
191pub fn set_ambient(ctx: &mut Context, color: [f32; 4]) {
193 ctx.set_ambient(color);
194}
195
196#[cfg(feature = "model-3d")]
197pub fn set_light(ctx: &mut Context, index: usize, position: [f32; 4], color: [f32; 4]) {
199 ctx.set_light(index, position, color);
200}
201
202#[cfg(all(feature = "model-3d", feature = "effects"))]
203pub fn set_fog(ctx: &mut Context, settings: FogSettings) {
205 ctx.set_fog(settings);
206}
207
208#[cfg(all(feature = "model-3d", feature = "effects"))]
209pub fn clear_fog(ctx: &mut Context) {
211 ctx.clear_fog();
212}
213
214#[cfg(feature = "model-3d")]
215pub fn set_ambient_light(ctx: &mut Context, color: [f32; 4]) {
217 ctx.set_ambient_light(color);
218}
219
220pub fn set_window_size(ctx: &mut Context, width: Pt, height: Pt) {
222 ctx.set_window_logical_size(width, height);
223}
224
225pub fn window_size(ctx: &Context) -> (Pt, Pt) {
227 ctx.window_logical_size()
228}
229
230pub fn insert_resource<T: std::any::Any>(ctx: &mut Context, value: std::rc::Rc<T>) {
232 ctx.insert_resource(value)
233}
234
235pub fn get_resource<T: std::any::Any>(ctx: &Context) -> Option<std::rc::Rc<T>> {
237 ctx.get_resource::<T>()
238}
239
240pub fn take_resource<T: std::any::Any>(ctx: &mut Context) -> Option<std::rc::Rc<T>> {
242 ctx.take_resource::<T>()
243}
244
245pub fn scale_factor(ctx: &Context) -> f64 {
247 ctx.scale_factor()
248}
249
250pub fn vw(ctx: &Context, percent: f32) -> Pt {
252 ctx.vw(percent)
253}
254
255pub fn vh(ctx: &Context, percent: f32) -> Pt {
257 ctx.vh(percent)
258}
259
260pub fn key_down(ctx: &Context, key: Key) -> bool {
262 ctx.input().key_down(key)
263}
264
265pub fn key_pressed(ctx: &Context, key: Key) -> bool {
267 ctx.input().key_pressed(key)
268}
269
270pub fn mouse_down(ctx: &Context, btn: MouseButton) -> bool {
272 ctx.input().mouse_down(btn)
273}
274
275pub fn mouse_pressed(ctx: &Context, btn: MouseButton) -> bool {
277 ctx.input().mouse_pressed(btn)
278}
279
280pub fn mouse_pos(ctx: &Context) -> Option<(Pt, Pt)> {
282 ctx.input().cursor_position()
283}
284
285pub fn cursor_position(ctx: &Context) -> Option<(Pt, Pt)> {
287 mouse_pos(ctx)
288}
289
290pub fn touches(ctx: &Context) -> &[TouchInfo] {
292 ctx.input().touches()
293}
294
295pub fn set_window_title(ctx: &mut Context, title: impl Into<String>) {
297 ctx.set_window_title(title);
298}
299
300pub fn set_cursor_visible(ctx: &mut Context, visible: bool) {
302 ctx.set_cursor_visible(visible);
303}
304
305pub fn set_fullscreen(ctx: &mut Context, enabled: bool) {
307 ctx.set_fullscreen(enabled);
308}
309
310pub fn switch_scene_ctx<T: Spot + 'static>(_ctx: &mut Context) {
312 switch_scene::<T>();
313}
314
315pub fn switch_scene_with_ctx<T: Spot + 'static, P: std::any::Any>(_ctx: &mut Context, payload: P) {
317 switch_scene_with::<T, P>(payload);
318}
319
320pub fn quit_ctx(_ctx: &mut Context) {
322 quit();
323}
324
325pub fn delta_time(ctx: &Context) -> std::time::Duration {
329 ctx.delta_time()
330}
331
332pub fn dt(ctx: &Context) -> f32 {
336 ctx.delta_time().as_secs_f32()
337}
338
339pub fn total_elapsed(ctx: &Context) -> std::time::Duration {
341 ctx.total_elapsed()
342}
343
344#[cfg(test)]
345mod tests {
346 use super::*;
347 use crate::drawable::{DrawCommand, ImageCommand};
348
349 #[test]
350 fn test_image_culling_flip() {
351 let mut ctx = Context::new();
352 ctx.set_window_logical_size(Pt::from(800.0), Pt::from(600.0));
353
354 let img_id = 1u32;
355 let img_size = [Pt::from(100.0), Pt::from(100.0)];
356
357 let opts = DrawOption::default().with_position([Pt::from(100.0), Pt::from(100.0)]);
358 ctx.push(DrawCommand::Image(Box::new(ImageCommand {
359 id: img_id,
360 target_texture_id: 0,
361 opts,
362 shader_id: 0,
363 shader_opts: ShaderOpts::default(),
364 size: img_size,
365 })));
366 assert_eq!(
367 ctx.runtime.draw_list.len(),
368 1,
369 "Normal image should be visible"
370 );
371 ctx.runtime.draw_list.clear();
372
373 let opts = DrawOption::default()
374 .with_position([Pt::from(100.0), Pt::from(100.0)])
375 .with_scale([-1.0, 1.0]);
376 ctx.push(DrawCommand::Image(Box::new(ImageCommand {
377 id: img_id,
378 target_texture_id: 0,
379 opts,
380 shader_id: 0,
381 shader_opts: ShaderOpts::default(),
382 size: img_size,
383 })));
384 assert_eq!(
385 ctx.runtime.draw_list.len(),
386 1,
387 "Flipped H image at 100 should be visible (covers 0-100)"
388 );
389 ctx.runtime.draw_list.clear();
390
391 let opts = DrawOption::default()
392 .with_position([Pt::from(-0.1), Pt::from(100.0)])
393 .with_scale([-1.0, 1.0]);
394 ctx.push(DrawCommand::Image(Box::new(ImageCommand {
395 id: img_id,
396 target_texture_id: 0,
397 opts,
398 shader_id: 0,
399 shader_opts: ShaderOpts::default(),
400 size: img_size,
401 })));
402 assert_eq!(
403 ctx.runtime.draw_list.len(),
404 0,
405 "Flipped H image at -0.1 should be culled (covers -100 to -0.1)"
406 );
407 ctx.runtime.draw_list.clear();
408
409 let opts = DrawOption::default()
410 .with_position([Pt::from(100.0), Pt::from(100.0)])
411 .with_scale([1.0, -1.0]);
412 ctx.push(DrawCommand::Image(Box::new(ImageCommand {
413 id: img_id,
414 target_texture_id: 0,
415 opts,
416 shader_id: 0,
417 shader_opts: ShaderOpts::default(),
418 size: img_size,
419 })));
420 assert_eq!(
421 ctx.runtime.draw_list.len(),
422 1,
423 "Flipped V image at 100 should be visible (covers 0-100 in Y)"
424 );
425 ctx.runtime.draw_list.clear();
426
427 let opts = DrawOption::default()
428 .with_position([Pt::from(100.0), Pt::from(100.0)])
429 .with_scale([-1.0, -1.0]);
430 ctx.push(DrawCommand::Image(Box::new(ImageCommand {
431 id: img_id,
432 target_texture_id: 0,
433 opts,
434 shader_id: 0,
435 shader_opts: ShaderOpts::default(),
436 size: img_size,
437 })));
438 assert_eq!(
439 ctx.runtime.draw_list.len(),
440 1,
441 "Both-flipped image at 100,100 should be visible"
442 );
443 ctx.runtime.draw_list.clear();
444 }
445
446 #[test]
447 fn test_render_target_registration() {
448 let mut ctx = Context::new();
449 let texture = Texture::new_render_target(&mut ctx, Pt::from(100.0), Pt::from(200.0));
450 let image = texture.view();
451
452 assert_eq!(texture.width(), Pt::from(100.0));
453 assert_eq!(texture.height(), Pt::from(200.0));
454 assert_eq!(image.width(), Pt::from(100.0));
455 assert_eq!(image.height(), Pt::from(200.0));
456
457 let texture_entry = ctx
458 .registry
459 .textures
460 .get(texture.id() as usize)
461 .unwrap()
462 .as_ref()
463 .unwrap();
464 assert!(texture_entry.is_render_target());
465 assert_eq!(texture_entry.pixel_width, 100);
466 assert_eq!(texture_entry.pixel_height, 200);
467 }
468}