# -*- coding: utf-8 -*-
"""
UTc! module: src.session_constants

Purpose
=======
 Provides a centralised location for session-specific constants.
 
Legal
=====
 All code, unless otherwise indicated, is original, and subject to the
 terms of the GPLv3, which is provided in COPYING.
 
 (C) Neil Tallim, 2009
"""
import pygame

import constants
import rendering.shading as shading

FPS = None #: The FPS at which this client will attempt to run.
WIDTH = None #: The width, in pixels, of the client's viewport.
WIDTH_HALF = None #: Half of the width of the client's viewport.
HEIGHT = None #: The height, in pixels, of the client's viewport.
HEIGHT_HALF = None #: Half of the height of the client's viewport.
SCALE = None #: The value against which viewport-aspect-ratio-sensitive-items should be scaled.
HUD_SCALE = None #: The value against which viewport-size-sensitive-items should be scaled.

RESURRECTION_TIME = None #: The number of seconds that must pass before a player will be revived.
SHIELD_RESTORATION = None #: The amount of shielding a ship must recover before its shields are brought back online.

PLAYER_COLOURS = [] #: A list of all player colours, indexed from 0.
TEAM_COLOURS = [] #: A list of all team colours, indexed from 0.
RADAR_ICONS = [] #: A list of tuples of PyGame Surfaces that may be used to indicate members of each team on the HUD radar.
_GL_SHADERS = {} #: A dictionary of all compiled shader IDs.
GL_PROGRAMS = {} #: A dictionary of all named compiled shader programs.

def init(fps, width, height):
	"""
	Sets session-specific environment constants.
	
	@type fps: int
	@param fps: The framerate this this client should attempt to maintain.
	@type width: int
	@param width: The width of the client's viewport, in pixels.
	@type height: int
	@param height: The height of the client's viewport, in pixels.
	"""
	global FPS
	FPS = fps
	
	global WIDTH, WIDTH_HALF
	WIDTH = width
	WIDTH_HALF = int(width / 2)
	
	global HEIGHT, HEIGHT_HALF
	HEIGHT = height
	HEIGHT_HALF = int(height / 2)
	
	global SCALE
	SCALE = max(WIDTH_HALF, HEIGHT_HALF)
	
	global HUD_SCALE
	HUD_SCALE = max((float(constants.BASE_WIDTH) / width), (float(constants.BASE_HEIGHT) / height))
	
def initColours(player_colours, team_colours, render_mode):
	"""
	Cache all new player and team colours to streamline the material-lookup
	process in basic drawing modes, and to pre-build all shaders in
	advanced drawing modes.
	
	This function may be called multiple times, to allow new ships to join
	mid-game, but it must be invoked at least once before invoking any
	operations that rely on colour data.
	
	@type player_colours: sequence
	@param player_colours: A sequence containing sequence(3) elements that
	    describe the colour to apply to the player's ship. (Indexed from 0
	    or from the last count if this is not the first call)
	@type team_colours: sequence
	@param team_colours: A sequence containing sequence(3) elements that
	    describe the colour to apply to the team's ships. (Indexed from 0
	    or from the last count if this is not the first call)
	@type render_mode: int
	@param render_mode: Indicates the style of rendering that will be used.
	
	@raise ValueError: If compilation fails, suggesting that shaders aren't
	    supported.
	"""
	if render_mode in (shading.RENDER_MODE_CEL, shading.RENDER_MODE_GRADIENT, shading.RENDER_MODE_FLAT): #Compile shaders and programs.
		vertex_shader_body = _GL_SHADERS.get('vertex:body')
		if vertex_shader_body is None: #First use; build everything.
			_GL_SHADERS['vertex:body'] = vertex_shader_body = shading.compileShader(shading.VERTEX_PROGRAM_BODY, shading.GL_VERTEX_SHADER)
			_GL_SHADERS['vertex:gloss'] = vertex_shader_gloss = shading.compileShader(shading.VERTEX_PROGRAM_GLOSS, shading.GL_VERTEX_SHADER)
			_GL_SHADERS['vertex:rainbow'] = vertex_shader_rainbow = shading.compileShader(shading.VERTEX_PROGRAM_RAINBOW, shading.GL_VERTEX_SHADER)
			
			shader = shading.compileShader(shading.FRAGMENT_PROGRAM_RAINBOW, shading.GL_FRAGMENT_SHADER)
			GL_PROGRAMS['Engine'] = shading.compileProgram(vertex_shader_rainbow, shader)
			shading.deleteShader(shader)
			(r, g, b) = (0.5, 0.6, 0.7)
			shader = shading.compileShader(shading.FRAGMENT_PROGRAM_GLOSS % (r, g, b, r/2, g/2, b/2, r/4, g/4, b/4, 0.45, 0.45), shading.GL_FRAGMENT_SHADER)
			GL_PROGRAMS['Glass'] = shading.compileProgram(vertex_shader_gloss, shader)
			shading.deleteShader(shader)
			(r, g, b) = (0.75, 0.75, 0.75)
			shader = shading.compileShader(shading.FRAGMENT_PROGRAM_GLOSS % (r, g, b, r/2, g/2, b/2, r/4, g/4, b/4, 0.6, 0.6), shading.GL_FRAGMENT_SHADER)
			GL_PROGRAMS['Frame'] = shading.compileProgram(vertex_shader_gloss, shader)
			shading.deleteShader(shader)
			if render_mode == shading.RENDER_MODE_CEL:
				shader = shading.compileShader(shading.FRAGMENT_PROGRAM_CEL, shading.GL_FRAGMENT_SHADER)
			elif render_mode == shading.RENDER_MODE_GRADIENT:
				shader = shading.compileShader(shading.FRAGMENT_PROGRAM_GRADIENT, shading.GL_FRAGMENT_SHADER)
			elif render_mode == shading.RENDER_MODE_FLAT:
				shader = shading.compileShader(shading.FRAGMENT_PROGRAM_FLAT, shading.GL_FRAGMENT_SHADER)
			GL_PROGRAMS['default'] = GL_PROGRAMS['team'] = shading.compileProgram(vertex_shader_body, shader)
			shading.deleteShader(shader)
			
	#Because shader support may be unavailable, this happens after exceptions may occur.
	global PLAYER_COLOURS
	global TEAM_COLOURS
	PLAYER_COLOURS += player_colours
	TEAM_COLOURS += team_colours
	for (r, g, b) in team_colours:
		colour = (int(r * 255), int(g * 255), int(b * 255), 255)
		blank = (0, 0, 0, 0) 
		
		flat_icon = pygame.Surface((5, 5), flags=(pygame.constants.SRCALPHA | pygame.constants.SWSURFACE))
		flat_icon.fill(colour)
		
		up_icon = flat_icon.copy()
		up_icon.fill(blank, (1, 2, 3, 1))
		up_icon.fill(blank, (2, 1, 1, 1))
		
		down_icon = flat_icon.copy()
		down_icon.fill(blank, (1, 2, 3, 1))
		down_icon.fill(blank, (2, 3, 1, 1))
		
		RADAR_ICONS.append((flat_icon, up_icon, down_icon))
		
def initVariables(resurrection_time, shield_restoration):
	"""
	Sets session-specific gameplay constants.
	
	@type resurrection_time: float
	@param resurrection_time: The number of seconds that must pass before a
	    player will be revived.
	@type shield_restoration: float
	@param shield_restoration: The amount of shielding that must be recovered
	    before a player's shields will be brought back online.
	"""
	global RESURRECTION_TIME
	RESURRECTION_TIME = resurrection_time
	
	global SHIELD_RESTORATION
	SHIELD_RESTORATION = shield_restoration
	