#! /usr/bin/env python
# encoding: utf-8
 
import flappy
from flappy.events import Event, KeyboardEvent
from flappy.ui import Keyboard
from flappy.geom import Matrix3D
from flappy.display3d import Scene3D, VertexBuffer3D, VertexBuffer3DFormat
from flappy.display3d import IndexBuffer3D, Program3D, Texture
from flappy.display import Sprite
 
from time import time
import os
 
 
WIDTH = 800
HEIGHT = 600
RES_X = 512
RES_Y = 512
 
RESOURCES_DIR = './resources'
 
class HerokuShaders(Sprite):
 
    def __init__(self):
        super(HerokuShaders, self).__init__()
 
        self.scene = Scene3D()
        self.scene.width = WIDTH
        self.scene.height = HEIGHT        
        self.addChild(self.scene)
 
        self.texture = Texture(RES_X, RES_Y)
 
        quad_vertices = [
            -1.0, -1.0,
             1.0, -1.0,
            -1.0,  1.0,
             1.0,  1.0,
        ]
 
        quad_indeces = [0, 1, 2, 2, 1, 3]
 
        self.vbuffer = VertexBuffer3D(data32_per_vertex=2, data=quad_vertices)
        self.ibuffer = IndexBuffer3D(quad_indeces)
 
        self.heroku_program = Program3D()
        self.render_program = Program3D()
 
        self.vshader_src = \
        '''
            attribute vec2 pos;
 
            uniform vec2 surfaceSize;
            uniform vec2 resolution;
 
            varying vec2 surfacePosition;
 
            void main() {
 
                surfacePosition = pos;
                vec2 p = (resolution / surfaceSize) * pos;
                gl_Position = vec4( p.x, p.y, 1.0, 1.0 );
 
            }
        '''
 
        self.fshader_src = \
        '''
            uniform sampler2D tex;
            varying vec2 surfacePosition;
 
            void main(void){
                gl_FragColor = texture2D(tex, (surfacePosition + 1.0) * 0.5);
            }
        '''
 
        self.render_program.upload(self.vshader_src, self.fshader_src)
 
        self.next_shader_index = 0
        self.shader_files = []
        for fname in os.listdir(RESOURCES_DIR):
            ffname = os.path.join(RESOURCES_DIR, fname)
            if os.path.isfile(ffname):
                if fname.startswith('heroku_') and fname.endswith('.frag'):
                    self.shader_files.append(ffname)
        self.set_next_shader()
 
        self.addEventListener(Event.ENTER_FRAME, self.on_enter_frame)
        self.addEventListener(Event.ADDED_TO_STAGE, self.on_stage)
        self.addEventListener(KeyboardEvent.KEY_DOWN, self.on_key_down)
 
        self.start_time = time()
 
    def on_stage(self, event):
        self.stage.focus = self
 
    def on_key_down(self, event):
        if event.keyCode == Keyboard.SPACE:
            self.set_next_shader()
 
    def on_enter_frame(self, event):
        timeval = time() - self.start_time
 
        scene = self.scene
        scene.clear(0.0, 0.0, 0.0, 1.0)
 
        scene.setRenderToTexture(self.texture)
        scene.setProgram(self.heroku_program)
        scene.setVertexBufferAt('pos', self.vbuffer, 0, 
                                            VertexBuffer3DFormat.FLOAT_2)
 
        scene.setProgramConstant('resolution', [float(RES_X), float(RES_Y)])
        scene.setProgramConstant('surfaceSize', [float(RES_X), float(RES_Y)])
        scene.setProgramConstant('time', timeval)
        scene.setProgramConstant('mouse', [0.5, 0.5])
        scene.setProgramConstant('backbuffer', 0)
        scene.drawTriangles(self.ibuffer)
 
        scene.setRenderToBackBuffer()
        scene.setProgram(self.render_program)
        scene.setVertexBufferAt('pos', self.vbuffer, 0, 
                                            VertexBuffer3DFormat.FLOAT_2)
        scene.setProgramConstant('resolution', [float(WIDTH), float(HEIGHT)])
        scene.setProgramConstant('surfaceSize', [float(WIDTH), float(HEIGHT)])
        scene.setTextureAt('tex', self.texture)
        scene.drawTriangles(self.ibuffer)
 
    def set_next_shader(self):
        file_name = self.shader_files[self.next_shader_index]
        print(file_name)
        fshader_file = open(file_name, 'r')
        fshader_src = fshader_file.read()
        self.heroku_program.upload(self.vshader_src, fshader_src)
        self.next_shader_index += 1
        if self.next_shader_index >= len(self.shader_files):
            self.next_shader_index = 0
 
 
if __name__ == '__main__':
    flappy.start(HerokuShaders, width=WIDTH, height=HEIGHT, title=__file__)