Source code for carbonkivy.effects.shimmer

from __future__ import annotations

__all__ = ("ShimmerEffect",)

from typing import Any

from kivy.clock import Clock
from kivy.event import EventDispatcher
from kivy.graphics import RenderContext
from kivy.properties import BooleanProperty, ColorProperty, NumericProperty


SHIMMER_FS = """
$HEADER$
uniform float time;
uniform vec2 widget_size;
uniform vec2 widget_pos;
uniform vec4 shimmer_color;
uniform vec4 shine_color;
uniform float do_shimmer; 

void main(void) {
    if (do_shimmer > 0.5) {
        vec2 uv = -(gl_FragCoord.xy - widget_pos.xy) / widget_size.xy;
        float slant = uv.x - uv.y;

        float highlight = (sin(slant * 2.0 + time * 5.0) + 1.0) * 0.5;
        
        gl_FragColor = mix(shimmer_color, shine_color, highlight * 0.6);
    } else {
        gl_FragColor = frag_color * texture2D(texture0, tex_coord0);
    }
}
"""


[docs] class ShimmerEffect(EventDispatcher):
[docs] shimmering = BooleanProperty(False)
[docs] shimmer_speed = NumericProperty(1.5)
[docs] shimmer_base_color = ColorProperty([0.6, 0.6, 0.6, 1])
[docs] shimmer_shine_color = ColorProperty([0.9, 0.9, 0.9, 1])
[docs] render_fps = NumericProperty(60)
def __init__(self, **kwargs):
[docs] self.canvas = RenderContext( use_parent_projection=True, use_parent_modelview=True )
self.canvas.shader.fs = SHIMMER_FS super().__init__(**kwargs) self.bind(shimmering=self._update_glsl_state) Clock.schedule_once(self._init_shimmer, 0) def _init_shimmer(self, dt: float | int) -> None: self.canvas["shimmer_color"] = list(self.shimmer_base_color) self.canvas["shine_color"] = list(self.shimmer_shine_color) self.canvas["widget_size"] = [float(v) for v in self.size] self.canvas["widget_pos"] = [float(v) for v in self.to_window(*self.pos)] self.canvas["time"] = 0.0 self.canvas["do_shimmer"] = 1.0 if self.shimmering else 0.0 self.bind(size=self._update_uniforms, pos=self._update_uniforms)
[docs] def on_shimmer_base_color(self, *args) -> None: self.canvas["shimmer_color"] = list(self.shimmer_base_color)
[docs] def on_shimmer_shine_color(self, *args) -> None: self.canvas["shine_color"] = list(self.shimmer_shine_color)
def _update_uniforms(self, instance: object, value: Any) -> None: self.canvas["widget_size"] = [float(v) for v in self.size] self.canvas["widget_pos"] = [float(v) for v in self.to_window(*self.pos)] def _update_glsl_state(self, instance: object, value: Any) -> None: self.canvas["do_shimmer"] = 1.0 if value else 0.0 if value: Clock.schedule_interval(self._update_time, 1 / self.render_fps) else: Clock.unschedule(self._update_time) self.canvas["time"] = 0.0 def _update_time(self, dt: float | int) -> None: self.canvas["time"] += dt * float(self.shimmer_speed)