Compare commits

..

1 Commits

Author SHA1 Message Date
xbzk 3e74fc9634 [android, ui] refresh game icons when updates are discovered 2026-08-22 17:51:54 -03:00
7 changed files with 64 additions and 61 deletions
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<item android:state_pressed="true" android:color="?attr/colorControlHighlight" />
<item android:state_focused="true" android:color="@android:color/transparent" />
<item android:state_selected="true" android:color="@android:color/transparent" />
<item android:state_hovered="true" android:color="@android:color/transparent" />
<item android:color="@android:color/transparent" />
</selector>
@@ -10,7 +10,6 @@
android:clipChildren="true"
android:layout_margin="0dp"
app:cardBackgroundColor="@color/eden_card_background"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="1dp"
app:strokeColor="@color/eden_border">
@@ -11,7 +11,6 @@
app:cardCornerRadius="16dp"
app:cardPreventCornerOverlap="true"
android:clipChildren="true"
app:rippleColor="@color/game_card_ripple"
android:layout_margin="4dp">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true"
android:transitionName="card_game"
app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -22,7 +22,6 @@
android:focusable="true"
android:transitionName="card_game_compact"
app:cardCornerRadius="16dp"
app:rippleColor="@color/game_card_ripple"
android:foreground="@color/eden_border_gradient_start">
<androidx.constraintlayout.widget.ConstraintLayout
@@ -12,7 +12,6 @@
app:cardCornerRadius="16dp"
app:cardElevation="0dp"
app:cardBackgroundColor="@android:color/transparent"
app:rippleColor="@color/game_card_ripple"
app:strokeWidth="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
+64 -48
View File
@@ -5,6 +5,7 @@ layout(location = 0) out vec4 color;
layout(binding = 0) uniform sampler2D color_texture;
#ifdef VULKAN
struct ScreenRectVertex {
vec2 position;
vec2 tex_coord;
@@ -13,79 +14,94 @@ layout (push_constant) uniform PushConstants {
mat4 modelview_matrix;
ScreenRectVertex vertices[4];
};
#else // OpenGL
layout(location = 1) uniform uvec2 screen_size;
#endif
/***** Area Sampling *****/
// By Sam Belliveau and Filippo Tarpini. Public Domain license.
// Effectively a more accurate sharp bilinear filter when upscaling,
// that also works as a mathematically perfect downscale filter.
// https://entropymine.com/imageworsener/pixelmixing/
// https://github.com/obsproject/obs-studio/pull/1715
// https://legacy.imagemagick.org/Usage/filter/
vec4 AreaSampling(sampler2D s, vec2 tc, vec4 trans_bounds) {
vec4 AreaSampling(sampler2D textureSampler, vec2 texCoords, vec2 source_size, vec2 target_size) {
// Determine the sizes of the source and target images.
vec2 inverted_target_size = vec2(1.0) / target_size;
// Determine the range of the source image that the target pixel will cover.
vec2 range = source_size * inverted_target_size;
vec2 beg = (texCoords.xy * source_size) - (range * 0.5);
vec2 end = beg + range;
// Compute the top-left and bottom-right corners of the pixel box.
ivec4 b = ivec4(floor(trans_bounds));
ivec2 f_beg = ivec2(floor(beg));
ivec2 f_end = ivec2(floor(end));
// Compute how much of the start and end pixels are covered horizontally & vertically.
// W,N,E,S
vec4 kb = vec4(1.0f - fract(trans_bounds.xy), fract(trans_bounds.zw));
float area_w = 1.0 - fract(beg.x);
float area_n = 1.0 - fract(beg.y);
float area_e = fract(end.x);
float area_s = fract(end.y);
// Compute the areas of the corner pixels in the pixel box.
// NW,NE,SW,SE
vec4 kc = kb.yyww * kb.xzxz;
// Accumulate corner pixels by forming a corner matrix.
vec4 r = mat4x4(
texelFetch(s, ivec2(b.xy), 0),
texelFetch(s, ivec2(b.zy), 0),
texelFetch(s, ivec2(b.xw), 0),
texelFetch(s, ivec2(b.zw), 0)
) * kc;
float area_nw = area_n * area_w;
float area_ne = area_n * area_e;
float area_sw = area_s * area_w;
float area_se = area_s * area_e;
// Initialize the color accumulator.
vec4 avg_color = vec4(0.0, 0.0, 0.0, 0.0);
// Accumulate corner pixels.
avg_color += area_nw * texelFetch(textureSampler, ivec2(f_beg.x, f_beg.y), 0);
avg_color += area_ne * texelFetch(textureSampler, ivec2(f_end.x, f_beg.y), 0);
avg_color += area_sw * texelFetch(textureSampler, ivec2(f_beg.x, f_end.y), 0);
avg_color += area_se * texelFetch(textureSampler, ivec2(f_end.x, f_end.y), 0);
// Determine the size of the pixel box.
ivec2 q = clamp(ivec2(
int(b.z - b.x - 0.5f),
int(b.w - b.y - 0.5f)
), ivec2(-16), ivec2(16));
vec2 qf = vec2(q);
int x_range = int(f_end.x - f_beg.x - 0.5);
int y_range = int(f_end.y - f_beg.y - 0.5);
// Accumulate top and bottom edge pixels.
for (int x = 0; x < q.x; ++x) {
r += kb.y * texelFetch(s, ivec2(x + b.x + 1, b.y), 0);
r += kb.w * texelFetch(s, ivec2(x + b.x + 1, b.w), 0);
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += area_n * texelFetch(textureSampler, ivec2(x, f_beg.y), 0);
avg_color += area_s * texelFetch(textureSampler, ivec2(x, f_end.y), 0);
}
// Accumulate left and right edge pixels and all the pixels in between.
for (int y = 0; y < q.y; ++y) {
r += kb.x * texelFetch(s, ivec2(b.x, y + b.y + 1), 0);
r += kb.z * texelFetch(s, ivec2(b.z, y + b.y + 1), 0);
for (int x = 0; x < q.x; ++x) {
r += texelFetch(s, ivec2(x, y) + b.xy + 1, 0);
for (int y = f_beg.y + 1; y <= f_beg.y + y_range; ++y) {
avg_color += area_w * texelFetch(textureSampler, ivec2(f_beg.x, y), 0);
avg_color += area_e * texelFetch(textureSampler, ivec2(f_end.x, y), 0);
for (int x = f_beg.x + 1; x <= f_beg.x + x_range; ++x) {
avg_color += texelFetch(textureSampler, ivec2(x, y), 0);
}
}
// Compute the area of the pixel box that was sampled.
float area_corners = area_nw + area_ne + area_sw + area_se;
float area_edges = float(x_range) * (area_n + area_s) + float(y_range) * (area_w + area_e);
float area_center = float(x_range) * float(y_range);
// Return the normalized average color.
return r / (
kc.x + kc.y + kc.z + kc.w //corners
+ qf.x * (kb.y + kb.w) + qf.y * (kb.x + kb.z) //edges
+ qf.x * qf.y // center
);
return avg_color / (area_corners + area_edges + area_center);
}
void main() {
#ifdef VULKAN
vec2 dst_size = vec2(
vertices[1].position.x - vertices[0].position.x,
vertices[2].position.y - vertices[0].position.y
);
#else // OpenGL
vec2 dst_size = screen_size;
#endif
vec2 source_image_size = textureSize(color_texture, 0);
vec2 window_size;
vec2 src_size = textureSize(color_texture, 0);
// Determine the range of the source image that the target pixel will cover.
vec2 scale = src_size * (1.0f / dst_size);
color = AreaSampling(color_texture, frag_tex_coord, vec4(
(frag_tex_coord * src_size) - (scale * 0.5f),
// (scale * 0.5f) + scale
// {A / 2 + A} ==> {(A + 2A) / 2} ==> {3A / 2} ==> {A * (3/2)}
(frag_tex_coord * src_size) + scale * 0.5f
));
#ifdef VULKAN
window_size.x = vertices[1].position.x - vertices[0].position.x;
window_size.y = vertices[2].position.y - vertices[0].position.y;
#else // OpenGL
window_size = screen_size;
#endif
color = AreaSampling(color_texture, frag_tex_coord, source_image_size, window_size);
}