#!/usr/bin/env python2.7

import platform, sys, os, math
import locale
import getopt
import numpy as np
import cv2

from PIL import Image

from OpenGL.GL import *
from OpenGL.GLUT import *
from OpenGL.GLU import *

global cap
global frame
global size
global out
global output
global texName
global vidpause

def usage(argv):
  print "Usage: ", argv[0], "\n" \
        "  --output\n" \
        "    output: if present output video\n"

def reshape(width, height):
  glViewport(0, 0, width, height)

  glMatrixMode(GL_PROJECTION)
  glLoadIdentity()

  # l, r, b, t, near, far
# glOrtho(-width/height, width/height, -1.0, 1.0, -1.0, 1.0)
  glOrtho(0, width, 0, height, -1.0, 1.0)
# gluOrtho2D(0, width, 0, height)

  glMatrixMode(GL_MODELVIEW)
  glLoadIdentity()

def keyboard(key, x, y):

  global vidpause

  if key is '\033':
    cleanup()
  elif key is 'q':
    cleanup()
  elif key == 'p' or key == ' ':
    vidpause = 1 - vidpause
  else:
    print "unknown key"

  glutPostRedisplay()

def init():

  global texName

  glEnable(GL_DEPTH_TEST)

  glClearColor(0.22, 0.28, 0.34, 0.0)

  glShadeModel(GL_FLAT)

  # obtain texture id from OpenGL
  texName = glGenTextures(1)
# print "got texName = ", texName

  # blending function
  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
  glEnable(GL_BLEND)

  glPolygonMode(GL_FRONT_AND_BACK, GL_FILL)

def texbind(frame):

  # convert OpenCV cv2 frame to OpenGL texture format
# gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
  frame = cv2.flip(frame,0)
  frame = cv2.cvtColor(frame,cv2.COLOR_BGR2RGB)
  img = Image.fromarray(frame)

  # img should be compatible with PIL Image
  (imw, imh) = img.size

  # which texture we are manipulating
  glBindTexture(GL_TEXTURE_2D,texName)

  # set up texture parameters
# glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP)
# glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP)
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_REPEAT)
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_REPEAT)
# glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_NEAREST)
# glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_NEAREST)
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)
  glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)

  # transfer image pixels to texture memory
  # target, level, internalFormat, img.w, img.h, border, format, type, pixels
  glTexImage2D(GL_TEXTURE_2D,
               0,
               GL_RGBA,
               imw,imh,
               0,
               GL_RGBA,
               GL_UNSIGNED_BYTE,
               img.convert("RGBA").tobytes())

  # GL_DECAL or GL_REPLACE will mask lighting, use GL_MODULATE instead
# glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)
  glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE)
# glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE)

def display():

  global out
  global output

  width = glutGet(GLUT_WINDOW_WIDTH)
  height = glutGet(GLUT_WINDOW_HEIGHT)

  glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

  glMatrixMode(GL_PROJECTION)
  glLoadIdentity()
  glOrtho(0, width, 0, height, -1.0, 1.0)

  glMatrixMode(GL_MODELVIEW)
  glLoadIdentity()

  # text color
  glColor4f(1.0, 1.0, 1.0, 1.0)

  # draw texture map (video frame)
  glEnable(GL_TEXTURE_2D)
  glBegin(GL_QUADS)

  glTexCoord2f(0.0, 0.0)
  glVertex3f(0.0, 0.0, 0.0)

  glTexCoord2f(1.0, 0.0)
  glVertex3f(width, 0.0, 0.0)

  glTexCoord2f(1.0, 1.0)
  glVertex3f(width, height, 0.0)

  glTexCoord2f(0.0, 1.0)
  glVertex3f(0.0, height, 0.0)
  glEnd()
  glDisable(GL_TEXTURE_2D)

  glFlush()
  glutSwapBuffers()

  # write out the frame, here we would need to screen grab
  if output:
    glReadBuffer(GL_FRONT)
    buf = glReadPixels(0,0,width,height,GL_RGBA,GL_UNSIGNED_BYTE)
    img = Image.frombytes(mode="RGBA",size=(width,height),data=buf)
#   img = img.transpose(Image.FLIP_TOP_BOTTOM)
    # convert OpenGL texture format to OpenCV cv2 frame
#   gray = cv2.cvtColor(np.asarray(img),cv2.COLOR_BGR2GRAY)
    frame = cv2.cvtColor(np.asarray(img),cv2.COLOR_RGB2BGR)
    frame = cv2.flip(frame,0)

    out.write(frame)

def main(argv):

  global cap
  global frame
  global size
  global texName
  global out
  global output

  cap = None
  texName = None
  output = False

  # get args
  try:
    opts, args = getopt.getopt(argv[1:], '', \
                 ['output'])
  except getopt.GetoptError, err:
    print "getopt error: ", err
    usage(argv)
    cleanup()

  # process args
  for opt,arg in opts:
    if opt == '--output':
      output = True
    else:
      sys.argv[1:]

  if output:
    print "Outputting to 'output.mov'"

  # gram video from available camera (e.g., laptop cam)
  cap = cv2.VideoCapture(0)

  size = (int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)), \
          int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)))

  fps = cap.get(cv2.CAP_PROP_FPS)

  # resize video by (.5,.5)
# size = (size[0]/4, size[1]/4)
# print "size, fps: ", size, fps
# cap.set(size[0],size[1])

 # for output
  if output:
    fourcc = cv2.VideoWriter_fourcc(*'mp4v') # MPEG not supported?
#   fps = 25.0
    out = cv2.VideoWriter('output.mov',fourcc,fps,size,True)

  # init glut
  glutInit(sys.argv)
  glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_ALPHA | GLUT_DEPTH)
  glutInitWindowPosition(500,500)
  window = glutCreateWindow('Python GL Video -- Esc to exit')
  glutSetWindow(window)
  #glutFullScreen()
  glutReshapeWindow(size[0],size[1])

  # set up callbacks
  glutReshapeFunc(reshape)
  glutDisplayFunc(display)
  glutIdleFunc(idle)
  glutKeyboardFunc(keyboard)
# glutMotionFunc(motion)
# glutMouseFunc(mouse)

  init()
  glutMainLoop()

def cleanup():

  # when everything is done, release the capture
  if cap is not None:
    cap.release()

  if output:
    out.release()

  #if using cv2 to play video
# cv2.destroyAllWindows()

  sys.exit()

def idle():

  global cap
  global frame
  global size
  global output
  global out

  if cap.isOpened():

    # capture frame-by-frame
    ret, frame = cap.read()

    if ret is True:

      frame = cv2.resize(frame, size, 0, 0, cv2.INTER_CUBIC)

      # our operations on the frame come here
      gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)

      # display the resulting frame
#     cv2.imshow('frame',gray)
#     if cv2.waitKey(1) & 0xFF == ord('q'):
#       break

      # DO SOMETHING, e.g., detect faces

      texbind(frame)

      glutPostRedisplay()

if __name__ == '__main__':
# main(sys.argv[1:])
  main(sys.argv)
