lunar_render/atlas.rs
1//! texture atlas integration for the render system.
2#![allow(clippy::missing_errors_doc, clippy::must_use_candidate)]
3//!
4//! provides [`TextureAtlas`] resource that wraps a packed atlas texture
5//! with named region lookup. sprites can reference atlas regions via
6//! `DrawKind::Sprite` with an optional `atlas_region` field.
7//!
8//! # example
9//!
10//! ```ignore
11//! use lunar_render::atlas::TextureAtlas;
12//! use lunar_atlas::{AtlasManifest, AtlasRegion};
13//!
14//! // load atlas texture via asset server
15//! let atlas_texture = asset_server.load_texture("sprites_atlas.li");
16//! let manifest = AtlasManifest::from_bytes(&manifest_bytes)?;
17//!
18//! let texture_atlas = TextureAtlas::new(atlas_texture, manifest);
19//! let region = texture_atlas.region("player_idle");
20//! ```
21
22use lunar_assets::Handle;
23use lunar_assets::Texture;
24use lunar_atlas::{AtlasManifest, AtlasRegion};
25
26/// a loaded texture atlas with GPU texture handle and region lookup.
27pub struct TextureAtlas {
28 /// handle to the atlas GPU texture
29 pub texture: Handle<Texture>,
30 /// manifest describing region layout
31 pub manifest: AtlasManifest,
32 /// pre-computed UV regions for fast lookup
33 regions: rustc_hash::FxHashMap<String, AtlasRegion>,
34}
35
36impl TextureAtlas {
37 /// create a new texture atlas from a loaded texture and manifest.
38 #[must_use]
39 pub fn new(texture: Handle<Texture>, manifest: AtlasManifest) -> Self {
40 let regions = manifest.resolve_regions();
41 Self {
42 texture,
43 manifest,
44 regions,
45 }
46 }
47
48 /// look up a region by name.
49 ///
50 /// returns the [`AtlasRegion`] with UV coordinates for this sprite.
51 /// # Panics
52 ///
53 /// panics if the region does not exist.
54 #[must_use]
55 pub fn region(&self, name: &str) -> &AtlasRegion {
56 self.regions
57 .get(name)
58 .unwrap_or_else(|| panic!("atlas region '{name}' not found"))
59 }
60
61 /// look up a region by name, returning None if not found.
62 #[must_use]
63 pub fn try_region(&self, name: &str) -> Option<&AtlasRegion> {
64 self.regions.get(name)
65 }
66
67 /// get the atlas texture handle.
68 #[must_use]
69 pub const fn texture_handle(&self) -> &Handle<Texture> {
70 &self.texture
71 }
72
73 /// get all region names.
74 pub fn region_names(&self) -> impl Iterator<Item = &String> {
75 self.regions.keys()
76 }
77}