mirror of
https://github.com/bevyengine/bevy
synced 2024-11-22 20:53:53 +00:00
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
4 changed files with 67 additions and 8 deletions
|
@ -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 a new issue