Add Pixelated/sharp bilinear filter, closes #746

This commit is contained in:
Lior Halphon
2026-09-27 16:10:36 +03:00
parent 5e71662bc8
commit 8733b87bc2
5 changed files with 32 additions and 8 deletions
+1 -1
View File
@@ -80,7 +80,7 @@ static uint32_t color_to_int(NSColor *color)
@"GBRewind": @(kVK_Tab),
@"GBSlow-Motion": @(kVK_Shift),
@"GBFilter": @"NearestNeighbor",
@"GBFilter": @"Pixelated",
@"GBColorCorrection": @(GB_COLOR_CORRECTION_MODERN_BALANCED),
@"GBHighpassFilter": @(GB_HIGHPASS_ACCURATE),
@"GBRewindLength": @(120),
+8 -2
View File
@@ -116,17 +116,23 @@
<popUpButton verticalHuggingPriority="750" fixedFrame="YES" translatesAutoresizingMaskIntoConstraints="NO" id="6pP-kK-EEC" customClass="GBPreferencePopUpButton">
<rect key="frame" x="30" y="500" width="262" height="25"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" flexibleMinY="YES"/>
<popUpButtonCell key="cell" type="push" title="Nearest neighbor (Pixelated)" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="neN-eo-LA7" id="I1w-05-lGl">
<popUpButtonCell key="cell" type="push" title="Nearest neighbor" bezelStyle="rounded" alignment="left" lineBreakMode="truncatingTail" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" selectedItem="neN-eo-LA7" id="I1w-05-lGl">
<behavior key="behavior" lightByBackground="YES" lightByGray="YES"/>
<font key="font" metaFont="message"/>
<menu key="menu" id="xDC-0T-Qg9">
<items>
<menuItem title="Nearest neighbor (Pixelated)" state="on" id="neN-eo-LA7" customClass="GBPreferenceMenuItem">
<menuItem title="Nearest neighbor" id="neN-eo-LA7" customClass="GBPreferenceMenuItem">
<modifierMask key="keyEquivalentModifierMask"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="preferenceValue" value="NearestNeighbor"/>
</userDefinedRuntimeAttributes>
</menuItem>
<menuItem title="Pixelated" state="on" id="lSa-83-lEf" customClass="GBPreferenceMenuItem">
<modifierMask key="keyEquivalentModifierMask"/>
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="preferenceValue" value="Pixelated"/>
</userDefinedRuntimeAttributes>
</menuItem>
<menuItem title="Bilinear (Blurry)" id="iDe-si-atu" customClass="GBPreferenceMenuItem">
<userDefinedRuntimeAttributes>
<userDefinedRuntimeAttribute type="string" keyPath="preferenceValue" value="Bilinear"/>
+4 -4
View File
@@ -1531,6 +1531,7 @@ struct shader_name {
} shaders[] =
{
{"NearestNeighbor", "Nearest Neighbor"},
{"Pixelated", "Pixelated"},
{"Bilinear", "Bilinear"},
{"SmoothBilinear", "Smooth Bilinear"},
{"MonoLCD", "Monochrome LCD"},
@@ -1557,7 +1558,6 @@ static void cycle_filter(unsigned index)
}
}
i += 1;
if (i >= sizeof(shaders) / sizeof(shaders[0])) {
i -= sizeof(shaders) / sizeof(shaders[0]);
@@ -1566,7 +1566,7 @@ static void cycle_filter(unsigned index)
strcpy(configuration.filter, shaders[i].file_name);
free_shader(&shader);
if (!init_shader_with_name(&shader, configuration.filter)) {
init_shader_with_name(&shader, "NearestNeighbor");
init_shader_with_name(&shader, "Pixelated");
}
}
@@ -1588,7 +1588,7 @@ static void cycle_filter_backwards(unsigned index)
strcpy(configuration.filter, shaders[i].file_name);
free_shader(&shader);
if (!init_shader_with_name(&shader, configuration.filter)) {
init_shader_with_name(&shader, "NearestNeighbor");
init_shader_with_name(&shader, "Pixelated");
}
}
@@ -1603,7 +1603,7 @@ static const char *current_filter_name(unsigned index)
}
if (i == sizeof(shaders) / sizeof(shaders[0])) {
i = 0;
i = 1; // Pixelated
}
return shaders[i].display_name;
+1 -1
View File
@@ -1596,7 +1596,7 @@ int main(int argc, char **argv)
SDL_EventState(SDL_DROPFILE, SDL_ENABLE);
if (!init_shader_with_name(&shader, configuration.filter)) {
init_shader_with_name(&shader, "NearestNeighbor");
init_shader_with_name(&shader, "Pixelated");
}
update_viewport();
+18
View File
@@ -0,0 +1,18 @@
STATIC vec4 scale(sampler2D image, vec2 position, vec2 input_resolution, vec2 output_resolution)
{
vec2 scale_factor = output_resolution / input_resolution;
vec2 pixel = position * input_resolution - vec2(0.5, 0.5);
vec4 q11 = texture(image, (floor(pixel) + 0.5) / input_resolution);
vec4 q12 = texture(image, (vec2(floor(pixel.x), ceil(pixel.y)) + 0.5) / input_resolution);
vec4 q21 = texture(image, (vec2(ceil(pixel.x), floor(pixel.y)) + 0.5) / input_resolution);
vec4 q22 = texture(image, (ceil(pixel) + 0.5) / input_resolution);
vec2 t = fract(pixel);
vec2 w = clamp((t - 0.5) * scale_factor + 0.5, 0.0, 1.0);
vec4 r1 = mix(q11, q21, w.x);
vec4 r2 = mix(q12, q22, w.x);
return mix(r1, r2, w.y);
}