1use super::{args::*, format::*, spec::*, *};
2
3derive_common_VAL! {
4pub struct TexParam {
5 pub w: i32,
6 pub h: i32,
7 pub d: i32,
8 pub l: i32,
9}}
10impl TexParam {
11 pub fn gen_mips(mut self) -> Self {
12 self.l = self.mips_max();
13 self
14 }
15 pub fn size<T>(self, lvl: T) -> usize
16 where
17 u32: Cast<T>,
18 {
19 let (w, h, d) = ulVec3(self.dim(lvl));
20 w * h * d
21 }
22 pub fn dim<T>(self, lvl: T) -> iVec3
23 where
24 u32: Cast<T>,
25 {
26 let lvl = u32(lvl);
27 ASSERT!(i32(lvl) < self.l, "Texture level {lvl} out of bounds, only has {} levels", self.l);
28 self.dim_unchecked(lvl)
29 }
30 pub fn dim_unchecked(self, lvl: u32) -> iVec3 {
31 let (lvl, Self { w, h, d, .. }) = (u32(lvl), self);
32 if lvl == 0 {
33 return (w, h, d);
34 }
35 let div = |v| 1.max(i32((f64(v) / f64(2_u32.pow(lvl))).floor()));
36 (div(w), div(h), div(d))
37 }
38 pub fn mips_max(&self) -> i32 {
39 let &Self { w, h, d, .. } = self;
40 let w = w.max(h).max(d);
41 1 + i32(f64(w).log2())
42 }
43 pub fn validate(self) -> Self {
44 let (_l, _m) = (self.l, self.mips_max());
45 ASSERT!(_l > 0 && _l <= _m, "Texture dimensions allow 1 to {} levels, asked for {_l}", _m);
46 self
47 }
48}
49
50#[derive(Default, Debug)]
51pub struct Tex<S, F, T: TexType> {
52 pub param: TexParam,
53 tex: Object<Texture<T>>,
54 unit: Cell<u32>,
55 s: Dummy<S>,
56 f: Dummy<F>,
57}
58macro_rules! impl_tex {
59 ($t: ty, $dim: ident, $arg_u: ident) => {
60 impl<S: TexSize, F: TexFmt> Tex<S, F, $t> {
61 pub fn new<D>(dimensions: D, args_u: impl $arg_u<F>) -> Self
62 where
63 $dim: Cast<D>,
64 {
65 let mut tex = Self::new_empty(dimensions, 1);
66 tex.Update(args_u);
67 tex
68 }
69 pub fn new_mips<D>(dimensions: D, args_u: impl $arg_u<F>) -> Self
70 where
71 $dim: Cast<D>,
72 {
73 let mut tex = Self::new_empty(dimensions, -1);
74 tex.Update(args_u);
75 GL!(glGenMipmaps(<$t>::TYPE, tex.tex.obj));
76 tex
77 }
78 pub fn new_empty<D, M>(dim: D, mip_levels: M) -> Self
79 where
80 $dim: Cast<D>,
81 i16: Cast<M>,
82 {
83 let (tex, f, s, l) = (Object::new(), Dummy, Dummy, i16(mip_levels) as i32);
84 let fmt = normalize_internal_fmt(get_internal_fmt::<S, F>());
85 macro_rules! tex_new {
86 (i32) => {{
87 let w = i32(dim);
88 let p = TexParam { w, h: 1, d: 1, l };
89 let p = if l > 0 { p.validate() } else { p.gen_mips() };
90 GL!(glTextureStorage1D(<$t>::TYPE, tex.obj, p.l, fmt, w));
91 p
92 }};
93 (iVec2) => {{
94 let (w, h) = iVec2(dim);
95 let p = TexParam { w, h, d: 1, l };
96 let p = if l > 0 { p.validate() } else { p.gen_mips() };
97 GL!(glTextureStorage2D(<$t>::TYPE, tex.obj, p.l, fmt, w, h));
98 p
99 }};
100 (iVec3) => {{
101 let (w, h, d) = iVec3(dim);
102 let p = TexParam { w, h, d, l };
103 let p = if l > 0 { p.validate() } else { p.gen_mips() };
104 GL!(glTextureStorage3D(<$t>::TYPE, tex.obj, p.l, fmt, w, h, d));
105 p
106 }};
107 }
108 let param = tex_new!($dim);
109 Self { param, tex, unit: Def(), s, f }
110 }
111 pub fn Update(&mut self, args: impl $arg_u<F>) {
112 self.UpdateCustom::<S, F, _>(args);
113 }
114 pub fn UpdateCustom<RS: TexSize, RF: TexFmt, T: $arg_u<RF>>(&mut self, args: T) {
115 let mip_size = |lvl, _len| {
116 ASSERT!(
117 _len <= self.param.size(u32(lvl)) * usize(S::SIZE),
118 "Texture data out of bounds at level {lvl}, size should be {}, given {_len}",
119 self.param.size(u32(lvl)) * usize(S::SIZE)
120 );
121 self.param.dim(lvl)
122 };
123 GL::PixelStoreUnpack::Set(1);
124 macro_rules! tex_new {
125 (UpdArgs1) => {{
126 let (data, lvl, x, len) = args.get1();
127 let (w, _, _) = mip_size(lvl, len);
128 GL!(glTextureSubImage1D(<$t>::TYPE, self.tex.obj, lvl, x, w, RS::TYPE, RF::TYPE, data));
129 }};
130 (UpdArgs2) => {{
131 let (data, lvl, x, y, len) = args.get2();
132 let (w, h, _) = mip_size(lvl, len);
133 GL!(glTextureSubImage2D(<$t>::TYPE, self.tex.obj, lvl, x, y, w, h, RS::TYPE, RF::TYPE, data));
134 }};
135 (UpdArgs3) => {{
136 let (data, lvl, x, y, z, len) = args.get3();
137 let (w, h, d) = mip_size(lvl, len);
138 GL!(glTextureSubImage3D(<$t>::TYPE, self.tex.obj, lvl, x, y, z, w, h, d, RS::TYPE, RF::TYPE, data));
139 }};
140 }
141 tex_new!($arg_u);
142 }
143 }
144 };
145}
146impl<S, F, T: TexType> Tex<S, F, T> {
147 pub fn obj(&self) -> u32 {
148 self.tex.obj
149 }
150 pub fn Save<RS: TexSize, RF: TexFmt>(&self, lvl: u32) -> Box<[RF]> {
151 ASSERT!(T::TYPE != gl::TEXTURE_CUBE_MAP && T::TYPE != gl::TEXTURE_CUBE_MAP_ARRAY, "unimpl");
152 let size = self.param.size(lvl) * usize(RS::SIZE);
153 let v = vec![Def(); size].into_boxed_slice();
154 let size = i32(size * type_size::<RF>());
155 GL::PixelStorePack::Set(1);
156 GL!(glGetTexture(T::TYPE, self.tex.obj, i32(lvl), RS::TYPE, RF::TYPE, size, v.as_ptr() as *mut GLvoid));
157 v
158 }
159 pub fn Bind<'l>(&'l self, samp: &'l Sampler) -> TextureBinding<T> {
160 let unit = self.unit.take();
161 let (b, u) = TextureBinding::new(&self.tex, samp, unit);
162 self.unit.set(u);
163 b
164 }
165}
166impl_tex!(GL_TEXTURE_1D, i32, UpdArgs1);
167impl_tex!(GL_TEXTURE_2D, iVec2, UpdArgs2);
168impl_tex!(GL_TEXTURE_3D, iVec3, UpdArgs3);
169impl_tex!(GL_TEXTURE_1D_ARRAY, iVec2, UpdArgs2);
170impl_tex!(GL_TEXTURE_2D_ARRAY, iVec3, UpdArgs3);
171impl_tex!(GL_TEXTURE_CUBE_MAP, iVec2, UpdArgs3);
172impl_tex!(GL_TEXTURE_CUBE_MAP_ARRAY, iVec3, UpdArgs3);
173
174#[derive(Debug)]
175pub struct TextureBinding<'l, T> {
176 t: Dummy<&'l T>,
177 pub u: u32,
178}
179impl<'l, T: TexType> TextureBinding<'l, T> {
180 pub fn new(o: &'l Object<Texture<T>>, samp: &'l Sampler, hint: u32) -> (Self, u32) {
181 let u = TexState::Bind::<T>(o.obj, samp.obj, hint);
182 (Self { t: Dummy, u }, u)
183 }
184}
185impl<T: TexType> Clone for TextureBinding<'_, T> {
186 fn clone(&self) -> Self {
187 let &Self { t, u } = self;
188 TexState::Clone(u);
189 Self { t, u }
190 }
191}
192impl<T> Drop for TextureBinding<'_, T> {
193 fn drop(&mut self) {
194 TexState::Unbind(self.u);
195 }
196}