#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TexturePreviewConfig {
pub background: [f32; 4],
pub max_zoom: f32,
pub min_zoom: f32,
pub auto_mips: bool,
}
#[allow(dead_code)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TexelFormat {
Rgba8,
Rgb8,
Grayscale8,
Hdr,
}
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub struct TexturePreview {
pub width: u32,
pub height: u32,
pub format: TexelFormat,
pub mip_count: u32,
pub zoom: f32,
pub pixels: Vec<f32>,
}
#[allow(dead_code)]
pub fn default_texture_preview_config() -> TexturePreviewConfig {
TexturePreviewConfig {
background: [0.1, 0.1, 0.1, 1.0],
max_zoom: 16.0,
min_zoom: 0.0625,
auto_mips: true,
}
}
#[allow(dead_code)]
pub fn new_texture_preview(width: u32, height: u32, format: TexelFormat) -> TexturePreview {
let mip_count = if width > 0 && height > 0 {
let max_dim = width.max(height);
(max_dim as f32).log2().floor() as u32 + 1
} else {
1
};
let pixel_count = (width as usize) * (height as usize) * 4;
TexturePreview {
width,
height,
format,
mip_count,
zoom: 1.0,
pixels: vec![0.0f32; pixel_count],
}
}
#[allow(dead_code)]
pub fn texture_preview_width(preview: &TexturePreview) -> u32 {
preview.width
}
#[allow(dead_code)]
pub fn texture_preview_height(preview: &TexturePreview) -> u32 {
preview.height
}
#[allow(dead_code)]
pub fn texture_preview_format(preview: &TexturePreview) -> TexelFormat {
preview.format
}
#[allow(dead_code)]
pub fn texture_preview_mip_count(preview: &TexturePreview) -> u32 {
preview.mip_count
}
#[allow(dead_code)]
pub fn set_texture_preview_zoom(preview: &mut TexturePreview, zoom: f32) {
preview.zoom = zoom.clamp(0.0625, 16.0);
}
#[allow(dead_code)]
pub fn texture_preview_sample(preview: &TexturePreview, u: f32, v: f32) -> [f32; 4] {
if preview.width == 0 || preview.height == 0 || preview.pixels.is_empty() {
return [0.0; 4];
}
let px = (u * preview.width as f32).floor() as i32;
let py = (v * preview.height as f32).floor() as i32;
if px < 0 || px >= preview.width as i32 || py < 0 || py >= preview.height as i32 {
return [0.0; 4];
}
let idx = (py as usize * preview.width as usize + px as usize) * 4;
if idx + 3 >= preview.pixels.len() {
return [0.0; 4];
}
[
preview.pixels[idx],
preview.pixels[idx + 1],
preview.pixels[idx + 2],
preview.pixels[idx + 3],
]
}
#[allow(dead_code)]
pub fn texel_format_name(fmt: TexelFormat) -> &'static str {
match fmt {
TexelFormat::Rgba8 => "RGBA8",
TexelFormat::Rgb8 => "RGB8",
TexelFormat::Grayscale8 => "Grayscale8",
TexelFormat::Hdr => "HDR",
}
}
#[allow(dead_code)]
pub fn texel_format_channels(fmt: TexelFormat) -> u32 {
match fmt {
TexelFormat::Rgba8 => 4,
TexelFormat::Rgb8 => 3,
TexelFormat::Grayscale8 => 1,
TexelFormat::Hdr => 4,
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_config() {
let cfg = default_texture_preview_config();
assert!(cfg.auto_mips);
assert!((cfg.max_zoom - 16.0).abs() < 1e-6);
assert!((cfg.min_zoom - 0.0625).abs() < 1e-6);
}
#[test]
fn test_new_preview_dimensions() {
let p = new_texture_preview(64, 64, TexelFormat::Rgba8);
assert_eq!(texture_preview_width(&p), 64);
assert_eq!(texture_preview_height(&p), 64);
}
#[test]
fn test_new_preview_mip_count() {
let p = new_texture_preview(64, 64, TexelFormat::Rgba8);
assert_eq!(texture_preview_mip_count(&p), 7);
}
#[test]
fn test_new_preview_format() {
let p = new_texture_preview(32, 32, TexelFormat::Hdr);
assert_eq!(texture_preview_format(&p), TexelFormat::Hdr);
}
#[test]
fn test_set_zoom_clamp() {
let mut p = new_texture_preview(32, 32, TexelFormat::Rgba8);
set_texture_preview_zoom(&mut p, 100.0);
assert!((p.zoom - 16.0).abs() < 1e-6);
set_texture_preview_zoom(&mut p, 0.0);
assert!((p.zoom - 0.0625).abs() < 1e-6);
}
#[test]
fn test_sample_out_of_range() {
let p = new_texture_preview(4, 4, TexelFormat::Rgba8);
let sample = texture_preview_sample(&p, 1.5, 1.5);
assert_eq!(sample, [0.0; 4]);
}
#[test]
fn test_sample_zero_pixels() {
let p = new_texture_preview(2, 2, TexelFormat::Rgba8);
let sample = texture_preview_sample(&p, 0.1, 0.1);
assert_eq!(sample, [0.0; 4]);
}
#[test]
fn test_texel_format_name() {
assert_eq!(texel_format_name(TexelFormat::Rgba8), "RGBA8");
assert_eq!(texel_format_name(TexelFormat::Rgb8), "RGB8");
assert_eq!(texel_format_name(TexelFormat::Grayscale8), "Grayscale8");
assert_eq!(texel_format_name(TexelFormat::Hdr), "HDR");
}
#[test]
fn test_texel_format_channels() {
assert_eq!(texel_format_channels(TexelFormat::Rgba8), 4);
assert_eq!(texel_format_channels(TexelFormat::Rgb8), 3);
assert_eq!(texel_format_channels(TexelFormat::Grayscale8), 1);
assert_eq!(texel_format_channels(TexelFormat::Hdr), 4);
}
}