bgfx: crt-geom and crt-geom-deluxe improvements: (#8653)

* crt-geom-deluxe: Increased number of taps for halation and increased maximum width.
* crt-geom*: Moved repeated crt-geom/crt-geom-deluxe functions into their own file.
* crt-geom and crt-geom-deluxe: added support for sRGB output gamma ramp and made it the default.
This commit is contained in:
cgwg 2022-07-07 10:15:55 +01:00 committed by GitHub
parent f3fb60fee6
commit 75466ad87d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
36 changed files with 265 additions and 374 deletions

View File

@ -133,7 +133,7 @@
"name": "blurwidth",
"text": "Halation blur width",
"default": 2.0,
"max" : 4.0,
"max" : 8.0,
"min" : 0.1,
"step" : 0.1,
"format": "%1.1f",
@ -210,9 +210,19 @@
"step" : 0.05,
"format": "%1.2f",
"screen": "raster" },
{ "type": "intenum",
"name": "monitorsRGB",
"text": "Gamma of output display",
"default": 1,
"max" : 1,
"min" : 0,
"step" : 1,
"format": "%s",
"strings": [ "custom", "sRGB" ],
"screen": "raster" },
{ "type": "float",
"name": "monitorgamma",
"text": "Gamma of output display",
"text": " custom gamma",
"default": 2.2,
"max" : 4.0,
"min" : 0.7,
@ -341,6 +351,7 @@
{ "uniform": "overscan", "slider": "overscan" },
{ "uniform": "aspect", "slider": "aspect" },
{ "uniform": "CRTgamma", "slider": "CRTgamma" },
{ "uniform": "monitorsRGB", "slider": "monitorsRGB" },
{ "uniform": "monitorgamma","slider": "monitorgamma" },
{ "uniform": "aperture_strength","slider": "aperture_strength" },
{ "uniform": "aperture_brightboost","slider": "aperture_brightboost" },

View File

@ -129,9 +129,19 @@
"step" : 0.05,
"format": "%1.2f",
"screen": "raster" },
{ "type": "intenum",
"name": "monitorsRGB",
"text": "Gamma of output display",
"default": 1,
"max" : 1,
"min" : 0,
"step" : 1,
"format": "%s",
"strings": [ "custom", "sRGB" ],
"screen": "raster" },
{ "type": "float",
"name": "monitorgamma",
"text": "Gamma of output display",
"text": " custom gamma",
"default": 2.2,
"max" : 4.0,
"min" : 0.7,
@ -165,6 +175,7 @@
{ "uniform": "overscan", "slider": "overscan" },
{ "uniform": "aspect", "slider": "aspect" },
{ "uniform": "CRTgamma", "slider": "CRTgamma" },
{ "uniform": "monitorsRGB", "slider": "monitorsRGB" },
{ "uniform": "monitorgamma","slider": "monitorgamma" },
{ "uniform": "aperture_strength", "slider": "aperture_strength" },
{ "uniform": "aperture_brightboost","slider": "aperture_brightboost" },

View File

@ -30,6 +30,7 @@
{ "name": "mipmap_texture", "type": "int", "values": [ 3 ] },
{ "name": "curvature", "type": "vec4", "values": [ 1.0, 0.0, 0.0, 0.0 ] },
{ "name": "CRTgamma", "type": "vec4", "values": [ 2.4, 0.0, 0.0, 0.0 ] },
{ "name": "monitorsRGB", "type": "vec4", "values": [ 1.0, 0.0, 0.0, 0.0 ] },
{ "name": "monitorgamma", "type": "vec4", "values": [ 2.2, 0.0, 0.0, 0.0 ] },
{ "name": "overscan", "type": "vec4", "values": [ 1.0, 1.0, 0.0, 0.0 ] },
{ "name": "aspect", "type": "vec4", "values": [ 1.0, 0.75,0.0, 0.0 ] },

View File

@ -28,6 +28,7 @@
{ "name": "mask_texture", "type": "int", "values": [ 1 ] },
{ "name": "curvature", "type": "vec4", "values": [ 1.0, 0.0, 0.0, 0.0 ] },
{ "name": "CRTgamma", "type": "vec4", "values": [ 2.4, 0.0, 0.0, 0.0 ] },
{ "name": "monitorsRGB", "type": "vec4", "values": [ 1.0, 0.0, 0.0, 0.0 ] },
{ "name": "monitorgamma", "type": "vec4", "values": [ 2.2, 0.0, 0.0, 0.0 ] },
{ "name": "overscan", "type": "vec4", "values": [ 1.0, 1.0, 0.0, 0.0 ] },
{ "name": "aspect", "type": "vec4", "values": [ 1.0, 0.75,0.0, 0.0 ] },

View File

@ -0,0 +1,203 @@
// Comment the next line to disable interpolation in linear gamma (and gain speed).
//#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile
#define OVERSAMPLE
// Use the older, purely gaussian beam profile
#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5)
#define PI 3.141592653589
vec4 TEX2D(vec2 c)
{
vec2 underscan = step(0.0,c) * step(0.0,vec2_splat(1.0)-c);
vec4 col = texture2D(mpass_texture, c) * vec4_splat(underscan.x*underscan.y);
#ifdef LINEAR_PROCESSING
col = pow(col, vec4_splat(CRTgamma.x));
#endif
return col;
}
// Enable screen curvature.
uniform vec4 curvature;
uniform vec4 spot_size;
uniform vec4 spot_growth;
uniform vec4 spot_growth_power;
uniform vec4 u_interp;
uniform vec4 aperture_strength;
uniform vec4 aperture_brightboost;
uniform vec4 CRTgamma;
uniform vec4 monitorsRGB;
uniform vec4 monitorgamma;
uniform vec4 overscan;
uniform vec4 aspect;
uniform vec4 d;
uniform vec4 R;
uniform vec4 cornersize;
uniform vec4 cornersmooth;
float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
{
float A = dot(xy,xy)+d.x*d.x;
float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
{
float c = intersect(xy, sinangle, cosangle);
vec2 pt = vec2_splat(c)*xy;
pt -= vec2_splat(-R.x)*sinangle;
pt /= vec2_splat(R.x);
vec2 tang = sinangle/cosangle;
vec2 poc = pt/cosangle;
float A = dot(tang,tang)+1.0;
float B = -2.0*dot(poc,tang);
float C = dot(poc,poc)-1.0;
float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
vec2 uv = (pt-a*sinangle)/cosangle;
float r = FIX(R.x*acos(a));
return uv*r/sin(r/R.x);
}
vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
{
coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
}
float corner(vec2 coord)
{
coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
vec2 cdist = vec2_splat(cornersize.x);
coord = (cdist - min(coord,cdist));
float dist = sqrt(dot(coord,coord));
return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
}
// Calculate the influence of a scanline on the current pixel.
//
// 'distance' is the distance in texture coordinates from the current
// pixel to the scanline in question.
// 'color' is the colour of the scanline at the horizontal location of
// the current pixel.
vec4 scanlineWeights(float distance, vec4 color)
{
// "wid" controls the width of the scanline beam, for each RGB channel
// The "weights" lines basically specify the formula that gives
// you the profile of the beam, i.e. the intensity as
// a function of distance from the vertical center of the
// scanline. In this case, it is gaussian if width=2, and
// becomes nongaussian for larger widths. Ideally this should
// be normalized so that the integral across the beam is
// independent of its width. That is, for a narrower beam
// "weights" should have a higher peak at the center of the
// scanline than for a wider beam.
#ifdef USEGAUSSIAN
vec4 wid = spot_size.x + spot_growth.x * pow(color, vec4_splat(spot_growth_power.x));
vec4 weights = vec4(distance / wid);
float maxwid = spot_size.x + spot_growth.x;
float norm = maxwid / ( 1.0 + exp(-1.0/(maxwid*maxwid)) );
return norm * exp(-weights * weights) / wid;
#else
vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
vec4 weights = vec4_splat(distance / 0.3);
return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
#endif
}
vec4 cubic(vec4 x, float B, float C)
{
// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters
vec2 a = x.yz; // components in [0,1]
vec2 b = x.xw; // components in [1,2]
vec2 a2 = a*a;
vec2 b2 = b*b;
a = (2.0-1.5*B-1.0*C)*a*a2 + (-3.0+2.0*B+C)*a2 + (1.0-(1.0/3.0)*B);
b = ((-1.0/6.0)*B-C)*b*b2 + (B+5.0*C)*b2 + (-2.0*B-8.0*C)*b + ((4.0/3.0)*B+4.0*C);
return vec4(b.x,a.x,a.y,b.y);
}
vec4 x_coeffs(vec4 x, float pos_x)
{
if (u_interp.x < 0.5) { // box
float wid = length(vec2(dFdx(pos_x),dFdy(pos_x)));
float dx = clamp((0.5 + 0.5*wid - x.y)/wid, 0.0, 1.0);
return vec4(0.0,dx,1.0-dx,0.0);
} else if (u_interp.x < 1.5) { // linear
return vec4(0.0, 1.0-x.y, 1.0-x.z, 0.0);
} else if (u_interp.x < 2.5) { // Lanczos
// Prevent division by zero.
vec4 coeffs = FIX(PI * x);
// Lanczos2 kernel.
coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
// Normalize.
coeffs /= dot(coeffs, vec4_splat(1.0));
return coeffs;
} else if (u_interp.x < 3.5) { // Catmull-Rom
return cubic(x,0.0,0.5);
} else if (u_interp.x < 4.5) { // Mitchell-Netravali
return cubic(x,1.0/3.0,1.0/3.0);
} else /*if (u_interp.x < 5.5)*/ { // B-spline
return cubic(x,1.0,0.0);
}
}
vec4 sample_scanline(vec2 xy, vec4 coeffs, float onex)
{
// Calculate the effective colour of the given
// scanline at the horizontal location of the current pixel,
// using the Lanczos coefficients.
vec4 col = clamp(TEX2D(xy + vec2(-onex, 0.0))*coeffs.x +
TEX2D(xy)*coeffs.y +
TEX2D(xy +vec2(onex, 0.0))*coeffs.z +
TEX2D(xy + vec2(2.0 * onex, 0.0))*coeffs.w , 0.0, 1.0);
return col;
}
vec3 apply_shadow_mask(vec2 coord, vec3 col)
{
vec2 xy = coord * u_quad_dims.xy / u_tex_size1.xy;
vec4 mask = texture2D(mask_texture, xy);
// count of total bright pixels is encoded in the mask's alpha channel
float nbright = 255.0 - 255.0*mask.a;
// fraction of bright pixels in the mask
float fbright = nbright / ( u_tex_size1.x * u_tex_size1.y );
// average darkening factor of the mask
float aperture_average = mix(1.0-aperture_strength.x*(1.0-aperture_brightboost.x), 1.0, fbright);
// colour of dark mask pixels
vec3 clow = vec3_splat(1.0-aperture_strength.x) * col + vec3_splat(aperture_strength.x*(aperture_brightboost.x)) * col * col;
float ifbright = 1.0 / fbright;
// colour of bright mask pixels
vec3 chi = vec3_splat(ifbright*aperture_average) * col - vec3_splat(ifbright - 1.0) * clow;
return mix(clow,chi,mask.rgb); // mask texture selects dark vs bright
}
vec3 linear_to_sRGB(vec3 col)
{
// only applies the gamma ramp; does not adjust the primaries
vec3 linear_ramp = vec3(lessThan(col, vec3_splat(0.0031308)));
vec3 clin = col * vec3_splat(12.92);
vec3 cpow = pow(col, vec3_splat(1.0/2.4)) * vec3_splat(1.055) - vec3_splat(0.055);
return mix(cpow, clin, linear_ramp);
}
vec3 linear_to_output(vec3 col)
{
if (monitorsRGB.x > 0.5)
return linear_to_sRGB(col);
else
return pow(col, vec3_splat(1.0 / monitorgamma.x));
}

View File

@ -12,61 +12,16 @@ $input v_sinangle, v_cosangle, v_stretch, v_one, v_texCoord
#include "common.sh"
// Comment the next line to disable interpolation in linear gamma (and gain speed).
//#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile
#define OVERSAMPLE
// Use the older, purely gaussian beam profile
#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5)
#define PI 3.141592653589
SAMPLER2D(mpass_texture, 0);
SAMPLER2D(mask_texture, 1);
SAMPLER2D(blur_texture, 2);
SAMPLER2D(mipmap_texture, 3);
vec4 TEX2D(vec2 c)
{
vec2 underscan = step(0.0,c) * step(0.0,vec2_splat(1.0)-c);
vec4 col = texture2D(mpass_texture, c) * vec4_splat(underscan.x*underscan.y);
#ifdef LINEAR_PROCESSING
col = pow(col, vec4_splat(CRTgamma.x));
#endif
return col;
}
// Enable screen curvature.
uniform vec4 curvature;
uniform vec4 u_tex_size0;
uniform vec4 u_tex_size1;
uniform vec4 u_quad_dims;
uniform vec4 spot_size;
uniform vec4 spot_growth;
uniform vec4 spot_growth_power;
uniform vec4 u_interp;
uniform vec4 aperture_strength;
uniform vec4 aperture_brightboost;
uniform vec4 CRTgamma;
uniform vec4 monitorgamma;
uniform vec4 overscan;
uniform vec4 aspect;
uniform vec4 d;
uniform vec4 R;
uniform vec4 cornersize;
uniform vec4 cornersmooth;
#include "crt-geom_common.sc"
uniform vec4 halation;
uniform vec4 rasterbloom;
@ -86,127 +41,6 @@ vec3 texblur(vec2 c)
return col * vec3_splat( c.x * c.y );
}
float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
{
float A = dot(xy,xy)+d.x*d.x;
float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
{
float c = intersect(xy, sinangle, cosangle);
vec2 pt = vec2_splat(c)*xy;
pt -= vec2_splat(-R.x)*sinangle;
pt /= vec2_splat(R.x);
vec2 tang = sinangle/cosangle;
vec2 poc = pt/cosangle;
float A = dot(tang,tang)+1.0;
float B = -2.0*dot(poc,tang);
float C = dot(poc,poc)-1.0;
float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
vec2 uv = (pt-a*sinangle)/cosangle;
float r = FIX(R.x*acos(a));
return uv*r/sin(r/R.x);
}
vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
{
coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
}
float corner(vec2 coord)
{
coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
vec2 cdist = vec2_splat(cornersize.x);
coord = (cdist - min(coord,cdist));
float dist = sqrt(dot(coord,coord));
return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
}
// Calculate the influence of a scanline on the current pixel.
//
// 'distance' is the distance in texture coordinates from the current
// pixel to the scanline in question.
// 'color' is the colour of the scanline at the horizontal location of
// the current pixel.
vec4 scanlineWeights(float distance, vec4 color)
{
// "wid" controls the width of the scanline beam, for each RGB channel
// The "weights" lines basically specify the formula that gives
// you the profile of the beam, i.e. the intensity as
// a function of distance from the vertical center of the
// scanline. In this case, it is gaussian if width=2, and
// becomes nongaussian for larger widths. Ideally this should
// be normalized so that the integral across the beam is
// independent of its width. That is, for a narrower beam
// "weights" should have a higher peak at the center of the
// scanline than for a wider beam.
#ifdef USEGAUSSIAN
vec4 wid = spot_size.x + spot_growth.x * pow(color, vec4_splat(spot_growth_power.x));
vec4 weights = vec4(distance / wid);
float maxwid = spot_size.x + spot_growth.x;
float norm = maxwid / ( 1.0 + 2.0 * exp(-1.0/(maxwid*maxwid)) );
return norm * exp(-weights * weights) / wid;
#else
vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
vec4 weights = vec4_splat(abs(distance) / 0.3);
return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
#endif
}
vec4 cubic(vec4 x, float B, float C)
{
// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters
vec2 a = x.yz; // components in [0,1]
vec2 b = x.xw; // components in [1,2]
vec2 a2 = a*a;
vec2 b2 = b*b;
a = (2.0-1.5*B-1.0*C)*a*a2 + (-3.0+2.0*B+C)*a2 + (1.0-(1.0/3.0)*B);
b = ((-1.0/6.0)*B-C)*b*b2 + (B+5.0*C)*b2 + (-2.0*B-8.0*C)*b + ((4.0/3.0)*B+4.0*C);
return vec4(b.x,a.x,a.y,b.y);
}
vec4 x_coeffs(vec4 x, float pos_x)
{
if (u_interp.x < 0.5) { // box
float wid = length(vec2(dFdx(pos_x),dFdy(pos_x)));
float dx = clamp((0.5 + 0.5*wid - x.y)/wid, 0.0, 1.0);
return vec4(0.0,dx,1.0-dx,0.0);
} else if (u_interp.x < 1.5) { // linear
return vec4(0.0, 1.0-x.y, 1.0-x.z, 0.0);
} else if (u_interp.x < 2.5) { // Lanczos
// Prevent division by zero.
vec4 coeffs = FIX(PI * x);
// Lanczos2 kernel.
coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
// Normalize.
coeffs /= dot(coeffs, vec4_splat(1.0));
return coeffs;
} else if (u_interp.x < 3.5) { // Catmull-Rom
return cubic(x,0.0,0.5);
} else if (u_interp.x < 4.5) { // Mitchell-Netravali
return cubic(x,1.0/3.0,1.0/3.0);
} else /*if (u_interp.x < 5.5)*/ { // B-spline
return cubic(x,1.0,0.0);
}
}
vec4 sample_scanline(vec2 xy, vec4 coeffs, float onex)
{
// Calculate the effective colour of the given
// scanline at the horizontal location of the current pixel,
// using the Lanczos coefficients.
vec4 col = clamp(TEX2D(xy + vec2(-onex, 0.0))*coeffs.x +
TEX2D(xy)*coeffs.y +
TEX2D(xy +vec2(onex, 0.0))*coeffs.z +
TEX2D(xy + vec2(2.0 * onex, 0.0))*coeffs.w , 0.0, 1.0);
return col;
}
void main()
{
// Here's a helpful diagram to keep in mind while trying to
@ -300,23 +134,10 @@ void main()
mul_res = mix(mul_res, blur, halation.x) * vec3_splat(cval*rbloom);
// Shadow mask
xy = v_texCoord.xy * u_quad_dims.xy / u_tex_size1.xy;
vec4 mask = texture2D(mask_texture, xy);
// count of total bright pixels is encoded in the mask's alpha channel
float nbright = 255.0 - 255.0*mask.a;
// fraction of bright pixels in the mask
float fbright = nbright / ( u_tex_size1.x * u_tex_size1.y );
// average darkening factor of the mask
float aperture_average = mix(1.0-aperture_strength.x*(1.0-aperture_brightboost.x), 1.0, fbright);
// colour of dark mask pixels
vec3 clow = vec3_splat(1.0-aperture_strength.x) * mul_res + vec3_splat(aperture_strength.x*(aperture_brightboost.x)) * mul_res * mul_res;
float ifbright = 1.0 / fbright;
// colour of bright mask pixels
vec3 chi = vec3_splat(ifbright*aperture_average) * mul_res - vec3_splat(ifbright - 1.0) * clow;
vec3 cout = mix(clow,chi,mask.rgb); // mask texture selects dark vs bright
vec3 cout = apply_shadow_mask(v_texCoord.xy, mul_res);
// Convert the image gamma for display on our output device.
cout = pow(cout, vec3_splat(1.0 / monitorgamma.x));
cout = linear_to_output(cout);
gl_FragColor = vec4(cout,1.0);
}

View File

@ -12,180 +12,15 @@ $input v_sinangle, v_cosangle, v_stretch, v_one, v_texCoord
#include "common.sh"
// Comment the next line to disable interpolation in linear gamma (and gain speed).
//#define LINEAR_PROCESSING
// Enable 3x oversampling of the beam profile
#define OVERSAMPLE
// Use the older, purely gaussian beam profile
#define USEGAUSSIAN
// Macros.
#define FIX(c) max(abs(c), 1e-5)
#define PI 3.141592653589
SAMPLER2D(mpass_texture, 0);
SAMPLER2D(mask_texture, 1);
vec4 TEX2D(vec2 c)
{
vec2 underscan = step(0.0,c) * step(0.0,vec2_splat(1.0)-c);
vec4 col = texture2D(mpass_texture, c) * vec4_splat(underscan.x*underscan.y);
#ifdef LINEAR_PROCESSING
col = pow(col, vec4_splat(CRTgamma.x));
#endif
return col;
}
// Enable screen curvature.
uniform vec4 curvature;
uniform vec4 u_tex_size0;
uniform vec4 u_tex_size1;
uniform vec4 u_quad_dims;
uniform vec4 spot_size;
uniform vec4 spot_growth;
uniform vec4 spot_growth_power;
#include "crt-geom_common.sc"
uniform vec4 u_interp;
uniform vec4 aperture_strength;
uniform vec4 aperture_brightboost;
uniform vec4 CRTgamma;
uniform vec4 monitorgamma;
uniform vec4 overscan;
uniform vec4 aspect;
uniform vec4 d;
uniform vec4 R;
uniform vec4 cornersize;
uniform vec4 cornersmooth;
float intersect(vec2 xy , vec2 sinangle, vec2 cosangle)
{
float A = dot(xy,xy)+d.x*d.x;
float B = 2.0*(R.x*(dot(xy,sinangle)-d.x*cosangle.x*cosangle.y)-d.x*d.x);
float C = d.x*d.x + 2.0*R.x*d.x*cosangle.x*cosangle.y;
return (-B-sqrt(B*B-4.0*A*C))/(2.0*A);
}
vec2 bkwtrans(vec2 xy, vec2 sinangle, vec2 cosangle)
{
float c = intersect(xy, sinangle, cosangle);
vec2 pt = vec2_splat(c)*xy;
pt -= vec2_splat(-R.x)*sinangle;
pt /= vec2_splat(R.x);
vec2 tang = sinangle/cosangle;
vec2 poc = pt/cosangle;
float A = dot(tang,tang)+1.0;
float B = -2.0*dot(poc,tang);
float C = dot(poc,poc)-1.0;
float a = (-B+sqrt(B*B-4.0*A*C))/(2.0*A);
vec2 uv = (pt-a*sinangle)/cosangle;
float r = FIX(R.x*acos(a));
return uv*r/sin(r/R.x);
}
vec2 transform(vec2 coord, vec3 stretch, vec2 sinangle, vec2 cosangle)
{
coord = (coord-vec2_splat(0.5))*aspect.xy*stretch.z+stretch.xy;
return (bkwtrans(coord, sinangle, cosangle)/overscan.xy/aspect.xy+vec2_splat(0.5));
}
float corner(vec2 coord)
{
coord = (coord - vec2_splat(0.5)) * overscan.xy + vec2_splat(0.5);
coord = min(coord, vec2_splat(1.0)-coord) * aspect.xy;
vec2 cdist = vec2_splat(cornersize.x);
coord = (cdist - min(coord,cdist));
float dist = sqrt(dot(coord,coord));
return clamp((max(cdist.x,1e-3)-dist)*cornersmooth.x,0.0, 1.0);
}
// Calculate the influence of a scanline on the current pixel.
//
// 'distance' is the distance in texture coordinates from the current
// pixel to the scanline in question.
// 'color' is the colour of the scanline at the horizontal location of
// the current pixel.
vec4 scanlineWeights(float distance, vec4 color)
{
// "wid" controls the width of the scanline beam, for each RGB channel
// The "weights" lines basically specify the formula that gives
// you the profile of the beam, i.e. the intensity as
// a function of distance from the vertical center of the
// scanline. In this case, it is gaussian if width=2, and
// becomes nongaussian for larger widths. Ideally this should
// be normalized so that the integral across the beam is
// independent of its width. That is, for a narrower beam
// "weights" should have a higher peak at the center of the
// scanline than for a wider beam.
#ifdef USEGAUSSIAN
vec4 wid = spot_size.x + spot_growth.x * pow(color, vec4_splat(spot_growth_power.x));
vec4 weights = vec4(distance / wid);
float maxwid = spot_size.x + spot_growth.x;
float norm = maxwid / ( 1.0 + exp(-1.0/(maxwid*maxwid)) );
return norm * exp(-weights * weights) / wid;
#else
vec4 wid = 2.0 + 2.0 * pow(color, vec4_splat(4.0));
vec4 weights = vec4_splat(distance / 0.3);
return 1.4 * exp(-pow(weights * inversesqrt(0.5 * wid), wid)) / (0.6 + 0.2 * wid);
#endif
}
vec4 cubic(vec4 x, float B, float C)
{
// https://en.wikipedia.org/wiki/Mitchell%E2%80%93Netravali_filters
vec2 a = x.yz; // components in [0,1]
vec2 b = x.xw; // components in [1,2]
vec2 a2 = a*a;
vec2 b2 = b*b;
a = (2.0-1.5*B-1.0*C)*a*a2 + (-3.0+2.0*B+C)*a2 + (1.0-(1.0/3.0)*B);
b = ((-1.0/6.0)*B-C)*b*b2 + (B+5.0*C)*b2 + (-2.0*B-8.0*C)*b + ((4.0/3.0)*B+4.0*C);
return vec4(b.x,a.x,a.y,b.y);
}
vec4 x_coeffs(vec4 x, float pos_x)
{
if (u_interp.x < 0.5) { // box
float wid = length(vec2(dFdx(pos_x),dFdy(pos_x)));
float dx = clamp((0.5 + 0.5*wid - x.y)/wid, 0.0, 1.0);
return vec4(0.0,dx,1.0-dx,0.0);
} else if (u_interp.x < 1.5) { // linear
return vec4(0.0, 1.0-x.y, 1.0-x.z, 0.0);
} else if (u_interp.x < 2.5) { // Lanczos
// Prevent division by zero.
vec4 coeffs = FIX(PI * x);
// Lanczos2 kernel.
coeffs = 2.0 * sin(coeffs) * sin(coeffs / 2.0) / (coeffs * coeffs);
// Normalize.
coeffs /= dot(coeffs, vec4_splat(1.0));
return coeffs;
} else if (u_interp.x < 3.5) { // Catmull-Rom
return cubic(x,0.0,0.5);
} else if (u_interp.x < 4.5) { // Mitchell-Netravali
return cubic(x,1.0/3.0,1.0/3.0);
} else /*if (u_interp.x < 5.5)*/ { // B-spline
return cubic(x,1.0,0.0);
}
}
vec4 sample_scanline(vec2 xy, vec4 coeffs, float onex)
{
// Calculate the effective colour of the given
// scanline at the horizontal location of the current pixel,
// using the Lanczos coefficients.
vec4 col = clamp(TEX2D(xy + vec2(-onex, 0.0))*coeffs.x +
TEX2D(xy)*coeffs.y +
TEX2D(xy +vec2(onex, 0.0))*coeffs.z +
TEX2D(xy + vec2(2.0 * onex, 0.0))*coeffs.w , 0.0, 1.0);
return col;
}
void main()
{
@ -258,23 +93,10 @@ void main()
vec3 mul_res = (col * weights + col2 * weights2).rgb * vec3_splat(cval);
// Shadow mask
xy = v_texCoord.xy * u_quad_dims.xy / u_tex_size1.xy;
vec4 mask = texture2D(mask_texture, xy);
// count of total bright pixels is encoded in the mask's alpha channel
float nbright = 255.0 - 255.0*mask.a;
// fraction of bright pixels in the mask
float fbright = nbright / ( u_tex_size1.x * u_tex_size1.y );
// average darkening factor of the mask
float aperture_average = mix(1.0-aperture_strength.x*(1.0-aperture_brightboost.x), 1.0, fbright);
// colour of dark mask pixels
vec3 clow = vec3_splat(1.0-aperture_strength.x) * mul_res + vec3_splat(aperture_strength.x*(aperture_brightboost.x)) * mul_res * mul_res;
float ifbright = 1.0 / fbright;
// colour of bright mask pixels
vec3 chi = vec3_splat(ifbright*aperture_average) * mul_res - vec3_splat(ifbright - 1.0) * clow;
vec3 cout = mix(clow,chi,mask.rgb); // mask texture selects dark vs bright
vec3 cout = apply_shadow_mask(v_texCoord.xy, mul_res);
// Convert the image gamma for display on our output device.
cout = pow(cout, vec3_splat(1.0 / monitorgamma.x));
cout = linear_to_output(cout);
gl_FragColor = vec4(cout,1.0);
}

View File

@ -1,4 +1,4 @@
$input v_texCoord, v_coeffs
$input v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@ -13,6 +13,10 @@ void main()
vec3 sum = vec3_splat(0.0);
float onex = 1.0/u_tex_size0.x;
sum += TEX2D(v_texCoord + vec2(-8.0 * onex, 0.0)) * vec3_splat(v_coeffs2.w);
sum += TEX2D(v_texCoord + vec2(-7.0 * onex, 0.0)) * vec3_splat(v_coeffs2.z);
sum += TEX2D(v_texCoord + vec2(-6.0 * onex, 0.0)) * vec3_splat(v_coeffs2.y);
sum += TEX2D(v_texCoord + vec2(-5.0 * onex, 0.0)) * vec3_splat(v_coeffs2.x);
sum += TEX2D(v_texCoord + vec2(-4.0 * onex, 0.0)) * vec3_splat(v_coeffs.w);
sum += TEX2D(v_texCoord + vec2(-3.0 * onex, 0.0)) * vec3_splat(v_coeffs.z);
sum += TEX2D(v_texCoord + vec2(-2.0 * onex, 0.0)) * vec3_splat(v_coeffs.y);
@ -22,8 +26,13 @@ void main()
sum += TEX2D(v_texCoord + vec2(+2.0 * onex, 0.0)) * vec3_splat(v_coeffs.y);
sum += TEX2D(v_texCoord + vec2(+3.0 * onex, 0.0)) * vec3_splat(v_coeffs.z);
sum += TEX2D(v_texCoord + vec2(+4.0 * onex, 0.0)) * vec3_splat(v_coeffs.w);
sum += TEX2D(v_texCoord + vec2(+5.0 * onex, 0.0)) * vec3_splat(v_coeffs2.x);
sum += TEX2D(v_texCoord + vec2(+6.0 * onex, 0.0)) * vec3_splat(v_coeffs2.y);
sum += TEX2D(v_texCoord + vec2(+7.0 * onex, 0.0)) * vec3_splat(v_coeffs2.z);
sum += TEX2D(v_texCoord + vec2(+8.0 * onex, 0.0)) * vec3_splat(v_coeffs2.w);
float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w));
float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w
+v_coeffs2.x+v_coeffs2.y+v_coeffs2.z+v_coeffs2.w));
gl_FragColor = vec4( pow(sum*vec3_splat(norm), vec3_splat(1.0/u_gamma.x)), 1.0 );
}

View File

@ -1,4 +1,4 @@
$input v_texCoord, v_coeffs
$input v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@ -13,6 +13,10 @@ void main()
vec3 sum = vec3_splat(0.0);
float oney = 1.0/u_tex_size0.y;
sum += TEX2D(v_texCoord + vec2(0.0, -8.0 * oney)) * vec3_splat(v_coeffs2.w);
sum += TEX2D(v_texCoord + vec2(0.0, -7.0 * oney)) * vec3_splat(v_coeffs2.z);
sum += TEX2D(v_texCoord + vec2(0.0, -6.0 * oney)) * vec3_splat(v_coeffs2.y);
sum += TEX2D(v_texCoord + vec2(0.0, -5.0 * oney)) * vec3_splat(v_coeffs2.x);
sum += TEX2D(v_texCoord + vec2(0.0, -4.0 * oney)) * vec3_splat(v_coeffs.w);
sum += TEX2D(v_texCoord + vec2(0.0, -3.0 * oney)) * vec3_splat(v_coeffs.z);
sum += TEX2D(v_texCoord + vec2(0.0, -2.0 * oney)) * vec3_splat(v_coeffs.y);
@ -22,8 +26,13 @@ void main()
sum += TEX2D(v_texCoord + vec2(0.0, +2.0 * oney)) * vec3_splat(v_coeffs.y);
sum += TEX2D(v_texCoord + vec2(0.0, +3.0 * oney)) * vec3_splat(v_coeffs.z);
sum += TEX2D(v_texCoord + vec2(0.0, +4.0 * oney)) * vec3_splat(v_coeffs.w);
sum += TEX2D(v_texCoord + vec2(0.0, +5.0 * oney)) * vec3_splat(v_coeffs2.x);
sum += TEX2D(v_texCoord + vec2(0.0, +6.0 * oney)) * vec3_splat(v_coeffs2.y);
sum += TEX2D(v_texCoord + vec2(0.0, +7.0 * oney)) * vec3_splat(v_coeffs2.z);
sum += TEX2D(v_texCoord + vec2(0.0, +8.0 * oney)) * vec3_splat(v_coeffs2.w);
float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w));
float norm = 1.0 / (1.0 + 2.0*(v_coeffs.x+v_coeffs.y+v_coeffs.z+v_coeffs.w
+v_coeffs2.x+v_coeffs2.y+v_coeffs2.z+v_coeffs2.w));
gl_FragColor = vec4( pow(sum*vec3_splat(norm), vec3_splat(1.0/u_gamma.x)), 1.0 );
}

View File

@ -4,8 +4,9 @@ vec2 v_sinangle : TEXCOORD2 = vec2(0.0,0.0);
vec2 v_cosangle : TEXCOORD3 = vec2(0.0,0.0);
vec2 v_one : TEXCOORD4 = vec2(0.0,0.0);
vec4 v_coeffs : TEXCOORD5 = vec4(0.0,0.0,0.0,0.0);
vec4 v_lpcoeffs1: TEXCOORD6 = vec4(0.0,0.0,0.0,0.0);
vec4 v_lpcoeffs2: TEXCOORD7 = vec4(0.0,0.0,0.0,0.0);
vec4 v_coeffs2 : TEXCOORD6 = vec4(0.0,0.0,0.0,0.0);
vec4 v_lpcoeffs1: TEXCOORD7 = vec4(0.0,0.0,0.0,0.0);
vec4 v_lpcoeffs2: TEXCOORD8 = vec4(0.0,0.0,0.0,0.0);
vec3 a_position : POSITION;
vec4 a_color0 : COLOR0;

View File

@ -1,5 +1,5 @@
$input a_position, a_texcoord0, a_color0
$output v_texCoord, v_coeffs
$output v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@ -11,6 +11,7 @@ void main()
{
float wid = u_width.x*u_tex_size0.x/(320.*u_aspect.x);
v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
v_coeffs2 = exp(vec4(25.,36.,49.,64.)*vec4_splat(-1.0/wid/wid));
// Do the standard vertex processing.
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));

View File

@ -1,5 +1,5 @@
$input a_position, a_texcoord0, a_color0
$output v_texCoord, v_coeffs
$output v_texCoord, v_coeffs, v_coeffs2
#include "common.sh"
@ -11,6 +11,7 @@ void main()
{
float wid = u_width.x*u_tex_size0.y/(320.*u_aspect.y);
v_coeffs = exp(vec4(1.,4.,9.,16.)*vec4_splat(-1.0/wid/wid));
v_coeffs2 = exp(vec4(25.,36.,49.,64.)*vec4_splat(-1.0/wid/wid));
// Do the standard vertex processing.
gl_Position = mul(u_viewProj, vec4(a_position.xy, 0.0, 1.0));