import pygame
import constants
from constants import TEXGROUPWIDTH, TEXGROUPHEIGHT
from pygame.locals import *
import os, sys
from math import *

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

def circleCollide(a,b,distance=None):
    
    if not distance:
        distance = (a.width + b.width) / 2.0
    vect = (a.x + a.width / 2.0) - (b.x + b.width / 2.0), (a.y + a.height / 2.0) - (b.y + b.height / 2.0)
    diff = sqrt(vect[0]*vect[0] + vect[1]*vect[1])
    
    if diff < distance:
        return True
    else:
        return False
    
    
    

#####################################################################
# setColor
#
# Sets texture colour and caches the state.  Doesn't seem to help
# performance unfotrunately, but may play into later optimizations.
#
#####################################################################
curColor = None
def setColor(color):
    global curColor
    
    if color != curColor:
        glColor4fv(color)
        curColor = color

#global switchCount
#switchCount=0
#####################################################################
#
# curTexture
#
# Sets the opengl texture and caches the state.
#####################################################################
curTexture = None
def setTex(texture):
    global curTexture#, switchCount
    
    if curTexture != texture:
        glBindTexture(GL_TEXTURE_2D, texture)
        curTexture = texture
        #switchCount += 1


#####################################################################
# load_sound
#
# returns the pygame Sound object for the given file name
#####################################################################
def load_sound(name):
    class NoneSound:
        def play(self): pass
    if not pygame.mixer or not pygame.mixer.get_init():
        return NoneSound()
    fullname = os.path.join('data', name)
    try:
        sound = pygame.mixer.Sound(fullname)
    except pygame.error, message:
        print 'Cannot load sound:', fullname
        raise SystemExit, message
    return sound

#####################################################################
# loadTexture
#
# loads a texture into OpenGL and returns the texture id thingy
#####################################################################
def loadTexture(image, colorkey=None):
    
    textureSurface = pygame.image.load(image)
    if colorkey:
        if colorkey == -1:
            colorkey = textureSurface.get_at((0,0))
        textureSurface.set_colorkey(colorkey, RLEACCEL)
    textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
    texture = glGenTextures(1)
    setTex(texture)
    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_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
    return texture


#####################################################################
# loadTextureG
#
# loads a texture onto the group texture
#####################################################################
groupTexCount = {'total':0, 16:0, 32:0}
texCoords = []
spriteList = []
def loadTextureG(image, colorkey=None):
    global texCoords, groupTexCount, texGroup, spriteList
    
    textureSurface = pygame.image.load(image)
    if colorkey:
        if colorkey == -1:
            colorkey = textureSurface.get_at((0,0))
        textureSurface.set_colorkey(colorkey, RLEACCEL)
    textureData = pygame.image.tostring(textureSurface, "RGBA", 1)
    
    width = textureSurface.get_width()
    height = textureSurface.get_height()
    
    if width != height:
        print "Non square textures probably can't be grouped, but I'll try anyway."
        
    size = width
    if size != 16 and size != 32:
        print "textures that aren't 16*16 or 32*32 probably won't work grouped."
    
    offset = 0
    if size == 32:
        offset = TEXGROUPHEIGHT / 2

    setTex(texGroup)
    
    x, y= getGroupPosition(groupTexCount[size],size)
    
    y = y + offset

    glTexSubImage2D( GL_TEXTURE_2D, 0, x, y, size, size, GL_RGBA, GL_UNSIGNED_BYTE, textureData )

    # calculate and cache texture coords, with a fudge factor to prevent ghosting around the edges
    # of the textures.
    fudge = 0.001
    
    xTex = x / (TEXGROUPWIDTH * 1.0) + fudge
    yTex = y / (TEXGROUPWIDTH * 1.0) + fudge
    sizeTex = size / (TEXGROUPWIDTH * 1.0) - fudge * 2
    texCoords.append((xTex,yTex,xTex+sizeTex,yTex+sizeTex))

    groupTexCount[size] += 1
    groupTexCount['total'] += 1

    (x,y,dx,dy) = (xTex,yTex,xTex+sizeTex,yTex+sizeTex)
    newList = glGenLists(1)
    spriteList.append(newList)
    glNewList(newList,GL_COMPILE);
    glBegin(GL_QUADS)
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(x, y); glVertex2f(0, constants.TEXSIZE)    # Bottom Left Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(dx, y); glVertex2f( constants.TEXSIZE, constants.TEXSIZE)    # Bottom Right Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(dx, dy); glVertex2f( constants.TEXSIZE,  0)    # Top Right Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(x, dy); glVertex2f(0, 0)    # Top Left Of The Texture and Quad
    glEnd()
    glEndList()

    return (newList)


######################################################################
# getGroupPostion
#
# returns the position for the next texture, only works for square
# textures.
######################################################################
def getGroupPosition(number, size):
    x = number * size % TEXGROUPWIDTH
    y = number * size / TEXGROUPWIDTH * size
    
    return x,y

   
######################################################################
# drawTileG
# 
# display a simple tile from the tex group
######################################################################
def drawTileG(width=constants.TEXSIZE, height=constants.TEXSIZE, texture=None):
    global texCoords, texGroup

    setTex(texGroup)

    if(width != constants.TEXSIZE or height != constants.TEXSIZE):
        glScalef(width/constants.TEXSIZE, height/constants.TEXSIZE, 1.0)
        glCallList(texture)
        glLoadIdentity()
    else:
        glCallList(texture)


######################################################################
# drawTile
# 
# display a simple tile
######################################################################
def drawTile(width=constants.TEXSIZE, height=constants.TEXSIZE, texture=None):
    global curTexture

    setTex(texture)
    glBegin(GL_QUADS)
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(0.0, 0.0); glVertex2f(0, height)    # Bottom Left Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(1.0, 0.0); glVertex2f( width, height)    # Bottom Right Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(1.0, 1.0); glVertex2f( width,  0)    # Top Right Of The Texture and Quad
    glColor4f(1.0,1.0,1.0,1.0)
    glTexCoord2f(0.0, 1.0); glVertex2f(0, 0)    # Top Left Of The Texture and Quad
    glEnd()


######################################################################
######################################################################
def shadeTile(x, y, color, width=constants.TEXSIZE, height=constants.TEXSIZE):
    x *= constants.TEXSIZE
    y *= constants.TEXSIZE
    glLoadIdentity()
    setColor(color)
    glBegin(GL_QUADS)
    glVertex2f(x, y + height)    # Bottom Left Of The Texture and Quad
    glVertex2f( x + width, y + height)    # Bottom Right Of The Texture and Quad
    glVertex2f( x + width, y)    # Top Right Of The Texture and Quad
    glVertex2f(x, y)    # Top Left Of The Texture and Quad
    glEnd()


############################################################################
######################################################################
def initializeDisplay(w, h):
    pygame.display.set_mode((w,h), OPENGL|DOUBLEBUF)
    # glShadeModel(GL_SMOOTH)
    glClearColor(0.0, 0.0, 0.0, 1.0)
    glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT)

    # switch to projection mode
    glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    # set a 2D orthographic projection
    gluOrtho2D(0, w, 0, h);
    glScalef(1, -1, 1);
    # move the origin from the bottom left corner
    # to the upper left corner
    glTranslatef(0, -h, 0);

    glMatrixMode(GL_MODELVIEW);
    
    #set up texturing
    glEnable(GL_TEXTURE_2D)
    glEnable (GL_BLEND);
    glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
           
    # try to eek out a bit more performance
    glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST)
    
    # create an empty texture for a texture group
    global texGroup
    texGroup = glGenTextures(1)
    setTex(texGroup)
    emptyList = "\x00\x00\x00\x00" * TEXGROUPWIDTH * TEXGROUPHEIGHT #* 4
    glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, TEXGROUPWIDTH, TEXGROUPHEIGHT, 0, GL_RGBA, GL_UNSIGNED_BYTE, emptyList )
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)

    # Enable vertex arrays
    """glEnableClientState(GL_VERTEX_ARRAY)
    glEnableClientState(GL_TEXTURE_COORD_ARRAY)        
    glEnableClientState(GL_COLOR_ARRAY)"""


######################################################################
#################################################################################
def loadText(text, size = 12, fore_RGBA = (0,0,0), back_RGBA = None, font = None, antialias = 1):
    global curTexture

    font = pygame.font.Font(None, size)
    if back_RGBA:
        image = font.render(text, antialias, fore_RGBA, back_RGBA)
    else:
        image = font.render(text, antialias, fore_RGBA)
    height = image.get_height()
    width = image.get_width()
    h = 16
    while(h < height):
        h = h*2
    w = 16
    while(w < width):
        w = w*2
    if( w > constants.max_tex_size):
        print "font width is too big on message",text
        sys.exit()
    if( h > constants.max_tex_size):
        print "font height is too big on message",text
        sys.exit()
        
    image = pygame.transform.scale(image, (w,h))
    label_texture= glGenTextures(1)
    setTex(label_texture)
    textureData = pygame.image.tostring(image, "RGBA", 1)
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR )
    glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR )
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image.get_width(), image.get_height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData)
    glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,GL_MODULATE) # Don't think this makes any difference.
    return [label_texture, image.get_width(), image.get_height()]