
"Shader support."

from __future__ import with_statement

import OpenGL.GL as gl
import OpenGL.GL.shaders as shaders

import glitch
from glitch.multicontext import MultiContext

class Shader(glitch.Node, MultiContext):
    "An OpenGL vertex and fragment shader."

    _context_key = 'shader'

    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;
        }
        """

    def __init__(self, vertex=None, fragment=None, **kw):
        if vertex:
            self.vertex = vertex
        if fragment:
            self.fragment = fragment
        glitch.Node.__init__(self, **kw)
        MultiContext.__init__(self)

    def compile(self, ctx):
        "Compile this shader."

        try:
            return shaders.compileProgram(
                shaders.compileShader(self.vertex, gl.GL_VERTEX_SHADER),
                shaders.compileShader(self.fragment, gl.GL_FRAGMENT_SHADER))
        except RuntimeError, e:
            print e
            return None

    def set_uniforms(self, ctx, shader):
        "Set any uniform variables the shader uses."

    def _context_create(self, ctx):
        return self.compile(ctx)

    def _context_update(self, ctx, _old_shader):
        return self.compile(ctx)

    def render(self, ctx):
        shader = self.context_get(ctx)

        if shader is not None:
            with shader:
                self.set_uniforms(ctx, shader)
                glitch.Node.render(self, ctx)
