import pygame
from pygame.locals import *
from Maths import *
from Classes import *
from math import *
import sys, os, random
if sys.platform == 'win32' or sys.platform == 'win64':
    os.environ['SDL_VIDEO_CENTERED'] = '1'
pygame.init()

Screen = (800,600)

pygame.display.set_caption("Sphere Simulation - v.1.0.0 - Ian Mallett - 2011")
icon = pygame.Surface((1,1)); icon.set_alpha(0); pygame.display.set_icon(icon)
Surface = pygame.display.set_mode(Screen)

RayOrigin = [-600,Screen[1]/2]
RayDir = [1,0]
MaxRayLen = 1500

Objects = [
    Circle([400,300],200,Material("Glass"))#,
    #Line([600,0],[600,Screen[1]])
]

SpaceRefract = 1.0
CircleRefract = 1.5

def GetInput():
    global CircleRefract
    key = pygame.key.get_pressed()
    mpos = pygame.mouse.get_pos()
    for event in pygame.event.get():
        if event.type == QUIT or key[K_ESCAPE]:
            pygame.quit(); sys.exit()
    if key[K_UP]:
        CircleRefract += 0.01
        print CircleRefract
        Trace()
    elif key[K_DOWN]:
        CircleRefract -= 0.01
        print CircleRefract
        Trace()
totally_reflected = False
def CastRay(CastingRay,nl,nr):
    global totally_reflected
    ObjectNumber = 0
    Collisions = []
    for o in Objects:
        Dist = o.Collide(CastingRay)
        if Dist != False and Dist > 0.0:
            if o.type=="line": hitline = True
            Collisions.append([Dist,ObjectNumber])
        ObjectNumber += 1
    if Collisions == []:
        return None, None
    else:
        #Find the closest collision point, and get the object the ray hit.
        ObjectCollision = min(Collisions)
        obj = Objects[ObjectCollision[1]]
        CollisionPoint = DistToPoint(CastingRay,ObjectCollision[0])
        n = obj.GetNormal(CollisionPoint)
        #Form the refraction ray.
        N = n
        L = VectorNegate(CastingRay.dir)
        nl_over_nr = nl / nr
        if nl_over_nr == CircleRefract/SpaceRefract:
            N = VectorNegate(N)
        ndotl = DotProduct(N,L)
        bracketquan = 1-(ndotl**2)
        undersqrt = 1 - ((nl_over_nr**2)*bracketquan)
        if undersqrt < 0: return None, None 
        radical = sqrt(undersqrt)
        pquan = ((nl_over_nr*ndotl) - radical)
        t = VectorSubtract(ScalarVector(pquan,N),ScalarVector(nl_over_nr,L))

        totally_reflected = False
        if DotProduct(Normalize(L),Normalize(N))>0.0 and nl_over_nr == CircleRefract/SpaceRefract:
            totally_reflected = True
        
        return CollisionPoint,t
def Trace():
    global hitline
    Surface.fill((255,255,255))
    for y in xrange(0,Screen[1],8):
        Angle = atan2((Screen[1]-y)-RayOrigin[1],800-RayOrigin[0])
        RayDir = [cos(Angle),sin(Angle)]
        
        p1 = RayOrigin
        dir = RayDir
        
        nl = float(SpaceRefract)
        nr = float(CircleRefract)

        hitline = False

        while True:
            CastingRay = Ray(VectorAdd(p1,ScalarVector(0.0001,dir)),dir)
            p2,dir = CastRay(CastingRay,nl,nr)
            
            if p2 == None:
                
                p2 = (RayOrigin[0]+(CastingRay.dir[0]*MaxRayLen),
                      RayOrigin[1]+(CastingRay.dir[1]*MaxRayLen))
                if p2[0]<p1[0]:
                    break
                pygame.draw.aaline(Surface,(255,0,0),[p1[0],Screen[1]-p1[1]],[p2[0],Screen[1]-p2[1]])
                break
            
            nl,nr = nr,nl
            pygame.draw.aaline(Surface,(255,0,0),[p1[0],Screen[1]-p1[1]],[p2[0],Screen[1]-p2[1]])
            p1 = p2
            

            #if totally_reflected: break

##        CastingRay = Ray(VectorAdd(p1,ScalarVector(0.0001,dir)),dir)
##        p2,dir = CastRay(CastingRay,nl,nr)
##        
##        if p2 == None:
##            p2 = (RayOrigin[0]+(CastingRay.dir[0]*MaxRayLen),
##                  RayOrigin[1]+(CastingRay.dir[1]*MaxRayLen))
##            pygame.draw.aaline(Surface,(255,0,0),[p1[0],Screen[1]-p1[1]],[p2[0],Screen[1]-p2[1]])
##        else:
##            nl,nr = nr,nl
##            pygame.draw.aaline(Surface,(255,0,0),[p1[0],Screen[1]-p1[1]],[p2[0],Screen[1]-p2[1]])
##            p1 = p2
##
##            CastingRay = Ray(VectorAdd(p1,ScalarVector(0.0001,dir)),dir)
##            p2,dir = CastRay(CastingRay,nl,nr)
##
##            p2 = (RayOrigin[0]+(CastingRay.dir[0]*MaxRayLen),
##                  RayOrigin[1]+(CastingRay.dir[1]*MaxRayLen))
##            pygame.draw.aaline(Surface,(255,0,0),[p1[0],Screen[1]-p1[1]],[p2[0],Screen[1]-p2[1]])

    pygame.draw.rect(Surface,(255,255,255),[600,0,Screen[0]-600,Screen[1]],0)
    pygame.draw.rect(Surface,(0,0,0),[600,0,1,Screen[1]],0)
    for o in Objects:
        o.Draw(Surface,Screen)
    #pygame.draw.line(Surface,(0,0,0),[600,0],[600,Screen[1]])
def Draw():
    pygame.display.flip()
def main():
    Trace()
    while True:
        GetInput()
        Draw()
if __name__ == '__main__': main()
















