#!/usr/bin/env python

import json
import sys
from math import * 
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *
import pygame
from pygame.locals import *

def renderInit(width, height):
    pygame.init()
    screen = pygame.display.set_mode((width, height), HWSURFACE|OPENGL|DOUBLEBUF)
    glViewport(0, 0, width, height)
    glMatrixMode(GL_PROJECTION)
    glLoadIdentity()
    gluPerspective(60.0, float(width)/height, .1, 1000.)
    glMatrixMode(GL_MODELVIEW)
    glLoadIdentity()

    glEnable(GL_DEPTH_TEST)
    glShadeModel(GL_FLAT)
    glClearColor(1.0, 1.0, 1.0, 0.0)
    glEnable(GL_COLOR_MATERIAL)
    
    glEnable(GL_LIGHTING)
    glEnable(GL_LIGHT0)        
    glLight(GL_LIGHT0, GL_POSITION,  (0, 1, 1, 0))    
    
    glutInit()
    glMaterial(GL_FRONT, GL_AMBIENT, (0.1, 0.1, 0.1, 1.0))    
    glMaterial(GL_FRONT, GL_DIFFUSE, (1.0, 1.0, 1.0, 1.0))

def renderCubeLst(num,cubelst):
    display_list = glGenLists(num)                
    glNewList(num, GL_COMPILE)
    for (i,j,k),color in cubelst:
        glPushMatrix()
        glTranslate(i,j,k)
        glColor( color )
        glutSolidCube(1.0)
        glPopMatrix()
    glEndList()
    return display_list

def render(obj3d,cam,zoom):
    pygame.display.flip()
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    glLoadIdentity( )
    px,py,pz,angle = cam
    gluLookAt(px,py,pz,px+sin(angle),py,pz+cos(angle),0,1,0)
    # Light must be transformed as well
    glLight(GL_LIGHT0, GL_POSITION,  (0, 1.5, 1, 0)) 
    glScale(zoom,zoom,zoom)
    for n,x,y,z in obj3d:
        glPushMatrix();
        glTranslate(x,y,z)
        glCallList(n)
        glPopMatrix();

def loadModel(filename):
    cubes = []
    struct = {}
    with open(filename) as f:
        struct = json.load(f)
    if struct['type'] == 'model':
        center = struct["center"]
        cx,cy,cz = float(center["x"]),float(center["y"]),float(center["z"])
        map_surface = pygame.image.load(struct['file'])
        map_surface.lock()
        bg = map_surface.get_at((0, 0))
        for layer in struct["layer"]:
            subst = struct["layer"][layer]
            sx = subst["x"]
            sy = subst["y"]
            w = subst["w"]
            h = subst["h"]
            for y in range(h):            
                for x in range(w):
                    color=map_surface.get_at((sx+x, sy+y))
                    if color != bg:
                        r, g, b, a = color
                        gl_col = (r/255.0, g/255.0, b/255.0, a/255.0)
                        position = (float(x)-cx, float(-y)+cy, float(layer)-cz)
                        
                        cubes.append(( position, gl_col ))
        map_surface.unlock()
    return cubes
    

if __name__ == '__main__':
    filename = "model.json"
    if len(sys.argv)>1:
        filename = sys.argv[1]

    width,height = (200, 200)
    SCALE = 0.05
    tspeed = 0.03
    mspeed = 0.003
    dist = 20.0

    renderInit(width,height)
    clock = pygame.time.Clock()

    renderCubeLst(1,loadModel(filename))
   
    px,py,pz,angle = 0.0,0.0,-1.0,0.0

    cont=True
    while cont:
        clock.tick(30)
        for event in pygame.event.get():
            if event.type == QUIT:
                cont=False
            if event.type == KEYUP and event.key == K_ESCAPE:
                cont  =False
        pressed = pygame.key.get_pressed()
        if pressed[K_SPACE]:
            renderCubeLst(1,loadModel('model.json'))
        elif pressed[K_a]:
            dist -= 0.1
        elif pressed[K_z]:
            dist += 0.1

        angle += 0.1
        px = sin(angle)*dist
        pz = cos(angle)*dist

        render([(1,0,0,0)],(px,py,pz,angle-pi),1)

