/fx.py
import pygame
import math
import os, os.path

ALIGN_LEFT = 0
ALIGN_RIGHT = 1

# FX is the abstract base class for all "effects" objects. They have two
# defining features:
#
# 1) The FX base class sets up self.screen so that you can draw to the
#    screen. It is then important to call FX.__init__(self) in your
#    __init__ routine.
# 2) Each FX object has a draw(self,t) method that draws itself to the
#    screen (possibly with appearance based on the current time).

class FX:
	def __init__(self):
		self.screen = pygame.display.get_surface()

	def draw(self,t):
		pass

class Blank(FX):
	def draw(self,t):
		self.screen.fill((0,0,0))

class Image(FX):
	align = ALIGN_LEFT

	def __init__(self,file,location=(0,0)):
		FX.__init__(self)
		self.surface = pygame.image.load(file).convert_alpha()
		self.location = location

	def draw(self,t):
		if self.align == ALIGN_RIGHT:
			rl = (self.location[0] - self.surface.get_width(),self.location[1])
			self.screen.blit(self.surface,rl)
		else:
			self.screen.blit(self.surface,self.location)

class Text(Image):
	def __init__(self,text,font,size,location=(0,0),color=(255,255,255)):
		FX.__init__(self)
		self.font = pygame.font.Font(font,size)
		self.location = location
		self.color = color
		self.settext(text)

	def settext(self,text):
		f = self.font.render(text,True,(0,0,0))
		self.surface = pygame.surface.Surface((f.get_width()+2,f.get_height()+2)).convert_alpha()
		self.surface.fill((0,0,0,0))
		self.surface.blit(f,(2,2))
		f = self.font.render(text,True,self.color)
		self.surface.blit(f,(0,0))

textglyphs = {}

class GlyphText(FX):
	def __init__(self,location=(0,0),glyphdir='gfx/glyph'):
		FX.__init__(self)
		if not textglyphs:
			l = os.listdir(glyphdir)
			for g in l:
				c = g.split('.')[0]
				textglyphs[c] = pygame.image.load(os.path.join(glyphdir,g)).convert_alpha()
		self.location = location
		self.text = ''

	def settext(self,str):
		self.text = str

	def draw(self,t):
		(x,y) = self.location
		for c in self.text:
			if textglyphs.has_key(c):
				self.screen.blit(textglyphs[c],(x,y))
				x += textglyphs[c].get_width()

class PulseLine(FX):
	r = -0.02

	def __init__(self, pointlist, color, period, maxwidth = 8, minwidth = 1):
		FX.__init__(self)
		self.period = period
		self.color = color
		if maxwidth:
			self.maxwidth = maxwidth
		if minwidth:
			self.minwidth = minwidth
		self.pointlist = pointlist
		self.location = (0,0)

	def draw(self,t):
		w = (self.maxwidth - 1) * math.exp(self.r * (t % self.period)) + self.minwidth
		pl = map(lambda x: (x[0] + self.location[0],x[1] + self.location[1]),self.pointlist)
		pygame.draw.lines(self.screen,self.color, 0, pl, int(w))

class ColumnPulse(FX):
	r = -0.03

	def __init__(self,rect,color):
		FX.__init__(self)
		self.rect = rect
		self.color = color
		self.st = 0
		self.surf = []
		t = 0
		a = 1.0
		while a > 0.01:
			s = pygame.Surface(self.rect.size).convert_alpha()
			s.lock()
			s.fill( (0,0,0,0) )
			for n in range(0,self.rect.height):
				c = (self.color[0],self.color[1],self.color[2],float(n) / self.rect.height * a * 255.0)
				w = (self.rect.width / 2) * (1.0 - a)
				pygame.draw.line(s,c,(w,n),(self.rect.width-w,n))
				#s.fill(c,(0,n,self.rect.width,1))
			s.unlock()
			self.surf.append(s)
			t += 16
			a = math.exp(self.r * t)

		self.hit = 0

	def down(self):
		self.hit = 1

	def up(self):
		self.st = pygame.time.get_ticks()
		self.hit = 0

	def draw(self):
		dt = pygame.time.get_ticks() - self.st
		if self.hit:
			self.screen.blit(self.surf[0],self.rect)
		else:
			n = dt / 16
			if n > len(self.surf) - 1:
				return
			self.screen.blit(self.surf[n],self.rect)

class PlaneScroll(FX):
	surface = None

	def __init__(self,file,direction,zoom=1.0,alpha=1.0):
		FX.__init__(self)
		ts = pygame.image.load(file)
		if zoom != 1.0:
			ts = pygame.transform.rotozoom(ts, 0.0, zoom)
		self.surface = ts.convert()
		del ts
		if alpha < 1.0 and alpha >= 0.0:
			self.surface.set_alpha(int(alpha * 255))
		self.direction = direction

	def draw(self,t):
		w = self.surface.get_width()
		h = self.surface.get_height()
		location = self.surface.get_rect()
		location.size = (640,480)
		location.move_ip((t * self.direction[0]) % w, (t * self.direction[1]) % h)
		self.screen.blit(self.surface,(0,0),location)
		if location.right > w:
			x = 640 - (location.right - w)
			self.screen.blit(self.surface,(x,0),(0,location.top,640,480))
		if location.bottom > h:
			y = 480 - (location.bottom - h)
			self.screen.blit(self.surface,(0,y),(location.left,0,640,480))
		if location.bottom > h and location.right > w:
			# x and y must be calculated from above two tests
			self.screen.blit(self.surface,(x,y),(0,0,640,480))