#!/usr/bin/env python

import os
from OpenGL.GL import *
from OpenGL.GLU import *
import pygame, pygame.image
from pygame.locals import *
import time

"""
Simple "cover flow" demo using PyGame and OpenGL. Loads all .jpg images 
in the current folder. Images are shown with "periodic boundary conditions", 
left/right arrow navigates, use "z" and "x" to zoom, esc to close.  

(NB: too big images crashes the demo, resize with PIL if needed. 
Images are also forced into 2:3 aspect ratio for simplicity)
"""

class CoverFlow(object):
    
    def __init__(self):
        
        self.z = -5.0 #distance to camera (zoom)
        self.textures = []
        self.rd = [1.4,  0.0, -0.5] #right delta
        self.ld = [-1.4,  0.0, -0.5] #left delta
        self.t = 0 #for transitions between images
        self.s = 0 #for transitions between images
        self.imlist = self.get_imlist()
        self.nbr_images = len(self.imlist)
        self.ndx = 0 #start by showing the first image
        
        #opengl stuff
        glEnable(GL_TEXTURE_2D)
        self.load_textures()
        glShadeModel(GL_SMOOTH)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LEQUAL)
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
        glEnable( GL_LIGHT1 )
        
    def get_imlist(self):
        imlist = []
        for filename in os.listdir('./'):
            if os.path.splitext(filename)[1] == '.jpg':
                imlist.append(filename)
        return imlist

    def load_textures(self):
        self.textures = glGenTextures(self.nbr_images)
        for i in range(self.nbr_images):
            texturefile = self.imlist[i]
            textureSurface = pygame.image.load(texturefile)
            textureData = pygame.image.tostring(textureSurface, "RGBX", 1)
    
            glBindTexture(GL_TEXTURE_2D, self.textures[i])
            glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, textureSurface.get_width(), textureSurface.get_height(), 0,
                      GL_RGBA, GL_UNSIGNED_BYTE, textureData )
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
    
    def reset(self):
        self.t = 0
        self.s = 0
        self.draw()
    
    def draw(self):
    
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        glTranslatef(0.0, 0.0, self.z)
    
        pos = (self.ndx) % self.nbr_images
        glBindTexture(GL_TEXTURE_2D, self.textures[pos])
        glBegin(GL_QUADS)
        glNormal3f(0.0, 0.0, 1.0)
        glTexCoord2f(0.0, 0.0); glVertex3f(-1.25+self.t*self.ld[0]+self.s*self.rd[0], -1.0+self.t*self.ld[1]+self.s*self.rd[1],  1.0+self.t*self.ld[2]+self.s*self.rd[2])	# Bottom Left Of The Texture and Quad
        glTexCoord2f(1.0, 0.0); glVertex3f( 1.25+self.t*self.ld[0]+self.s*self.rd[0], -1.0+self.t*self.ld[1]+self.s*self.rd[1],  1.0+self.t*self.ld[2]+self.s*self.rd[2])	# Bottom Right Of The Texture and Quad
        glTexCoord2f(1.0, 1.0); glVertex3f( 1.25+self.t*self.ld[0]+self.s*self.rd[0],  1.0+self.t*self.ld[1]+self.s*self.rd[1],  1.0+self.t*self.ld[2]+self.s*self.rd[2])	# Top Right Of The Texture and Quad
        glTexCoord2f(0.0, 1.0); glVertex3f(-1.25+self.t*self.ld[0]+self.s*self.rd[0],  1.0+self.t*self.ld[1]+self.s*self.rd[1],  1.0+self.t*self.ld[2]+self.s*self.rd[2])	# Top Left Of The Texture and Quad
        glEnd()
    
        pos = (self.ndx+1) % self.nbr_images
        glBindTexture(GL_TEXTURE_2D, self.textures[pos])
        glBegin(GL_QUADS)
        glNormal3f(0.0, 0.0, 1.0)
        glTexCoord2f(0.0, 0.0); glVertex3f(-1.25+(1-self.t+self.s)*self.rd[0], -1.0+(1-self.t+self.s)*self.rd[1],  1.0+(1-self.t+self.s)*self.rd[2])	# Bottom Left Of The Texture and Quad
        glTexCoord2f(1.0, 0.0); glVertex3f( 1.25+(1-self.t+self.s)*self.rd[0], -1.0+(1-self.t+self.s)*self.rd[1],  1.0+(1-self.t+self.s)*self.rd[2])	# Bottom Right Of The Texture and Quad
        glTexCoord2f(1.0, 1.0); glVertex3f( 1.25+(1-self.t+self.s)*self.rd[0],  1.0+(1-self.t+self.s)*self.rd[1],  1.0+(1-self.t+self.s)*self.rd[2])	# Top Right Of The Texture and Quad
        glTexCoord2f(0.0, 1.0); glVertex3f(-1.25+(1-self.t+self.s)*self.rd[0],  1.0+(1-self.t+self.s)*self.rd[1],  1.0+(1-self.t+self.s)*self.rd[2])	# Top Left Of The Texture and Quad
        glEnd()
    
        pos = (self.ndx-1) % self.nbr_images
        glBindTexture(GL_TEXTURE_2D, self.textures[pos])
        glBegin(GL_QUADS)
        glNormal3f(0.0, 0.0, 1.0)
        glTexCoord2f(0.0, 0.0); glVertex3f(-1.25+(1+self.t-self.s)*self.ld[0], -1.0+(1+self.t-self.s)*self.ld[1],  1.0+(1+self.t-self.s)*self.ld[2])	# Bottom Left Of The Texture and Quad
        glTexCoord2f(1.0, 0.0); glVertex3f( 1.25+(1+self.t-self.s)*self.ld[0], -1.0+(1+self.t-self.s)*self.ld[1],  1.0+(1+self.t-self.s)*self.ld[2])	# Bottom Right Of The Texture and Quad
        glTexCoord2f(1.0, 1.0); glVertex3f( 1.25+(1+self.t-self.s)*self.ld[0],  1.0+(1+self.t-self.s)*self.ld[1],  1.0+(1+self.t-self.s)*self.ld[2])	# Top Right Of The Texture and Quad
        glTexCoord2f(0.0, 1.0); glVertex3f(-1.25+(1+self.t-self.s)*self.ld[0],  1.0+(1+self.t-self.s)*self.ld[1],  1.0+(1+self.t-self.s)*self.ld[2])	# Top Left Of The Texture and Quad
        glEnd()


    def handle_keys(self,key):
        if key == K_ESCAPE:
            return 0
        elif key == K_z:
            self.z -= 0.10
        elif key == K_x:
            self.z += 0.10
        elif key == K_LEFT:
            for i in range(10):
                self.s += 0.1
                pygame.time.delay(50)
                self.draw()
                pygame.display.flip()
            self.ndx -= 1
            self.reset()
        elif key == K_RIGHT:
            for i in range(10):
                self.t += 0.1
                pygame.time.delay(50)
                self.draw()
                pygame.display.flip()
            self.ndx += 1
            self.reset()
        return 1
    
def resize((width, height)):
    if height==0:
        height=1
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(45, 1.0*width/height, 0.1, 100.0)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()



def main():
    video_flags = OPENGL|DOUBLEBUF
    pygame.init()
    surface = pygame.display.set_mode((640,480), video_flags)
    pygame.display.set_caption('Cover flow demo')
    resize((640,480))
    cf = CoverFlow()

    while 1:
        event = pygame.event.poll()
        if event.type == QUIT:
            break
        if event.type == KEYDOWN:
            if cf.handle_keys(event.key) == 0:
                break
        cf.draw()
        pygame.display.flip()

if __name__ == '__main__': main()
