
import gobject
import gtk
import gtksourceview2

import OpenGL.GL as gl

import glitch, glitch.gtk
from glitch.limbo.objects import ColorfulTriangle
import OpenGL.GL.shaders as shaders

vertex = """
varying vec4 vertex_color;
void main() {
    gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;
    vertex_color = gl_Color;
}
"""
fragment = """
varying vec4 vertex_color;
void main() {
    gl_FragColor = vertex_color;
}
"""
error_color = gtk.gdk.Color(1.0, 0.7, 0.7)
white = gtk.gdk.Color(1.0, 1.0, 1.0)

class InteractiveShadedNode(glitch.Shader):
    def compile(self, ctx):
        print 'compiling...',

        try:
            vshader = shaders.compileShader(self.vertex, gl.GL_VERTEX_SHADER)
        except Exception, e:
            print
            print e
            srcview1.modify_base(gtk.STATE_NORMAL, error_color)
            return ctx['shaders'][self][1]
        else:
            srcview1.modify_base(gtk.STATE_NORMAL, white)

        try:
            fshader = shaders.compileShader(self.fragment,
                gl.GL_FRAGMENT_SHADER)
        except Exception, e:
            print
            print e
            srcview2.modify_base(gtk.STATE_NORMAL, error_color)
            return ctx['shaders'][self][1]
        else:
            srcview2.modify_base(gtk.STATE_NORMAL, white)

        print 'ok'
        program = shaders.compileProgram(vshader, fshader)
        return program

def make_srcview(initial_text):
    buffer = gtksourceview2.Buffer()
    buffer.set_language(glsl)
    buffer.set_text(initial_text)

    srcview = gtksourceview2.View(buffer)
    srcview.set_size_request(400, -1)

    frame = gtk.Frame()
    frame.props.shadow_type = gtk.SHADOW_IN
    frame.add(srcview)
    return (frame, srcview, buffer)

def change_timeout(vertex_buffer, fragment_buffer, camera, obj):
    global change_timeout_id
    obj.vertex = vertex_buffer.get_text(*vertex_buffer.get_bounds())
    obj.fragment = fragment_buffer.get_text(*fragment_buffer.get_bounds())
    obj.version += 1
    camera.refresh()
    change_timeout_id = None

def vertex_changed(buffer, fragment_buffer, camera, obj):
    global change_timeout_id

    if change_timeout_id is not None:
        gobject.source_remove(change_timeout_id)

    change_timeout_id = gobject.timeout_add(1000,
        change_timeout, buffer, fragment_buffer, camera, obj)

def fragment_changed(buffer, vertex_buffer, camera, obj):
    global change_timeout_id

    if change_timeout_id is not None:
        gobject.source_remove(change_timeout_id)

    change_timeout_id = gobject.timeout_add(1000,
        change_timeout, vertex_buffer, buffer, camera, obj)

if __name__ == '__main__':
    change_timeout_id = None

    mgr = gtksourceview2.LanguageManager()
    glsl = mgr.get_language('glsl')

    w = gtk.Window()
    w.connect('destroy', lambda w: gtk.main_quit())

    hbox = gtk.HBox()
    vbox = gtk.VBox()
    vbox.set_spacing(1)

    (srcview1_frame, srcview1, buffer1) = make_srcview(vertex)
    (srcview2_frame, srcview2, buffer2) = make_srcview(fragment)

    obj = InteractiveShadedNode(children=[ColorfulTriangle()])
    camera = glitch.gtk.GtkCamera(eye=[1, 0, 3], children=[obj])
    buffer1.connect('changed', vertex_changed, buffer2, camera, obj)
    buffer2.connect('changed', fragment_changed, buffer1, camera, obj)

    vbox.pack_start(srcview1_frame, True)
    vbox.pack_start(srcview2_frame, True)
    hbox.pack_start(vbox, False)
    hbox.pack_start(camera, True)
    w.add(hbox)
    w.show_all()
    gtk.main()

