sRGB awareness for Color (#616)
Color is now sRGB aware, added SrgbColorSpace trait for f32
This commit is contained in:
parent
e89301ad29
commit
a92790c011
@ -6,7 +6,16 @@
|
|||||||
|
|
||||||
- [Another fast compile flag for macOS][552]
|
- [Another fast compile flag for macOS][552]
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
|
||||||
|
- Breaking Change: [sRGB awareness for `Color`][616]
|
||||||
|
- Color is now assumed to be provided in the non-linear sRGB colorspace, and constructors such as `Color::rgb` and `Color::rgba` will be converted to linear sRGB under-the-hood.
|
||||||
|
- This allows drop-in use of colors from most applications.
|
||||||
|
- New methods `Color::rgb_linear` and `Color::rgba_linear` will accept colors already in linear sRGB (the old behavior)
|
||||||
|
- Individual color-components must now be accessed through setters and getters: `.r`, `.g`, `.b`, `.a`, `.set_r`, `.set_g`, `.set_b`, `.set_a`, and the corresponding methods with the `*_linear` suffix.
|
||||||
|
|
||||||
[552]: https://github.com/bevyengine/bevy/pull/552
|
[552]: https://github.com/bevyengine/bevy/pull/552
|
||||||
|
[616]: https://github.com/bevyengine/bevy/pull/616
|
||||||
|
|
||||||
## Version 0.2.1 (2020-9-20)
|
## Version 0.2.1 (2020-9-20)
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use super::texture::Texture;
|
use super::texture::Texture;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
colorspace::*,
|
||||||
impl_render_resource_bytes,
|
impl_render_resource_bytes,
|
||||||
renderer::{RenderResource, RenderResourceType},
|
renderer::{RenderResource, RenderResourceType},
|
||||||
};
|
};
|
||||||
@ -10,32 +11,68 @@ use bevy_property::Property;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
use std::ops::{Add, AddAssign, Mul, MulAssign};
|
||||||
|
|
||||||
/// A RGBA color
|
/// RGBA color in the Linear sRGB colorspace (often colloquially referred to as "linear", "RGB", or "linear RGB").
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)]
|
#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize, Property)]
|
||||||
pub struct Color {
|
pub struct Color {
|
||||||
pub r: f32,
|
red: f32,
|
||||||
pub g: f32,
|
green: f32,
|
||||||
pub b: f32,
|
blue: f32,
|
||||||
pub a: f32,
|
alpha: f32,
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe impl Byteable for Color {}
|
unsafe impl Byteable for Color {}
|
||||||
|
|
||||||
impl Color {
|
impl Color {
|
||||||
pub const BLACK: Color = Color::rgb(0.0, 0.0, 0.0);
|
pub const BLACK: Color = Color::rgb_linear(0.0, 0.0, 0.0);
|
||||||
pub const BLUE: Color = Color::rgb(0.0, 0.0, 1.0);
|
pub const BLUE: Color = Color::rgb_linear(0.0, 0.0, 1.0);
|
||||||
pub const GREEN: Color = Color::rgb(0.0, 1.0, 0.0);
|
pub const GREEN: Color = Color::rgb_linear(0.0, 1.0, 0.0);
|
||||||
pub const NONE: Color = Color::rgba(0.0, 0.0, 0.0, 0.0);
|
pub const NONE: Color = Color::rgba_linear(0.0, 0.0, 0.0, 0.0);
|
||||||
pub const RED: Color = Color::rgb(1.0, 0.0, 0.0);
|
pub const RED: Color = Color::rgb_linear(1.0, 0.0, 0.0);
|
||||||
pub const WHITE: Color = Color::rgb(1.0, 1.0, 1.0);
|
pub const WHITE: Color = Color::rgb_linear(1.0, 1.0, 1.0);
|
||||||
|
|
||||||
pub const fn rgb(r: f32, g: f32, b: f32) -> Color {
|
// TODO: cant make rgb and rgba const due traits not allowed in const functions
|
||||||
Color { r, g, b, a: 1.0 }
|
// see issue #57563 https://github.com/rust-lang/rust/issues/57563
|
||||||
|
/// New ``Color`` from sRGB colorspace.
|
||||||
|
pub fn rgb(r: f32, g: f32, b: f32) -> Color {
|
||||||
|
Color {
|
||||||
|
red: r,
|
||||||
|
green: g,
|
||||||
|
blue: b,
|
||||||
|
alpha: 1.0,
|
||||||
|
}
|
||||||
|
.as_nonlinear_srgb_to_linear_srgb()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub const fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
|
/// New ``Color`` from sRGB colorspace.
|
||||||
Color { r, g, b, a }
|
pub fn rgba(r: f32, g: f32, b: f32, a: f32) -> Color {
|
||||||
|
Color {
|
||||||
|
red: r,
|
||||||
|
green: g,
|
||||||
|
blue: b,
|
||||||
|
alpha: a,
|
||||||
|
}
|
||||||
|
.as_nonlinear_srgb_to_linear_srgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New ``Color`` from linear colorspace.
|
||||||
|
pub const fn rgb_linear(r: f32, g: f32, b: f32) -> Color {
|
||||||
|
Color {
|
||||||
|
red: r,
|
||||||
|
green: g,
|
||||||
|
blue: b,
|
||||||
|
alpha: 1.0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// New ``Color`` from linear colorspace.
|
||||||
|
pub const fn rgba_linear(r: f32, g: f32, b: f32, a: f32) -> Color {
|
||||||
|
Color {
|
||||||
|
red: r,
|
||||||
|
green: g,
|
||||||
|
blue: b,
|
||||||
|
alpha: a,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn hex<T: AsRef<str>>(hex: T) -> Result<Color, HexColorError> {
|
pub fn hex<T: AsRef<str>>(hex: T) -> Result<Color, HexColorError> {
|
||||||
@ -74,12 +111,14 @@ impl Color {
|
|||||||
Err(HexColorError::Length)
|
Err(HexColorError::Length)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// New ``Color`` from sRGB colorspace.
|
||||||
pub fn rgb_u8(r: u8, g: u8, b: u8) -> Color {
|
pub fn rgb_u8(r: u8, g: u8, b: u8) -> Color {
|
||||||
Color::rgba_u8(r, g, b, u8::MAX)
|
Color::rgba_u8(r, g, b, u8::MAX)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Float operations in const fn are not stable yet
|
// Float operations in const fn are not stable yet
|
||||||
// see https://github.com/rust-lang/rust/issues/57241
|
// see https://github.com/rust-lang/rust/issues/57241
|
||||||
|
/// New ``Color`` from sRGB colorspace.
|
||||||
pub fn rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Color {
|
pub fn rgba_u8(r: u8, g: u8, b: u8, a: u8) -> Color {
|
||||||
Color::rgba(
|
Color::rgba(
|
||||||
r as f32 / u8::MAX as f32,
|
r as f32 / u8::MAX as f32,
|
||||||
@ -88,6 +127,82 @@ impl Color {
|
|||||||
a as f32 / u8::MAX as f32,
|
a as f32 / u8::MAX as f32,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_nonlinear_srgb_to_linear_srgb(self) -> Color {
|
||||||
|
Color {
|
||||||
|
red: self.red.nonlinear_to_linear_srgb(),
|
||||||
|
green: self.green.nonlinear_to_linear_srgb(),
|
||||||
|
blue: self.blue.nonlinear_to_linear_srgb(),
|
||||||
|
alpha: self.alpha, //alpha is always linear
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-linear-sRGB Component Getter
|
||||||
|
pub fn r(&self) -> f32 {
|
||||||
|
self.red.linear_to_nonlinear_srgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn g(&self) -> f32 {
|
||||||
|
self.red.linear_to_nonlinear_srgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn b(&self) -> f32 {
|
||||||
|
self.red.linear_to_nonlinear_srgb()
|
||||||
|
}
|
||||||
|
|
||||||
|
// linear-sRGB Component Getter
|
||||||
|
pub fn g_linear(&self) -> f32 {
|
||||||
|
self.green
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn r_linear(&self) -> f32 {
|
||||||
|
self.red
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn b_linear(&self) -> f32 {
|
||||||
|
self.blue
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn a(&self) -> f32 {
|
||||||
|
self.alpha
|
||||||
|
}
|
||||||
|
|
||||||
|
// non-linear-sRGB Component Setter
|
||||||
|
pub fn set_r(&mut self, r: f32) -> &mut Self {
|
||||||
|
self.red = r.nonlinear_to_linear_srgb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_g(&mut self, g: f32) -> &mut Self {
|
||||||
|
self.green = g.nonlinear_to_linear_srgb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_b(&mut self, b: f32) -> &mut Self {
|
||||||
|
self.blue = b.nonlinear_to_linear_srgb();
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// linear-sRGB Component Setter
|
||||||
|
pub fn set_r_linear(&mut self, r: f32) -> &mut Self {
|
||||||
|
self.red = r;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_g_linear(&mut self, g: f32) -> &mut Self {
|
||||||
|
self.green = g;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_b_linear(&mut self, b: f32) -> &mut Self {
|
||||||
|
self.blue = b;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_a(&mut self, a: f32) -> &mut Self {
|
||||||
|
self.alpha = a;
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Color {
|
impl Default for Color {
|
||||||
@ -99,10 +214,10 @@ impl Default for Color {
|
|||||||
impl AddAssign<Color> for Color {
|
impl AddAssign<Color> for Color {
|
||||||
fn add_assign(&mut self, rhs: Color) {
|
fn add_assign(&mut self, rhs: Color) {
|
||||||
*self = Color {
|
*self = Color {
|
||||||
r: self.r + rhs.r,
|
red: self.red + rhs.red,
|
||||||
g: self.g + rhs.g,
|
green: self.green + rhs.green,
|
||||||
b: self.b + rhs.b,
|
blue: self.blue + rhs.blue,
|
||||||
a: self.a + rhs.a,
|
alpha: self.alpha + rhs.alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -112,10 +227,10 @@ impl Add<Color> for Color {
|
|||||||
|
|
||||||
fn add(self, rhs: Color) -> Self::Output {
|
fn add(self, rhs: Color) -> Self::Output {
|
||||||
Color {
|
Color {
|
||||||
r: self.r + rhs.r,
|
red: self.red + rhs.red,
|
||||||
g: self.g + rhs.g,
|
green: self.green + rhs.green,
|
||||||
b: self.b + rhs.b,
|
blue: self.blue + rhs.blue,
|
||||||
a: self.a + rhs.a,
|
alpha: self.alpha + rhs.alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -125,10 +240,10 @@ impl Add<Vec4> for Color {
|
|||||||
|
|
||||||
fn add(self, rhs: Vec4) -> Self::Output {
|
fn add(self, rhs: Vec4) -> Self::Output {
|
||||||
Color {
|
Color {
|
||||||
r: self.r + rhs.x(),
|
red: self.red + rhs.x(),
|
||||||
g: self.g + rhs.y(),
|
green: self.green + rhs.y(),
|
||||||
b: self.b + rhs.z(),
|
blue: self.blue + rhs.z(),
|
||||||
a: self.a + rhs.w(),
|
alpha: self.alpha + rhs.w(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -136,17 +251,17 @@ impl Add<Vec4> for Color {
|
|||||||
impl From<Vec4> for Color {
|
impl From<Vec4> for Color {
|
||||||
fn from(vec4: Vec4) -> Self {
|
fn from(vec4: Vec4) -> Self {
|
||||||
Color {
|
Color {
|
||||||
r: vec4.x(),
|
red: vec4.x(),
|
||||||
g: vec4.y(),
|
green: vec4.y(),
|
||||||
b: vec4.z(),
|
blue: vec4.z(),
|
||||||
a: vec4.w(),
|
alpha: vec4.w(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<[f32; 4]> for Color {
|
impl Into<[f32; 4]> for Color {
|
||||||
fn into(self) -> [f32; 4] {
|
fn into(self) -> [f32; 4] {
|
||||||
[self.r, self.g, self.b, self.a]
|
[self.red, self.green, self.blue, self.alpha]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Mul<f32> for Color {
|
impl Mul<f32> for Color {
|
||||||
@ -154,20 +269,20 @@ impl Mul<f32> for Color {
|
|||||||
|
|
||||||
fn mul(self, rhs: f32) -> Self::Output {
|
fn mul(self, rhs: f32) -> Self::Output {
|
||||||
Color {
|
Color {
|
||||||
r: self.r * rhs,
|
red: self.red * rhs,
|
||||||
g: self.g * rhs,
|
green: self.green * rhs,
|
||||||
b: self.b * rhs,
|
blue: self.blue * rhs,
|
||||||
a: self.a * rhs,
|
alpha: self.alpha * rhs,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MulAssign<f32> for Color {
|
impl MulAssign<f32> for Color {
|
||||||
fn mul_assign(&mut self, rhs: f32) {
|
fn mul_assign(&mut self, rhs: f32) {
|
||||||
self.r *= rhs;
|
self.red *= rhs;
|
||||||
self.g *= rhs;
|
self.green *= rhs;
|
||||||
self.b *= rhs;
|
self.blue *= rhs;
|
||||||
self.a *= rhs;
|
self.alpha *= rhs;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -176,20 +291,20 @@ impl Mul<Vec4> for Color {
|
|||||||
|
|
||||||
fn mul(self, rhs: Vec4) -> Self::Output {
|
fn mul(self, rhs: Vec4) -> Self::Output {
|
||||||
Color {
|
Color {
|
||||||
r: self.r * rhs.x(),
|
red: self.red * rhs.x(),
|
||||||
g: self.g * rhs.y(),
|
green: self.green * rhs.y(),
|
||||||
b: self.b * rhs.z(),
|
blue: self.blue * rhs.z(),
|
||||||
a: self.a * rhs.w(),
|
alpha: self.alpha * rhs.w(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MulAssign<Vec4> for Color {
|
impl MulAssign<Vec4> for Color {
|
||||||
fn mul_assign(&mut self, rhs: Vec4) {
|
fn mul_assign(&mut self, rhs: Vec4) {
|
||||||
self.r *= rhs.x();
|
self.red *= rhs.x();
|
||||||
self.g *= rhs.y();
|
self.green *= rhs.y();
|
||||||
self.b *= rhs.z();
|
self.blue *= rhs.z();
|
||||||
self.a *= rhs.w();
|
self.alpha *= rhs.w();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -198,19 +313,19 @@ impl Mul<Vec3> for Color {
|
|||||||
|
|
||||||
fn mul(self, rhs: Vec3) -> Self::Output {
|
fn mul(self, rhs: Vec3) -> Self::Output {
|
||||||
Color {
|
Color {
|
||||||
r: self.r * rhs.x(),
|
red: self.red * rhs.x(),
|
||||||
g: self.g * rhs.y(),
|
green: self.green * rhs.y(),
|
||||||
b: self.b * rhs.z(),
|
blue: self.blue * rhs.z(),
|
||||||
a: self.a,
|
alpha: self.alpha,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MulAssign<Vec3> for Color {
|
impl MulAssign<Vec3> for Color {
|
||||||
fn mul_assign(&mut self, rhs: Vec3) {
|
fn mul_assign(&mut self, rhs: Vec3) {
|
||||||
self.r *= rhs.x();
|
self.red *= rhs.x();
|
||||||
self.g *= rhs.y();
|
self.green *= rhs.y();
|
||||||
self.b *= rhs.z();
|
self.blue *= rhs.z();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,6 +404,17 @@ fn decode_rgba(data: &[u8]) -> Result<Color, HexColorError> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_color_components_roundtrip() {
|
||||||
|
let mut color = Color::NONE;
|
||||||
|
color.set_r(0.5).set_g(0.5).set_b(0.5).set_a(0.5);
|
||||||
|
const EPS: f32 = 0.001;
|
||||||
|
assert!((color.r() - 0.5).abs() < EPS);
|
||||||
|
assert!((color.g() - 0.5).abs() < EPS);
|
||||||
|
assert!((color.b() - 0.5).abs() < EPS);
|
||||||
|
assert!((color.a() - 0.5).abs() < EPS);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_hex_color() {
|
fn test_hex_color() {
|
||||||
assert_eq!(Color::hex("FFF").unwrap(), Color::rgb(1.0, 1.0, 1.0));
|
assert_eq!(Color::hex("FFF").unwrap(), Color::rgb(1.0, 1.0, 1.0));
|
||||||
|
50
crates/bevy_render/src/colorspace.rs
Normal file
50
crates/bevy_render/src/colorspace.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
// sRGB
|
||||||
|
//==================================================================================================
|
||||||
|
pub trait SrgbColorSpace {
|
||||||
|
fn linear_to_nonlinear_srgb(self) -> Self;
|
||||||
|
fn nonlinear_to_linear_srgb(self) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
//source: https://entropymine.com/imageworsener/srgbformula/
|
||||||
|
impl SrgbColorSpace for f32 {
|
||||||
|
fn linear_to_nonlinear_srgb(self) -> f32 {
|
||||||
|
if self <= 0.0 {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
|
||||||
|
if self <= 0.0031308 {
|
||||||
|
self * 12.92 // linear falloff in dark values
|
||||||
|
} else {
|
||||||
|
(1.055 * self.powf(1.0 / 2.4)) - 0.055 //gamma curve in other area
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn nonlinear_to_linear_srgb(self) -> f32 {
|
||||||
|
if self <= 0.0 {
|
||||||
|
return self;
|
||||||
|
}
|
||||||
|
if self <= 0.04045 {
|
||||||
|
self / 12.92 // linear falloff in dark values
|
||||||
|
} else {
|
||||||
|
((self + 0.055) / 1.055).powf(2.4) //gamma curve in other area
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_srgb_full_roundtrip() {
|
||||||
|
let u8max: f32 = u8::max_value() as f32;
|
||||||
|
for color in 0..u8::max_value() {
|
||||||
|
let color01 = color as f32 / u8max;
|
||||||
|
let color_roundtrip = color01
|
||||||
|
.linear_to_nonlinear_srgb()
|
||||||
|
.nonlinear_to_linear_srgb();
|
||||||
|
// roundtrip is not perfect due to numeric precision, even with f64
|
||||||
|
// so ensure the error is at least ready for u8 (where sRGB is used)
|
||||||
|
assert_eq!(
|
||||||
|
(color01 * u8max).round() as u8,
|
||||||
|
(color_roundtrip * u8max).round() as u8
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//==================================================================================================
|
@ -1,6 +1,7 @@
|
|||||||
pub mod batch;
|
pub mod batch;
|
||||||
pub mod camera;
|
pub mod camera;
|
||||||
pub mod color;
|
pub mod color;
|
||||||
|
pub mod colorspace;
|
||||||
pub mod draw;
|
pub mod draw;
|
||||||
pub mod entity;
|
pub mod entity;
|
||||||
pub mod mesh;
|
pub mod mesh;
|
||||||
|
@ -30,9 +30,9 @@ impl Font {
|
|||||||
// TODO: make this texture grayscale
|
// TODO: make this texture grayscale
|
||||||
let color = Color::WHITE;
|
let color = Color::WHITE;
|
||||||
let color_u8 = [
|
let color_u8 = [
|
||||||
(color.r * 255.0) as u8,
|
(color.r() * 255.0) as u8,
|
||||||
(color.g * 255.0) as u8,
|
(color.g() * 255.0) as u8,
|
||||||
(color.b * 255.0) as u8,
|
(color.b() * 255.0) as u8,
|
||||||
];
|
];
|
||||||
Texture::new(
|
Texture::new(
|
||||||
Vec2::new(width as f32, height as f32),
|
Vec2::new(width as f32, height as f32),
|
||||||
@ -43,7 +43,7 @@ impl Font {
|
|||||||
color_u8[0],
|
color_u8[0],
|
||||||
color_u8[1],
|
color_u8[1],
|
||||||
color_u8[2],
|
color_u8[2],
|
||||||
(color.a * a * 255.0) as u8,
|
(color.a() * a * 255.0) as u8,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
@ -75,9 +75,9 @@ impl Font {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let color_u8 = [
|
let color_u8 = [
|
||||||
(color.r * 255.0) as u8,
|
(color.r() * 255.0) as u8,
|
||||||
(color.g * 255.0) as u8,
|
(color.g() * 255.0) as u8,
|
||||||
(color.b * 255.0) as u8,
|
(color.b() * 255.0) as u8,
|
||||||
];
|
];
|
||||||
|
|
||||||
// TODO: this offset is a bit hackey
|
// TODO: this offset is a bit hackey
|
||||||
@ -108,7 +108,7 @@ impl Font {
|
|||||||
color_u8[0],
|
color_u8[0],
|
||||||
color_u8[1],
|
color_u8[1],
|
||||||
color_u8[2],
|
color_u8[2],
|
||||||
(color.a * a * 255.0) as u8,
|
(color.a() * a * 255.0) as u8,
|
||||||
]
|
]
|
||||||
})
|
})
|
||||||
.flatten()
|
.flatten()
|
||||||
|
@ -124,10 +124,10 @@ impl<'a> From<&'a OwnedWgpuVertexBufferDescriptor> for wgpu::VertexBufferDescrip
|
|||||||
impl WgpuFrom<Color> for wgpu::Color {
|
impl WgpuFrom<Color> for wgpu::Color {
|
||||||
fn from(color: Color) -> Self {
|
fn from(color: Color) -> Self {
|
||||||
wgpu::Color {
|
wgpu::Color {
|
||||||
r: color.r as f64,
|
r: color.r_linear() as f64,
|
||||||
g: color.g as f64,
|
g: color.g_linear() as f64,
|
||||||
b: color.b as f64,
|
b: color.b_linear() as f64,
|
||||||
a: color.a as f64,
|
a: color.a() as f64,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user