use crate::assets::image::{ImageAssetDataLayer, ImageAssetDataMipLevel};
use crate::schema::{
GpuCompressedImageAssetRecord, GpuCompressedImageImportedDataRecord,
GpuImageAssetDataFormatEnum,
};
use crate::ImageAssetDataFormat;
use ddsfile::DxgiFormat;
use hydrate_data::Record;
use hydrate_pipeline::{ImportContext, Importer, PipelineResult, ScanContext};
use std::sync::Arc;
use type_uuid::*;
#[derive(TypeUuid, Default)]
#[uuid = "a66a5767-0a03-4c3e-ac06-ce02c1a0a561"]
pub struct GpuCompressedImageImporterDds;
impl Importer for GpuCompressedImageImporterDds {
fn supported_file_extensions(&self) -> &[&'static str] {
&["dds"]
}
fn scan_file(
&self,
context: ScanContext,
) -> PipelineResult<()> {
context.add_default_importable::<GpuCompressedImageAssetRecord>()?;
Ok(())
}
fn import_file(
&self,
context: ImportContext,
) -> PipelineResult<()> {
let dds_bytes = std::fs::read(context.path).unwrap();
let dds = ddsfile::Dds::read(&mut &dds_bytes[..]).unwrap();
let format = if let Some(dxgi_format) = dds.get_dxgi_format() {
match dxgi_format {
DxgiFormat::BC1_UNorm => ImageAssetDataFormat::BC1_UNorm_Linear,
DxgiFormat::BC1_UNorm_sRGB => ImageAssetDataFormat::BC1_UNorm_Srgb,
DxgiFormat::BC2_UNorm => ImageAssetDataFormat::BC2_UNorm_Linear,
DxgiFormat::BC2_UNorm_sRGB => ImageAssetDataFormat::BC2_UNorm_Srgb,
DxgiFormat::BC3_UNorm => ImageAssetDataFormat::BC3_UNorm_Linear,
DxgiFormat::BC3_UNorm_sRGB => ImageAssetDataFormat::BC3_UNorm_Srgb,
DxgiFormat::BC4_UNorm => ImageAssetDataFormat::BC4_UNorm,
DxgiFormat::BC4_SNorm => ImageAssetDataFormat::BC4_SNorm,
DxgiFormat::BC5_UNorm => ImageAssetDataFormat::BC5_UNorm,
DxgiFormat::BC5_SNorm => ImageAssetDataFormat::BC5_SNorm,
DxgiFormat::BC6H_UF16 => ImageAssetDataFormat::BC6H_UFloat,
DxgiFormat::BC6H_SF16 => ImageAssetDataFormat::BC6H_SFloat,
DxgiFormat::BC7_UNorm => ImageAssetDataFormat::BC7_Unorm_Linear,
DxgiFormat::BC7_UNorm_sRGB => ImageAssetDataFormat::BC7_Unorm_Srgb,
_ => unimplemented!(),
}
} else {
unimplemented!();
};
let width = dds.get_width();
let height = dds.get_height();
let array_layer_count = dds.get_num_array_layers();
let mip_level_count = dds.get_num_mipmap_levels();
if dds.get_depth() != 1 {
unimplemented!("DDS importer only supports image depth = 1");
}
log::trace!(
"w: {} h: {} layers: {} mips: {} format: {:?} dxgi_format: {:?} d3d_format: {:?}",
width,
height,
array_layer_count,
mip_level_count,
format,
dds.get_dxgi_format(),
dds.get_d3d_format()
);
let mut layers_asset_data = Vec::with_capacity(array_layer_count as usize);
for layer_index in 0..array_layer_count {
let layer = dds.get_data(0).unwrap();
let mut current_mipmap_size_bytes = dds.get_main_texture_size().unwrap() as usize;
let min_mipmap_size_bytes = dds.get_min_mipmap_size_in_bytes() as usize;
let mut offset_bytes = 0_usize;
let mut mip_width = width;
let mut mip_height = height;
let mut mip_levels_asset_data = Vec::with_capacity(mip_level_count as usize);
for mip_index in 0..mip_level_count {
let mip_data: Vec<u8> = layer
[offset_bytes..(offset_bytes + current_mipmap_size_bytes)]
.iter()
.copied()
.collect();
log::trace!(
"Gathered mip data {} {} {}",
layer_index,
mip_index,
mip_data.len()
);
mip_levels_asset_data.push(ImageAssetDataMipLevel {
width: mip_width,
height: mip_height,
bytes: mip_data,
});
offset_bytes += current_mipmap_size_bytes;
current_mipmap_size_bytes /= 4;
if current_mipmap_size_bytes < min_mipmap_size_bytes {
current_mipmap_size_bytes = min_mipmap_size_bytes;
}
mip_width /= 2;
mip_height /= 2;
}
layers_asset_data.push(ImageAssetDataLayer {
mip_levels: mip_levels_asset_data,
});
}
let import_data = GpuCompressedImageImportedDataRecord::new_builder(context.schema_set);
import_data.height().set(height).unwrap();
import_data.width().set(width).unwrap();
import_data
.format()
.set(match format {
ImageAssetDataFormat::RGBA32_Linear => GpuImageAssetDataFormatEnum::RGBA32_Linear,
ImageAssetDataFormat::RGBA32_Srgb => GpuImageAssetDataFormatEnum::RGBA32_Srgb,
ImageAssetDataFormat::Basis_Linear => GpuImageAssetDataFormatEnum::Basis_Linear,
ImageAssetDataFormat::Basis_Srgb => GpuImageAssetDataFormatEnum::Basis_Srgb,
ImageAssetDataFormat::BC1_UNorm_Linear => {
GpuImageAssetDataFormatEnum::BC1_UNorm_Linear
}
ImageAssetDataFormat::BC1_UNorm_Srgb => GpuImageAssetDataFormatEnum::BC1_UNorm_Srgb,
ImageAssetDataFormat::BC2_UNorm_Linear => {
GpuImageAssetDataFormatEnum::BC2_UNorm_Linear
}
ImageAssetDataFormat::BC2_UNorm_Srgb => GpuImageAssetDataFormatEnum::BC2_UNorm_Srgb,
ImageAssetDataFormat::BC3_UNorm_Linear => {
GpuImageAssetDataFormatEnum::BC3_UNorm_Linear
}
ImageAssetDataFormat::BC3_UNorm_Srgb => GpuImageAssetDataFormatEnum::BC3_UNorm_Srgb,
ImageAssetDataFormat::BC4_UNorm => GpuImageAssetDataFormatEnum::BC4_UNorm,
ImageAssetDataFormat::BC4_SNorm => GpuImageAssetDataFormatEnum::BC4_SNorm,
ImageAssetDataFormat::BC5_UNorm => GpuImageAssetDataFormatEnum::BC5_UNorm,
ImageAssetDataFormat::BC5_SNorm => GpuImageAssetDataFormatEnum::BC5_SNorm,
ImageAssetDataFormat::BC6H_UFloat => GpuImageAssetDataFormatEnum::BC6H_UFloat,
ImageAssetDataFormat::BC6H_SFloat => GpuImageAssetDataFormatEnum::BC6H_SFloat,
ImageAssetDataFormat::BC7_Unorm_Linear => {
GpuImageAssetDataFormatEnum::BC7_Unorm_Linear
}
ImageAssetDataFormat::BC7_Unorm_Srgb => GpuImageAssetDataFormatEnum::BC7_Unorm_Srgb,
})
.unwrap();
for layer in layers_asset_data {
let layer_entry = import_data.data_layers().add_entry().unwrap();
let layer_record = import_data.data_layers().entry(layer_entry);
for mip_level in layer.mip_levels {
let mip_level_entry = layer_record.mip_levels().add_entry().unwrap();
let mip_record = layer_record.mip_levels().entry(mip_level_entry);
mip_record.width().set(mip_level.width).unwrap();
mip_record.height().set(mip_level.height).unwrap();
mip_record.bytes().set(Arc::new(mip_level.bytes)).unwrap();
}
}
let default_asset = GpuCompressedImageAssetRecord::new_builder(context.schema_set);
context
.add_default_importable(default_asset.into_inner()?, Some(import_data.into_inner()?));
Ok(())
}
}