webgl: Implement linear RGB gradients

This commit is contained in:
Mike Welsh 2020-05-20 15:02:31 -07:00
parent c30453c144
commit 09ca11f788
4 changed files with 55 additions and 6 deletions

View File

@ -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],
]
}

View File

@ -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)]

View File

@ -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;;
}

View File

@ -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,
}