148 lines
3.8 KiB
Python
148 lines
3.8 KiB
Python
|
'''
|
||
|
Live Shader Editor
|
||
|
==================
|
||
|
|
||
|
This provides a live editor for vertex and fragment editors.
|
||
|
You should see a window with two editable panes on the left
|
||
|
and a large kivy logo on the right.The top pane is the
|
||
|
Vertex shader and the bottom is the Fragment shader. The file shadereditor.kv
|
||
|
describes the interface.
|
||
|
|
||
|
On each keystroke to either shader, declarations are added and the shaders
|
||
|
are compiled. If there are no errors, the screen is updated. Otherwise,
|
||
|
the error is visible as logging message in your terminal.
|
||
|
'''
|
||
|
|
||
|
|
||
|
import sys
|
||
|
import kivy
|
||
|
kivy.require('1.0.6')
|
||
|
|
||
|
from kivy.app import App
|
||
|
from kivy.uix.floatlayout import FloatLayout
|
||
|
from kivy.core.window import Window
|
||
|
from kivy.factory import Factory
|
||
|
from kivy.graphics import RenderContext
|
||
|
from kivy.properties import StringProperty, ObjectProperty
|
||
|
from kivy.clock import Clock
|
||
|
from kivy.compat import PY2
|
||
|
|
||
|
fs_header = '''
|
||
|
#ifdef GL_ES
|
||
|
precision highp float;
|
||
|
#endif
|
||
|
|
||
|
/* Outputs from the vertex shader */
|
||
|
varying vec4 frag_color;
|
||
|
varying vec2 tex_coord0;
|
||
|
|
||
|
/* uniform texture samplers */
|
||
|
uniform sampler2D texture0;
|
||
|
|
||
|
/* custom one */
|
||
|
uniform vec2 resolution;
|
||
|
uniform float time;
|
||
|
'''
|
||
|
|
||
|
vs_header = '''
|
||
|
#ifdef GL_ES
|
||
|
precision highp float;
|
||
|
#endif
|
||
|
|
||
|
/* Outputs to the fragment shader */
|
||
|
varying vec4 frag_color;
|
||
|
varying vec2 tex_coord0;
|
||
|
|
||
|
/* vertex attributes */
|
||
|
attribute vec2 vPosition;
|
||
|
attribute vec2 vTexCoords0;
|
||
|
|
||
|
/* uniform variables */
|
||
|
uniform mat4 modelview_mat;
|
||
|
uniform mat4 projection_mat;
|
||
|
uniform vec4 color;
|
||
|
'''
|
||
|
|
||
|
|
||
|
class ShaderViewer(FloatLayout):
|
||
|
fs = StringProperty(None)
|
||
|
vs = StringProperty(None)
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
self.canvas = RenderContext()
|
||
|
super(ShaderViewer, self).__init__(**kwargs)
|
||
|
Clock.schedule_interval(self.update_shader, 0)
|
||
|
|
||
|
def update_shader(self, *args):
|
||
|
s = self.canvas
|
||
|
s['projection_mat'] = Window.render_context['projection_mat']
|
||
|
s['time'] = Clock.get_boottime()
|
||
|
s['resolution'] = list(map(float, self.size))
|
||
|
s.ask_update()
|
||
|
|
||
|
def on_fs(self, instance, value):
|
||
|
self.canvas.shader.fs = value
|
||
|
|
||
|
def on_vs(self, instance, value):
|
||
|
self.canvas.shader.vs = value
|
||
|
|
||
|
|
||
|
Factory.register('ShaderViewer', cls=ShaderViewer)
|
||
|
|
||
|
|
||
|
class ShaderEditor(FloatLayout):
|
||
|
|
||
|
source = StringProperty('data/logo/kivy-icon-512.png')
|
||
|
|
||
|
fs = StringProperty('''
|
||
|
void main (void){
|
||
|
gl_FragColor = frag_color * texture2D(texture0, tex_coord0);
|
||
|
}
|
||
|
''')
|
||
|
vs = StringProperty('''
|
||
|
void main (void) {
|
||
|
frag_color = color;
|
||
|
tex_coord0 = vTexCoords0;
|
||
|
gl_Position = projection_mat * modelview_mat * vec4(vPosition.xy, 0.0, 1.0);
|
||
|
}
|
||
|
''')
|
||
|
|
||
|
viewer = ObjectProperty(None)
|
||
|
|
||
|
def __init__(self, **kwargs):
|
||
|
super(ShaderEditor, self).__init__(**kwargs)
|
||
|
self.test_canvas = RenderContext()
|
||
|
s = self.test_canvas.shader
|
||
|
self.trigger_compile = Clock.create_trigger(self.compile_shaders, -1)
|
||
|
self.bind(fs=self.trigger_compile, vs=self.trigger_compile)
|
||
|
|
||
|
def compile_shaders(self, *largs):
|
||
|
print('try compile')
|
||
|
if not self.viewer:
|
||
|
return
|
||
|
|
||
|
# we don't use str() here because it will crash with non-ascii char
|
||
|
if PY2:
|
||
|
fs = fs_header + self.fs.encode('utf-8')
|
||
|
vs = vs_header + self.vs.encode('utf-8')
|
||
|
else:
|
||
|
fs = fs_header + self.fs
|
||
|
vs = vs_header + self.vs
|
||
|
|
||
|
print('-->', fs)
|
||
|
self.viewer.fs = fs
|
||
|
print('-->', vs)
|
||
|
self.viewer.vs = vs
|
||
|
|
||
|
|
||
|
class ShaderEditorApp(App):
|
||
|
def build(self):
|
||
|
kwargs = {}
|
||
|
if len(sys.argv) > 1:
|
||
|
kwargs['source'] = sys.argv[1]
|
||
|
return ShaderEditor(**kwargs)
|
||
|
|
||
|
|
||
|
if __name__ == '__main__':
|
||
|
ShaderEditorApp().run()
|