Skip to content

Instantly share code, notes, and snippets.

@tshirtman
Created September 11, 2021 00:48
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tshirtman/adc06eb3b1187248ea20d8244b1d5ff7 to your computer and use it in GitHub Desktop.
Save tshirtman/adc06eb3b1187248ea20d8244b1d5ff7 to your computer and use it in GitHub Desktop.
#!/usr/bin/env python
'''
GLSLiewer
=======
GlslViewer, for KV-Viewer, is a simple tool allowing you to dynamically display
a GLSL file, taking its changes into account (thanks to watchdog).
You can use the script as follows::
python glsl_viewer.py ./test.glsl
This will display the test.glsl and automatically update the display when the
file changes.
.. note: This scripts uses watchdog to listen for file changes. To install
watchdog::
pip install watchdog
'''
from kivy.lang import Builder
from kivy.app import App
from kivy.core.window import Window
from kivy.clock import Clock, mainthread
from kivy.uix.label import Label
from kivy.animation import Animation
from kivy.uix.widget import Widget
from kivy.properties import StringProperty
from kivy.graphics import RenderContext
from watchdog.observers import Observer
from watchdog.events import FileSystemEventHandler
from os.path import dirname, basename, join
from pathlib import Path
kv = '''
<ShaderWidget>:
canvas:
Color:
rgb: 1, 0, 0
Rectangle:
pos: self.pos
size: self.size
'''
class ShaderWidget(Widget):
fs = StringProperty(None)
def __init__(self, **kwargs):
self.canvas = RenderContext()
super().__init__(**kwargs)
# We'll update our glsl variables in a clock
Clock.schedule_interval(self.update_glsl, 1 / 60.)
def on_fs(self, instance, value):
shader = self.canvas.shader
old_value = shader.fs
shader.fs = value
if not shader.success:
shader.fs = old_value
raise Exception('failed')
def update_glsl(self, *largs):
self.canvas['time'] = Clock.get_boottime()
self.canvas['resolution'] = list(map(float, self.size))
win_rc = Window.render_context
self.canvas['projection_mat'] = win_rc['projection_mat']
self.canvas['modelview_mat'] = win_rc['modelview_mat']
self.canvas['frag_modelview_mat'] = win_rc['frag_modelview_mat']
class GlslHandler(FileSystemEventHandler):
def __init__(self, callback, target, **kwargs):
super().__init__(**kwargs)
self.callback = callback
self.target = target
def on_any_event(self, event):
if basename(event.src_path) == self.target.name:
self.callback()
class GLSLViewerApp(App):
def __init__(self, path):
self.path = path
super().__init__()
def build(self):
event_handler = GlslHandler(self.update, self.path)
o = Observer()
o.schedule(event_handler, self.path.parent)
o.start()
Clock.schedule_once(self.update, 0)
return ShaderWidget()
@mainthread
def update(self, *args):
print("load new shader content")
try:
self.root.fs = self.path.read_text()
print("loaded successfully")
except Exception as e:
pass
Builder.load_string(kv)
if __name__ == '__main__':
from sys import argv
if len(argv) != 2:
print('usage: %s filename.glsl' % argv[0])
exit(1)
GLSLViewerApp(Path(argv[1])).run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment