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