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)
|
||||
{
|
||||
/* 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;
|
||||
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 > 1.0) return vec4(0,0,0,0);
|
||||
|
||||
float x_curve = cos(position.y - 0.5) * CURVENESS + (1 - CURVENESS);
|
||||
float x_multiplier = 1/x_curve;
|
||||
float x_curve = cos(position.y - 0.5) * CURVENESS + (1.0 - CURVENESS);
|
||||
float x_multiplier = 1.0 / x_curve;
|
||||
position.x *= x_multiplier;
|
||||
position.x -= (x_multiplier - 1) / 2;
|
||||
if (position.x < 0.0) return vec4(0,0,0,0);
|
||||
if (position.x > 1.0) return vec4(0,0,0,0);
|
||||
position.x -= (x_multiplier - 1.0) / 2.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, 0.0, 0.0);
|
||||
|
||||
/* Setting up common vars */
|
||||
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 left = texture(image, position - vec2(1.0 / input_resolution.x, 0));
|
||||
vec4 right = 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.0));
|
||||
|
||||
/* Vertical blurring */
|
||||
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);
|
||||
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) {
|
||||
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);
|
||||
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 */
|
||||
float scanline_multiplier;
|
||||
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 {
|
||||
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;
|
||||
@ -55,7 +55,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
||||
right *= scanline_multiplier;
|
||||
|
||||
/* 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) {
|
||||
pos.y += 0.5;
|
||||
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) {
|
||||
float gradient_position = pos.y * 3.0;
|
||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
right *= 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.0 - VERTICAL_BORDER_DEPTH);
|
||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||
}
|
||||
else if (pos.y > 2.0 / 3.0) {
|
||||
float gradient_position = (1 - pos.y) * 3.0;
|
||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
float gradient_position = (1.0 - pos.y) * 3.0;
|
||||
center *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
float gradient_position = pos.y * 3.0;
|
||||
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 {
|
||||
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);
|
||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
right *= 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.0 - VERTICAL_BORDER_DEPTH);
|
||||
right *= gradient_position * VERTICAL_BORDER_DEPTH + (1.0 - VERTICAL_BORDER_DEPTH);
|
||||
}
|
||||
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) {
|
||||
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 {
|
||||
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);
|
||||
left *= gradient_position * VERTICAL_BORDER_DEPTH + (1 - VERTICAL_BORDER_DEPTH);
|
||||
right *= 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.0 - 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;
|
||||
if (pos.x < 1.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1),
|
||||
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_HIGH * left.b, 1.0),
|
||||
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 2.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
||||
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 3.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
||||
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 4.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1),
|
||||
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * 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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 5.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1),
|
||||
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else {
|
||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
||||
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
|
||||
/* Anti alias the curve */
|
||||
vec2 pixel_position = position * output_resolution;
|
||||
if (pixel_position.x < 1) {
|
||||
if (pixel_position.x < 1.0) {
|
||||
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;
|
||||
}
|
||||
if (pixel_position.y < 1) {
|
||||
if (pixel_position.y < 1.0) {
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
/* 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. */
|
||||
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,
|
||||
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)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 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 w3 = texture(image, position + vec2( -o.x, 0));
|
||||
vec4 w4 = texture(image, position + vec2( 0, 0));
|
||||
vec4 w5 = 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, 0.0));
|
||||
vec4 w5 = texture(image, position + vec2( o.x, 0.0));
|
||||
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));
|
||||
|
||||
int pattern = 0;
|
||||
|
@ -5,27 +5,27 @@
|
||||
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_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 left = 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) {
|
||||
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);
|
||||
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);
|
||||
left *= sub_pos.y * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
||||
right *= 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.0 - SCANLINE_DEPTH);
|
||||
right *= sub_pos.y * SCANLINE_DEPTH + (1.0 - SCANLINE_DEPTH);
|
||||
}
|
||||
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);
|
||||
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);
|
||||
left *= (1.0 - sub_pos.y) * SCANLINE_DEPTH + (1 - SCANLINE_DEPTH);
|
||||
right *= (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.0 - 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;
|
||||
if (pos.x < 1.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_HIGH * left.b, 1),
|
||||
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_HIGH * left.b, 1.0),
|
||||
vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 2.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r, COLOR_LOW * center.g, COLOR_LOW * left.b, 1),
|
||||
vec4(COLOR_HIGH * center.r, COLOR_HIGH * center.g, COLOR_LOW * midleft.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 3.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_HIGH * center.r , COLOR_HIGH * center.g, COLOR_LOW * midleft.b, 1),
|
||||
vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g, COLOR_LOW * center.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 4.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_LOW * midright.r, COLOR_HIGH * center.g , COLOR_LOW * center.b, 1),
|
||||
vec4(COLOR_LOW * right.r , COLOR_HIGH * center.g, COLOR_HIGH * 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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else if (pos.x < 5.0 / 6.0) {
|
||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_HIGH * center.g , COLOR_HIGH * center.b, 1),
|
||||
vec4(COLOR_LOW * right.r, COLOR_LOW * midright.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
else {
|
||||
ret = mix(vec4(COLOR_LOW * right.r, COLOR_LOW * midright.g, COLOR_HIGH * center.b, 1),
|
||||
vec4(COLOR_HIGH * right.r, COLOR_LOW * right.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.0),
|
||||
sub_pos.x);
|
||||
}
|
||||
|
||||
|
@ -2,9 +2,9 @@
|
||||
- The actual output calculating was completely redesigned as resolution independent graphic generator. This allows
|
||||
scaling to any factor.
|
||||
- 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
|
||||
- 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.
|
||||
- "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
|
||||
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. */
|
||||
@ -28,7 +28,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
||||
{
|
||||
// o = offset, the width of a pixel
|
||||
vec2 o = 1.0 / input_resolution;
|
||||
|
||||
|
||||
/* 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]
|
||||
@ -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 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 w3 = texture(image, position + vec2( -o.x, 0));
|
||||
vec4 w4 = texture(image, position + vec2( 0, 0));
|
||||
vec4 w5 = 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, 0.0));
|
||||
vec4 w5 = texture(image, position + vec2( o.x, 0.0));
|
||||
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));
|
||||
|
||||
int pattern = 0;
|
||||
@ -81,7 +81,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
||||
if (P(0x2f,0x2f)) {
|
||||
float dist = length(p - vec2(0.5));
|
||||
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;
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
||||
if (dist > 0.5 + pixel_size / 2) {
|
||||
if (dist > 0.5 + pixel_size / 2.0) {
|
||||
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)) {
|
||||
float dist = p.x - 2.0 * p.y;
|
||||
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;
|
||||
}
|
||||
vec4 r = mix(w3, w4, p.x + 0.5);
|
||||
if (dist < -pixel_size / 2) {
|
||||
if (dist < -pixel_size / 2.0) {
|
||||
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)) {
|
||||
float dist = p.y - 2.0 * p.x;
|
||||
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;
|
||||
}
|
||||
vec4 r = mix(w1, w4, p.x + 0.5);
|
||||
if (dist < -pixel_size / 2) {
|
||||
if (dist < -pixel_size / 2.0) {
|
||||
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)) {
|
||||
float dist = p.x + 2.0 * p.y;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
if (dist < 1.0 - pixel_size / 2) {
|
||||
if (dist < 1.0 - pixel_size / 2.0) {
|
||||
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 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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
if (dist < 1.0 - pixel_size / 2) {
|
||||
if (dist < 1.0 - pixel_size / 2.0) {
|
||||
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))
|
||||
@ -185,7 +185,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
||||
float dist = p.x + p.y;
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
if (dist < 0.5 - pixel_size / 2) {
|
||||
if (dist < 0.5 - pixel_size / 2.0) {
|
||||
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))
|
||||
@ -213,7 +213,7 @@ STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 ou
|
||||
float dist = p.x + p.y;
|
||||
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;
|
||||
|
||||
/* 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) {
|
||||
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 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;
|
||||
}
|
||||
|
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 += -DGB_INTERNAL=1 # get access to internal APIs
|
||||
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
|
||||
WASM_LDFLAGS :=
|
||||
|
||||
@ -95,7 +96,9 @@ WASM_OBJECTS := $(patsubst %,$(OBJ)/%.o,$(WASM_SOURCES))
|
||||
WEB_SOURCES := $(shell ls ressources/.)
|
||||
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
|
||||
|
||||
# Automatic dependency generation
|
||||
|
131
wasm/main.c
131
wasm/main.c
@ -1,7 +1,6 @@
|
||||
#include <emscripten.h>
|
||||
#include <SDL2/SDL.h>
|
||||
#include <SDL2/SDL_opengl.h>
|
||||
#include <SDL2/SDL_video.h>
|
||||
#include <SDL2/SDL.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
@ -9,6 +8,7 @@
|
||||
#include <Core/gb.h>
|
||||
#include "main.h"
|
||||
#include "utils.h"
|
||||
#include "shader.h"
|
||||
|
||||
GB_gameboy_t gb;
|
||||
|
||||
@ -19,12 +19,36 @@ SDL_Texture *texture;
|
||||
SDL_PixelFormat *pixel_format;
|
||||
SDL_AudioDeviceID device_id;
|
||||
|
||||
shader_t shader;
|
||||
|
||||
static SDL_Rect rect;
|
||||
static unsigned factor;
|
||||
static SDL_AudioSpec want_aspec, have_aspec;
|
||||
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 *previous_pixel_buffer = pixel_buffer_2;
|
||||
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 =
|
||||
{
|
||||
.keys = {
|
||||
@ -62,9 +86,11 @@ configuration_t configuration =
|
||||
},
|
||||
.color_correction_mode = GB_COLOR_CORRECTION_EMULATE_HARDWARE,
|
||||
.highpass_mode = GB_HIGHPASS_ACCURATE,
|
||||
.scaling_mode = GB_SDL_SCALING_INTEGER_FACTOR,
|
||||
.blend_frames = true,
|
||||
.rewind_length = 60 * 2,
|
||||
.model = MODEL_CGB
|
||||
.model = MODEL_CGB,
|
||||
.filter = "OmniScale",
|
||||
};
|
||||
|
||||
// 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)
|
||||
{
|
||||
if (renderer) {
|
||||
@ -112,7 +178,7 @@ void render_texture(void *pixels, void *previous)
|
||||
SDL_RenderCopy(renderer, texture, NULL, NULL);
|
||||
SDL_RenderPresent(renderer);
|
||||
}
|
||||
/*else {
|
||||
else {
|
||||
static void *_pixels = NULL;
|
||||
if (pixels) {
|
||||
_pixels = pixels;
|
||||
@ -123,7 +189,7 @@ void render_texture(void *pixels, void *previous)
|
||||
GB_get_screen_width(&gb), GB_get_screen_height(&gb),
|
||||
rect.x, rect.y, rect.w, rect.h);
|
||||
SDL_GL_SwapWindow(window);
|
||||
}*/
|
||||
}
|
||||
}
|
||||
|
||||
static void handle_events(GB_gameboy_t *gb) {
|
||||
@ -243,8 +309,8 @@ int EMSCRIPTEN_KEEPALIVE init() {
|
||||
"SameBoy v" xstr(VERSION),
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
SDL_WINDOWPOS_UNDEFINED,
|
||||
VIDEO_WIDTH,
|
||||
VIDEO_HEIGHT,
|
||||
VIDEO_WIDTH * 4,
|
||||
VIDEO_HEIGHT * 4,
|
||||
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_SetWindowMaximumSize(window, VIDEO_WIDTH, VIDEO_HEIGHT);
|
||||
|
||||
renderer = SDL_CreateRenderer(
|
||||
window,
|
||||
-1,
|
||||
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC
|
||||
);
|
||||
// Try to get a GLES 3.0 context
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
|
||||
SDL_GLContext gl_context = SDL_GL_CreateContext(window);
|
||||
|
||||
if (!renderer) {
|
||||
fprintf(stderr, "SDL_CreateRenderer Error: %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
if (gl_context == NULL) {
|
||||
// Try to get a GLES 2.0 context
|
||||
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(
|
||||
0,
|
||||
VIDEO_WIDTH,
|
||||
VIDEO_HEIGHT,
|
||||
32,
|
||||
0, 0, 0, 0
|
||||
);
|
||||
|
||||
if (!screen) {
|
||||
SDL_Log("SDL_CreateRGBSurface() failed: %s", SDL_GetError());
|
||||
exit(1);
|
||||
if (gl_context == NULL) {
|
||||
fprintf(stderr, "Using software renderer!\n");
|
||||
renderer = SDL_CreateRenderer(window, -1, 0);
|
||||
texture = SDL_CreateTexture(renderer, SDL_GetWindowPixelFormat(window), SDL_TEXTUREACCESS_STREAMING, 160, 144);
|
||||
pixel_format = SDL_AllocFormat(SDL_GetWindowPixelFormat(window));
|
||||
}
|
||||
else {
|
||||
fprintf(stderr, "Using OpenGL renderer!\n");
|
||||
pixel_format = SDL_AllocFormat(SDL_PIXELFORMAT_ABGR8888);
|
||||
|
||||
pixel_format = screen->format;
|
||||
|
||||
texture = SDL_CreateTextureFromSurface(renderer, screen);
|
||||
|
||||
if (!texture) {
|
||||
fprintf(stderr, "SDL_CreateTextureFromSurface Error: %s\n", SDL_GetError());
|
||||
return EXIT_FAILURE;
|
||||
fprintf(stderr, "GLES: %s\n", glGetString(GL_VERSION));
|
||||
fprintf(stderr, "GLSL: %s\n", glGetString(GL_SHADING_LANGUAGE_VERSION));
|
||||
fprintf(stderr, "Parsed GL version: %hu\n", get_gl_version());
|
||||
}
|
||||
|
||||
unsigned audio_sample_rate = query_sample_rate_of_audiocontexts();
|
||||
@ -355,6 +415,11 @@ int EMSCRIPTEN_KEEPALIVE init() {
|
||||
|
||||
init_gb();
|
||||
|
||||
if (!init_shader_with_name(&shader, configuration.filter)) {
|
||||
init_shader_with_name(&shader, "NearestNeighbor");
|
||||
}
|
||||
update_viewport();
|
||||
|
||||
SDL_PauseAudioDevice(device_id, 0);
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
|
@ -34,9 +34,17 @@ typedef enum {
|
||||
JOYPAD_AXISES_MAX
|
||||
} 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 {
|
||||
SDL_Scancode keys[9];
|
||||
GB_color_correction_mode_t color_correction_mode;
|
||||
enum scaling_mode scaling_mode;
|
||||
bool blend_frames;
|
||||
|
||||
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