Fix KTX2 R8_SRGB, R8_UNORM, R8G8_SRGB, R8G8_UNORM, R8G8B8_SRGB, R8G8B8_UNORM support (#4594)
# Objective - Fixes #4592 ## Solution - Implement `SrgbColorSpace` for `u8` via `f32` - Convert KTX2 R8 and R8G8 non-linear sRGB to wgpu `R8Unorm` and `Rg8Unorm` as non-linear sRGB are not supported by wgpu for these formats - Convert KTX2 R8G8B8 formats to `Rgba8Unorm` and `Rgba8UnormSrgb` by adding an alpha channel as the Rgb variants don't exist in wgpu --- ## Changelog - Added: Support for KTX2 `R8_SRGB`, `R8_UNORM`, `R8G8_SRGB`, `R8G8_UNORM`, `R8G8B8_SRGB`, `R8G8B8_UNORM` formats by converting to supported wgpu formats as appropriate
This commit is contained in:
		
							parent
							
								
									daa45ebb4d
								
							
						
					
					
						commit
						c9a53bf5dd
					
				@ -31,6 +31,18 @@ impl SrgbColorSpace for f32 {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl SrgbColorSpace for u8 {
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn linear_to_nonlinear_srgb(self) -> Self {
 | 
			
		||||
        ((self as f32 / u8::MAX as f32).linear_to_nonlinear_srgb() * u8::MAX as f32) as u8
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    #[inline]
 | 
			
		||||
    fn nonlinear_to_linear_srgb(self) -> Self {
 | 
			
		||||
        ((self as f32 / u8::MAX as f32).nonlinear_to_linear_srgb() * u8::MAX as f32) as u8
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub struct HslRepresentation;
 | 
			
		||||
impl HslRepresentation {
 | 
			
		||||
    /// converts a color in HLS space to sRGB space
 | 
			
		||||
 | 
			
		||||
@ -2,7 +2,6 @@ mod colorspace;
 | 
			
		||||
 | 
			
		||||
pub use colorspace::*;
 | 
			
		||||
 | 
			
		||||
use crate::color::{HslRepresentation, SrgbColorSpace};
 | 
			
		||||
use bevy_math::{Vec3, Vec4};
 | 
			
		||||
use bevy_reflect::{FromReflect, Reflect, ReflectDeserialize, ReflectSerialize};
 | 
			
		||||
use serde::{Deserialize, Serialize};
 | 
			
		||||
 | 
			
		||||
@ -406,9 +406,13 @@ pub enum DataFormat {
 | 
			
		||||
#[derive(Clone, Copy, Debug)]
 | 
			
		||||
pub enum TranscodeFormat {
 | 
			
		||||
    Etc1s,
 | 
			
		||||
    Uastc(DataFormat),
 | 
			
		||||
    // Has to be transcoded to R8Unorm for use with `wgpu`
 | 
			
		||||
    R8UnormSrgb,
 | 
			
		||||
    // Has to be transcoded to R8G8Unorm for use with `wgpu`
 | 
			
		||||
    Rg8UnormSrgb,
 | 
			
		||||
    // Has to be transcoded to Rgba8 for use with `wgpu`
 | 
			
		||||
    Rgb8,
 | 
			
		||||
    Uastc(DataFormat),
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/// An error that occurs when loading a texture
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,7 @@
 | 
			
		||||
#[cfg(any(feature = "flate2", feature = "ruzstd"))]
 | 
			
		||||
use std::io::Read;
 | 
			
		||||
 | 
			
		||||
use crate::color::SrgbColorSpace;
 | 
			
		||||
#[cfg(feature = "basis-universal")]
 | 
			
		||||
use basis_universal::{
 | 
			
		||||
    DecodeFlags, LowLevelUastcTranscoder, SliceParametersUastc, TranscoderBlockFormat,
 | 
			
		||||
@ -86,6 +87,44 @@ pub fn ktx2_buffer_to_image(
 | 
			
		||||
        TextureError::FormatRequiresTranscodingError(transcode_format) => {
 | 
			
		||||
            let mut transcoded = vec![Vec::default(); levels.len()];
 | 
			
		||||
            let texture_format = match transcode_format {
 | 
			
		||||
                TranscodeFormat::R8UnormSrgb => {
 | 
			
		||||
                    let (mut original_width, mut original_height) = (width, height);
 | 
			
		||||
 | 
			
		||||
                    for level_data in &levels {
 | 
			
		||||
                        transcoded.push(
 | 
			
		||||
                            level_data
 | 
			
		||||
                                .iter()
 | 
			
		||||
                                .copied()
 | 
			
		||||
                                .map(|v| v.nonlinear_to_linear_srgb())
 | 
			
		||||
                                .collect::<Vec<u8>>(),
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        // Next mip dimensions are half the current, minimum 1x1
 | 
			
		||||
                        original_width = (original_width / 2).max(1);
 | 
			
		||||
                        original_height = (original_height / 2).max(1);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    TextureFormat::R8Unorm
 | 
			
		||||
                }
 | 
			
		||||
                TranscodeFormat::Rg8UnormSrgb => {
 | 
			
		||||
                    let (mut original_width, mut original_height) = (width, height);
 | 
			
		||||
 | 
			
		||||
                    for level_data in &levels {
 | 
			
		||||
                        transcoded.push(
 | 
			
		||||
                            level_data
 | 
			
		||||
                                .iter()
 | 
			
		||||
                                .copied()
 | 
			
		||||
                                .map(|v| v.nonlinear_to_linear_srgb())
 | 
			
		||||
                                .collect::<Vec<u8>>(),
 | 
			
		||||
                        );
 | 
			
		||||
 | 
			
		||||
                        // Next mip dimensions are half the current, minimum 1x1
 | 
			
		||||
                        original_width = (original_width / 2).max(1);
 | 
			
		||||
                        original_height = (original_height / 2).max(1);
 | 
			
		||||
                    }
 | 
			
		||||
 | 
			
		||||
                    TextureFormat::Rg8Unorm
 | 
			
		||||
                }
 | 
			
		||||
                TranscodeFormat::Rgb8 => {
 | 
			
		||||
                    let mut rgba = vec![255u8; width as usize * height as usize * 4];
 | 
			
		||||
                    for (level, level_data) in levels.iter().enumerate() {
 | 
			
		||||
@ -1163,9 +1202,9 @@ pub fn ktx2_format_to_texture_format(
 | 
			
		||||
    Ok(match ktx2_format {
 | 
			
		||||
        ktx2::Format::R8_UNORM | ktx2::Format::R8_SRGB => {
 | 
			
		||||
            if is_srgb {
 | 
			
		||||
                return Err(TextureError::UnsupportedTextureFormat(format!(
 | 
			
		||||
                    "{ktx2_format:?}"
 | 
			
		||||
                )));
 | 
			
		||||
                return Err(TextureError::FormatRequiresTranscodingError(
 | 
			
		||||
                    TranscodeFormat::R8UnormSrgb,
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            TextureFormat::R8Unorm
 | 
			
		||||
        }
 | 
			
		||||
@ -1174,15 +1213,20 @@ pub fn ktx2_format_to_texture_format(
 | 
			
		||||
        ktx2::Format::R8_SINT => TextureFormat::R8Sint,
 | 
			
		||||
        ktx2::Format::R8G8_UNORM | ktx2::Format::R8G8_SRGB => {
 | 
			
		||||
            if is_srgb {
 | 
			
		||||
                return Err(TextureError::UnsupportedTextureFormat(format!(
 | 
			
		||||
                    "{ktx2_format:?}"
 | 
			
		||||
                )));
 | 
			
		||||
                return Err(TextureError::FormatRequiresTranscodingError(
 | 
			
		||||
                    TranscodeFormat::Rg8UnormSrgb,
 | 
			
		||||
                ));
 | 
			
		||||
            }
 | 
			
		||||
            TextureFormat::Rg8Unorm
 | 
			
		||||
        }
 | 
			
		||||
        ktx2::Format::R8G8_SNORM => TextureFormat::Rg8Snorm,
 | 
			
		||||
        ktx2::Format::R8G8_UINT => TextureFormat::Rg8Uint,
 | 
			
		||||
        ktx2::Format::R8G8_SINT => TextureFormat::Rg8Sint,
 | 
			
		||||
        ktx2::Format::R8G8B8_UNORM | ktx2::Format::R8G8B8_SRGB => {
 | 
			
		||||
            return Err(TextureError::FormatRequiresTranscodingError(
 | 
			
		||||
                TranscodeFormat::Rgb8,
 | 
			
		||||
            ));
 | 
			
		||||
        }
 | 
			
		||||
        ktx2::Format::R8G8B8A8_UNORM | ktx2::Format::R8G8B8A8_SRGB => {
 | 
			
		||||
            if is_srgb {
 | 
			
		||||
                TextureFormat::Rgba8UnormSrgb
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user