From 09ca11f788ef5c5efa45a40d96e3cbe5be9e940b Mon Sep 17 00:00:00 2001 From: Mike Welsh Date: Wed, 20 May 2020 15:02:31 -0700 Subject: [PATCH] webgl: Implement linear RGB gradients --- core/src/backend/render.rs | 17 +++++++++++++++++ render/common_tess/src/lib.rs | 6 +++++- render/webgl/shaders/gradient.frag | 16 +++++++++++++++- render/webgl/src/lib.rs | 22 ++++++++++++++++++---- 4 files changed, 55 insertions(+), 6 deletions(-) diff --git a/core/src/backend/render.rs b/core/src/backend/render.rs index fab5e2f79..ebf021b2b 100644 --- a/core/src/backend/render.rs +++ b/core/src/backend/render.rs @@ -478,3 +478,20 @@ pub fn unmultiply_alpha_rgba(rgba: &mut [u8]) { } }) } + +/// Converts an RGBA color from sRGB space to linear color space. +pub fn srgb_to_linear(color: [f32; 4]) -> [f32; 4] { + fn to_linear_channel(n: f32) -> f32 { + if n <= 0.04045 { + n / 12.92 + } else { + f32::powf((n + 0.055) / 1.055, 2.4) + } + } + [ + to_linear_channel(color[0]), + to_linear_channel(color[1]), + to_linear_channel(color[2]), + color[3], + ] +} diff --git a/render/common_tess/src/lib.rs b/render/common_tess/src/lib.rs index 0899efeee..be09a3217 100644 --- a/render/common_tess/src/lib.rs +++ b/render/common_tess/src/lib.rs @@ -5,7 +5,7 @@ use lyon::tessellation::{ FillAttributes, FillTessellator, StrokeAttributes, StrokeTessellator, StrokeVertexConstructor, }; use lyon::tessellation::{FillOptions, StrokeOptions}; -use ruffle_core::backend::render::swf::{self, FillStyle, Twips}; +use ruffle_core::backend::render::swf::{self, FillStyle, GradientInterpolation, Twips}; use ruffle_core::shape_utils::{DistilledShape, DrawCommand, DrawPath}; pub struct ShapeTessellator { @@ -102,6 +102,7 @@ impl ShapeTessellator { matrix: swf_to_gl_matrix(gradient.matrix), repeat_mode: gradient.spread, focal_point: 0.0, + interpolation: gradient.interpolation, }; flush_draw(DrawType::Gradient(gradient), &mut mesh, &mut lyon_mesh); @@ -144,6 +145,7 @@ impl ShapeTessellator { matrix: swf_to_gl_matrix(gradient.matrix), repeat_mode: gradient.spread, focal_point: 0.0, + interpolation: gradient.interpolation, }; flush_draw(DrawType::Gradient(gradient), &mut mesh, &mut lyon_mesh); @@ -189,6 +191,7 @@ impl ShapeTessellator { matrix: swf_to_gl_matrix(gradient.matrix), repeat_mode: gradient.spread, focal_point: *focal_point, + interpolation: gradient.interpolation, }; flush_draw(DrawType::Gradient(gradient), &mut mesh, &mut lyon_mesh); @@ -319,6 +322,7 @@ pub struct Gradient { pub num_colors: u32, pub repeat_mode: GradientSpread, pub focal_point: f32, + pub interpolation: GradientInterpolation, } #[derive(Copy, Clone, Debug)] diff --git a/render/webgl/shaders/gradient.frag b/render/webgl/shaders/gradient.frag index 98c206045..53177f87e 100644 --- a/render/webgl/shaders/gradient.frag +++ b/render/webgl/shaders/gradient.frag @@ -13,9 +13,18 @@ uniform vec4 u_colors[8]; uniform int u_num_colors; uniform int u_repeat_mode; uniform float u_focal_point; +uniform int u_interpolation; varying vec2 frag_uv; +vec3 linear_to_srgb(vec3 linear) +{ + vec3 a = 12.92 * linear; + vec3 b = 1.055 * pow(linear, vec3(1.0 / 2.4)) - 0.055; + vec3 c = step(vec3(0.0031308), linear); + return mix(a, b, c); +} + void main() { float t; if( u_gradient_type == 0 ) @@ -90,5 +99,10 @@ void main() { color = u_colors[7]; } - gl_FragColor = mult_color * color + add_color; + if( u_interpolation != 0 ) { + color = vec4(linear_to_srgb(vec3(color)), color.a); + } + + gl_FragColor = mult_color * color + add_color;; } + diff --git a/render/webgl/src/lib.rs b/render/webgl/src/lib.rs index def697b3e..9778d1778 100644 --- a/render/webgl/src/lib.rs +++ b/render/webgl/src/lib.rs @@ -1,7 +1,7 @@ use ruffle_core::backend::render::swf::{self, FillStyle}; use ruffle_core::backend::render::{ - Bitmap, BitmapFormat, BitmapHandle, BitmapInfo, Color, Letterbox, RenderBackend, ShapeHandle, - Transform, + srgb_to_linear, Bitmap, BitmapFormat, BitmapHandle, BitmapInfo, Color, Letterbox, + RenderBackend, ShapeHandle, Transform, }; use ruffle_core::shape_utils::DistilledShape; use ruffle_render_common_tess::{GradientSpread, GradientType, ShapeTessellator, Vertex}; @@ -74,7 +74,6 @@ impl WebGlRenderBackend { ("antialias", JsValue::FALSE), ("depth", JsValue::FALSE), ]; - let context_options = js_sys::Object::new(); for (name, value) in options.iter() { js_sys::Reflect::set(&context_options, &JsValue::from(*name), value).warn_on_error(); @@ -484,6 +483,12 @@ impl WebGlRenderBackend { let num_colors = gradient.num_colors as usize; ratios[..num_colors].copy_from_slice(&gradient.ratios[..num_colors]); colors[..num_colors].copy_from_slice(&gradient.colors[..num_colors]); + // Convert to linear color space if this is a linear-interpolated gradient. + if gradient.interpolation == swf::GradientInterpolation::LinearRGB { + for color in &mut colors[..num_colors] { + *color = srgb_to_linear(*color); + } + } for i in num_colors..8 { ratios[i] = ratios[i - 1]; colors[i] = colors[i - 1]; @@ -504,6 +509,7 @@ impl WebGlRenderBackend { GradientSpread::Reflect => 2, }, focal_point: gradient.focal_point, + interpolation: gradient.interpolation, }; ( &self.gradient_program, @@ -1032,6 +1038,11 @@ impl RenderBackend for WebGlRenderBackend { ShaderUniform::GradientFocalPoint, gradient.focal_point, ); + program.uniform1i( + &self.gl, + ShaderUniform::GradientInterpolation, + (gradient.interpolation == swf::GradientInterpolation::LinearRGB) as i32, + ); } DrawType::Bitmap(bitmap) => { let texture = &self @@ -1186,6 +1197,7 @@ struct Gradient { num_colors: u32, repeat_mode: i32, focal_point: f32, + interpolation: swf::GradientInterpolation, } #[derive(Clone, Debug)] @@ -1235,7 +1247,7 @@ struct ShaderProgram { } // These should match the uniform names in the shaders. -const NUM_UNIFORMS: usize = 12; +const NUM_UNIFORMS: usize = 13; const UNIFORM_NAMES: [&str; NUM_UNIFORMS] = [ "world_matrix", "view_matrix", @@ -1248,6 +1260,7 @@ const UNIFORM_NAMES: [&str; NUM_UNIFORMS] = [ "u_num_colors", "u_repeat_mode", "u_focal_point", + "u_interpolation", "u_texture", ]; @@ -1263,6 +1276,7 @@ enum ShaderUniform { GradientNumColors, GradientRepeatMode, GradientFocalPoint, + GradientInterpolation, BitmapTexture, }