pub mod atlas;
pub mod bindings;
pub mod config;
pub mod depth;
pub mod paint_texture;
pub mod pipelines;
pub mod present;
pub mod shader_src;
pub mod strips;
pub mod targets;
pub use atlas::{ATLAS_FORMAT, ATLAS_USAGES, AtlasArray, lower_encoded_image};
pub use bindings::{ExternalRuns, ExternalTextures, lower_encoded_external};
pub use config::{GpuConfig, tex_width_bits};
pub use depth::{DepthAttachment, DepthTexture};
pub use paint_texture::{
GpuBlurredRoundedRect, GpuEncodedImage, GpuEncodedPaint, GpuLinearGradient, GpuRadialGradient,
GpuSweepGradient,
};
pub use pipelines::{EnginePipeline, EngineShaderModule, EngineShaders};
pub use strips::{GpuStrip, StripDraw};
pub use targets::{IntermediateTargets, IntermediateTexture};
use crate::EngineError;
pub const RESOURCE_TEXTURE_FORMAT: wgpu::TextureFormat = wgpu::TextureFormat::Rgba32Uint;
pub const RESOURCE_TEXTURE_USAGES: wgpu::TextureUsages =
wgpu::TextureUsages::TEXTURE_BINDING.union(wgpu::TextureUsages::COPY_DST);
pub const TEXEL_BYTES_SHIFT: u32 = 4;
pub const TEXEL_BYTES: u32 = 1 << TEXEL_BYTES_SHIFT;
pub const ALPHAS_PER_TEXEL: u32 = TEXEL_BYTES;
pub const ALPHAS_PER_CHANNEL: u32 = 4;
pub const MIN_RESOURCE_TEXTURE_HEIGHT: u32 = 1;
#[must_use]
pub const fn resource_bytes_per_row(width: u32) -> u32 {
width << TEXEL_BYTES_SHIFT
}
#[must_use]
pub const fn resource_texture_bytes(width: u32, height: u32) -> u64 {
(width as u64 * height as u64) << TEXEL_BYTES_SHIFT
}
#[must_use]
pub fn resource_texture_descriptor(
label: &str,
width: u32,
height: u32,
) -> wgpu::TextureDescriptor<'_> {
wgpu::TextureDescriptor {
label: Some(label),
size: wgpu::Extent3d {
width,
height,
depth_or_array_layers: 1,
},
mip_level_count: 1,
sample_count: 1,
dimension: wgpu::TextureDimension::D2,
format: RESOURCE_TEXTURE_FORMAT,
usage: RESOURCE_TEXTURE_USAGES,
view_formats: &[],
}
}
#[must_use]
pub fn alpha_texture_descriptor(width: u32, height: u32) -> wgpu::TextureDescriptor<'static> {
resource_texture_descriptor("frust-engine alpha texture", width, height)
}
pub fn alpha_texture_height(
alphas_len: usize,
resource_texture_dim: u32,
) -> Result<u32, EngineError> {
let alphas_len = u32::try_from(alphas_len).map_err(|_| EngineError::AlphaCapacity)?;
let required = alphas_len.div_ceil(resource_texture_dim << TEXEL_BYTES_SHIFT);
if required > resource_texture_dim {
return Err(EngineError::AlphaCapacity);
}
Ok(required.max(MIN_RESOURCE_TEXTURE_HEIGHT))
}
pub fn grow_alpha_texture_height(
current_height: u32,
alphas_len: usize,
resource_texture_dim: u32,
) -> Result<Option<u32>, EngineError> {
let required = alpha_texture_height(alphas_len, resource_texture_dim)?;
Ok((required > current_height).then_some(required))
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct AlphaAddress {
pub x: u32,
pub y: u32,
pub channel: u32,
pub byte: u32,
}
impl AlphaAddress {
#[must_use]
pub const fn byte_offset(self, width: u32) -> u32 {
((self.y * width + self.x) << TEXEL_BYTES_SHIFT)
+ self.channel * ALPHAS_PER_CHANNEL
+ self.byte
}
}
#[must_use]
pub const fn alpha_address(alpha_idx: u32, width: u32) -> AlphaAddress {
let texel = alpha_idx >> TEXEL_BYTES_SHIFT;
let within = alpha_idx & (ALPHAS_PER_TEXEL - 1);
AlphaAddress {
x: texel % width,
y: texel / width,
channel: within / ALPHAS_PER_CHANNEL,
byte: within % ALPHAS_PER_CHANNEL,
}
}
pub fn with_padded_alphas<R>(
alphas: &mut Vec<u8>,
width: u32,
height: u32,
upload: impl FnOnce(&[u8]) -> R,
) -> R {
let original_len = alphas.len();
let padded_len = resource_texture_bytes(width, height);
let padded_len = usize::try_from(padded_len)
.unwrap_or(usize::MAX)
.max(original_len);
alphas.resize(padded_len, 0);
let result = upload(alphas);
alphas.truncate(original_len);
result
}