Skip to content

Commit d9ece3e

Browse files
Wumpfemilk
authored andcommitted
Clear color values are now explicitely sent to the rendering backend as-is. (emilk#2666)
* Clear color values are not explicitely sent to the rendering backend as-is. Previously, converting from Color32 to Rgba caused an srgb->linear conversion. This conversion is incorrect if the backbuffer doesn't perform automatic conversion from linear->srgb (lack of this conversion is generally what egui assumes!). * fill in pr numbers in changelog * Epi comment fix Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * Color32 comment fix Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com> * move changelog line * rename fix * use backticks in doc --------- Co-authored-by: Emil Ernerfeldt <emil.ernerfeldt@gmail.com>
1 parent 5edbcf0 commit d9ece3e

File tree

10 files changed

+52
-42
lines changed

10 files changed

+52
-42
lines changed

crates/ecolor/src/color32.rs

+15
Original file line numberDiff line numberDiff line change
@@ -198,4 +198,19 @@ impl Color32 {
198198
// we need a somewhat expensive conversion to linear space and back.
199199
Rgba::from(self).multiply(factor).into()
200200
}
201+
202+
/// Converts to floating point values in the range 0-1 without any gamma space conversion.
203+
///
204+
/// Use this with great care! In almost all cases, you want to convert to [`crate::Rgba`] instead
205+
/// in order to obtain linear space color values.
206+
#[inline]
207+
pub fn to_normalized_gamma_f32(self) -> [f32; 4] {
208+
let Self([r, g, b, a]) = self;
209+
[
210+
r as f32 / 255.0,
211+
g as f32 / 255.0,
212+
b as f32 / 255.0,
213+
a as f32 / 255.0,
214+
]
215+
}
201216
}

crates/eframe/CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ NOTE: [`egui-winit`](../egui-winit/CHANGELOG.md), [`egui_glium`](../egui_glium/C
55

66

77
## Unreleased
8+
* ⚠️ BREAKING: `App::clear_color` now expects you to return a raw float array ([#2666](https://github.com/emilk/egui/pull/2666)):
89

910
#### Desktop/Native:
1011
* `eframe::run_native` now returns a `Result` ([#2433](https://github.com/emilk/egui/pull/2433)).

crates/eframe/src/epi.rs

+11-3
Original file line numberDiff line numberDiff line change
@@ -149,13 +149,21 @@ pub trait App {
149149
egui::Vec2::INFINITY
150150
}
151151

152-
/// Background color for the app, e.g. what is sent to `gl.clearColor`.
152+
/// Background color values for the app, e.g. what is sent to `gl.clearColor`.
153+
///
153154
/// This is the background of your windows if you don't set a central panel.
154-
fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba {
155+
///
156+
/// ATTENTION:
157+
/// Since these float values go to the render as-is, any color space conversion as done
158+
/// e.g. by converting from [`egui::Color32`] to [`egui::Rgba`] may cause incorrect results.
159+
/// egui recommends that rendering backends use a normal "gamma-space" (non-sRGB-aware) blending,
160+
/// which means the values you return here should also be in `sRGB` gamma-space in the 0-1 range.
161+
/// You can use [`egui::Color32::to_normalized_gamma_f32`] for this.
162+
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
155163
// NOTE: a bright gray makes the shadows of the windows look weird.
156164
// We use a bit of transparency so that if the user switches on the
157165
// `transparent()` option they get immediate results.
158-
egui::Color32::from_rgba_unmultiplied(12, 12, 12, 180).into()
166+
egui::Color32::from_rgba_unmultiplied(12, 12, 12, 180).to_normalized_gamma_f32()
159167

160168
// _visuals.window_fill() would also be a natural choice
161169
}

crates/eframe/src/web/web_painter.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use egui::Rgba;
21
use wasm_bindgen::JsValue;
32

43
/// Renderer for a browser canvas.
@@ -19,7 +18,7 @@ pub(crate) trait WebPainter {
1918
/// Update all internal textures and paint gui.
2019
fn paint_and_update_textures(
2120
&mut self,
22-
clear_color: Rgba,
21+
clear_color: [f32; 4],
2322
clipped_primitives: &[egui::ClippedPrimitive],
2423
pixels_per_point: f32,
2524
textures_delta: &egui::TexturesDelta,

crates/eframe/src/web/web_painter_glow.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ use wasm_bindgen::JsCast;
22
use wasm_bindgen::JsValue;
33
use web_sys::HtmlCanvasElement;
44

5-
use egui::Rgba;
65
use egui_glow::glow;
76

87
use crate::{WebGlContextOption, WebOptions};
@@ -49,7 +48,7 @@ impl WebPainter for WebPainterGlow {
4948

5049
fn paint_and_update_textures(
5150
&mut self,
52-
clear_color: Rgba,
51+
clear_color: [f32; 4],
5352
clipped_primitives: &[egui::ClippedPrimitive],
5453
pixels_per_point: f32,
5554
textures_delta: &egui::TexturesDelta,

crates/eframe/src/web/web_painter_wgpu.rs

+6-6
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::sync::Arc;
33
use wasm_bindgen::JsValue;
44
use web_sys::HtmlCanvasElement;
55

6-
use egui::{mutex::RwLock, Rgba};
6+
use egui::mutex::RwLock;
77
use egui_wgpu::{renderer::ScreenDescriptor, RenderState, SurfaceErrorAction};
88

99
use crate::WebOptions;
@@ -135,7 +135,7 @@ impl WebPainter for WebPainterWgpu {
135135

136136
fn paint_and_update_textures(
137137
&mut self,
138-
clear_color: Rgba,
138+
clear_color: [f32; 4],
139139
clipped_primitives: &[egui::ClippedPrimitive],
140140
pixels_per_point: f32,
141141
textures_delta: &egui::TexturesDelta,
@@ -228,10 +228,10 @@ impl WebPainter for WebPainterWgpu {
228228
resolve_target: None,
229229
ops: wgpu::Operations {
230230
load: wgpu::LoadOp::Clear(wgpu::Color {
231-
r: clear_color.r() as f64,
232-
g: clear_color.g() as f64,
233-
b: clear_color.b() as f64,
234-
a: clear_color.a() as f64,
231+
r: clear_color[0] as f64,
232+
g: clear_color[1] as f64,
233+
b: clear_color[2] as f64,
234+
a: clear_color[3] as f64,
235235
}),
236236
store: true,
237237
},

crates/egui-wgpu/src/winit.rs

+5-5
Original file line numberDiff line numberDiff line change
@@ -255,7 +255,7 @@ impl Painter {
255255
pub fn paint_and_update_textures(
256256
&mut self,
257257
pixels_per_point: f32,
258-
clear_color: epaint::Rgba,
258+
clear_color: [f32; 4],
259259
clipped_primitives: &[epaint::ClippedPrimitive],
260260
textures_delta: &epaint::textures::TexturesDelta,
261261
) {
@@ -335,10 +335,10 @@ impl Painter {
335335
resolve_target: None,
336336
ops: wgpu::Operations {
337337
load: wgpu::LoadOp::Clear(wgpu::Color {
338-
r: clear_color.r() as f64,
339-
g: clear_color.g() as f64,
340-
b: clear_color.b() as f64,
341-
a: clear_color.a() as f64,
338+
r: clear_color[0] as f64,
339+
g: clear_color[1] as f64,
340+
b: clear_color[2] as f64,
341+
a: clear_color[3] as f64,
342342
}),
343343
store: true,
344344
},

crates/egui_demo_app/src/wrap_app.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -175,8 +175,8 @@ impl eframe::App for WrapApp {
175175
eframe::set_value(storage, eframe::APP_KEY, &self.state);
176176
}
177177

178-
fn clear_color(&self, visuals: &egui::Visuals) -> egui::Rgba {
179-
visuals.panel_fill.into()
178+
fn clear_color(&self, visuals: &egui::Visuals) -> [f32; 4] {
179+
visuals.panel_fill.to_normalized_gamma_f32()
180180
}
181181

182182
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {

crates/egui_glow/src/painter.rs

+8-20
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ use std::{collections::HashMap, sync::Arc};
55

66
use egui::{
77
emath::Rect,
8-
epaint::{Color32, Mesh, PaintCallbackInfo, Primitive, Vertex},
8+
epaint::{Mesh, PaintCallbackInfo, Primitive, Vertex},
99
};
1010
use glow::HasContext as _;
1111
use memoffset::offset_of;
@@ -665,7 +665,7 @@ impl Painter {
665665
}
666666
}
667667

668-
pub fn clear(gl: &glow::Context, screen_size_in_pixels: [u32; 2], clear_color: egui::Rgba) {
668+
pub fn clear(gl: &glow::Context, screen_size_in_pixels: [u32; 2], clear_color: [f32; 4]) {
669669
crate::profile_function!();
670670
unsafe {
671671
gl.disable(glow::SCISSOR_TEST);
@@ -676,24 +676,12 @@ pub fn clear(gl: &glow::Context, screen_size_in_pixels: [u32; 2], clear_color: e
676676
screen_size_in_pixels[0] as i32,
677677
screen_size_in_pixels[1] as i32,
678678
);
679-
680-
if true {
681-
// verified to be correct on eframe native (on Mac).
682-
gl.clear_color(
683-
clear_color[0],
684-
clear_color[1],
685-
clear_color[2],
686-
clear_color[3],
687-
);
688-
} else {
689-
let clear_color: Color32 = clear_color.into();
690-
gl.clear_color(
691-
clear_color[0] as f32 / 255.0,
692-
clear_color[1] as f32 / 255.0,
693-
clear_color[2] as f32 / 255.0,
694-
clear_color[3] as f32 / 255.0,
695-
);
696-
}
679+
gl.clear_color(
680+
clear_color[0],
681+
clear_color[1],
682+
clear_color[2],
683+
clear_color[3],
684+
);
697685
gl.clear(glow::COLOR_BUFFER_BIT);
698686
}
699687
}

examples/custom_window_frame/src/main.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ fn main() -> Result<(), eframe::Error> {
2525
struct MyApp {}
2626

2727
impl eframe::App for MyApp {
28-
fn clear_color(&self, _visuals: &egui::Visuals) -> egui::Rgba {
29-
egui::Rgba::TRANSPARENT // Make sure we don't paint anything behind the rounded corners
28+
fn clear_color(&self, _visuals: &egui::Visuals) -> [f32; 4] {
29+
egui::Rgba::TRANSPARENT.to_array() // Make sure we don't paint anything behind the rounded corners
3030
}
3131

3232
fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {

0 commit comments

Comments
 (0)