Work with WebGL 1.0 and WebGL 2.0
This commit is contained in:
parent
f9c932b737
commit
c2432b7348
@ -7,36 +7,36 @@
|
|||||||
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
|
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
|
||||||
{
|
{
|
||||||
/* Curve and pixel ratio */
|
/* Curve and pixel ratio */
|
||||||
float y_curve = cos(position.x - 0.5) * CURVENESS + (1 - CURVENESS);
|
float y_curve = cos(position.x - 0.5) * CURVENESS + (1.0 - CURVENESS);
|
||||||
float y_multiplier = 8.0 / 7.0 / y_curve;
|
float y_multiplier = 8.0 / 7.0 / y_curve;
|
||||||
position.y *= y_multiplier;
|
position.y *= y_multiplier;
|
||||||
position.y -= (y_multiplier - 1) / 2;
|
position.y -= (y_multiplier - 1.0) / 2.0;
|
||||||
if (position.y < 0.0) return vec4(0,0,0,0);
|
if (position.y < 0.0) return vec4(0,0,0,0);
|
||||||
if (position.y > 1.0) return vec4(0,0,0,0);
|
if (position.y > 1.0) return vec4(0,0,0,0);
|
||||||
|
|
||||||
float x_curve = cos(position.y - 0.5) * CURVENESS + (1 - CURVENESS);
|
float x_curve = cos(position.y - 0.5) * CURVENESS + (1.0 - CURVENESS);
|
||||||
float x_multiplier = 1/x_curve;
|
float x_multiplier = 1.0 / x_curve;
|
||||||
position.x *= x_multiplier;
|
position.x *= x_multiplier;
|
||||||
position.x -= (x_multiplier - 1) / 2;
|
position.x -= (x_multiplier - 1.0) / 2.0;
|
||||||
if (position.x < 0.0) return vec4(0,0,0,0);
|
if (position.x < 0.0) return vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
if (position.x > 1.0) return vec4(0,0,0,0);
|
if (position.x > 1.0) return vec4(0.0, 0.0, 0.0, 0.0);
|
||||||
|
|
||||||
/* Setting up common vars */
|
/* Setting up common vars */
|
||||||
vec2 pos = fract(position * input_resolution);
|
vec2 pos = fract(position * input_resolution);
|
||||||
vec2 sub_pos = fract(position * input_resolution * 6);
|
vec2 sub_pos = fract(position * input_resolution * 6.0);
|
||||||
|
|
||||||
vec4 center = texture(image, position);
|
vec4 center = texture(image, position);
|
||||||
vec4 left = texture(image, position - vec2(1.0 / input_resolution.x, 0));
|
vec4 left = texture(image, position - vec2(1.0 / input_resolution.x, 0.0));
|
||||||
vec4 right = texture(image, position + vec2(1.0 / input_resolution.x, 0));
|
vec4 right = texture(image, position + vec2(1.0 / input_resolution.x, 0.0));
|
||||||
|
|
||||||
/* Vertical blurring */
|
/* Vertical blurring */
|
||||||
if (pos.y < 1.0 / 6.0) {
|
if (pos.y < 1.0 / 6.0) {
|
||||||
center = mix(center, texture(image, position + vec2(0, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
center = mix(center, texture(image, position + vec2(0.0, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
}
|
}
|
||||||
else if (pos.y > 5.0 / 6.0) {
|
else if (pos.y > 5.0 / 6.0) {
|
||||||
center = mix(center, texture(image, position + vec2(0, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
center = mix(center, texture(image, position + vec2(0.0, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
}
|
}
|
||||||
@ -44,10 +44,10 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
/* Scanlines */
|
/* Scanlines */
|
||||||
float scanline_multiplier;
|
float scanline_multiplier;
|
||||||
if (pos.y < 0.5) {
|
if (pos.y < 0.5) {
|
||||||
scanline_multiplier = (pos.y * 2) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
scanline_multiplier = (pos.y * 2.0) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
scanline_multiplier = ((1 - pos.y) * 2) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
scanline_multiplier = ((1.0 - pos.y) * 2.0) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
center *= scanline_multiplier;
|
center *= scanline_multiplier;
|
||||||
@ -55,7 +55,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
right *= scanline_multiplier;
|
right *= scanline_multiplier;
|
||||||
|
|
||||||
/* Vertical seperator for shadow masks */
|
/* Vertical seperator for shadow masks */
|
||||||
bool odd = bool(int((position * input_resolution).x) & 1);
|
bool odd = bool(int((position * input_resolution).x) >= 1);
|
||||||
if (odd) {
|
if (odd) {
|
||||||
pos.y += 0.5;
|
pos.y += 0.5;
|
||||||
pos.y = fract(pos.y);
|
pos.y = fract(pos.y);
|
||||||
@ -63,15 +63,15 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
|
|
||||||
if (pos.y < 1.0 / 3.0) {
|
if (pos.y < 1.0 / 3.0) {
|
||||||
float gradient_position = pos.y * 3.0;
|
float gradient_position = pos.y * 3.0;
|
||||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
}
|
}
|
||||||
else if (pos.y > 2.0 / 3.0) {
|
else if (pos.y > 2.0 / 3.0) {
|
||||||
float gradient_position = (1 - pos.y) * 3.0;
|
float gradient_position = (1.0 - pos.y) * 3.0;
|
||||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Blur the edges of the separators of adjacent columns */
|
/* Blur the edges of the separators of adjacent columns */
|
||||||
@ -82,26 +82,26 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
if (pos.y < 1.0 / 3.0) {
|
if (pos.y < 1.0 / 3.0) {
|
||||||
float gradient_position = pos.y * 3.0;
|
float gradient_position = pos.y * 3.0;
|
||||||
if (pos.x < 0.5) {
|
if (pos.x < 0.5) {
|
||||||
gradient_position = 1 - (1 - gradient_position) * (1 - (pos.x) * 6.0);
|
gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (pos.x) * 6.0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gradient_position = 1 - (1 - gradient_position) * (1 - (1 - pos.x) * 6.0);
|
gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (1.0 - pos.x) * 6.0);
|
||||||
}
|
}
|
||||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
}
|
}
|
||||||
else if (pos.y > 2.0 / 3.0) {
|
else if (pos.y > 2.0 / 3.0) {
|
||||||
float gradient_position = (1 - pos.y) * 3.0;
|
float gradient_position = (1.0 - pos.y) * 3.0;
|
||||||
if (pos.x < 0.5) {
|
if (pos.x < 0.5) {
|
||||||
gradient_position = 1 - (1 - gradient_position) * (1 - (pos.x) * 6.0);
|
gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (pos.x) * 6.0);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
gradient_position = 1 - (1 - gradient_position) * (1 - (1 - pos.x) * 6.0);
|
gradient_position = 1.0 - (1.0 - gradient_position) * (1.0 - (1.0 - pos.x) * 6.0);
|
||||||
}
|
}
|
||||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -113,48 +113,48 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
|
|
||||||
vec4 ret;
|
vec4 ret;
|
||||||
if (pos.x < 1.0 / 6.0) {
|
if (pos.x < 1.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1.0),
|
||||||
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 2.0 / 6.0) {
|
else if (pos.x < 2.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||||
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 3.0 / 6.0) {
|
else if (pos.x < 3.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0),
|
||||||
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1),
|
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 4.0 / 6.0) {
|
else if (pos.x < 4.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1.0),
|
||||||
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1),
|
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 5.0 / 6.0) {
|
else if (pos.x < 5.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1.0),
|
||||||
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0),
|
||||||
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1),
|
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Anti alias the curve */
|
/* Anti alias the curve */
|
||||||
vec2 pixel_position = position * output_resolution;
|
vec2 pixel_position = position * output_resolution;
|
||||||
if (pixel_position.x < 1) {
|
if (pixel_position.x < 1.0) {
|
||||||
ret *= pixel_position.x;
|
ret *= pixel_position.x;
|
||||||
}
|
}
|
||||||
else if (pixel_position.x > output_resolution.x - 1) {
|
else if (pixel_position.x > output_resolution.x - 1.0) {
|
||||||
ret *= output_resolution.x - pixel_position.x;
|
ret *= output_resolution.x - pixel_position.x;
|
||||||
}
|
}
|
||||||
if (pixel_position.y < 1) {
|
if (pixel_position.y < 1.0) {
|
||||||
ret *= pixel_position.y;
|
ret *= pixel_position.y;
|
||||||
}
|
}
|
||||||
else if (pixel_position.y > output_resolution.y - 1) {
|
else if (pixel_position.y > output_resolution.y - 1.0) {
|
||||||
ret *= output_resolution.y - pixel_position.y;
|
ret *= output_resolution.y - pixel_position.y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
/* The colorspace used by the HQnx filters is not really YUV, despite the algorithm description claims it is. It is
|
/* The colorspace used by the HQnx filters is not really YUV, despite the algorithm description claims it is. It is
|
||||||
also not normalized. Therefore, we shall call the colorspace used by HQnx "HQ Colorspace" to avoid confusion. */
|
also not normalized. Therefore, we shall call the colorspace used by HQnx "HQ Colorspace" to avoid confusion. */
|
||||||
STATIC vec3 rgb_to_hq_colospace(vec4 rgb)
|
STATIC vec3 rgb_to_hq_colorspace(vec4 rgb)
|
||||||
{
|
{
|
||||||
return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
|
return vec3( 0.250 * rgb.r + 0.250 * rgb.g + 0.250 * rgb.b,
|
||||||
0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
|
0.250 * rgb.r - 0.000 * rgb.g - 0.250 * rgb.b,
|
||||||
@ -11,7 +11,7 @@ STATIC vec3 rgb_to_hq_colospace(vec4 rgb)
|
|||||||
|
|
||||||
STATIC bool is_different(vec4 a, vec4 b)
|
STATIC bool is_different(vec4 a, vec4 b)
|
||||||
{
|
{
|
||||||
vec3 diff = abs(rgb_to_hq_colospace(a) - rgb_to_hq_colospace(b));
|
vec3 diff = abs(rgb_to_hq_colorspace(a) - rgb_to_hq_colorspace(b));
|
||||||
return diff.x > 0.188 || diff.y > 0.027 || diff.z > 0.031;
|
return diff.x > 0.188 || diff.y > 0.027 || diff.z > 0.031;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -43,13 +43,13 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
|
|
||||||
|
|
||||||
vec4 w0 = texture(image, position + vec2( -o.x, -o.y));
|
vec4 w0 = texture(image, position + vec2( -o.x, -o.y));
|
||||||
vec4 w1 = texture(image, position + vec2( 0, -o.y));
|
vec4 w1 = texture(image, position + vec2( 0.0, -o.y));
|
||||||
vec4 w2 = texture(image, position + vec2( o.x, -o.y));
|
vec4 w2 = texture(image, position + vec2( o.x, -o.y));
|
||||||
vec4 w3 = texture(image, position + vec2( -o.x, 0));
|
vec4 w3 = texture(image, position + vec2( -o.x, 0.0));
|
||||||
vec4 w4 = texture(image, position + vec2( 0, 0));
|
vec4 w4 = texture(image, position + vec2( 0.0, 0.0));
|
||||||
vec4 w5 = texture(image, position + vec2( o.x, 0));
|
vec4 w5 = texture(image, position + vec2( o.x, 0.0));
|
||||||
vec4 w6 = texture(image, position + vec2( -o.x, o.y));
|
vec4 w6 = texture(image, position + vec2( -o.x, o.y));
|
||||||
vec4 w7 = texture(image, position + vec2( 0, o.y));
|
vec4 w7 = texture(image, position + vec2( 0.0, o.y));
|
||||||
vec4 w8 = texture(image, position + vec2( o.x, o.y));
|
vec4 w8 = texture(image, position + vec2( o.x, o.y));
|
||||||
|
|
||||||
int pattern = 0;
|
int pattern = 0;
|
||||||
|
@ -5,27 +5,27 @@
|
|||||||
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
|
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
|
||||||
{
|
{
|
||||||
vec2 pos = fract(position * input_resolution);
|
vec2 pos = fract(position * input_resolution);
|
||||||
vec2 sub_pos = fract(position * input_resolution * 6);
|
vec2 sub_pos = fract(position * input_resolution * 6.0);
|
||||||
|
|
||||||
vec4 center = texture(image, position);
|
vec4 center = texture(image, position);
|
||||||
vec4 left = texture(image, position - vec2(1.0 / input_resolution.x, 0));
|
vec4 left = texture(image, position - vec2(1.0 / input_resolution.x, 0));
|
||||||
vec4 right = texture(image, position + vec2(1.0 / input_resolution.x, 0));
|
vec4 right = texture(image, position + vec2(1.0 / input_resolution.x, 0));
|
||||||
|
|
||||||
if (pos.y < 1.0 / 6.0) {
|
if (pos.y < 1.0 / 6.0) {
|
||||||
center = mix(center, texture(image, position + vec2(0, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
center = mix(center, texture(image, position + vec2(0.0, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, -1.0 / input_resolution.y)), 0.5 - sub_pos.y / 2.0);
|
||||||
center *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
center *= sub_pos.y * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
left *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
left *= sub_pos.y * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
right *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
right *= sub_pos.y * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
}
|
}
|
||||||
else if (pos.y > 5.0 / 6.0) {
|
else if (pos.y > 5.0 / 6.0) {
|
||||||
center = mix(center, texture(image, position + vec2(0, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
center = mix(center, texture(image, position + vec2(0.0, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
left = mix(left, texture(image, position + vec2(-1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
right = mix(right, texture(image, position + vec2( 1.0 / input_resolution.x, 1.0 / input_resolution.y)), sub_pos.y / 2.0);
|
||||||
center *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
center *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
left *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
left *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
right *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
right *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -34,33 +34,33 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
|
|
||||||
vec4 ret;
|
vec4 ret;
|
||||||
if (pos.x < 1.0 / 6.0) {
|
if (pos.x < 1.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1.0),
|
||||||
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 2.0 / 6.0) {
|
else if (pos.x < 2.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||||
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 3.0 / 6.0) {
|
else if (pos.x < 3.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1.0),
|
||||||
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1),
|
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 4.0 / 6.0) {
|
else if (pos.x < 4.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1.0),
|
||||||
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1),
|
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else if (pos.x < 5.0 / 6.0) {
|
else if (pos.x < 5.0 / 6.0) {
|
||||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1.0),
|
||||||
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1.0),
|
||||||
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1),
|
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.g , COLOR_HIGH * center.b, 1.0),
|
||||||
sub_pos.x);
|
sub_pos.x);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
- The actual output calculating was completely redesigned as resolution independent graphic generator. This allows
|
- The actual output calculating was completely redesigned as resolution independent graphic generator. This allows
|
||||||
scaling to any factor.
|
scaling to any factor.
|
||||||
- HQnx approximations that were good enough for a 2x/3x/4x factor were refined, creating smoother gradients.
|
- HQnx approximations that were good enough for a 2x/3x/4x factor were refined, creating smoother gradients.
|
||||||
- "Quarters" can be interpolated in more ways than in the HQnx filters
|
- "Quarters" can be interpolated in more ways than in the HQnx filters
|
||||||
- If a pattern does not provide enough information to determine the suitable scaling interpolation, up to 16 pixels
|
- If a pattern does not provide enough information to determine the suitable scaling interpolation, up to 16 pixels
|
||||||
per quarter are sampled (in contrast to the usual 9) in order to determine the best interpolation.
|
per quarter are sampled (in contrast to the usual 9) in order to determine the best interpolation.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* We use the same colorspace as the HQ algorithms. */
|
/* We use the same colorspace as the HQ algorithms. */
|
||||||
@ -28,7 +28,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
{
|
{
|
||||||
// o = offset, the width of a pixel
|
// o = offset, the width of a pixel
|
||||||
vec2 o = 1.0 / input_resolution;
|
vec2 o = 1.0 / input_resolution;
|
||||||
|
|
||||||
/* We always calculate the top left quarter. If we need a different quarter, we flip our co-ordinates */
|
/* We always calculate the top left quarter. If we need a different quarter, we flip our co-ordinates */
|
||||||
|
|
||||||
// p = the position within a pixel [0...1]
|
// p = the position within a pixel [0...1]
|
||||||
@ -44,13 +44,13 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
}
|
}
|
||||||
|
|
||||||
vec4 w0 = texture(image, position + vec2( -o.x, -o.y));
|
vec4 w0 = texture(image, position + vec2( -o.x, -o.y));
|
||||||
vec4 w1 = texture(image, position + vec2( 0, -o.y));
|
vec4 w1 = texture(image, position + vec2( 0.0, -o.y));
|
||||||
vec4 w2 = texture(image, position + vec2( o.x, -o.y));
|
vec4 w2 = texture(image, position + vec2( o.x, -o.y));
|
||||||
vec4 w3 = texture(image, position + vec2( -o.x, 0));
|
vec4 w3 = texture(image, position + vec2( -o.x, 0.0));
|
||||||
vec4 w4 = texture(image, position + vec2( 0, 0));
|
vec4 w4 = texture(image, position + vec2( 0.0, 0.0));
|
||||||
vec4 w5 = texture(image, position + vec2( o.x, 0));
|
vec4 w5 = texture(image, position + vec2( o.x, 0.0));
|
||||||
vec4 w6 = texture(image, position + vec2( -o.x, o.y));
|
vec4 w6 = texture(image, position + vec2( -o.x, o.y));
|
||||||
vec4 w7 = texture(image, position + vec2( 0, o.y));
|
vec4 w7 = texture(image, position + vec2( 0.0, o.y));
|
||||||
vec4 w8 = texture(image, position + vec2( o.x, o.y));
|
vec4 w8 = texture(image, position + vec2( o.x, o.y));
|
||||||
|
|
||||||
int pattern = 0;
|
int pattern = 0;
|
||||||
@ -81,7 +81,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
if (P(0x2f,0x2f)) {
|
if (P(0x2f,0x2f)) {
|
||||||
float dist = length(p - vec2(0.5));
|
float dist = length(p - vec2(0.5));
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
||||||
if (dist < 0.5 - pixel_size / 2) {
|
if (dist < 0.5 - pixel_size / 2.0) {
|
||||||
return w4;
|
return w4;
|
||||||
}
|
}
|
||||||
vec4 r;
|
vec4 r;
|
||||||
@ -92,40 +92,40 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist > 0.5 + pixel_size / 2) {
|
if (dist > 0.5 + pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return mix(w4, r, (dist - 0.5 + pixel_size / 2) / pixel_size);
|
return mix(w4, r, (dist - 0.5 + pixel_size / 2.0) / pixel_size);
|
||||||
}
|
}
|
||||||
if (P(0xbf,0x37) || P(0xdb,0x13)) {
|
if (P(0xbf,0x37) || P(0xdb,0x13)) {
|
||||||
float dist = p.x - 2.0 * p.y;
|
float dist = p.x - 2.0 * p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
if (dist > pixel_size / 2) {
|
if (dist > pixel_size / 2.0) {
|
||||||
return w1;
|
return w1;
|
||||||
}
|
}
|
||||||
vec4 r = mix(w3, w4, p.x + 0.5);
|
vec4 r = mix(w3, w4, p.x + 0.5);
|
||||||
if (dist < -pixel_size / 2) {
|
if (dist < -pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return mix(r, w1, (dist + pixel_size / 2) / pixel_size);
|
return mix(r, w1, (dist + pixel_size / 2.0) / pixel_size);
|
||||||
}
|
}
|
||||||
if (P(0xdb,0x49) || P(0xef,0x6d)) {
|
if (P(0xdb,0x49) || P(0xef,0x6d)) {
|
||||||
float dist = p.y - 2.0 * p.x;
|
float dist = p.y - 2.0 * p.x;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
if (p.y - 2.0 * p.x > pixel_size / 2) {
|
if (p.y - 2.0 * p.x > pixel_size / 2.0) {
|
||||||
return w3;
|
return w3;
|
||||||
}
|
}
|
||||||
vec4 r = mix(w1, w4, p.x + 0.5);
|
vec4 r = mix(w1, w4, p.x + 0.5);
|
||||||
if (dist < -pixel_size / 2) {
|
if (dist < -pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return mix(r, w3, (dist + pixel_size / 2) / pixel_size);
|
return mix(r, w3, (dist + pixel_size / 2.0) / pixel_size);
|
||||||
}
|
}
|
||||||
if (P(0xbf,0x8f) || P(0x7e,0x0e)) {
|
if (P(0xbf,0x8f) || P(0x7e,0x0e)) {
|
||||||
float dist = p.x + 2.0 * p.y;
|
float dist = p.x + 2.0 * p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
|
|
||||||
if (dist > 1.0 + pixel_size / 2) {
|
if (dist > 1.0 + pixel_size / 2.0) {
|
||||||
return w4;
|
return w4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -137,11 +137,11 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist < 1.0 - pixel_size / 2) {
|
if (dist < 1.0 - pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mix(r, w4, (dist + pixel_size / 2 - 1.0) / pixel_size);
|
return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -149,7 +149,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
float dist = p.y + 2.0 * p.x;
|
float dist = p.y + 2.0 * p.x;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
float pixel_size = length(1.0 / (output_resolution / input_resolution)) * sqrt(5.0);
|
||||||
|
|
||||||
if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2) {
|
if (p.y + 2.0 * p.x > 1.0 + pixel_size / 2.0) {
|
||||||
return w4;
|
return w4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +162,11 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist < 1.0 - pixel_size / 2) {
|
if (dist < 1.0 - pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mix(r, w4, (dist + pixel_size / 2 - 1.0) / pixel_size);
|
return mix(r, w4, (dist + pixel_size / 2.0 - 1.0) / pixel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
|
if (P(0x1b,0x03) || P(0x4f,0x43) || P(0x8b,0x83) || P(0x6b,0x43))
|
||||||
@ -185,7 +185,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
float dist = p.x + p.y;
|
float dist = p.x + p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
||||||
|
|
||||||
if (dist > 0.5 + pixel_size / 2) {
|
if (dist > 0.5 + pixel_size / 2.0) {
|
||||||
return w4;
|
return w4;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,11 +197,11 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
r = mix(mix(w1 * 0.375 + w0 * 0.25 + w3 * 0.375, w3, p.y * 2.0), w1, p.x * 2.0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dist < 0.5 - pixel_size / 2) {
|
if (dist < 0.5 - pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
return mix(r, w4, (dist + pixel_size / 2 - 0.5) / pixel_size);
|
return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (P(0x0b,0x01))
|
if (P(0x0b,0x01))
|
||||||
@ -213,7 +213,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
float dist = p.x + p.y;
|
float dist = p.x + p.y;
|
||||||
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
float pixel_size = length(1.0 / (output_resolution / input_resolution));
|
||||||
|
|
||||||
if (dist > 0.5 + pixel_size / 2)
|
if (dist > 0.5 + pixel_size / 2.)
|
||||||
return w4;
|
return w4;
|
||||||
|
|
||||||
/* We need more samples to "solve" this diagonal */
|
/* We need more samples to "solve" this diagonal */
|
||||||
@ -241,11 +241,11 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
|||||||
|
|
||||||
if (diagonal_bias <= 0) {
|
if (diagonal_bias <= 0) {
|
||||||
vec4 r = mix(w1, w3, p.y - p.x + 0.5);
|
vec4 r = mix(w1, w3, p.y - p.x + 0.5);
|
||||||
if (dist < 0.5 - pixel_size / 2) {
|
if (dist < 0.5 - pixel_size / 2.0) {
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
return mix(r, w4, (dist + pixel_size / 2 - 0.5) / pixel_size);
|
return mix(r, w4, (dist + pixel_size / 2.0 - 0.5) / pixel_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
return w4;
|
return w4;
|
||||||
}
|
}
|
||||||
|
40
Shaders/WasmMasterShader.fsh
Normal file
40
Shaders/WasmMasterShader.fsh
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
precision mediump float;
|
||||||
|
|
||||||
|
uniform sampler2D image;
|
||||||
|
uniform sampler2D previous_image;
|
||||||
|
uniform bool mix_previous;
|
||||||
|
|
||||||
|
uniform vec2 input_resolution;
|
||||||
|
uniform vec2 output_resolution;
|
||||||
|
uniform vec2 origin;
|
||||||
|
|
||||||
|
#define equal(x, y) ((x) == (y))
|
||||||
|
#define inequal(x, y) ((x) != (y))
|
||||||
|
#define STATIC
|
||||||
|
|
||||||
|
#if VERSION >= 0x300
|
||||||
|
#define FRAG_COLOR fragColor
|
||||||
|
out vec4 FRAG_COLOR;
|
||||||
|
#else
|
||||||
|
#define FRAG_COLOR gl_FragColor
|
||||||
|
vec4 texture(sampler2D s, vec2 c) { return texture2D(s, c); }
|
||||||
|
vec4 texture(sampler2D s, vec2 c, float b) { return texture2D(s, c, b); }
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#line 1
|
||||||
|
{filter}
|
||||||
|
|
||||||
|
void main()
|
||||||
|
{
|
||||||
|
vec2 position = gl_FragCoord.xy - origin;
|
||||||
|
position /= output_resolution;
|
||||||
|
position.y = 1.0 - position.y;
|
||||||
|
|
||||||
|
if (mix_previous) {
|
||||||
|
FRAG_COLOR = mix(scale(image, position, input_resolution, output_resolution),
|
||||||
|
scale(previous_image, position, input_resolution, output_resolution), 0.5);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
FRAG_COLOR = scale(image, position, input_resolution, output_resolution);
|
||||||
|
}
|
||||||
|
}
|
@ -58,7 +58,8 @@ endif
|
|||||||
CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
CFLAGS += -Werror -Wall -Wno-strict-aliasing -Wno-unknown-warning -Wno-unknown-warning-option -Wno-multichar -Wno-int-in-bool-context -std=gnu11 -D_GNU_SOURCE -DVERSION="$(VERSION)" -I. -D_USE_MATH_DEFINES
|
||||||
# CFLAGS += -DGB_INTERNAL=1 # get access to internal APIs
|
# CFLAGS += -DGB_INTERNAL=1 # get access to internal APIs
|
||||||
CFLAGS += -I$(CORE_DIR)
|
CFLAGS += -I$(CORE_DIR)
|
||||||
CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap', 'getValue', 'AsciiToString', 'FS']"
|
CFLAGS += -s WASM=1 -s USE_SDL=2 --preload-file $(BOOTROMS_DIR)@/BootROMs --preload-file $(CORE_DIR)/Shaders@/Shaders -s "EXTRA_EXPORTED_RUNTIME_METHODS=['ccall', 'cwrap', 'getValue', 'AsciiToString', 'FS']"
|
||||||
|
CFLAGS += -s USE_WEBGL2=1
|
||||||
# CFLAGS += -Wcast-align -Wover-aligned -s SAFE_HEAP=1 -s WARN_UNALIGNED=1
|
# CFLAGS += -Wcast-align -Wover-aligned -s SAFE_HEAP=1 -s WARN_UNALIGNED=1
|
||||||
WASM_LDFLAGS :=
|
WASM_LDFLAGS :=
|
||||||
|
|
||||||
@ -95,7 +96,9 @@ WASM_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(WASM_SOURCES))
|
|||||||
WEB_SOURCES := $(shell ls ressources/.)
|
WEB_SOURCES := $(shell ls ressources/.)
|
||||||
WEB_OBJECTS := $(patsubst %,$(BIN)/ressources/%,$(WEB_SOURCES))
|
WEB_OBJECTS := $(patsubst %,$(BIN)/ressources/%,$(WEB_SOURCES))
|
||||||
|
|
||||||
wasm: bootroms $(BIN)/index.html $(WEB_OBJECTS)
|
SHADERS := $(shell ls $(CORE_DIR)/Shaders/*.fsh)
|
||||||
|
|
||||||
|
wasm: bootroms $(BIN)/index.html $(WEB_OBJECTS) $(SHADERS)
|
||||||
all: wasm
|
all: wasm
|
||||||
|
|
||||||
# Automatic dependency generation
|
# Automatic dependency generation
|
||||||
|
131
wasm/main.c
131
wasm/main.c
@ -1,7 +1,6 @@
|
|||||||
#include <emscripten.h>
|
#include <emscripten.h>
|
||||||
#include <SDL2/SDL.h>
|
|
||||||
#include <SDL2/SDL_opengl.h>
|
|
||||||
#include <SDL2/SDL_video.h>
|
#include <SDL2/SDL_video.h>
|
||||||
|
#include <SDL2/SDL.h>
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
@ -9,6 +8,7 @@
|
|||||||
#include <Core/gb.h>
|
#include <Core/gb.h>
|
||||||
#include "main.h"
|
#include "main.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "shader.h"
|
||||||
|
|
||||||
GB_gameboy_t gb;
|
GB_gameboy_t gb;
|
||||||
|
|
||||||
@ -19,12 +19,36 @@ SDL_Texture *texture;
|
|||||||
SDL_PixelFormat *pixel_format;
|
SDL_PixelFormat *pixel_format;
|
||||||
SDL_AudioDeviceID device_id;
|
SDL_AudioDeviceID device_id;
|
||||||
|
|
||||||
|
shader_t shader;
|
||||||
|
|
||||||
|
static SDL_Rect rect;
|
||||||
|
static unsigned factor;
|
||||||
static SDL_AudioSpec want_aspec, have_aspec;
|
static SDL_AudioSpec want_aspec, have_aspec;
|
||||||
static uint32_t pixel_buffer_1[256 * 224], pixel_buffer_2[256 * 224];
|
static uint32_t pixel_buffer_1[256 * 224], pixel_buffer_2[256 * 224];
|
||||||
static uint32_t *active_pixel_buffer = pixel_buffer_1;
|
static uint32_t *active_pixel_buffer = pixel_buffer_1;
|
||||||
static uint32_t *previous_pixel_buffer = pixel_buffer_2;
|
static uint32_t *previous_pixel_buffer = pixel_buffer_2;
|
||||||
static char *battery_save_path_ptr;
|
static char *battery_save_path_ptr;
|
||||||
|
|
||||||
|
struct shader_name {
|
||||||
|
const char *file_name;
|
||||||
|
const char *display_name;
|
||||||
|
} shaders[] =
|
||||||
|
{
|
||||||
|
{"NearestNeighbor", "Nearest Neighbor"},
|
||||||
|
{"Bilinear", "Bilinear"},
|
||||||
|
{"SmoothBilinear", "Smooth Bilinear"},
|
||||||
|
{"LCD", "LCD Display"},
|
||||||
|
{"CRT", "CRT Display"},
|
||||||
|
{"Scale2x", "Scale2x"},
|
||||||
|
{"Scale4x", "Scale4x"},
|
||||||
|
{"AAScale2x", "Anti-aliased Scale2x"},
|
||||||
|
{"AAScale4x", "Anti-aliased Scale4x"},
|
||||||
|
// {"HQ2x", "HQ2x"}, // requires OpenGL ES 1.30 features
|
||||||
|
// {"OmniScale", "OmniScale"}, // requires OpenGL ES 1.30 features
|
||||||
|
{"OmniScaleLegacy", "OmniScale Legacy"},
|
||||||
|
{"AAOmniScaleLegacy", "AA OmniScale Legacy"},
|
||||||
|
};
|
||||||
|
|
||||||
configuration_t configuration =
|
configuration_t configuration =
|
||||||
{
|
{
|
||||||
.keys = {
|
.keys = {
|
||||||
@ -62,9 +86,11 @@ configuration_t configuration =
|
|||||||
},
|
},
|
||||||
.color_correction_mode = GB_COLOR_CORRECTION_EMULATE_HARDWARE,
|
.color_correction_mode = GB_COLOR_CORRECTION_EMULATE_HARDWARE,
|
||||||
.highpass_mode = GB_HIGHPASS_ACCURATE,
|
.highpass_mode = GB_HIGHPASS_ACCURATE,
|
||||||
|
.scaling_mode = GB_SDL_SCALING_INTEGER_FACTOR,
|
||||||
.blend_frames = true,
|
.blend_frames = true,
|
||||||
.rewind_length = 60 * 2,
|
.rewind_length = 60 * 2,
|
||||||
.model = MODEL_CGB
|
.model = MODEL_CGB,
|
||||||
|
.filter = "OmniScale",
|
||||||
};
|
};
|
||||||
|
|
||||||
// Use this function instead of GB_save_battery()
|
// Use this function instead of GB_save_battery()
|
||||||
@ -102,6 +128,46 @@ static void audio_callback(void *gb, Uint8 *stream, int len)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void update_viewport(void)
|
||||||
|
{
|
||||||
|
int win_width, win_height;
|
||||||
|
SDL_GL_GetDrawableSize(window, &win_width, &win_height);
|
||||||
|
int logical_width, logical_height;
|
||||||
|
SDL_GetWindowSize(window, &logical_width, &logical_height);
|
||||||
|
factor = win_width / logical_width;
|
||||||
|
|
||||||
|
double x_factor = win_width / (double) GB_get_screen_width(&gb);
|
||||||
|
double y_factor = win_height / (double) GB_get_screen_height(&gb);
|
||||||
|
|
||||||
|
if (configuration.scaling_mode == GB_SDL_SCALING_INTEGER_FACTOR) {
|
||||||
|
x_factor = (int)(x_factor);
|
||||||
|
y_factor = (int)(y_factor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (configuration.scaling_mode != GB_SDL_SCALING_ENTIRE_WINDOW) {
|
||||||
|
if (x_factor > y_factor) {
|
||||||
|
x_factor = y_factor;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y_factor = x_factor;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned new_width = x_factor * GB_get_screen_width(&gb);
|
||||||
|
unsigned new_height = y_factor * GB_get_screen_height(&gb);
|
||||||
|
|
||||||
|
rect = (SDL_Rect){(win_width - new_width) / 2, (win_height - new_height) / 2,
|
||||||
|
new_width, new_height};
|
||||||
|
|
||||||
|
if (renderer) {
|
||||||
|
SDL_RenderSetViewport(renderer, &rect);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
glViewport(rect.x, rect.y, rect.w, rect.h);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void render_texture(void *pixels, void *previous)
|
void render_texture(void *pixels, void *previous)
|
||||||
{
|
{
|
||||||
if (renderer) {
|
if (renderer) {
|
||||||
@ -112,7 +178,7 @@ void render_texture(void *pixels, void *previous)
|
|||||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||||
SDL_RenderPresent(renderer);
|
SDL_RenderPresent(renderer);
|
||||||
}
|
}
|
||||||
/*else {
|
else {
|
||||||
static void *_pixels = NULL;
|
static void *_pixels = NULL;
|
||||||
if (pixels) {
|
if (pixels) {
|
||||||
_pixels = pixels;
|
_pixels = pixels;
|
||||||
@ -123,7 +189,7 @@ void render_texture(void *pixels, void *previous)
|
|||||||
GB_get_screen_width(&gb), GB_get_screen_height(&gb),
|
GB_get_screen_width(&gb), GB_get_screen_height(&gb),
|
||||||
rect.x, rect.y, rect.w, rect.h);
|
rect.x, rect.y, rect.w, rect.h);
|
||||||
SDL_GL_SwapWindow(window);
|
SDL_GL_SwapWindow(window);
|
||||||
}*/
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void handle_events(GB_gameboy_t *gb) {
|
static void handle_events(GB_gameboy_t *gb) {
|
||||||
@ -243,8 +309,8 @@ int EMSCRIPTEN_KEEPALIVE init() {
|
|||||||
"SameBoy v" xstr(VERSION),
|
"SameBoy v" xstr(VERSION),
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
SDL_WINDOWPOS_UNDEFINED,
|
SDL_WINDOWPOS_UNDEFINED,
|
||||||
VIDEO_WIDTH,
|
VIDEO_WIDTH * 4,
|
||||||
VIDEO_HEIGHT,
|
VIDEO_HEIGHT * 4,
|
||||||
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI
|
SDL_WINDOW_OPENGL | SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALLOW_HIGHDPI
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -256,37 +322,31 @@ int EMSCRIPTEN_KEEPALIVE init() {
|
|||||||
SDL_SetWindowMinimumSize(window, VIDEO_WIDTH, VIDEO_HEIGHT);
|
SDL_SetWindowMinimumSize(window, VIDEO_WIDTH, VIDEO_HEIGHT);
|
||||||
SDL_SetWindowMaximumSize(window, VIDEO_WIDTH, VIDEO_HEIGHT);
|
SDL_SetWindowMaximumSize(window, VIDEO_WIDTH, VIDEO_HEIGHT);
|
||||||
|
|
||||||
renderer = SDL_CreateRenderer(
|
// Try to get a GLES 3.0 context
|
||||||
window,
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||||
-1,
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
|
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||||
);
|
|
||||||
|
|
||||||
if (!renderer) {
|
if (gl_context == NULL) {
|
||||||
fprintf(stderr, "SDL_CreateRenderer Error: %s\n", SDL_GetError());
|
// Try to get a GLES 2.0 context
|
||||||
return EXIT_FAILURE;
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
|
||||||
|
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||||
|
gl_context = SDL_GL_CreateContext(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
screen = SDL_CreateRGBSurface(
|
if (gl_context == NULL) {
|
||||||
0,
|
fprintf(stderr, "Using software renderer!\n");
|
||||||
VIDEO_WIDTH,
|
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||||
VIDEO_HEIGHT,
|
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
|
||||||
32,
|
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
|
||||||
0, 0, 0, 0
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!screen) {
|
|
||||||
SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
|
|
||||||
exit(1);
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
fprintf(stderr, "Using OpenGL renderer!\n");
|
||||||
|
pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
|
||||||
|
|
||||||
pixel_format = screen->format;
|
fprintf(stderr, "GLES: %s\n", glGetString(GL_VERSION));
|
||||||
|
fprintf(stderr, "GLSL: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||||
texture = SDL_CreateTextureFromSurface(renderer, screen);
|
fprintf(stderr, "Parsed GL version: %hu\n", get_gl_version());
|
||||||
|
|
||||||
if (!texture) {
|
|
||||||
fprintf(stderr, "SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
|
|
||||||
return EXIT_FAILURE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned audio_sample_rate = query_sample_rate_of_audiocontexts();
|
unsigned audio_sample_rate = query_sample_rate_of_audiocontexts();
|
||||||
@ -355,6 +415,11 @@ int EMSCRIPTEN_KEEPALIVE init() {
|
|||||||
|
|
||||||
init_gb();
|
init_gb();
|
||||||
|
|
||||||
|
if (!init_shader_with_name(&shader, configuration.filter)) {
|
||||||
|
init_shader_with_name(&shader, "NearestNeighbor");
|
||||||
|
}
|
||||||
|
update_viewport();
|
||||||
|
|
||||||
SDL_PauseAudioDevice(device_id, 0);
|
SDL_PauseAudioDevice(device_id, 0);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
|
@ -34,9 +34,17 @@ typedef enum {
|
|||||||
JOYPAD_AXISES_MAX
|
JOYPAD_AXISES_MAX
|
||||||
} joypad_axis_t;
|
} joypad_axis_t;
|
||||||
|
|
||||||
|
enum scaling_mode {
|
||||||
|
GB_SDL_SCALING_ENTIRE_WINDOW,
|
||||||
|
GB_SDL_SCALING_KEEP_RATIO,
|
||||||
|
GB_SDL_SCALING_INTEGER_FACTOR,
|
||||||
|
GB_SDL_SCALING_MAX,
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
SDL_Scancode keys[9];
|
SDL_Scancode keys[9];
|
||||||
GB_color_correction_mode_t color_correction_mode;
|
GB_color_correction_mode_t color_correction_mode;
|
||||||
|
enum scaling_mode scaling_mode;
|
||||||
bool blend_frames;
|
bool blend_frames;
|
||||||
|
|
||||||
GB_highpass_mode_t highpass_mode;
|
GB_highpass_mode_t highpass_mode;
|
||||||
|
1
wasm/opengl_compat.c
Normal file
1
wasm/opengl_compat.c
Normal file
@ -0,0 +1 @@
|
|||||||
|
#include "opengl_compat.h"
|
7
wasm/opengl_compat.h
Normal file
7
wasm/opengl_compat.h
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
#ifndef opengl_compat_h
|
||||||
|
#define opengl_compat_h
|
||||||
|
|
||||||
|
#define GL_GLEXT_PROTOTYPES 1
|
||||||
|
#include <GLES3/gl3.h>
|
||||||
|
|
||||||
|
#endif /* opengl_compat_h */
|
261
wasm/shader.c
Normal file
261
wasm/shader.c
Normal file
@ -0,0 +1,261 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "shader.h"
|
||||||
|
#include "utils.h"
|
||||||
|
|
||||||
|
static const char *vertex_shader_100 = "\
|
||||||
|
#version 100 \n\
|
||||||
|
attribute vec4 aPosition;\n\
|
||||||
|
void main(void) {\n\
|
||||||
|
gl_Position = aPosition;\n\
|
||||||
|
}\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
static const char *vertex_shader_300 = "\
|
||||||
|
#version 300 es\n\
|
||||||
|
in vec4 aPosition;\n\
|
||||||
|
void main(void) {\n\
|
||||||
|
gl_Position = aPosition;\n\
|
||||||
|
}\n\
|
||||||
|
";
|
||||||
|
|
||||||
|
uint16_t get_gl_version() {
|
||||||
|
GLint major = 0, minor = 0;
|
||||||
|
|
||||||
|
#if defined(GL_MAJOR_VERSION) && defined(GL_MINOR_VERSION)
|
||||||
|
glGetIntegerv(GL_MAJOR_VERSION, &major);
|
||||||
|
glGetIntegerv(GL_MINOR_VERSION, &minor);
|
||||||
|
#else
|
||||||
|
char *version = (char *) glGetString(GL_VERSION);
|
||||||
|
|
||||||
|
int res = sscanf(version, "OpenGL ES %d.%d", &major, &minor);
|
||||||
|
|
||||||
|
if (res != 2) {
|
||||||
|
// Maybe the OpenGL ES prefixed was missing
|
||||||
|
res = sscanf(version, "%d.%d", &major, &minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (res != 2) {
|
||||||
|
major = 0;
|
||||||
|
minor = 0;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return (uint16_t)(major * 0x100 + minor);
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLuint create_shader(const char *source, GLenum type)
|
||||||
|
{
|
||||||
|
// Create the shader object
|
||||||
|
GLuint shader = glCreateShader(type);
|
||||||
|
// Load the shader source
|
||||||
|
glShaderSource(shader, 1, &source, 0);
|
||||||
|
// Compile the shader
|
||||||
|
glCompileShader(shader);
|
||||||
|
// Check for errors
|
||||||
|
GLint status = 0;
|
||||||
|
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||||
|
if (status == GL_FALSE) {
|
||||||
|
GLchar messages[1024];
|
||||||
|
glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
|
||||||
|
fprintf(stderr, "GLSL Shader Error: %s", messages);
|
||||||
|
}
|
||||||
|
return shader;
|
||||||
|
}
|
||||||
|
|
||||||
|
static GLuint create_program(const char *vsh, const char *fsh)
|
||||||
|
{
|
||||||
|
// Build shaders
|
||||||
|
GLuint vertex_shader = create_shader(vsh, GL_VERTEX_SHADER);
|
||||||
|
GLuint fragment_shader = create_shader(fsh, GL_FRAGMENT_SHADER);
|
||||||
|
|
||||||
|
// Create program
|
||||||
|
GLuint program = glCreateProgram();
|
||||||
|
|
||||||
|
fprintf(stderr, "Creating program...\n");
|
||||||
|
|
||||||
|
// Attach shaders
|
||||||
|
glAttachShader(program, vertex_shader);
|
||||||
|
glAttachShader(program, fragment_shader);
|
||||||
|
|
||||||
|
fprintf(stderr, "Linking program...\n");
|
||||||
|
|
||||||
|
// Link program
|
||||||
|
glLinkProgram(program);
|
||||||
|
|
||||||
|
fprintf(stderr, "Checking for errors...\n");
|
||||||
|
|
||||||
|
// Check for errors
|
||||||
|
GLint status;
|
||||||
|
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||||
|
|
||||||
|
if (status == GL_FALSE) {
|
||||||
|
GLint info_len = 0;
|
||||||
|
|
||||||
|
glGetProgramiv(program, GL_INFO_LOG_LENGTH, &info_len);
|
||||||
|
|
||||||
|
if (info_len > 1) {
|
||||||
|
char* info_log = (char*)malloc(sizeof(char) * info_len);
|
||||||
|
|
||||||
|
glGetProgramInfoLog(program, info_len, NULL, info_log);
|
||||||
|
printf("Error linking program:\n%s\n", info_log);
|
||||||
|
|
||||||
|
free(info_log);
|
||||||
|
}
|
||||||
|
|
||||||
|
glDeleteProgram(program);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Delete shaders
|
||||||
|
glDeleteShader(vertex_shader);
|
||||||
|
glDeleteShader(fragment_shader);
|
||||||
|
|
||||||
|
return program;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool init_shader_with_name(shader_t *shader, const char *name)
|
||||||
|
{
|
||||||
|
uint16_t gl_version = get_gl_version();
|
||||||
|
|
||||||
|
static char master_shader_code[0x801] = {0,};
|
||||||
|
static char shader_code[0x10001] = {0,};
|
||||||
|
static char final_shader_code[0x10801] = {0,};
|
||||||
|
static signed long filter_token_location = 0;
|
||||||
|
|
||||||
|
if (!master_shader_code[0]) {
|
||||||
|
size_t header_len = 0;
|
||||||
|
|
||||||
|
if (gl_version >= 0x300) {
|
||||||
|
char* header = "#version 300 es\n#define VERSION 0x300\n";
|
||||||
|
header_len = strlen(header);
|
||||||
|
|
||||||
|
strcpy(master_shader_code, header);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
char* header = "#version 100\n#define VERSION 0x100\n";
|
||||||
|
header_len = strlen(header);
|
||||||
|
|
||||||
|
strcpy(master_shader_code, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
FILE *master_shader_f = fopen(resource_path("Shaders/WasmMasterShader.fsh"), "r");
|
||||||
|
if (!master_shader_f) return false;
|
||||||
|
fread(master_shader_code + header_len, 1, sizeof(master_shader_code) - 1, master_shader_f);
|
||||||
|
fclose(master_shader_f);
|
||||||
|
filter_token_location = strstr(master_shader_code, "{filter}") - master_shader_code;
|
||||||
|
if (filter_token_location < 0) {
|
||||||
|
master_shader_code[0] = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
char shader_path[1024];
|
||||||
|
sprintf(shader_path, "Shaders/%s.fsh", name);
|
||||||
|
|
||||||
|
FILE *shader_f = fopen(resource_path(shader_path), "r");
|
||||||
|
if (!shader_f) return false;
|
||||||
|
memset(shader_code, 0, sizeof(shader_code));
|
||||||
|
fread(shader_code, 1, sizeof(shader_code) - 1, shader_f);
|
||||||
|
fclose(shader_f);
|
||||||
|
|
||||||
|
memset(final_shader_code, 0, sizeof(final_shader_code));
|
||||||
|
memcpy(final_shader_code, master_shader_code, filter_token_location);
|
||||||
|
strcpy(final_shader_code + filter_token_location, shader_code);
|
||||||
|
strcat(final_shader_code + filter_token_location,
|
||||||
|
master_shader_code + filter_token_location + sizeof("{filter}") - 1);
|
||||||
|
|
||||||
|
fprintf(stderr, "Shader code:\n%s\n", final_shader_code);
|
||||||
|
|
||||||
|
if (gl_version >= 0x300) {
|
||||||
|
shader->program = create_program(vertex_shader_300, final_shader_code);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
shader->program = create_program(vertex_shader_100, final_shader_code);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
shader->position_attribute = glGetAttribLocation(shader->program, "aPosition");
|
||||||
|
// Uniforms
|
||||||
|
shader->input_resolution_uniform = glGetUniformLocation(shader->program, "input_resolution");
|
||||||
|
shader->resolution_uniform = glGetUniformLocation(shader->program, "output_resolution");
|
||||||
|
shader->origin_uniform = glGetUniformLocation(shader->program, "origin");
|
||||||
|
|
||||||
|
glGenTextures(1, &shader->texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
shader->texture_uniform = glGetUniformLocation(shader->program, "image");
|
||||||
|
|
||||||
|
glGenTextures(1, &shader->previous_texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
shader->previous_texture_uniform = glGetUniformLocation(shader->program, "previous_image");
|
||||||
|
|
||||||
|
shader->mix_previous_uniform = glGetUniformLocation(shader->program, "mix_previous");
|
||||||
|
|
||||||
|
// Program
|
||||||
|
|
||||||
|
glUseProgram(shader->program);
|
||||||
|
|
||||||
|
GLuint vao;
|
||||||
|
if (gl_version >= 0x300) {
|
||||||
|
glGenVertexArrays(1, &vao);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
}
|
||||||
|
|
||||||
|
GLuint vbo;
|
||||||
|
glGenBuffers(1, &vbo);
|
||||||
|
|
||||||
|
// Attributes
|
||||||
|
|
||||||
|
static GLfloat const quad[16] = {
|
||||||
|
-1.f, -1.f, 0, 1,
|
||||||
|
-1.f, +1.f, 0, 1,
|
||||||
|
+1.f, -1.f, 0, 1,
|
||||||
|
+1.f, +1.f, 0, 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(shader->position_attribute);
|
||||||
|
glVertexAttribPointer(shader->position_attribute, 4, GL_FLOAT, GL_FALSE, 0, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void render_bitmap_with_shader(shader_t *shader, void *bitmap, void *previous,
|
||||||
|
unsigned source_width, unsigned source_height,
|
||||||
|
unsigned x, unsigned y, unsigned w, unsigned h)
|
||||||
|
{
|
||||||
|
glUseProgram(shader->program);
|
||||||
|
glUniform2f(shader->origin_uniform, x, y);
|
||||||
|
glUniform2f(shader->input_resolution_uniform, source_width, source_height);
|
||||||
|
glUniform2f(shader->resolution_uniform, w, h);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source_width, source_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, bitmap);
|
||||||
|
glUniform1i(shader->texture_uniform, 0);
|
||||||
|
glUniform1i(shader->mix_previous_uniform, previous != NULL);
|
||||||
|
if (previous) {
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, shader->previous_texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, source_width, source_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, previous);
|
||||||
|
glUniform1i(shader->previous_texture_uniform, 1);
|
||||||
|
}
|
||||||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
void free_shader(shader_t *shader)
|
||||||
|
{
|
||||||
|
glDeleteProgram(shader->program);
|
||||||
|
glDeleteTextures(1, &shader->texture);
|
||||||
|
glDeleteTextures(1, &shader->previous_texture);
|
||||||
|
}
|
29
wasm/shader.h
Normal file
29
wasm/shader.h
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
#ifndef shader_h
|
||||||
|
#define shader_h
|
||||||
|
|
||||||
|
#include "opengl_compat.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
typedef struct shader_s {
|
||||||
|
GLuint input_resolution_uniform;
|
||||||
|
GLuint resolution_uniform;
|
||||||
|
GLuint origin_uniform;
|
||||||
|
GLuint texture_uniform;
|
||||||
|
GLuint previous_texture_uniform;
|
||||||
|
GLuint mix_previous_uniform;
|
||||||
|
|
||||||
|
GLuint position_attribute;
|
||||||
|
GLuint texture;
|
||||||
|
GLuint previous_texture;
|
||||||
|
GLuint program;
|
||||||
|
} shader_t;
|
||||||
|
|
||||||
|
uint16_t get_gl_version();
|
||||||
|
|
||||||
|
bool init_shader_with_name(shader_t *shader, const char *name);
|
||||||
|
void render_bitmap_with_shader(shader_t *shader, void *bitmap, void *previous,
|
||||||
|
unsigned source_width, unsigned source_height,
|
||||||
|
unsigned x, unsigned y, unsigned w, unsigned h);
|
||||||
|
void free_shader(struct shader_s *shader);
|
||||||
|
|
||||||
|
#endif /* shader_h */
|
Loading…
Reference in New Issue
Block a user