mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 13:21:38 +03:00
split shaders, adjust srgb opengl render settings
https://learnopengl.com/Advanced-Lighting/Gamma-Correction suggests some good practices: * Only enable SRGB output on the final draw call, so that all prior stages can operate on linear values and avoid converting to/from linear multiple times. * The SRGBA textures automatically linearize when sampled, but: * The RGB data must be SRGB (non-linear) * The A channel is assumed to be linear! This commit nudges us closer to that by: * Converting the freetype coverage map from its linear value to non-linear when rasterizing. * Splitting the shader files into one per stage (background, lines, glyphs) and only setting outputs_srgb for the glyph stage refs: #491
This commit is contained in:
parent
dd70a8a53b
commit
4e2b2eddba
@ -7,6 +7,7 @@ use anyhow::bail;
|
||||
use std::cell::RefCell;
|
||||
use std::mem;
|
||||
use std::slice;
|
||||
use window::color::linear_u8_to_srgb8;
|
||||
|
||||
pub struct FreeTypeRasterizer {
|
||||
has_color: bool,
|
||||
@ -112,12 +113,19 @@ impl FreeTypeRasterizer {
|
||||
let src_offset = y * pitch;
|
||||
let dest_offset = y * width * 4;
|
||||
for x in 0..width {
|
||||
let gray = data[src_offset + x];
|
||||
let linear_gray = data[src_offset + x];
|
||||
|
||||
let gray = linear_u8_to_srgb8(linear_gray);
|
||||
|
||||
// Texture is SRGBA, which in OpenGL means
|
||||
// that the RGB values are gamma adjusted
|
||||
// non-linear values, but the A value is
|
||||
// linear!
|
||||
|
||||
rgba[dest_offset + (x * 4)] = gray;
|
||||
rgba[dest_offset + (x * 4) + 1] = gray;
|
||||
rgba[dest_offset + (x * 4) + 2] = gray;
|
||||
rgba[dest_offset + (x * 4) + 3] = gray;
|
||||
rgba[dest_offset + (x * 4) + 3] = linear_gray;
|
||||
}
|
||||
}
|
||||
RasterizedGlyph {
|
||||
@ -151,6 +159,16 @@ impl FreeTypeRasterizer {
|
||||
let green = data[src_offset + (x * 3) + 1];
|
||||
let blue = data[src_offset + (x * 3) + 2];
|
||||
let alpha = red.min(green).min(blue);
|
||||
|
||||
// Texture is SRGBA, which in OpenGL means
|
||||
// that the RGB values are gamma adjusted
|
||||
// non-linear values, but the A value is
|
||||
// linear!
|
||||
|
||||
let red = linear_u8_to_srgb8(red);
|
||||
let green = linear_u8_to_srgb8(green);
|
||||
let blue = linear_u8_to_srgb8(blue);
|
||||
|
||||
rgba[dest_offset + (x * 4)] = red;
|
||||
rgba[dest_offset + (x * 4) + 1] = green;
|
||||
rgba[dest_offset + (x * 4) + 2] = blue;
|
||||
|
20
wezterm-gui/src/gui/background-frag.glsl
Normal file
20
wezterm-gui/src/gui/background-frag.glsl
Normal file
@ -0,0 +1,20 @@
|
||||
// This shader is responsible for coloring the window background.
|
||||
|
||||
// Note: fragment-common.glsl is automatically prepended!
|
||||
|
||||
uniform sampler2D atlas_linear_sampler;
|
||||
|
||||
void main() {
|
||||
if (o_has_color == 2.0) {
|
||||
// We're the window background image.
|
||||
color = texture(atlas_linear_sampler, o_tex);
|
||||
// Apply window_background_image_opacity to the background image
|
||||
color.a = o_bg_color.a;
|
||||
} else if (o_has_color == 3.0) {
|
||||
color = o_bg_color;
|
||||
} else {
|
||||
// Nothing else should render on the background layer
|
||||
discard;
|
||||
}
|
||||
color = apply_hsv(color, o_hsv);
|
||||
}
|
16
wezterm-gui/src/gui/background-vertex.glsl
Normal file
16
wezterm-gui/src/gui/background-vertex.glsl
Normal file
@ -0,0 +1,16 @@
|
||||
// This is the window background shader.
|
||||
// It places the background image in the full viewport.
|
||||
|
||||
// Note: vertex-common.glsl is automatically prepended!
|
||||
|
||||
void main() {
|
||||
pass_through_vertex();
|
||||
|
||||
if (o_has_color == 2.0) {
|
||||
// Background image takes up its full coordinates
|
||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||
} else {
|
||||
// Nothing else should render on the background layer
|
||||
gl_Position = off_screen();
|
||||
}
|
||||
}
|
@ -1,3 +1,5 @@
|
||||
// This file is automatically prepended to the various -frag shaders.
|
||||
|
||||
precision highp float;
|
||||
|
||||
in float o_has_color;
|
||||
@ -10,18 +12,10 @@ in vec4 o_cursor_color;
|
||||
in vec4 o_fg_color;
|
||||
in vec4 o_underline_color;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform bool window_bg_layer;
|
||||
uniform bool bg_and_line_layer;
|
||||
uniform bool has_background_image;
|
||||
|
||||
uniform sampler2D atlas_nearest_sampler;
|
||||
uniform sampler2D atlas_linear_sampler;
|
||||
out vec4 color;
|
||||
|
||||
uniform vec3 foreground_text_hsb;
|
||||
|
||||
out vec4 color;
|
||||
|
||||
float multiply_one(float src, float dst, float inv_dst_alpha, float inv_src_alpha) {
|
||||
return (src * dst) + (src * (inv_dst_alpha)) + (dst * (inv_src_alpha));
|
||||
}
|
||||
@ -56,9 +50,9 @@ vec3 hsv2rgb(vec3 c)
|
||||
return c.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), c.y);
|
||||
}
|
||||
|
||||
vec4 apply_hsv(vec4 c)
|
||||
vec4 apply_hsv(vec4 c, vec3 transform)
|
||||
{
|
||||
vec3 hsv = rgb2hsv(c.rgb) * o_hsv;
|
||||
vec3 hsv = rgb2hsv(c.rgb) * transform;
|
||||
return vec4(hsv2rgb(hsv).rgb, c.a);
|
||||
}
|
||||
|
||||
@ -93,73 +87,4 @@ vec4 colorize_hsv(vec4 glyph, vec4 color) {
|
||||
return vec4(hsv2rgb(hsv * foreground_text_hsb), glyph.a);
|
||||
}
|
||||
|
||||
void main() {
|
||||
if (window_bg_layer) {
|
||||
if (o_has_color == 2.0) {
|
||||
// We're the window background image.
|
||||
color = texture(atlas_linear_sampler, o_tex);
|
||||
// Apply window_background_image_opacity to the background image
|
||||
color.a = o_bg_color.a;
|
||||
} else if (o_has_color == 3.0) {
|
||||
color = o_bg_color;
|
||||
} else {
|
||||
// Nothing else should render on the background layer
|
||||
discard;
|
||||
}
|
||||
} else if (bg_and_line_layer) {
|
||||
if (o_has_color >= 2.0) {
|
||||
// Don't render the background image on anything other than
|
||||
// the window_bg_layer.
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
// Note that o_bg_color is set to transparent if the background
|
||||
// color is "default" and there is a window background attachment
|
||||
color = o_bg_color;
|
||||
|
||||
// Sample the underline glyph texture for this location.
|
||||
// Note that the texture is whitespace in the case where this is
|
||||
// no underline or strikethrough.
|
||||
vec4 under_color = texture(atlas_nearest_sampler, o_underline);
|
||||
if (under_color.a != 0.0) {
|
||||
// if the underline glyph isn't transparent in this position then
|
||||
// we take the underline color, otherwise we'll leave the color
|
||||
// at the background color.
|
||||
color = o_underline_color;
|
||||
}
|
||||
|
||||
// Similar to the above: if the cursor texture isn't transparent
|
||||
// in this location, we'll use the cursor color instead of the background.
|
||||
// The cursor color overrides any underline color we might have picked
|
||||
// in the section above.
|
||||
vec4 cursor_outline = texture(atlas_nearest_sampler, o_cursor);
|
||||
if (cursor_outline.a != 0.0) {
|
||||
color = o_cursor_color;
|
||||
}
|
||||
} else {
|
||||
if (o_has_color >= 2.0) {
|
||||
// Don't render the background image on anything other than
|
||||
// the window_bg_layer.
|
||||
discard;
|
||||
} else {
|
||||
color = texture(atlas_nearest_sampler, o_tex);
|
||||
if (o_has_color == 0.0) {
|
||||
// if it's not a color emoji it will be grayscale
|
||||
// and we need to tint with the fg_color
|
||||
if (o_fg_color == o_bg_color) {
|
||||
// However, if we're a monochrome glyph and the foreground and
|
||||
// background colors are the same, just render a transparent pixel
|
||||
// instead; this avoids generating shadowy anti-aliasing artifacts
|
||||
// for something that should otherwise be invisible.
|
||||
color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
color = colorize_hsv(color, o_fg_color);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
color = apply_hsv(color);
|
||||
}
|
35
wezterm-gui/src/gui/glyph-frag.glsl
Normal file
35
wezterm-gui/src/gui/glyph-frag.glsl
Normal file
@ -0,0 +1,35 @@
|
||||
// This is the Glyph fragment shader.
|
||||
// It is the last stage in drawing, and is responsible
|
||||
// for laying down the glyph graphics on top of the other layers.
|
||||
|
||||
// Note: fragment-common.glsl is automatically prepended!
|
||||
|
||||
uniform sampler2D atlas_nearest_sampler;
|
||||
|
||||
void main() {
|
||||
if (o_has_color >= 2.0) {
|
||||
// Don't render the background image on anything other than
|
||||
// the window_bg_layer.
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
color = texture(atlas_nearest_sampler, o_tex);
|
||||
if (o_has_color == 0.0) {
|
||||
// if it's not a color emoji it will be grayscale
|
||||
// and we need to tint with the fg_color
|
||||
if (o_fg_color == o_bg_color) {
|
||||
// However, if we're a monochrome glyph and the foreground and
|
||||
// background colors are the same, just render a transparent pixel
|
||||
// instead; this avoids generating shadowy anti-aliasing artifacts
|
||||
// for something that should otherwise be invisible.
|
||||
color = vec4(0.0, 0.0, 0.0, 0.0);
|
||||
discard;
|
||||
return;
|
||||
} else {
|
||||
color = colorize_hsv(color, o_fg_color);
|
||||
}
|
||||
}
|
||||
|
||||
color = apply_hsv(color, o_hsv);
|
||||
}
|
18
wezterm-gui/src/gui/glyph-vertex.glsl
Normal file
18
wezterm-gui/src/gui/glyph-vertex.glsl
Normal file
@ -0,0 +1,18 @@
|
||||
// This is the Glyph vertex shader.
|
||||
// It is responsible for placing the glyph images in the
|
||||
// correct place on screen.
|
||||
|
||||
// Note: vertex-common.glsl is automatically prepended!
|
||||
|
||||
void main() {
|
||||
pass_through_vertex();
|
||||
|
||||
if (o_has_color == 2.0) {
|
||||
// If we're the background image and we're not rendering
|
||||
// the background layer, then move this off screen
|
||||
gl_Position = off_screen();
|
||||
} else {
|
||||
// Use only the adjusted cell position to render the glyph
|
||||
gl_Position = projection * vec4(position + adjust, 0.0, 1.0);
|
||||
}
|
||||
}
|
41
wezterm-gui/src/gui/line-frag.glsl
Normal file
41
wezterm-gui/src/gui/line-frag.glsl
Normal file
@ -0,0 +1,41 @@
|
||||
// This shader is responsible for coloring the underline and
|
||||
// glyph background graphics.
|
||||
|
||||
// Note: fragment-common.glsl is automatically prepended!
|
||||
|
||||
uniform sampler2D atlas_nearest_sampler;
|
||||
|
||||
void main() {
|
||||
if (o_has_color >= 2.0) {
|
||||
// Don't render the background image on anything other than
|
||||
// the window_bg_layer.
|
||||
discard;
|
||||
return;
|
||||
}
|
||||
|
||||
// Note that o_bg_color is set to transparent if the background
|
||||
// color is "default" and there is a window background attachment
|
||||
color = o_bg_color;
|
||||
|
||||
// Sample the underline glyph texture for this location.
|
||||
// Note that the texture is whitespace in the case where this is
|
||||
// no underline or strikethrough.
|
||||
vec4 under_color = texture(atlas_nearest_sampler, o_underline);
|
||||
if (under_color.a != 0.0) {
|
||||
// if the underline glyph isn't transparent in this position then
|
||||
// we take the underline color, otherwise we'll leave the color
|
||||
// at the background color.
|
||||
color = o_underline_color;
|
||||
}
|
||||
|
||||
// Similar to the above: if the cursor texture isn't transparent
|
||||
// in this location, we'll use the cursor color instead of the background.
|
||||
// The cursor color overrides any underline color we might have picked
|
||||
// in the section above.
|
||||
vec4 cursor_outline = texture(atlas_nearest_sampler, o_cursor);
|
||||
if (cursor_outline.a != 0.0) {
|
||||
color = o_cursor_color;
|
||||
}
|
||||
|
||||
color = apply_hsv(color, o_hsv);
|
||||
}
|
17
wezterm-gui/src/gui/line-vertex.glsl
Normal file
17
wezterm-gui/src/gui/line-vertex.glsl
Normal file
@ -0,0 +1,17 @@
|
||||
// This is the underline/strikethrough and text-background color
|
||||
// shader. It is responsible for locating the cell boundaries.
|
||||
|
||||
// Note: vertex-common.glsl is automatically prepended!
|
||||
|
||||
void main() {
|
||||
pass_through_vertex();
|
||||
|
||||
if (o_has_color == 2.0) {
|
||||
// If we're the background image and we're not rendering
|
||||
// the background layer, then move this off screen
|
||||
gl_Position = off_screen();
|
||||
} else {
|
||||
// Want to fill the whole cell when painting backgrounds
|
||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||
}
|
||||
}
|
@ -6,7 +6,6 @@ use ::window::glium::backend::Context as GliumContext;
|
||||
use ::window::glium::texture::SrgbTexture2d;
|
||||
use ::window::glium::{IndexBuffer, VertexBuffer};
|
||||
use ::window::*;
|
||||
use anyhow::anyhow;
|
||||
use config::configuration;
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
@ -16,7 +15,9 @@ pub struct RenderState {
|
||||
pub context: Rc<GliumContext>,
|
||||
pub glyph_cache: RefCell<GlyphCache<SrgbTexture2d>>,
|
||||
pub util_sprites: UtilSprites<SrgbTexture2d>,
|
||||
pub program: glium::Program,
|
||||
pub background_prog: glium::Program,
|
||||
pub line_prog: glium::Program,
|
||||
pub glyph_prog: glium::Program,
|
||||
pub glyph_vertex_buffer: RefCell<VertexBuffer<Vertex>>,
|
||||
pub glyph_index_buffer: IndexBuffer<u32>,
|
||||
pub quads: Quads,
|
||||
@ -37,32 +38,12 @@ impl RenderState {
|
||||
let result = UtilSprites::new(&mut *glyph_cache.borrow_mut(), metrics);
|
||||
match result {
|
||||
Ok(util_sprites) => {
|
||||
let mut errors = vec![];
|
||||
let mut program = None;
|
||||
for version in &["330", "300 es"] {
|
||||
let source = glium::program::ProgramCreationInput::SourceCode {
|
||||
vertex_shader: &Self::vertex_shader(version),
|
||||
fragment_shader: &Self::fragment_shader(version),
|
||||
outputs_srgb: true,
|
||||
tessellation_control_shader: None,
|
||||
tessellation_evaluation_shader: None,
|
||||
transform_feedback_varyings: None,
|
||||
uses_point_size: false,
|
||||
geometry_shader: None,
|
||||
};
|
||||
log::trace!("compiling a prog with version {}", version);
|
||||
match glium::Program::new(&context, source) {
|
||||
Ok(prog) => {
|
||||
program = Some(prog);
|
||||
break;
|
||||
}
|
||||
Err(err) => errors.push(err.to_string()),
|
||||
};
|
||||
}
|
||||
let background_prog =
|
||||
Self::compile_prog(&context, false, Self::background_shader)?;
|
||||
let line_prog = Self::compile_prog(&context, false, Self::line_shader)?;
|
||||
|
||||
let program = program.ok_or_else(|| {
|
||||
anyhow!("Failed to compile shaders: {}", errors.join("\n"))
|
||||
})?;
|
||||
// Last prog outputs srgb for gamma correction
|
||||
let glyph_prog = Self::compile_prog(&context, true, Self::glyph_shader)?;
|
||||
|
||||
let (glyph_vertex_buffer, glyph_index_buffer, quads) = Self::compute_vertices(
|
||||
&context,
|
||||
@ -75,7 +56,9 @@ impl RenderState {
|
||||
context,
|
||||
glyph_cache,
|
||||
util_sprites,
|
||||
program,
|
||||
background_prog,
|
||||
line_prog,
|
||||
glyph_prog,
|
||||
glyph_vertex_buffer: RefCell::new(glyph_vertex_buffer),
|
||||
glyph_index_buffer,
|
||||
quads,
|
||||
@ -91,6 +74,36 @@ impl RenderState {
|
||||
}
|
||||
}
|
||||
|
||||
fn compile_prog(
|
||||
context: &Rc<GliumContext>,
|
||||
outputs_srgb: bool,
|
||||
fragment_shader: fn(&str) -> (String, String),
|
||||
) -> anyhow::Result<glium::Program> {
|
||||
let mut errors = vec![];
|
||||
for version in &["330", "300 es"] {
|
||||
let (vertex_shader, fragment_shader) = fragment_shader(version);
|
||||
let source = glium::program::ProgramCreationInput::SourceCode {
|
||||
vertex_shader: &vertex_shader,
|
||||
fragment_shader: &fragment_shader,
|
||||
outputs_srgb,
|
||||
tessellation_control_shader: None,
|
||||
tessellation_evaluation_shader: None,
|
||||
transform_feedback_varyings: None,
|
||||
uses_point_size: false,
|
||||
geometry_shader: None,
|
||||
};
|
||||
log::trace!("compiling a prog with version {}", version);
|
||||
match glium::Program::new(context, source) {
|
||||
Ok(prog) => {
|
||||
return Ok(prog);
|
||||
}
|
||||
Err(err) => errors.push(err.to_string()),
|
||||
};
|
||||
}
|
||||
|
||||
anyhow::bail!("Failed to compile shaders: {}", errors.join("\n"))
|
||||
}
|
||||
|
||||
pub fn advise_of_window_size_change(
|
||||
&mut self,
|
||||
metrics: &RenderMetrics,
|
||||
@ -110,12 +123,55 @@ impl RenderState {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn vertex_shader(version: &str) -> String {
|
||||
format!("#version {}\n{}", version, include_str!("vertex.glsl"))
|
||||
fn glyph_shader(version: &str) -> (String, String) {
|
||||
(
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("vertex-common.glsl"),
|
||||
include_str!("glyph-vertex.glsl")
|
||||
),
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("fragment-common.glsl"),
|
||||
include_str!("glyph-frag.glsl")
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn fragment_shader(version: &str) -> String {
|
||||
format!("#version {}\n{}", version, include_str!("fragment.glsl"))
|
||||
fn line_shader(version: &str) -> (String, String) {
|
||||
(
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("vertex-common.glsl"),
|
||||
include_str!("line-vertex.glsl")
|
||||
),
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("fragment-common.glsl"),
|
||||
include_str!("line-frag.glsl")
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
fn background_shader(version: &str) -> (String, String) {
|
||||
(
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("vertex-common.glsl"),
|
||||
include_str!("background-vertex.glsl")
|
||||
),
|
||||
format!(
|
||||
"#version {}\n{}\n{}",
|
||||
version,
|
||||
include_str!("fragment-common.glsl"),
|
||||
include_str!("background-frag.glsl")
|
||||
),
|
||||
)
|
||||
}
|
||||
|
||||
/// Compute a vertex buffer to hold the quads that comprise the visible
|
||||
|
@ -2774,8 +2774,6 @@ impl TermWindow {
|
||||
.magnify_filter(MagnifySamplerFilter::Linear)
|
||||
.minify_filter(MinifySamplerFilter::Linear);
|
||||
|
||||
let has_background_image = self.window_background.is_some();
|
||||
|
||||
let foreground_text_hsb = configuration().foreground_text_hsb;
|
||||
let foreground_text_hsb = (
|
||||
foreground_text_hsb.hue,
|
||||
@ -2787,14 +2785,10 @@ impl TermWindow {
|
||||
frame.draw(
|
||||
&*vb,
|
||||
&gl_state.glyph_index_buffer,
|
||||
&gl_state.program,
|
||||
&gl_state.background_prog,
|
||||
&uniform! {
|
||||
projection: projection,
|
||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
||||
atlas_linear_sampler: atlas_linear_sampler,
|
||||
window_bg_layer: true,
|
||||
bg_and_line_layer: false,
|
||||
has_background_image: has_background_image,
|
||||
foreground_text_hsb: foreground_text_hsb,
|
||||
},
|
||||
&alpha_blending,
|
||||
@ -2804,14 +2798,11 @@ impl TermWindow {
|
||||
frame.draw(
|
||||
&*vb,
|
||||
&gl_state.glyph_index_buffer,
|
||||
&gl_state.program,
|
||||
&gl_state.line_prog,
|
||||
&uniform! {
|
||||
projection: projection,
|
||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
||||
atlas_linear_sampler: atlas_linear_sampler,
|
||||
window_bg_layer: false,
|
||||
bg_and_line_layer: true,
|
||||
has_background_image: has_background_image,
|
||||
foreground_text_hsb: foreground_text_hsb,
|
||||
},
|
||||
&alpha_blending,
|
||||
@ -2861,14 +2852,11 @@ impl TermWindow {
|
||||
frame.draw(
|
||||
&*vb,
|
||||
&gl_state.glyph_index_buffer,
|
||||
&gl_state.program,
|
||||
&gl_state.glyph_prog,
|
||||
&uniform! {
|
||||
projection: projection,
|
||||
atlas_nearest_sampler: atlas_nearest_sampler,
|
||||
atlas_linear_sampler: atlas_linear_sampler,
|
||||
window_bg_layer: false,
|
||||
bg_and_line_layer: false,
|
||||
has_background_image: has_background_image,
|
||||
foreground_text_hsb: foreground_text_hsb,
|
||||
},
|
||||
&blend_but_set_alpha_to_one,
|
||||
|
49
wezterm-gui/src/gui/vertex-common.glsl
Normal file
49
wezterm-gui/src/gui/vertex-common.glsl
Normal file
@ -0,0 +1,49 @@
|
||||
// This file is automatically prepended to the various
|
||||
// vertex.glsl files.
|
||||
|
||||
precision highp float;
|
||||
|
||||
in vec2 position;
|
||||
in vec2 adjust;
|
||||
in vec2 tex;
|
||||
in vec2 underline;
|
||||
in vec4 bg_color;
|
||||
in vec4 fg_color;
|
||||
in vec4 underline_color;
|
||||
in float has_color;
|
||||
in vec2 cursor;
|
||||
in vec4 cursor_color;
|
||||
in vec3 hsv;
|
||||
|
||||
uniform mat4 projection;
|
||||
|
||||
out float o_has_color;
|
||||
out vec2 o_cursor;
|
||||
out vec2 o_tex;
|
||||
out vec2 o_underline;
|
||||
out vec3 o_hsv;
|
||||
out vec4 o_bg_color;
|
||||
out vec4 o_cursor_color;
|
||||
out vec4 o_fg_color;
|
||||
out vec4 o_underline_color;
|
||||
|
||||
void pass_through_vertex() {
|
||||
o_tex = tex;
|
||||
o_has_color = has_color;
|
||||
o_fg_color = fg_color;
|
||||
o_bg_color = bg_color;
|
||||
o_underline = underline;
|
||||
o_underline_color = underline_color;
|
||||
o_cursor = cursor;
|
||||
o_cursor_color = cursor_color;
|
||||
o_hsv = hsv;
|
||||
}
|
||||
|
||||
// Returns a position that is outside of the viewport,
|
||||
// such that this vertex effectively won't contribute
|
||||
// the scene being rendered.
|
||||
// There may be a better way to do this.
|
||||
vec4 off_screen() {
|
||||
return vec4(100.0, 100.0, 100.0, 100.0);
|
||||
}
|
||||
|
@ -1,68 +0,0 @@
|
||||
precision highp float;
|
||||
|
||||
in vec2 position;
|
||||
in vec2 adjust;
|
||||
in vec2 tex;
|
||||
in vec2 underline;
|
||||
in vec4 bg_color;
|
||||
in vec4 fg_color;
|
||||
in vec4 underline_color;
|
||||
in float has_color;
|
||||
in vec2 cursor;
|
||||
in vec4 cursor_color;
|
||||
in vec3 hsv;
|
||||
|
||||
uniform mat4 projection;
|
||||
uniform bool window_bg_layer;
|
||||
uniform bool bg_and_line_layer;
|
||||
uniform bool has_background_image;
|
||||
|
||||
out float o_has_color;
|
||||
out vec2 o_cursor;
|
||||
out vec2 o_tex;
|
||||
out vec2 o_underline;
|
||||
out vec3 o_hsv;
|
||||
out vec4 o_bg_color;
|
||||
out vec4 o_cursor_color;
|
||||
out vec4 o_fg_color;
|
||||
out vec4 o_underline_color;
|
||||
|
||||
// Returns a position that is outside of the viewport,
|
||||
// such that this vertex effectively won't contribute
|
||||
// the scene being rendered.
|
||||
// There may be a better way to do this.
|
||||
vec4 off_screen() {
|
||||
return vec4(100.0, 100.0, 100.0, 100.0);
|
||||
}
|
||||
|
||||
void main() {
|
||||
o_tex = tex;
|
||||
o_has_color = has_color;
|
||||
o_fg_color = fg_color;
|
||||
o_bg_color = bg_color;
|
||||
o_underline = underline;
|
||||
o_underline_color = underline_color;
|
||||
o_cursor = cursor;
|
||||
o_cursor_color = cursor_color;
|
||||
o_hsv = hsv;
|
||||
|
||||
if (window_bg_layer) {
|
||||
if (o_has_color == 2.0) {
|
||||
// Background image takes up its full coordinates
|
||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||
} else {
|
||||
// Nothing else should render on the background layer
|
||||
gl_Position = off_screen();
|
||||
}
|
||||
} else if (o_has_color == 2.0) {
|
||||
// If we're the background image and we're not rendering
|
||||
// the background layer, then move this off screen
|
||||
gl_Position = off_screen();
|
||||
} else if (bg_and_line_layer) {
|
||||
// Want to fill the whole cell when painting backgrounds
|
||||
gl_Position = projection * vec4(position, 0.0, 1.0);
|
||||
} else {
|
||||
// Use only the adjusted cell position to render the glyph
|
||||
gl_Position = projection * vec4(position + adjust, 0.0, 1.0);
|
||||
}
|
||||
}
|
@ -4,6 +4,16 @@ use palette::{Blend, LinSrgb, LinSrgba, Srgb, Srgba};
|
||||
lazy_static::lazy_static! {
|
||||
static ref SRGB_TO_F32_TABLE: [f32;256] = generate_srgb8_to_linear_f32_table();
|
||||
static ref F32_TO_U8_TABLE: [u32;104] = generate_linear_f32_to_srgb8_table();
|
||||
static ref RGB_TO_SRGB_TABLE: [u8;256] = generate_rgb_to_srgb8_table();
|
||||
}
|
||||
|
||||
fn generate_rgb_to_srgb8_table() -> [u8; 256] {
|
||||
let mut table = [0; 256];
|
||||
for (val, entry) in table.iter_mut().enumerate() {
|
||||
let linear = (val as f32) / 255.0;
|
||||
*entry = linear_f32_to_srgb8_using_table(linear);
|
||||
}
|
||||
table
|
||||
}
|
||||
|
||||
fn generate_srgb8_to_linear_f32_table() -> [f32; 256] {
|
||||
@ -107,6 +117,10 @@ fn linear_f32_to_srgbf32(f: f32) -> f32 {
|
||||
}
|
||||
*/
|
||||
|
||||
pub fn linear_u8_to_srgb8(f: u8) -> u8 {
|
||||
unsafe { *RGB_TO_SRGB_TABLE.get_unchecked(f as usize) }
|
||||
}
|
||||
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
const ALMOST_ONE: u32 = 0x3f7fffff;
|
||||
#[allow(clippy::unreadable_literal)]
|
||||
@ -289,6 +303,16 @@ impl Color {
|
||||
Color(word.to_be())
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn with_linear_rgba_u8(red: u8, green: u8, blue: u8, alpha: u8) -> Color {
|
||||
Self::rgba(
|
||||
linear_u8_to_srgb8(red),
|
||||
linear_u8_to_srgb8(green),
|
||||
linear_u8_to_srgb8(blue),
|
||||
linear_u8_to_srgb8(alpha),
|
||||
)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn as_rgba(self) -> (u8, u8, u8, u8) {
|
||||
let host = u32::from_be(self.0);
|
||||
|
Loading…
Reference in New Issue
Block a user