#! /usr/bin/env ppython
# -*- coding: utf-8 -*-

import sys
import os
import math

from pandac.PandaModules import loadPrcFile, loadPrcFileData
loadPrcFileData('','audio-library-name null')
loadPrcFileData('','win-size 1024 768')
#loadPrcFileData('','undecorated #t')
loadPrcFileData('','win-origin 100 100')

import direct.directbase.DirectStart
from direct.showbase import DirectObject
from direct.gui.OnscreenImage import OnscreenImage
from panda3d.core import MeshDrawer
from pandac.PandaModules import *



# Parameters...
eyeballCornerRot = 115.0



# Make the escape key work...
class EscExit(DirectObject.DirectObject):
  def __init__(self):
    self.accept('escape',self.exit)

  def exit(self):
    sys.exit()

escExit = EscExit()



# Move to the directory of the script...
scriptDir = os.path.abspath(os.path.dirname(sys.argv[0]))
os.chdir(scriptDir)



# Get a list of filenames in the directory with .epd extensions...
files = os.listdir('.')
files = filter(lambda f: f[-3:]=='epd',files)



# Iterate them and construct a dictionary of information for each...
class Empty:
  pass

frames = []
for fn in files:
  newFrame = Empty()
  exec(open(fn,'r')) in newFrame.__dict__
  frames.append(newFrame)



# Open the centre files, get the filename and find the relevant entry...
gtFN = open('centre.txt','r').readline().strip()
gtFrame = filter(lambda f:f.filename==gtFN,frames)[0]

# Define a function that provides a normalised coordinate system for each eyeball - x axis is the corner line, y axis is perpendicular, goes from -1 to 1 for the two corner points, assumes pixels are square...
def dot(a,b):
  return sum(map(lambda x,y: x*y,a,b))

def getCoord(frame):
  origin = (0.5*(frame.leftCorner[0]+frame.rightCorner[0]),0.5*(frame.leftCorner[1]+frame.rightCorner[1]))
  xAxis = (0.5*(frame.rightCorner[0]-frame.leftCorner[0]),0.5*(frame.rightCorner[1]-frame.leftCorner[1]))
  yAxis = (xAxis[1],-xAxis[0])
  
  return (dot(xAxis,frame.centre) - dot(xAxis,origin), dot(yAxis,frame.centre) - dot(yAxis,origin))


# Add an eyeball direction vector to each eyeballs info...
gtCoord = getCoord(gtFrame)
scale = 1.0/math.cos((eyeballCornerRot/180.0)*math.pi*0.5)

for frame in frames:
  coord = getCoord(frame)
  coord = (scale*(coord[0]-gtCoord[0]), scale*(coord[1]-gtCoord[1]))

  rot = math.atan2(coord[1],coord[0])
  defl = math.acos(1.0/math.sqrt(coord[0]**2+coord[1]**2+1.0))
  
  frame.n = (math.sin(defl)*math.cos(rot),math.sin(defl)*math.sin(rot),math.cos(defl))



# Setup the initial state...
curFrame = gtFrame
imageNode = OnscreenImage(curFrame.filename, scale=(16.0/9.0,1.0,1.0))



# Setup a task to get the position and update the view...
def posTask(task):
  if base.mouseWatcherNode.hasMouse():
    mpos = base.mouseWatcherNode.getMouse()
    rot = math.atan2(mpos.getY(),mpos.getX())
    defl = math.acos(1.0/math.sqrt(mpos.getX()**2+mpos.getY()**2+1.0))

    n = (math.sin(defl)*math.cos(rot),-math.sin(defl)*math.sin(rot),math.cos(defl))

    best = frames[0]
    for frame in frames[1:]:
      if dot(n,frame.n)>dot(n,best.n):
        best = frame

    global curFrame
    if curFrame.filename!=best.filename:
      #print curFrame.n, '->', best.n
      curFrame = best
      global imageNode
      imageNode.destroy()
      imageNode = OnscreenImage(curFrame.filename, scale=(16.0/9.0,1.0,1.0))

  return task.cont

taskMgr.add(posTask,'posTask')



# Run the application...
run()
