1use crabslab::SlabItem;
15
16#[cfg(cpu)]
17mod atlas_image;
18#[cfg(cpu)]
19pub use atlas_image::*;
20#[cfg(cpu)]
21mod cpu;
22#[cfg(cpu)]
23pub use cpu::*;
24
25pub mod shader;
26
27#[derive(
29 Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, SlabItem, core::fmt::Debug,
30)]
31pub struct TextureModes {
32 pub s: TextureAddressMode,
33 pub t: TextureAddressMode,
34}
35
36pub fn repeat(mut input: f32) -> f32 {
40 let gto = input >= 1.0;
41 input %= 1.0;
42 if gto && input == 0.0 {
43 1.0
44 } else {
45 input
46 }
47}
48
49pub fn clamp(input: f32) -> f32 {
51 if input > 1.0 {
52 1.0 - f32::EPSILON
53 } else if input < 0.0 {
54 0.0 + f32::EPSILON
55 } else {
56 input
57 }
58}
59
60#[repr(u32)]
62#[derive(
63 Clone, Copy, Default, PartialEq, Eq, Hash, PartialOrd, Ord, SlabItem, core::fmt::Debug,
64)]
65pub enum TextureAddressMode {
66 #[default]
67 ClampToEdge,
68 Repeat,
69 MirroredRepeat,
70}
71
72impl core::fmt::Display for TextureAddressMode {
73 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
74 f.write_str(match *self {
75 TextureAddressMode::ClampToEdge => "clamp to edge",
76 TextureAddressMode::Repeat => "repeat",
77 TextureAddressMode::MirroredRepeat => "mirrored repeat",
78 })
79 }
80}
81
82impl TextureAddressMode {
83 pub fn wrap(&self, input: f32) -> f32 {
86 match self {
87 TextureAddressMode::Repeat => {
88 let sign = if input >= 0.0 { 1.0f32 } else { -1.0 };
89 let input = repeat(input.abs());
90 if sign > 0.0 {
91 input
92 } else {
93 1.0 - input
94 }
95 }
96 TextureAddressMode::MirroredRepeat => {
97 let sign = if input >= 0.0 { 1.0f32 } else { -1.0 };
98 let i = input.abs();
99 #[cfg_attr(
102 cpu,
103 expect(
104 clippy::manual_is_multiple_of,
105 reason = "rust-gpu is not yet on rustc 1.91, which introduced this lint"
106 )
107 )]
108 let flip = ((i as u32) % 2) == 0;
109 let t = repeat(i);
110 if sign > 0.0 {
111 if flip {
112 t
113 } else {
114 1.0 - t
115 }
116 } else if flip {
117 1.0 - t
118 } else {
119 t
120 }
121 }
122 _ => clamp(input),
123 }
124 }
125}
126
127#[cfg(test)]
128mod test {
129 use glam::{UVec2, UVec3, Vec2, Vec3Swizzles, Vec4Swizzles};
130
131 use crate::atlas::shader::AtlasTextureDescriptor;
132
133 use super::*;
134
135 #[test]
136 fn can_repeat() {
137 assert_eq!(0.0, TextureAddressMode::Repeat.wrap(0.0));
138 assert_eq!(1.0, TextureAddressMode::Repeat.wrap(2.0));
139 assert_eq!(1.0, TextureAddressMode::Repeat.wrap(3.0));
140 }
141
142 #[test]
143 fn constrain_clip_coords_sanity() {
146 let atlas_texture = AtlasTextureDescriptor {
147 offset_px: UVec2::splat(0),
148 size_px: UVec2::splat(800),
149 layer_index: 0,
150 frame_index: 0,
151 modes: TextureModes {
152 s: TextureAddressMode::ClampToEdge,
153 t: TextureAddressMode::ClampToEdge,
154 },
155 };
156 let atlas_size = UVec3::new(1024, 1024, 4);
157 let corners @ [tl, tr, br, bl] = [
158 crate::math::CLIP_SPACE_COORD_QUAD_CCW_TL,
159 crate::math::CLIP_SPACE_COORD_QUAD_CCW_TR,
160 crate::math::CLIP_SPACE_COORD_QUAD_CCW_BR,
161 crate::math::CLIP_SPACE_COORD_QUAD_CCW_BL,
162 ]
163 .map(|coord| {
164 atlas_texture.constrain_clip_coords_to_texture_space(coord.xy(), atlas_size.xy())
165 });
166 log::info!("uv_corners: {corners:#?}");
167
168 let clip_br = crate::math::CLIP_SPACE_COORD_QUAD_CCW_BR.xy();
169 log::info!("clip_br: {clip_br}");
170 let input_uv_br = (clip_br * Vec2::new(1.0, -1.0) + Vec2::splat(1.0)) * Vec2::splat(0.5);
171 log::info!("input_uv_br: {input_uv_br}");
172 assert_eq!(Vec2::ONE, input_uv_br, "incorrect uv");
173
174 let d = 800.0 / 1024.0;
175 assert_eq!(Vec2::splat(0.0), tl, "incorrect tl");
176 assert_eq!(Vec2::new(d, 0.0), tr, "incorrect tr");
177 assert_eq!(Vec2::new(d, d), br, "incorrect br");
178 assert_eq!(Vec2::new(0.0, d), bl, "incorrect bl");
179
180 let corners = [
181 crate::math::CLIP_SPACE_COORD_QUAD_CCW_TL,
182 crate::math::CLIP_SPACE_COORD_QUAD_CCW_TR,
183 crate::math::CLIP_SPACE_COORD_QUAD_CCW_BR,
184 crate::math::CLIP_SPACE_COORD_QUAD_CCW_BL,
185 ]
186 .map(|coord| atlas_texture.constrain_clip_coords(coord.xy(), atlas_size.xy()));
187 log::info!("clip_corners: {corners:#?}");
188 }
207}