extern crate futures_util;
extern crate gl;
extern crate ktx_async as ktx;
extern crate lazy_static;
extern crate tokio;
use futures_util::stream::StreamExt as _;
use ktx::Decoder;
use lazy_static::lazy_static;
use tokio::fs::File;
const GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT: u32 = 0x8A57;
const GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: u32 = 0x83F3;
const GL_COMPRESSED_RGB8_ETC2: u32 = 0x9274;
const GL_ETC1_RGB8_OES: u32 = 0x8D64;
#[allow(non_upper_case_globals)]
const GL_COMPRESSED_RGBA_ASTC_8x8_KHR: u32 = 0x93B7;
#[tokio::test]
async fn test_rgb_reference() {
let path = "data/khr/rgb-reference.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, gl::UNSIGNED_BYTE);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, gl::RGB);
assert_eq!(info.gl_internal_format, gl::RGB8);
assert_eq!(info.gl_base_internal_format, gl::RGB);
assert_eq!(info.pixel_width, 128);
assert_eq!(info.pixel_height, 128);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 1);
let (frame, buf) = stream.next().await.map(|r| r.unwrap()).unwrap();
let expected_image_size = ((128 * 3 + 3) / 4) * 4 * 128;
assert_eq!(frame.level, 0);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, 128);
assert_eq!(frame.pixel_height, 128);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
}
#[tokio::test]
async fn test_rgb_mipmap_reference() {
let path = "data/khr/rgb-mipmap-reference.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, gl::UNSIGNED_BYTE);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, gl::RGB);
assert_eq!(info.gl_internal_format, gl::RGB8);
assert_eq!(info.gl_base_internal_format, gl::RGB);
assert_eq!(info.pixel_width, 64);
assert_eq!(info.pixel_height, 64);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 7);
let mut level = 0;
while let Some((frame, buf)) = stream.next().await.map(|r| r.unwrap()) {
let width = info.pixel_width >> level;
let height = info.pixel_height >> level;
let expected_image_size = ((width * 3 + 3) / 4) * 4 * height;
assert_eq!(frame.level, level);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, width);
assert_eq!(frame.pixel_height, height);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size as usize);
level += 1;
}
assert!(stream.next().await.is_none());
}
#[tokio::test]
async fn test_rgba_reference() {
let path = "data/khr/rgba-reference.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, gl::UNSIGNED_BYTE);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, gl::RGBA);
assert_eq!(info.gl_internal_format, gl::RGBA8);
assert_eq!(info.gl_base_internal_format, gl::RGBA);
assert_eq!(info.pixel_width, 128);
assert_eq!(info.pixel_height, 128);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 1);
let (frame, buf) = stream.next().await.map(|r| r.unwrap()).unwrap();
let expected_image_size = ((128 * 4 + 3) / 4) * 4 * 128;
assert_eq!(frame.level, 0);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, 128);
assert_eq!(frame.pixel_height, 128);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
}
#[tokio::test]
async fn test_etc1() {
let path = "data/khr/etc1.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, 0);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, 0);
assert_eq!(info.gl_internal_format, GL_ETC1_RGB8_OES);
assert_eq!(info.gl_base_internal_format, gl::RGB);
assert_eq!(info.pixel_width, 128);
assert_eq!(info.pixel_height, 128);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 1);
let (frame, buf) = stream.next().await.map(|r| r.unwrap()).unwrap();
let expected_image_size = etc1_block_image_size(128, 128) as usize;
assert_eq!(frame.level, 0);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, 128);
assert_eq!(frame.pixel_height, 128);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
}
#[tokio::test]
async fn test_cubemap_etc2() {
let path = "data/khr/cubemap_yokohama_etc2_unorm.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, 0);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, 0);
assert_eq!(info.gl_internal_format, GL_COMPRESSED_RGB8_ETC2);
assert_eq!(info.gl_base_internal_format, gl::RGB);
assert_eq!(info.pixel_width, 512);
assert_eq!(info.pixel_height, 512);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 6);
assert_eq!(info.number_of_mipmap_levels, 1);
let mut face = 0;
while let Some((frame, buf)) = stream.next().await.map(|r| r.unwrap()) {
let expected_image_size = etc2_block_image_size(512, 512) as usize;
assert_eq!(frame.level, 0);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, face);
assert_eq!(frame.pixel_width, 512);
assert_eq!(frame.pixel_height, 512);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
face += 1;
}
}
#[tokio::test]
async fn test_cubemap_mipmap_reference() {
let path = "data/khr/cubemap_yokohama_astc_8x8_unorm.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, 0);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, 0);
assert_eq!(info.gl_internal_format, GL_COMPRESSED_RGBA_ASTC_8x8_KHR);
assert_eq!(info.gl_base_internal_format, gl::RGBA);
assert_eq!(info.pixel_width, 512);
assert_eq!(info.pixel_height, 512);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 0);
assert_eq!(info.number_of_faces, 6);
assert_eq!(info.number_of_mipmap_levels, 10);
for level in 0..10 {
let width = 512 >> level;
let height = 512 >> level;
for face in 0..6 {
let (frame, buf) = stream.next().await.map(|r| r.unwrap()).unwrap();
assert_eq!(frame.level, level);
assert_eq!(frame.layer, 0);
assert_eq!(frame.face, face);
assert_eq!(frame.pixel_width, width);
assert_eq!(frame.pixel_height, height);
assert_eq!(frame.pixel_depth, 1);
let _ = buf;
}
}
}
#[tokio::test]
async fn test_array_pvrtc() {
let path = "data/pvr/array-pvrtc-mipmap.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, 0);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, 0);
assert_eq!(
info.gl_internal_format,
GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT
);
assert_eq!(info.gl_base_internal_format, gl::RGBA);
assert_eq!(info.pixel_width, 256);
assert_eq!(info.pixel_height, 256);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 7);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 9);
for level in 0..9 {
let width = 256 >> level;
let height = 256 >> level;
for layer in 0..7 {
let (frame, buf) = stream.next().await.map(|r| r.unwrap()).unwrap();
let expected_image_size = pvrtc4bppv1_block_image_size(width, height) as usize;
assert_eq!(frame.level, level);
assert_eq!(frame.layer, layer);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, width);
assert_eq!(frame.pixel_height, height);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
}
}
}
#[tokio::test]
async fn test_array_bc3_unorm() {
let path = "data/khr/texturearray_bc3_unorm.ktx";
let file = File::open(PROJECT_DIR.join(path)).await.unwrap();
let decoder = Decoder::new(file);
let (info, mut stream) = decoder.read_async().await.unwrap();
assert_eq!(info.gl_type, 0);
assert_eq!(info.gl_type_size, 1);
assert_eq!(info.gl_format, 0);
assert_eq!(info.gl_internal_format, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT);
assert_eq!(info.gl_base_internal_format, gl::RGBA);
assert_eq!(info.pixel_width, 256);
assert_eq!(info.pixel_height, 256);
assert_eq!(info.pixel_depth, 0);
assert_eq!(info.number_of_array_elements, 7);
assert_eq!(info.number_of_faces, 1);
assert_eq!(info.number_of_mipmap_levels, 1);
let mut lyr = 0;
while let Some((frame, buf)) = stream.next().await.map(|r| r.unwrap()) {
let expected_image_size = bc3_block_image_size(256, 256) as usize;
assert_eq!(frame.level, 0);
assert_eq!(frame.layer, lyr);
assert_eq!(frame.face, 0);
assert_eq!(frame.pixel_width, 256);
assert_eq!(frame.pixel_height, 256);
assert_eq!(frame.pixel_depth, 1);
assert_eq!(buf.len(), expected_image_size);
lyr += 1;
}
}
lazy_static! {
static ref PROJECT_DIR: std::path::PathBuf = {
use std::env::var_os;
var_os("CARGO_MANIFEST_DIR")
.map(|s| std::path::PathBuf::from(s))
.unwrap()
};
}
fn pvrtc4bppv1_block_image_size(w: u32, h: u32) -> u32 {
use std::cmp::max;
(max(w, 8) * max(h, 8) * 4 + 7) / 8
}
fn bc3_block_image_size(w: u32, h: u32) -> u32 {
let bw = (w + 3) / 4;
let bh = (h + 3) / 4;
(16 * bw * bh)
}
fn etc2_block_image_size(w: u32, h: u32) -> u32 {
let bw = (w + 3) / 4;
let bh = (h + 3) / 4;
(8 * bw * bh)
}
fn etc1_block_image_size(w: u32, h: u32) -> u32 {
let bw = (w + 3) / 4;
let bh = (h + 3) / 4;
(8 * bw * bh)
}