#!BPY
""" Registration info Blender menues:
Name:'Sflender'
Blender: 236
Group: 'Export'
Tooltip: 'S2flender(V2.6 BETA) Exporter to Macromedia(R) Flash(TM)'
"""
# -------------------------------------------------------------
#	 Copyright (c) 2003,2004,2005 Emilio Aguirre 
#
#    This program is free software; you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation; either version 2 of the License, or
#    (at your option) any later version.
#
#    This program is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with this program; if not, write to the Free Software
#    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#
# -------------------------------------------------------------
# -------------------------------------------------------------
# *This program is based on the Macromedia Flash SWF File Format Specification (version 3)
# by Macromedia, Inc. Copyright(c) 1995-2003 Macromedia, Inc. All rights reserved. 
# Macromedia and Flash are trademarks of Macromedia, Inc. (www.macromedia.com)
# -------------------------------------------------------------

# ---------------------------------------------------------------
# 	
#	Import Section			
#
# ---------------------------------------------------------------	
import Blender
from os import listdir
from Blender import Object,Lamp,Camera,NMesh,Types,sys
from Blender.Mathutils import *
from Blender.Draw import *
from Blender.Types import *
from Blender.BGL import *
from Blender.Noise import *
from math import *
from operator import add,sub,mul
from time import *
from zlib import *

# -------------------------------------------------------------
# Generic Functions
# -------------------------------------------------------------

INFINITY = 1e300000
NAN = INFINITY-INFINITY
sINF = str(INFINITY)
sNAN = str(NAN)
			
def getMid(p,q):
	return [(p[0]+q[0])/2,(p[1]+q[1])/2]
	
def dist(p,q):
	w = [q[0]-p[0], q[1]-p[1]]
	return sqrt((w[0]*w[0])+(w[1]*w[1]))

def bez3(p1,p2,p3,t):
	p = [0,0]
	t2 = t*t
	ct = 1 - t
	ct2 = ct*ct
	ct3 = 2 * ct * t
	p[0] = p1[0]*ct2 + ct3 *p2[0] + p3[0]*t2
	p[1] = p1[1]*ct2 + ct3 *p2[1] + p3[1]*t2
	return p

def Rot(x,y,theta):
	angle = theta*pi/180
	x1 = x*cos(angle) - y*sin(angle)
	y1 = x*sin(angle) - y*cos(angle)
	return [x1,y1]
	
def MaxAbs(l):
	if len(l)>0:
		m = abs(l[0])
		for i in l:
			if abs(i)>m:	m = abs(i)
		return m
	else:	return 0

def BitSgn(val):
	if val>0: return 0
	else:	return 128

def Pad0(n):
	return [0]*n

def Pad1(n):
	return [1]*n

def Padding(s):
	if s<8:	return Pad0(8-s)
	d = s % 8
	if d == 0:
		return []
	else:
		n = 8 - d
		return Pad0(n)

def SetFileLength(movie,a):
	r =	UI32(a)
	movie[4] = r[0]
	movie[5] = r[1]
	movie[6] = r[2]
	movie[7] = r[3]
	return
	
def GetChars(list):
	k = 0
	l = 0
	size = len(list)
	numbytes = size/8
	if ((size % 8) >0):	numbytes+=1
	bytes = Pad0(numbytes)
	byte = 0	
	for i in range(size):
		byte += list[i] * (2**(7-k)) 
		k+=1
		if k>7:
			bytes[l]=chr(byte)
			byte = 0
			k = 0
			l+=1
	if k>0 and k<8:	bytes[l] = chr(byte)
	return bytes

def PadChars(l):
	l.extend(Padding(len(l)))
   	return GetChars(l)

def GetBinary(number,digits=0):
	if digits == 0:
		maxbits = 1024
	else:
		maxbits = digits
	Bits = Pad0(maxbits)	
	idx = maxbits-1
	while (((number/2)!=0) and (idx>=0)):
		# Get modulus
		Bits[idx] = number % 2 
		number/=2
		idx-=1
	if (number==1):	Bits[idx]=1
	else:	Bits[idx]=0
	if digits >0:	return Bits
	else:	return Bits[idx:]

def NBits(val):	return len(val)

def InverseBits(l):
	return map(lambda x:abs(x-1),l)

def TwosComplement(val):
	b = InverseBits(GetBinary(val))
	d = GetBinary(1,len(b))
	r = []
	c = 0
	l = range(len(b))
	l.reverse()
	for i in l:
		s = b[i]+d[i]+c
		if s == 2:	
			r.append(0)
			c = 1
		else:
			r.append(s)
			c = 0
	r.reverse()
	return r

# -------------------------------------------------------------
# SWF Constants
# -------------------------------------------------------------
SOLID_FILL = 0
LINEAR_GRADIENT_FILL = 16
RADIAL_GRADIENT_FILL = 18
TILED_BITMAP_FILL = 64
CLIPPED_BITMAP_FILL = 65

#Place Object Flags
PO_NAME = 32
PO_RATIO = 16
PO_COLOR_TRANS = 8
PO_MATRIX = 4
PO_CHAR_ID = 2
PO_MOVE = 1
#Shape Object Flags
SH_MOVE = 1
SH_FILL0 = 2
SH_FILL1 = 4
SH_LINESTYLE = 8
SH_NEWSTYLES = 16
#Button state flags
BT_HIT = 8
BT_DOWN = 4
BT_OVER = 2
BT_UP = 1
#Buttons State transitions triggering actions
BT_IDLE_TO_OVERUP = 1
BT_OVERUP_TO_IDLE = 2
BT_OVERUP_TO_OVERDOWN = 4
BT_OVERDOWN_TO_OVERUP = 8
BT_OVERDOWN_TO_OUTDOWN = 16
BT_OUTDOWN_TO_OVERDOWN = 32
BT_OUTDOWN_TO_IDLE = 64
BT_IDLE_TO_OVERDOWN = 128
BT_OVERDOWN_TO_IDLE = 256
#Font Flags
FONT_HASLAYOUT = 128 
FONT_SHIFTJIS = 64
FONT_UNICODE = 32	
FONT_ANSI = 16		
FONT_WIDEOFFSETS = 8
FONT_WIDECODES = 4
FONT_ITALIC = 2
FONT_BOLD = 1
#Text Flags
TEXT_HASFONT = 8
TEXT_HASCOLOR = 4
TEXT_HASYOFFSET = 2
TEXT_HASXOFFSET = 1

# -------------------------------------------------------------
# Basic Data Types
# -------------------------------------------------------------

def UI8(val):
	return chr(val)

def UI16(val):
	"""Return in little-endian"""
	return chr((val&0x00ff)),chr(val>>8)

def UI32(val):
	"""Return in little-endian"""
	hi = UI16(val&0x0000ffff)
	lo = UI16(val>>16)
	return hi[0],hi[1],lo[0],lo[1]

def REVUI32(v):
	h2 = ord(v[0])
	h1 = ord(v[1])
	l2 = ord(v[2])
	l1 = ord(v[3])	
	return (((l1*256) + l2)*65536)+((h1*256) + h2)

def UB(val,size=0):
	v = GetBinary(val)
	z = size - len(v)
	if z>0:
		r = Pad0(z)
		r.extend(v)
		return r
	else:
		return v  

def SB(val,size=0):
	if val>=0:
		r=[0]
		r.extend(GetBinary(abs(val)))
	else:	
		r=[1]
		r.extend(TwosComplement(abs(val)))
	z = size - len(r)
	if z>0:
		if (val<0):	v = Pad1(z)
		else:	v = Pad0(z)
		v.extend(r)
		return v
	else:
		return r

def SI16(val):
	r = GetChars(SB(val,16))
	return r[1],r[0]

def SI32(val):
	r = GetChars(SB(val,32))
	return r[3],r[2],r[1],r[0]
	
def FB(val,size=0):
	midpos = 512
	maxbits= 1024
	if val>=0:	r=[0]
	else:	r=[1] 
	
	#Create bit list
	Bits = Pad0(maxbits)
	num = abs(val)

	#Get integer part
	intnum = abs(int(num))

	#Get decimal part
	decnum = num - intnum

	# Get binary representation of integer part
	idxI = midpos
	while (((intnum/2)!=0) and (idxI>=0)):
		# Get modulus
		Bits[idxI] = intnum % 2 
		intnum/=2
		idxI-=1
	if (intnum==1):	Bits[idxI]=1
	else:	Bits[idxI]=0

	# Get binary representation of decimal part
	idxD = midpos+1
	while (decnum>0.0 and idxD<maxbits):
		decnum*=2
		if (decnum>=1):
			Bits[idxD] = 1
			decnum-=1.0
		else:
			Bits[idxD] = 0
		idxD+=1

	i = idxI
	while (i<=midpos):
		r.extend([Bits[i]])
		i+=1
	i = 1
	while (i<=16):
		r.extend([Bits[i+midpos]])
		i+=1
	
	z = size - len(r)
	if z>0:
		if (val<0):	v = Pad1(z)
		else:	v = Pad0(z)
		v.extend(r)
		return v
	else:
		return r

def IEEE_FIXED(val):
	"""This returns a memory representation of a float point
	   according to the IEEE 32 bits flotating point representation.
		+- 1.x * 2^e
		where x is the matissa field
		and e is the bias exponent (bias = 127)
	
	Memory out put: Bit 3	3222222	222211111111110000000000
						1	0987654	321098765432109876543210
						Sign  Bias		Matissa
							  exponent					"""
	midpos = 512
	maxbits= 1024

	#Create bit list
	Bits = Pad0(maxbits)
	num = abs(val)

	#Get integer part
	intnum = int(num)

	#Get decimal part
	decnum = num - intnum

	# Get binary representation of integer part
	idxI = midpos
	while (((intnum/2)!=0) and (idxI>=0)):
		# Get modulus
		Bits[idxI] = intnum % 2 
		intnum/=2
		idxI-=1
	if (intnum==1):	Bits[idxI]=1
	else:	Bits[idxI]=0

	# Get binary representation of decimal part
	idxD = midpos+1
	while (decnum>0.0 and idxD<maxbits):
		decnum*=2
		if (decnum>=1):
			Bits[idxD] = 1
			decnum-=1.0
		else:
			Bits[idxD] = 0
		idxD+=1

	#Get exponent
	idx = 0
	while ((idx<maxbits) and (Bits[idx]!=1)):	idx+=1
	exponent = midpos - idx
	if exponent<-126:
		#infinite number
		exponent = -127
	bytes = [0,0,0,0]
	biasExponent = exponent + 127
	bytes[0] = BitSgn(val)+ (biasExponent >> 1)
	j = (midpos+1+(-1*exponent))
	k = 1
	l = 1
	byte = 0	
	for i in range(j,j+23):
		byte += Bits[i] * (2**(7-k)) 
		k+=1
		if k>7:
			bytes[l]=byte
			byte = 0
			k = 0
			l+=1
	bytes[1] += ((biasExponent << 7) & 128)
	# Return value in little-endian
	return [chr(bytes[3]),chr(bytes[2]),chr(bytes[1]),chr(bytes[0])]	 

def FIXED(val):
	midpos = 512
	maxbits= 1024
	if val>=0:	r=[0]
	else:	r=[1] 
	
	#Create bit list
	Bits = Pad0(maxbits)
	num = abs(val)

	#Get integer part
	intnum = abs(int(num))

	#Get decimal part
	decnum = num - intnum

	# Get binary representation of integer part
	idxI = midpos
	while (((intnum/2)!=0) and (idxI>=0)):
		# Get modulus
		Bits[idxI] = intnum % 2 
		intnum/=2
		idxI-=1
	if (intnum==1):	Bits[idxI]=1
	else:	Bits[idxI]=0

	# Get binary representation of decimal part
	idxD = midpos+1
	while (decnum>0.0 and idxD<maxbits):
		decnum*=2
		if (decnum>=1):
			Bits[idxD] = 1
			decnum-=1.0
		else:
			Bits[idxD] = 0
		idxD+=1
	for i in range(31):
		r.extend([Bits[midpos-14+i]])
	return r[24:]+r[16:24]+r[8:16]+r[0:8]

def RECT(x0,y0,x1,y1):
	#Convert values from pixels to TWIPS
	xmin =x0*20
	xmax =x1*20
	ymin =y0*20
	ymax =y1*20
	#Number of bits per value
	nbits = NBits(SB(MaxAbs([xmin,xmax,ymin,ymax])))
	#Create struct RECT
	r = []
	r = UB(nbits,5)
	r.extend(SB(xmin,nbits))
	r.extend(SB(xmax,nbits))
	r.extend(SB(ymin,nbits))
	r.extend(SB(ymax,nbits))
	return r

def MATRIX(sx,sy,rot0,rot1,tx,ty):
	r = []
	hasscale = 0
	hasrotate = 0
	if (sx!=1.0 or sy!=1.0):	hasscale = 1
	if (rot0!=0.0 or rot1!=0.0):	hasrotate = 1
	r = [hasscale]
	if (hasscale==1):
		nScaleBits =NBits(FB(MaxAbs([sx,sy])))
		r.extend(UB(nScaleBits,5))
		r.extend(FB(sx,nScaleBits))
		r.extend(FB(sy,nScaleBits))
	r.extend([hasrotate])
	if (hasrotate==1):
		nRotateBits = NBits(FB(MaxAbs([rot0,rot1])))
		r.extend(UB(nRotateBits,5))
		r.extend(FB(rot0,nRotateBits))
		r.extend(FB(rot1,nRotateBits))
	nTranslateBits = NBits(SB(MaxAbs([tx,ty])))
	r.extend(UB(nTranslateBits,5))
	r.extend(SB(tx,nTranslateBits))
	r.extend(SB(ty,nTranslateBits))
	return r

def RGB(r,g,b):
	return [chr(r),chr(g),chr(b)]

def RGBn(r,g,b):
	return [chr(r*255),chr(g*255),chr(b*255)]	

def RGBA(r,g,b,a):
	return [chr(r),chr(g),chr(b),chr(a)]

def RGBAn(r,g,b,a):
	return [chr(r*255),chr(g*255),chr(b*255),chr(a*255)]
	
def CXFORM(rmul,gmul,bmul,radd,gadd,badd):
	hasmult = 0
	hasadd = 0
	if (rmul!=0 or gmul!=0 or bmul!=0):	hasmult = 1
	if (radd!=0 or gadd!=0 or badd!=0):	hasadd = 1
	r = [hasadd,hasmult]
	nbits =  NBits(SB(MaxAbs([rmul,gmul,bmul,radd,gadd,badd])))
	r.extend(UB(nbits,4))
	if (hasmult>0):
		r.extend(SB(rmul,nbits))
		r.extend(SB(gmul,nbits))
		r.extend(SB(bmul,nbits))
	if (hasadd>0):
		r.extend(SB(radd,nbits))
		r.extend(SB(gadd,nbits))
		r.extend(SB(badd,nbits))
	return r 

def CXFORMWITHALPHA(rmul,gmul,bmul,amul,radd,gadd,badd,aadd):
	hasmult = 0
	hasadd = 0
	if (rmul!=0 or gmul!=0 or bmul!=0 or amul!=0):	hasmult = 1
	if (radd!=0 or gadd!=0 or badd!=0 or aadd!=0):	hasadd = 1
	r = [hasadd,hasmult]
	nbits = NBits(SB(MaxAbs([rmul,gmul,bmul,amul,radd,gadd,badd,aadd])))
	r.extend(UB(nbits,4))
	if (hasmult>0):
		r.extend(SB(rmul,nbits))
		r.extend(SB(gmul,nbits))
		r.extend(SB(bmul,nbits))
		r.extend(SB(amul,nbits))
	if (hasadd>0):
		r.extend(SB(radd,nbits))
		r.extend(SB(gadd,nbits))
		r.extend(SB(badd,nbits))
		r.extend(SB(aadd,nbits))
	return r

def STRING(s):
	r = []
	for i in range(len(s)):	r.append(s[i])
	r.append(chr(0))
	return r

# -------------------------------------------------------------
# Core Data Types
# -------------------------------------------------------------
def GRADRECORD(ratio,color):
	r = [chr(ratio)]
	if (len(color)>3):
		r.extend(RGBA(color[0],color[1],color[2],color[3]))
	else:
		r.extend(RGB(color[0],color[1],color[2]))
	return r

def GRADIENT(NumGradients,records):
	r = [chr(NumGradients)]
	for i in records:
		r.extend(i)
	return r	
	
def FILLSTYLE(type,param1=None,param2=None):
	r = [chr(type)]
	if type == SOLID_FILL:
		if len(param1)>3:
			r.extend(RGBA(param1[0],param1[1],param1[2],param1[3]))
		else:
			r.extend(RGB(param1[0],param1[1],param1[2]))
	elif (type == LINEAR_GRADIENT_FILL or type == RADIAL_GRADIENT_FILL):
		r.extend(PadChars(MATRIX(param1[0],param1[1],param1[2],param1[3],param1[4],param1[5])))
		r.extend(GRADIENT(param2[0],param2[1]))
	elif (type == TILED_BITMAP_FILL or type == CLIPPED_BITMAP_FILL):
		r.extend(UI16(param1))
		r.extend(PadChars(MATRIX(param2[0],param2[1],param2[2],param2[3],param2[4],param2[5])))
	return r

def FILLSTYLEARRAY(fillstyles):
	count = len(fillstyles)
	r = []
	if count>=255:
		r = [UI16(count)]
	else:
		r.extend(UI8(count))
	for i in fillstyles:
		r.extend(i)
	return r

def LINESTYLE(width,color):
	# Width in TWIPS
	w = UI16(width*10)
	r = [w[0],w[1]]
	# Color value
	if (len(color)>3):
		r.extend(RGBA(color[0],color[1],color[2],color[3]))
	else:
		r.extend(RGB(color[0],color[1],color[2]))
	return r
		
def LINESTYLEARRAY(linestyles):
	count = len(linestyles)
	r = []
	if count>255:	r.extend(UI16(count))
	else:	r.extend(UI8(count))
	for i in linestyles:
		r.extend(i)
	return r

def CURVEEDGERECORD(ControlDeltaX,ControlDeltaY,AnchorDeltaX,AnchorDeltaY):
	"""SWF uses Quadratic Bezier curves, they need only 3 points:
			- 2 on-curve anchor points, and 
			  1 off-curve control point.
		So, the first anchor point is the current drawing position,
			the control point is the current drawing position plus the ControlDelta
			the last anchor point is the current drawing position plus ControlDelta plus AnchorDelta
	Parameters:
			ControlDeltaX, ControlDeltaY, LastAnchorDeltaX, LastAnchorDeltaY."""
	r = [1,0]	# Curved Edge
	nbits = NBits(SB(MaxAbs([ControlDeltaX*20,ControlDeltaY*20,AnchorDeltaX*20,AnchorDeltaY*20])))
	r.extend(UB(nbits-2,4))	# Nbits is biased by 2 in the swf reader
	r.extend(SB(ControlDeltaX*20,nbits))	# X Control point change
	r.extend(SB(ControlDeltaY*20,nbits))	# Y Control point change
	r.extend(SB(AnchorDeltaX*20,nbits))	# X anchor point change
	r.extend(SB(AnchorDeltaY*20,nbits))	# Y anchor point change
	return r

def LINEEDGERECORD(DeltaX,DeltaY,lineflag=1,vertflag=0):
	""" Parameters: Delta X - Position X
					Delta Y - Position Y
					Line Flag - 1 General Line (Default option)
								  DeltaX and DeltaY are used.
								  Vert Flag parameter not used
								0 Vertical or Hotizontal Lines
					Vert Flag - 0 Horizontal Line Only DeltaX used
								1 Vertical line only DeltaY used
	"""
	r = [1,1] 	#Straight Edge
	nbits = NBits(SB(MaxAbs([DeltaX*20,DeltaY*20])))
	r.extend(UB(nbits-2,4))
	r.extend([lineflag])
	if lineflag==1: 	# Save General Lines	#Nbits are biased by 2 in swf reader
		r.extend(SB(DeltaX*20,nbits))
		r.extend(SB(DeltaY*20,nbits))
	else:
		r.extend([vertflag])
		if vertflag == 0:	r.extend(SB(DeltaX*20,nbits))
		else:	r.extend(SB(DeltaY*20,nbits))	
	return r
		

def ENDSHAPERECORD():
	return [0,0,0,0,0,0]

def STYLESHAPERECORD(f,DeltaX=0,DeltaY=0,Fill0Style=0,Fill1Style=0,LineStyle=0,nfbits=1,nlbits=1,FillArr=[],LineArr=[],sizepad=0):
	# Defines changes in line style, fill style, position
	flags = GetBinary(f,5)
	r = [0]
	r.extend(flags)
	if flags[4]==1:
		MoveBits = NBits(SB(MaxAbs([DeltaX*20,DeltaY*20])))
		r.extend(UB(MoveBits,5))
		r.extend(SB(DeltaX*20,MoveBits))	# Move x converted to TWIPS (1 TWIP = 1 Pixel * 20 )
		r.extend(SB(DeltaY*20,MoveBits))	# Move y
	if flags[3]==1:							# StateFillStyle0
		r.extend(UB(Fill0Style,nfbits))	#Fill 0 style
	if flags[2]==1:
		r.extend(UB(Fill1Style,nfbits))	#Fill 1 style
	if flags[1]==1:
		r.extend(UB(LineStyle,nlbits))	#Line style
	if flags[0]== 1:
		r.extend(Padding(sizepad+len(r)))
		nfill = ord(FillArr[0])
		for i in FillArr:					# FillStylesArray
			r.extend(GetBinary(ord(i),8))
		nline = ord(LineArr[0])
		for i in LineArr:					# LineStylesArray
			r.extend(GetBinary(ord(i),8))
		r.extend(UB(NBits(GetBinary(nfill)),4))
		r.extend(UB(NBits(GetBinary(nline)),4))
	return r

def SHAPE(records,nfbits=15,nlbits=15):
	r = UB(nfbits,4)
	r.extend(UB(nlbits,4))
	for i in records:	r.extend(i)
	return r

def SHAPEWITHSTYLE(fillstylesarr,linestylesarr,records,nfbits=15,nlbits=15):
	r = []
	r.extend(fillstylesarr)
	r.extend(linestylesarr)
	r.extend([chr(((nfbits << 4) + nlbits) & 255)])
	for i in records:	r.extend(i)
	return r	

def BUTTONRECORD(flags,characterID,layer,matrix,ColorTransform=None):
	r = []
	r.extend(flags)
	r.extend(UI16(characterID))
	r.extend(UI16(layer))
	r.extend(PadChars(matrix))
	if ColorTransform!=None:
		r.extend(PadChars(ColorTransform))
	return r

def KERNINGRECORD(wideflag,Code1,Code2,Adjustment):
	r = []
	if wideflag == 1:
		r.extend(UI16(Code1))
		r.extend(UI16(Code2))
	else:
		r.extend(chr(Code1))
		r.extend(chr(Code2))
	r.extend(SI16(Adjustment))
	return r
		
# -------------------------------------------------------------
# SWF File Tags Headers
# -------------------------------------------------------------

def swfWrite(name,buf):
	ans = 0
	try:
		f = open(name,'wb')
		for byte in buf:
			f.write(byte)
		f.close()
	except IOError, (errno,strerror):
		print "I/O Error(%s):%s" % (errno,strerror)
		ans = 1
	return ans

def CompressSWF(name):
	f = open(name,'rb')
	header = f.read(8)
	sz =  REVUI32([header[4],header[5],header[6],header[7]])
	sz-=8
	data = f.read(sz)
	f.close()
	
	cm = compress(data)
	
	cmpheader = [chr(67),header[1],header[2],header[3],header[4],header[5],header[6],header[7]]
	f = open(name,'wb')
	for byte in cmpheader:
		f.write(byte);
	f.write(cm)
	f.close()
	del cm,header,data,sz,cmpheader
	
	return 

def swfHeaderBlock(filelength,framesize,framerate,framecount):
	"""Header Block:
		Signature	'F'	1 byte
					'W'	1 byte
					'S'	1 byte
		Version	 		1 byte
		File length	    4 bytes
		Frame size      5 bytes
		Frame rate      2 bytes
		Frame count     2 bytes"""
	#Initialize	
	buf = ['F','W','S',chr(6)] # SWF Version 6 to allow compression
	#FileLength
	buf.extend(UI32(filelength))
	#Frame Size
	buf.extend(PadChars(RECT(framesize[0],framesize[1],framesize[2],framesize[3])))
	#Frame rate
	fr = UI16(framerate)
	buf.extend(fr[1])
	buf.extend(fr[0])
	#Frame count
	fr = UI16(framecount)
	buf.extend(fr)
	# Return the buffer
	return buf
	
def swfTagHeader(tag,length):
	r = []
	if (length<=62):
		#Short Header
		n = (tag << 6) + length
		r.extend(UI16(n))
	else:
		#Long Header
		n = (tag << 6) + 63
		r.extend(UI16(n))
		r.extend(UI32(length))
	return r

# -------------------------------------------------------------
# SWF File Tags
# There are two categories of tags: definition and control
# Definition tags manage a dictionary of resources. 
# Control tags control the display list and enable actions.
#
# CAUTION: Not all the tags were defined in this program
# because I only use a base set of SWF tags to be able to
# export blender animations.
# -------------------------------------------------------------

# -------------------------------------------------------------
# 		Control Tags
# 		- Control:
#			SetBackgroundColor
#			Protect 
#			FrameLabel
#			StartSound
#			End
#		- Display List: 
#			PlaceObject
#			PlaceObject2
#			RemoveObject
#			RemoveObject2
#			ShowFrame
#		- Actions
#			DoAction
# -------------------------------------------------------------
def swfPlaceObject(characterId,depth,matrix,colortransform = None):
	size = 4 + len(matrix)
	if colortransform != None:
		size+= len(colortransform)
	r = swfTagHeader(4,size)
	r.extend(UI16(characterId))
	r.extend(UI16(depth))
	r.extend(PadChars(matrix))
	if colortransform !=None:	r.extend(PadChars(colortransform))
	return r

def swfPlaceObject2(f,depth,param):
	flags = GetBinary(f,6)
	size = 3 
	if flags[0] == 1:	#Has name
		name = STRING(param[0])
		size+=len(name)
	if flags[1] == 1:	#Has ratio
		ratio = UI16(param[1])
		size+=2
	if flags[2] == 1:	#Has color transform
		colortrans =  PadChars(CXFORM(param[2][0],param[2][1],param[2][2],param[2][3],param[2][4],param[2][5]))
		size+= len(colortrans)
	if flags[3] == 1:	#Has matrix
		matrix =  PadChars(MATRIX(param[3][0],param[3][1],param[3][2],param[3][3],param[3][4],param[3][5]))
		size+= len(matrix)
	if flags[4] == 1:	#Has place a character
		character = UI16(param[4])
		size+=2
	if flags[5] == 1:	#Move
  		pass
	r = swfTagHeader(26,size)
	bits = [0,0]	# Reserved flags
	bits.extend(flags)
	r.extend(GetChars(bits))
	r.extend(UI16(depth))
	if (flags[4]==1):	r.extend(character)
	if (flags[3]==1):	r.extend(matrix)
	if (flags[2]==1):	r.extend(colortrans)
	if (flags[1]==1):	r.extend(ratio)
	if (flags[0]==1):	r.extend(name)
	return r

def swfRemoveObject(id,depth):
	r = swfTagHeader(5,4)
	r.extend(UI16(id))
	r.extend(UI16(depth))
	return r

def swfRemoveObject2(depth):
	r = swfTagHeader(28,2)
	r.extend(UI16(depth))
	return r

def swfShowFrame():
	"""Flag the end of the current frame. During playback, the 
	characters present in the display list will be rendered and
	the mouvie paused for the duration of a single frame."""
	return swfTagHeader(1,0)

def swfSetBackgroundColor(r,g,b):
	""" Set the background color of the display  Tag ID = 9 """
	return swfTagHeader(9,3) + RGB(r,g,b)

def swfFrameLabel(label):
	str = STRING(label)
	r = swfTagHeader(43,len(str))
	r.extend(str)
	return r

def swfProtect():
	""" Marks a file as not importable for editing in the authoring tool."""
	return swfTagHeader(24,0)

def swfStartSound(id,soundinfo):
	"""Start playing the sound character"""
	size = 2 + len(soundinfo)
	r = swfTagHeader(15,size)
	r.extend(UI16(id))
	r.extend(soundinfo)
	return r

def swfEnd():
	"""Marks the end of a file. This should always be the last tag 
		in the file."""
	return swfTagHeader(0,0) 


# -------------------------------------------------------------
# 		Action Tags
# -------------------------------------------------------------
def swfActionGotoFrame(frame):
	r = [chr(129)]
	r.extend(UI16(2))
	r.extend(UI16(frame))
	return r

def swfActionGetURL(url,window):
	r = [chr(131)]
	us = STRING(url)
	uw = STRING(window)
	r.extend(UI16(len(us)+len(uw)))
	r.extend(us)
	r.extend(uw)
	return r

def swfActionNextFrame():
	return [chr(4)]

def swfActionPrevFrame():
	return [chr(5)]

def swfActionPlay():
	return [chr(6)]

def swfActionStop():
	return [chr(7)]

def swfActionToggleQualty():
	return [chr(8)]

def swfActionStopSounds():
	return [chr(9)]

def swfActionWaitForFrame(frame,skipcount):
	r = [chr(138)]
	r.extend(UI16(3))
	r.extend(UI16(frame))
	r.extend([chr(skipcount)])
	return r

def swfActionSetTarget(length,targetname):
	r = [chr(139)]
	r.extend(UI16(length))
	tn = STRING(targetname)
	r.extend(tn)
	return r

def swfActionGoToLabel(length,label):
	r = [chr(140)]
	r.extend(UI16(length))
	tn = STRING(label)
	r.extend(tn)
	return r
	
def swfDoAction(actionlist):
	r = swfTagHeader(12,len(actionlist)+1)
	if len(actionlist)>0:	r.extend(actionlist)
	r.extend([chr(0)])
	return r
# -------------------------------------------------------------
# 		Definition Tags
#		- DefineShape
#		- DefineShape2
# 		- DefineShape3
#		- DefineSprite	(SWF 3.0)
#		- DefineBits
#		- DefineButton
#		- DefineButton2
#		- DefineButtonCxform
# -------------------------------------------------------------
def swfDefineShape(id,rect,shapewithstyle):
	""" Defines a vector shape object. The shape definition
	is a full-length encoded list of bezier curve information
	line styles and fill styles. (SWF 1.0)"""
	c = PadChars(rect)
	size = len(c) + len(shapewithstyle)
	r = swfTagHeader(2,size+2)
	r.extend(UI16(id))
	r.extend(c)
	r.extend(shapewithstyle)
	return r

def swfDefineShape2(id,rect,shapewithstyle):
	"""Extends the capabilities of DefineShape with the ability
	to support more than 255 styles in the style list and multiple
	style lists in a single shape (SWF 2.0) """
	c = PadChars(rect)
	size = len(c) + len(shapeinfo)
	r = swfTagHeader(22,size+2)
	r.extend(UI16(id))
	r.extend(c)
	r.extend(shapewithstyle)
	return r

def swfDefineShape3(id,rect,shapewithstyle):
	"""Extends the capabilitys of the DefineShape2 
	by extending all of the RGB color fields to support
	RGBA with alpha transparency (SWF 3.0)"""
	c = PadChars(rect)
	size = len(c) + len(shapewithstyle)
	r = swfTagHeader(32,size+2)
	r.extend(UI16(id))
	r.extend(c)
	r.extend(shapewithstyle)
	return r

def swfDefineSprite(id,numframes,movie):
	size = len(movie) + 4
	r = swfTagHeader(39,size)
	r.extend(UI16(id))
	r.extend(UI16(numframes))
	r.extend(movie)
	return r

def swfDefineBits(id,jpeg):
	"""Define a Bitmap character with JPEG compression."""
	size = len(jpeg) + 2
	r = swfTagHeader(6,size)
	r.extend(UI16(id))
	r.extend(jpeg)
	return r

def JPEGTables(jpegencodingtable):
	"""Defines the JPEG encoding table for the JPEG images
		defined using the DefineBits records."""
	size = len(jpegencodingtable)
 	r = swfTagHeader(8,size)
	r.extend(jpegencodingtable)
	return r

def swfDefineBitsJPEG2(id,jpeg,jpegencodingtable):
	"""Define a Bitmap character with JPEG compression. This tag
	differs from DefineBits in that the record contains both JPEG
	encoding table and image data. This record allows multiple
	JPEGs with different compression rations inside a single SWF file.
	The JPEG encoding and image data contained here are two separate
	JPEG streams.
	Important NOTE:  Each JPEG stream begins with the tag (0xFF,0xD8)
	and a end of tream tag (0xFF,0xD9). This differs from the 
	standard JPEG file that combines the image and the encoding data
	into the same stream"""
	size = len(jpeg) + len(jpegencodingtable) + 2
	r = swfTagHeader(21,size)
	r.extend(UI16(id))
	r.extend(jpegencodingtable)
	r.extend(jpeg)
	return r

def swfDefineButton(id,buttonrecords,actions):
	"""Define a button character. A button is defined by an 
	up image, mouse over image, depressed image and a hit region.
	There is also a list of actions to take when the button is clicked
	and released."""
	size = 2 + len(buttonrecords) + len(actions)
	r = swfTagHeader(7,size)
	r.extend(UI16(id))
	r.extend(buttonrecords)
	r.extend([chr(0)])	# Button End Flag always 0
	r.extend(actions)
	r.extend([chr(0)])	# Actions End Flag always 0
	return r

def ACTCONDITIONLST(actconditions):
	r = []
	offset = 0
	for act in actconditions:
		r.extend(UI16(offset))
		r.extend(act)
		offset += len(act)
	return r

def ACTCONDITION(flags,actions):
	r = UI16(flags)
	r.extend(actions)
	r.extend([chr(0)]) #Actions End Flag always 0
	return

	
def swfDefineButton2(id,flags,buttonrecords,actconditionlst):
	"""Define a button character. A button is defined by an 
	up image, mouse over image, depressed image and a hit region.
	You can also specif the color transformation and sound data.
	There is also a list of actions to take when the button is clicked
	and released. (SWF 3.0) """	
	size = 3 + len(buttonrecords) + len(actconditionlst)
	r = swfTagHeader(34,size)
	r.extend(UI16(id))
	r.extend([chr(flags)])	# flags = 0 or 1
	r.extend(buttonrecords) # This records has to have COLORTRANSFORM with ALPHA
	r.extend([chr(0)])	# Button End Flag always 0
	r.extend(actionsconditions)
	return r

def swfDefineButtonCxform(id,colortransform):
	size = 2 + len(colortransform)
	r = swfTagHeader(23,size)
	r.extend(UI16(id))
	r.extend(colortransform)
	return r

# ------------------------------------------------------
# Fonts and Text
# ------------------------------------------------------

def swfDefineFont(id,OffsetTable,ShapeTable):
	size = 2 + len(OffsetTable)+ len(ShapeTable)
	r = swfTagHeader(10,size)
	r.extend(UI16(id))
	for offset in OffsetTable:	r.extend(UI16(offset))
	for shape in ShapeTable:	r.extend(shape)
	return r

def swfDefineFont2(id,FontFlags,Fontname,OffsetTable,ShapeTable,FontCodeTable,Layout=None):
	"""
		Id - Object Id
		
		FontFlags:
			FONT_HASLAYOUT	- FontFlagsHasLayout UB[1]: Has font metrics/layout information
			FONT_SHIFTJIS	- FontFlagsShiftJIS  UB[1]: ShiftJIS encoding
			FONT_UNICODE	- FontFlagsUnicode   UB[1]: Unicode encoding
			FONT_ANSI		- FontFlagsAnsi		 UB[1]: ANSI encoding
			FONT_WIDEOFFSETS- FontFlagsWideOffsets UB[1]: if 1, uses 32 bit offsets
			FONT_WIDECODES  - FontFlagsWideCodes UB[1]: If 1 fonts uses 16-bit codes
														o uses 8 bit codes.
			FONT_ITALIC		- FontFlagsItalic	 UB[1]: Italic Font
			FONT_BOLD		- FontFlagsBold		 UB[1]: Bold Font
		Fontname - String font name
		Offset Table - Beginnig of next shape in the Shape Table
		Shape Table - List of ShapeObjects that define each glyph
		FontCodeTable- Table of font codes
		Layout:
			[FontAscent,FontDescent,FontLeading,[{FontAdvanceTable <SI16>} list],[{FontBoundsTable <RECT>} list ],[Kerning <KERNINGRECORD> list]]
			
	"""
	flags = GetBinary(FontFlags)

	r = [] 
	r.extend(UI16(id))
	r.extend(chr(0))	# FontFlagsReserved UB[8]
	r.extend(chr(FontFlags))
	name = STRING(Fontname) 
	r.extend(chr(len(name)))
	r.extend(name)
  	r.extend(UI16(len(ShapeTable)))	#nGlyphs
	for offset in OffsetTable:	
		if (flags[4]==1):	# FONT_WIDEOFFSETS 
			r.extend(UI32(offset))
		else:	r.extend(UI16(offset))
	for shape in ShapeTable:	r.extend(shape)
	for code in FontCodeTable:
		if (flags[5]==1):	# FONT_WIDECODES
			r.extend(UI16(code))
		else:	r.extend(chr(code))
	if (flags[0]==1):		#FONT_HASLAYOUT
		r.extend(SI16(LayOut[0]))	#FontAscent	
		r.extend(SI16(Layout[1]))	#FontDescent
		r.extend(SI16(Layout[2]))	#FontLeading
		for glyph in Layout[3]:
			r.extend(SI16(glyph))	#FontAdvanceTable
		Bounds = []
		for rect in Layout[4]:	Bounds.extend(rect)	#FontBoundsTable
		r.extend(PadChars(Bounds))
		r.extend(UI16(len(Layout[5])))	#FontKerningCount
		for kerning in Layout[5]:	r.extend(kerning)
	
	r1 = swfTagHeader(48,len(r))
	r1.extend(r)
	return r1

def swfDefineFontInfo(FontId,Fontname,FontFlags,CodeTable):
	"""
		Font Id	- Id Font
		Font name - string 
		FontFlags:
			FONT_UNICODE	- FontFlagsUnicode   UB[1]: Unicode encoding
			FONT_SHIFTJIS	- FontFlagsShiftJIS  UB[1]: ShiftJIS encoding
			FONT_ANSI		- FontFlagsAnsi		 UB[1]: ANSI encoding
			FONT_ITALIC		- FontFlagsItalic	 UB[1]: Italic Font
			FONT_BOLD		- FontFlagsBold		 UB[1]: Bold Font
			FONT_WIDECODES  - FontFlagsWideCodes UB[1]: If 1 fonts uses 16-bit codes
														o uses 8 bit codes.
		CodeTable - Glyph code table 
	"""
	r = []
	r.extend(UI16(FontId))
	name = STRING(Fontname)
	r.extend(char(len(name)))
	r.extend(name)
	flags = GetBinary[FontFlags]
	newflags = [0,0,flags[2],flags[1],flags[3],flags[6],flags[7],flags[5]]
	r.extend(GetChars(newflags))
	for glyphs in CodeTable:
		if (flags[7]==1):	r.extend(UI16(glyphs))
		else:	r.extend(chr(glyphs))

	r1 = swfTagHeader(13,len(r))
	r1.extend(r)
	return r1

def GLYPHENTRY(idx,value,nGlyphBits=8,nAdvanceBits=8):
	r = []
	r.extend(UB(idx,nGlyphBits))
	r.extend(UB(value,nAdvanceBits))
	return r	

def TEXTRECORDTYPE0(TextGplyphEntries):
	r = [0]
	nglyphs = len(TextGplyphEntries)
	r.extend(UB(nglyphs,7))
	for glyph in TextGplyphEntries:
		r.extend(glyph)
	return PadChars(r)

def TEXTRECORDTYPE1(TextFlags,Fontid=0,height=0,color=None,x=0,y=0):
	f = [1,0,0,0]
	f.extend(GetBinary(flags))
	r = GetChars(f)
	if (f[4]==1):	r.extend(UI16(Fontid))
	if (f[5]==1):   
		if len(color)>3:	r.extend(RGBA(color))
		else:	r.extend(RGB(color))
	if (f[7]==1):	r.extend(UI16(x))
	if (f[6]==1):	r.extend(UI16(y))
	if (f[4]==1):	r.extend(UI16(height))
	return r

def swfDefineText(Textid,bounds,matrix,textrecords,nGlyphBits=8,nAdvanceBits=8):
	r = []
	r.extend(UI16(Textid))
	a = []
	a.extend(bounds)
	a.extend(matrix)
	r.extend(PadChars(a))
	r.append(chr(nGlyphBits))
	r.append(chr(nAdvanceBits))
	for record in textrecords:	r.extend(record)
	r.append(chr(0))
	r1 = swfTagHeader(11,len(r))
	r1.extend(r)
	return r1

def swfDefineText2(Textid,bounds,matrix,textrecords,nGlyphBits=8,nAdvanceBits=8):
	r = []
	r.extend(UI16(Textid))
	a = []
	a.extend(bounds)
	a.extend(matrix)
	r.extend(PadChars(a))
	r.append(chr(nGlyphBits))
	r.append(chr(nAdvanceBits))
	for record in textrecords:	r.extend(record)
	r.append(chr(0))
	r1 = swfTagHeader(11,len(r))
	r1.extend(r)
	return r1

# ------------------------------------------------------
# Blender SWF Wrap Classes
# ------------------------------------------------------

# --------------------------------------------------------------
# 
# Class bShape
# 
# -------------------------------------------------------------
class bShape:
	"Blender swf shape class"
	recbits = []
	fsa = []
	lsa = []
	nFills = 0
	nLines = 0
	def __init__(self,fillstylearr=[],linestylearr=[]):
		"bShape initialization."	
		recbits = []
		fsa = fillstylearr
		lsa = linestylearr
	def AddFillStyle(self,fillstyle):
		self.fsa.append(fillstyle)
		self.nFills+=1
	def AddLineStyle(self,linestyle):
		self.lsa.append(linestyle)
		self.nLines+=1
	def MoveTo(self,x,y):
		self.recbits.extend(STYLESHAPERECORD(SH_MOVE,x,y))
	def SetCurrentFill0(self,id,numfills=0):
		if numfills>0:	self.recbits.extend(STYLESHAPERECORD(SH_FILL0,0,0,id,0,0,NBits(UB(numfills))))
		else:	self.recbits.extend(STYLESHAPERECORD(SH_FILL0,0,0,id,0,0,NBits(UB(self.nFills))))
	def SetCurrentFill1(self,id,numfills=0):
		if numfills>0:	self.recbits.extend(STYLESHAPERECORD(SH_FILL1,0,0,0,id,0,NBits(UB(numfills))))
		else:	self.recbits.extend(STYLESHAPERECORD(SH_FILL1,0,0,0,id,0,NBits(UB(self.nFills))))
	def SetCurrentLine(self,id,numlines=0):
		if numlines>0:	self.recbits.extend(STYLESHAPERECORD(SH_LINESTYLE,0,0,0,0,id,0,NBits(UB(numlines))))
		else:	self.recbits.extend(STYLESHAPERECORD(SH_LINESTYLE,0,0,0,0,id,0,NBits(UB(self.nLines))))
	def AddNewStyles(self,nfb=1,nlb=1,FillArr=[],LineArr=[],sizepad=0):
		self.recbits.extend(STYLESHAPERECORD(SH_NEWSTYLES,0,0,0,0,0,nfb,nlb,FillArr,LineArr,len(self.recbits)))
	def SetStyleRecord(self,f,DeltaX=0,DeltaY=0,Fill0Style=0,Fill1Style=0,LineStyle=0,nfbits=1,nlbits=1,FillArr=[],LineArr=[]):
		self.recbits.extend(STYLESHAPERECORD(f,DeltaX,DeltaY,Fill0Style,Fill1Style,LineStyle,nfbits,nlbits,FillArr,LineArr,len(self.recbits)))
	def LineTo(self,x,y):
		self.recbits.extend(LINEEDGERECORD(x,y))
	def CurveTo(self,cx,cy,ax,ay):
		self.recbits.extend(CURVEEDGERECORD(cx,cy,ax,ay))
	def EndShape(self):
		self.recbits.extend(ENDSHAPERECORD())
	def GetShape(self):
		nFillBits = NBits(UB(self.nFills))
		nLineBits = NBits(UB(self.nLines))
		return SHAPEWITHSTYLE(FILLSTYLEARRAY(self.fsa),LINESTYLEARRAY(self.lsa),PadChars(self.recbits),nFillBits,nLineBits)
	def Reset(self):
		self.recbits = []
		self.fsa = []
		self.lsa = []
		self.nFills = 0
		self.nLines = 0

# -----------------------------------------------------------------
# Test SWF
# -----------------------------------------------------------------
#movie = swfHeaderBlock(0,[0,0,4000,4000],12,1)
#movie+=swfSetBackgroundColor(255,255,255)
#actions = swfActionStop()
#movie+=swfDoAction(actions)
#a = FILLSTYLEARRAY([FILLSTYLE(SOLID_FILL,[0,255,0,255]),FILLSTYLE(SOLID_FILL,[0,0,255,255]),FILLSTYLE(SOLID_FILL,[255,255,0,255])])
#b = LINESTYLEARRAY([LINESTYLE(1,[0,0,0,255]),LINESTYLE(3,[0,255,255,255])])
#nFillBits = NBits(UB(3)) 
#nLineBits = NBits(UB(2))
#sh = bShape()
#sh.AddFillStyle(FILLSTYLE(RADIAL_GRADIENT_FILL,[0.065,0.065,0.0,0.0,1000,3500],[2,[GRADRECORD(0,[255,0,0,255]),GRADRECORD(255,[0,0,0,255])]]))
#sh.AddFillStyle(FILLSTYLE(LINEAR_GRADIENT_FILL,[0.065,0.065,0.0,0.0,1000,3500],[2,[GRADRECORD(0,[0,255,0,255]),GRADRECORD(255,[0,0,0,255])]]))
#sh.AddFillStyle(FILLSTYLE(SOLID_FILL,[255,255,0,255]))
#sh.AddLineStyle(LINESTYLE(1,[0,0,0,255]))
#sh.AddLineStyle(LINESTYLE(3,[0,255,255,255]))
#sh.SetStyleRecord(SH_MOVE+SH_FILL0+SH_FILL1+SH_LINESTYLE,0,3000,0,1,0,nFillBits,nLineBits)
#sh.LineTo(0,1000)
#sh.CurveTo(1000,0,0,-1000)
#sh.LineTo(-1000,0)
#sh.SetStyleRecord(SH_MOVE+SH_FILL0+SH_FILL1+SH_LINESTYLE,1000,3000,0,2,0,nFillBits,nLineBits)
#sh.LineTo(0,1000)
#sh.LineTo(1000,0)
#sh.LineTo(0,-1000)
#sh.LineTo(-1000,0)
#sh.MoveTo(150,305)
#sh.LineTo(250,0)
#sh.LineTo(0,200)
#sh.LineTo(-250,0)
#sh.LineTo(0,-250)
#sh.SetStyleRecord(SH_MOVE+SH_FILL0+SH_FILL1,0,2900,3,1,0,nFillBits,nLineBits)
#sh.LineTo(0,500)
#sh.LineTo(500,0)
#sh.LineTo(0,-500)
#sh.MoveTo(1000,2900)
#sh.LineTo(0,500)
#sh.CurveTo(200,0,0,-500)
#sh.LineTo(-500,0)
#sh.MoveTo(2000,2900)
#sh.LineTo(0,500)
#sh.LineTo(500,0)
#sh.LineTo(0,-500)
#sh.LineTo(-500,0)
#sh.EndShape()
#movie+=swfDefineShape3(1,RECT(0,0,4000,4000),sh.GetShape())
#movie+=swfPlaceObject2(PO_MATRIX+PO_CHAR_ID,2,[0,0,0,[1.0,1.0,0.0,0.0,0.0,0.0],1])
#movie+=swfShowFrame()
#movie+=swfEnd()
#SetFileLength(movie,len(movie))
#print movie
#swfWrite('c:\swf\demo.swf',movie)
#print "Saved!"

# --------------------------------------------------------------
# 
# Class CRect
# 
# -------------------------------------------------------------
class CRect:
	""" CRect (Left,Top, Right, Bottom) Rectangle class
		Remember that the position (0,0) correspond to the
		left-bottom of the screen. """
	def __init__(self,l=0,t=0,r=0,b=0):
		self.SetRect(l,t,r,b)
	def SetRect(self,l=0,t=0,r=0,b=0):
		self.L = l
		self.T = t
		self.R = r
		self.B = b
	def SetNullRect(self):
		self.L = 0
		self.T = 0
		self.R = 0
		self.B = 0
	def Width(self):
		return abs(self.R-self.L)
	def Height(self):
		return abs(self.T-self.B)
	def Center(self):
		return self.L+int((float(self.Width())/2.0)+0.5),self.B+int((float(self.Height())/2.0)+0.5)
	def PtInRect(self,x,y):
		if (x>=self.L and x<=self.R and y>=self.B and y<=self.T):	return 1
		else:	return 0
	def OffsetRect(self,x,y):
		self.L += x
		self.T += y
		self.R += x
		self.B += y
		
def drawFrame(l,t,w,h,b=3):
	glShadeModel(GL_SMOOTH)
	glBegin(GL_QUADS)
	glColor3f(0.8,0.8,0.8)
	glVertex2d(l,t)
	glColor3f(0.5,0.5,0.5)
	glVertex2d(l+w,t)
	glColor3f(0.2,0.2,0.2)
	glVertex2d(l+w,t-h)
	glColor3f(0.5,0.5,0.5)
	glVertex2d(l,t-h)
	glEnd()		
	glBegin(GL_QUADS)
	glColor3f(0.2,0.2,0.2)
	glVertex2d(l+b,t-b)
	glColor3f(0.5,0.5,0.5)
	glVertex2d(l+w-b,t-b)
	glColor3f(0.8,0.8,0.8)
	glVertex2d(l+w-b,t-h+b)
	glColor3f(0.5,0.5,0.5)
	glVertex2d(l+b,t-h+b)
	glEnd()		
	glShadeModel(GL_FLAT)
	return

# --------------------------------------------------------------
# 
# Class CGHandle
# 
# -------------------------------------------------------------
class CGHandle:
	"Graphic Handle class"
	rc = None
	id = 0
	intensity = 0
	maxcolors = 32
	def __init__(self,i=0,id=0,l=0,t=0,r=0,b=0,ty=0):
		self.rc = CRect(l,t,r,b)
		self.id = id
		self.intensity = i
		self.type = ty
	def SetID(self,id):
		self.id = id
	def SetType(self,ty):
		self.type = ty
	def MoveTo(self,x,y):
		ctr = self.rc.Center()
		dx = x - ctr[0]
		dy = y - ctr[1]
		self.rc.OffsetRect(dx,dy)
		del dx,dy,ctr
	def SetIntensity(self,i):
		self.intensity = i
	def Draw(self):
		if self.type == 0:
			glColor3f(1.0,0.0,0.0)
			glBegin(GL_TRIANGLES)
			glVertex2d(self.rc.L,self.rc.B+15)
			glVertex2d(self.rc.R,self.rc.B+15)
			glVertex2d(self.rc.Center()[0],self.rc.T+5)
			glEnd()
			glColor3f(0.0,0.0,0.0)
			glRasterPos2d(self.rc.L,self.rc.B+5)
			Text(str(self.id))
		else:
			glColor3f(1.0,1.0,1.0)
			glBegin(GL_LINE_LOOP)
			glVertex2d(self.rc.L,self.rc.B)
			glVertex2d(self.rc.R,self.rc.B)
			glVertex2d(self.rc.R,self.rc.T)
			glVertex2d(self.rc.L,self.rc.T)
			glEnd()	
			glColor3f(0.0,0.0,0.0)
			glBegin(GL_LINES)
			glVertex2d(self.rc.L+1,self.rc.B-1)
			glVertex2d(self.rc.R,self.rc.B-1)
			glEnd()	
			glBegin(GL_LINES)
			glVertex2d(self.rc.L+1,self.rc.T)
			glVertex2d(self.rc.L+1,self.rc.B-2)
			glEnd()	
	def HitTest(self,x,y):
		return self.rc.PtInRect(x,y)

# --------------------------------------------------------------
# 
# Class CFlatButton
# 
# -------------------------------------------------------------
class CFlatButton:
	"Flat Button class"
	def __init__(self,l=0,b=0,w=0,h=0,oncolor=[255,0,0],offcolor=[75,0,0],text="button"):
		self.rc = CRect(l,b+h,l+w,b)
		self.oncolor = oncolor
		self.offcolor = offcolor
		self.text = text
		self.state = 0
		self.over = 0
		self.fmouse = 0
	def SetState(self,s):
		self.state=s
	def GetState(self):
		return self.state
	def Draw(self):
		drawFrame(self.rc.L,self.rc.T,self.rc.Width(),self.rc.Height())

		glColor3f(0.0,0.0,0.0)
		glBegin(GL_LINE_LOOP)
		glVertex2d(self.rc.L,self.rc.T)
		glVertex2d(self.rc.R,self.rc.T)
		glVertex2d(self.rc.R,self.rc.B)
		glVertex2d(self.rc.L,self.rc.B)
		glEnd()	
		glShadeModel(GL_SMOOTH)
		glColor3f(1,1,1)
		
		glBegin(GL_QUADS)
		glColor3f(0,0,0)
		glVertex2d(self.rc.L+5,self.rc.T-15)
		glVertex2d(self.rc.R-5,self.rc.T-15)
		if self.state == 1:
			clr = self.oncolor
		elif self.over==1:
			clr = self.offcolor
		else:
			clr = [0,0,0]
		glColor3f(clr[0]/255.0,clr[1]/255.0,clr[2]/255.0)
		glVertex2d(self.rc.R-5,self.rc.T-10)
		glVertex2d(self.rc.L+5,self.rc.T-10)
		glEnd()
		glBegin(GL_QUADS)
		if self.state == 1:
			clr = self.oncolor
		elif self.over==1:
			clr = self.offcolor
		else:
			clr = [0,0,0]
		glColor3f(clr[0]/255.0,clr[1]/255.0,clr[2]/255.0)
		glVertex2d(self.rc.L+5,self.rc.T-10)	
		glVertex2d(self.rc.R-5,self.rc.T-10)
		glColor3f(1,1,1)
		glVertex2d(self.rc.R-5,self.rc.T-5)
		glVertex2d(self.rc.L+5,self.rc.T-5)
		glEnd()
		glShadeModel(GL_FLAT)
		if self.over==1:
			glColor3f(0.3,0.3,0.3)
		else:
			glColor3f(0,0,0)
		ctr = self.rc.Center()
		glRasterPos2d(ctr[0]-(len(self.text)*3),self.rc.B+5)
		Text(self.text)	
		
	def HitTest(self,x,y):
		return self.rc.PtInRect(x,y)
	
	def OnMouseMove(self,dx,dy,buttons):
		""" Mouse Move Rutine for this control."""	
		rtn = 0
		
		if self.HitTest(dx,dy)==0:
			self.over=0
			return rtn
		rtn=1	
		if (buttons[0] == 1):	# Left Button Down
			if self.fmouse==0:
				self.SetState(not self.GetState())
				self.fmouse==1
				rtn = 2
		elif (buttons[0] == 0):	# Left Button Up
			self.fmouse = 0
			self.over=1			
		elif (buttons[1]==1):	# Middle Button Down
			rtn = 0
		elif (buttons[2]==1):	# Right Button Down
			rtn = 0
		Draw()
		
		
		return rtn
		
# --------------------------------------------------------------
# 
# Class CVScrollList
# 
# -------------------------------------------------------------
class CVScrollLst:
	"Vertical Scroll List class"
	def __init__(self,l=0,b=0,w=0,h=0,clr = [0.0,0.0,1.0]):
		self.selidx = -1
		self.topline = 0
		self.datalst = []
		self.color = [clr[0],clr[1],clr[2]]
		self.wndrc = CRect(l,b+h,l+w,b)
		self.fmouse = 0
	def SetPos(self,l,b,w,h):
		self.wndrc.SetRect(l,b+h,l+w,b)
	def ClearLst(self):
		del self.datalst
		self.datalst = []
	def AddItem(self,s,tag=""):
		self.datalst.append([s,tag])
	def DelItem(self,idx):
		del self.datalst[idx]
		if self.selidx==idx:	self.selidx=-1
	def Sort(self):
		self.datalst.sort()
	def GetSelected(self):
		if (self.selidx>-1):	return self.datalst[self.selidx]
		else:	return None
	def Draw(self):
		glPushAttrib(GL_LIGHTING_BIT|GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT)
		glColor3f(0.75,0.75,0.75)
		glRectf(self.wndrc.L,self.wndrc.T,self.wndrc.R,self.wndrc.B)
		glColor3f(0.0,0.0,0.0)
		glBegin(GL_LINE_LOOP)
		glVertex2d(self.wndrc.L,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.B)
		glVertex2d(self.wndrc.L,self.wndrc.B)
		glEnd()	
		glLineWidth(2.0)
		glColor3f(1.0,1.0,1.0)
		glBegin(GL_LINE_STRIP)
		glVertex2d(self.wndrc.L+2,self.wndrc.B+2)
		glVertex2d(self.wndrc.L+2,self.wndrc.T-2)
		glVertex2d(self.wndrc.R-2,self.wndrc.T-2)
		glEnd()
		glColor3f(0.45,0.45,0.45)
		glBegin(GL_LINE_STRIP)
		glVertex2d(self.wndrc.L+2,self.wndrc.B+2)
		glVertex2d(self.wndrc.R-2,self.wndrc.B+2)
		glVertex2d(self.wndrc.R-2,self.wndrc.T-2)
		glEnd()
		glColor3f(0.55,0.55,0.55)
		glRectd(self.wndrc.L+5,self.wndrc.T-5,self.wndrc.R-27,self.wndrc.B+5)
		# Draw Items
		sz = len(self.datalst)
		max = self.wndrc.Height()/15
		strmax = self.wndrc.Width()/8
		for i in range(max):
			if self.selidx==i+self.topline:
				glColor3f(self.color[0],self.color[1],self.color[2])
				glRectf(self.wndrc.L+7,self.wndrc.T-5-(i*15),self.wndrc.R-30,self.wndrc.T-(i*15)-20)
				glColor3d(1,1,1)
			else:
				glColor3d(0,0,0)
			glRasterPos2d(self.wndrc.L+7,self.wndrc.T-(i*15)-15)
			try:
				msg = self.datalst[i+self.topline][0]
				if len(msg)>strmax:	msg = msg[0:strmax]
				Text(msg)
			except:
				pass
		#Draw Handle
		if sz==0:	sz=1
		glColor3f(0.75,0.75,0.75)
		glRectf(self.wndrc.R-27,self.wndrc.T-5,self.wndrc.R-25,self.wndrc.B+5)
		glColor3f(0.55,0.55,0.55)
		glRectd(self.wndrc.R-25,self.wndrc.T-5,self.wndrc.R-5,self.wndrc.B+5)
		if sz<max:	l = 1.0
		else:	l = float(max)/float(sz)
		glColor3f(self.color[0],self.color[1],self.color[2])
		hand = int(float(self.wndrc.Height())*l)
		k = int((float(self.wndrc.Height())/float(sz))*self.topline)
		glRectd(self.wndrc.R-22,self.wndrc.T-(5+k),self.wndrc.R-7,self.wndrc.T-(hand+k))
		del i,l,sz,max,strmax
		glPopAttrib()

	def HitTest(self,x,y):
		return self.wndrc.PtInRect(x,y)

	def OnMouseMove(self,dx,dy,buttons):
		""" Mouse Move Rutine for this control."""	
		rtn = 0
		if self.HitTest(dx,dy)==0:	return
		if (buttons[0] == 1):	# Left Button Down
			# if handle was hit
			sz = len(self.datalst)
			max = self.wndrc.Height()/15
			if (dx>=self.wndrc.R-27) and (dx<=self.wndrc.R-5) and (dy>=self.wndrc.B+5) and (dy<=self.wndrc.T-5):
				if (sz>max) and ((self.fmouse == 0) or (self.fmouse == 1)):
					self.topline = int(float(self.wndrc.T-dy)/float(self.wndrc.Height())*float(sz))
					if self.topline>sz-max:	self.topline = sz-max
					self.fmouse = 1
			elif (dy>=self.wndrc.B+5) and (dy<=self.wndrc.T-5):
				if (self.fmouse == 0) or (self.fmouse ==2):
					nidx = int(float(self.wndrc.T-dy)/float(self.wndrc.Height()-8)*float(max))
					if nidx>max-1:	nidx = max-1
					self.selidx=self.topline+ nidx
					rtn=1
					self.fmouse = 2
		elif (buttons[0] == 0):	# Left Button Up
			self.fmouse = 0
		elif (buttons[1]==1):	# Middle Button Down
			pass
		elif (buttons[2]==1):	# Right Button Down
			pass
		Draw()

		return rtn
	
# --------------------------------------------------------------
# 
# Class CColorPicker
# 
# -------------------------------------------------------------	
def rgb2hsb(r,g,b):
	fr = r/255.0
	fg = g/255.0
	fb = b/255.0
	lst = [fr,fg,fb]
	lst.sort()
	max=lst[2]
	min=lst[0]
	del lst
	d = max-min
	l = (max+min)/2.0
	if (min==max):
		s = 0.0
		h = 0.0
	else:
		if l<0.5:	s = d/(max+min)
		else:	s = d/(2.0-d)
		if fr == max:	h = (fg-fb)/d
		if fg == max:	h = 2.0+(fb-fr)/d
		if fb == max:	h = 4.0+(fr-fg)/d
		h = h*60
		if h<0:	h+=360.0	
	hsb = [int(h),int(s*100),int(l*100)]
	return hsb
	
def hsb2rgb(h,s,l):
	rgb=[0,0,0]
	if s>0:
		fl = float(l)/100.0
		fs = float(s)/100.0
		fh = float(h)/360.0
		temp2 = 0
		if fl<0.5:	temp2 = fl*(1.0+fs)
		else:	temp2 = fl+fs - fl*fs
	
		temp1 = 2.0*fl - temp2

	
		temp3=[0,0,0]
		temp3[0] = fh+0.33333333
		temp3[1] = fh
		temp3[2] = fh-0.33333333
		for i in [0,1,2]:
			if temp3[i]<0.0:	temp3[i] = temp3[i]+1.0
			if temp3[i]>1.0:	temp3[i] = temp3[i]-1.0	

		for i in [0,1,2]:
			if ((6.0*temp3[i])<1):	rgb[i]= temp1+(temp2-temp1)*6.0*temp3[i]
			elif ((2.0*temp3[i])<1):	rgb[i]= temp2
			elif ((3.0*temp3[i])<2):	rgb[i]= temp1+(temp2-temp1)*(0.66666667-temp3[i])*6.0
			else:	rgb[i] = temp1
			rgb[i]=int(rgb[i]*255.0)
	else:
		r = l*255.0/100.0
		rgb = [int(r),int(r),int(r)]
	return rgb	
	
class CColorPicker:
	"Color Picker class"
	def __init__(self,l=0,b=0,w=0,h=0,clr = [0.0,0.0,1.0]):
		self.rgb = [0,0,0]
		self.hsl = [0,0,0]
		self.wndrc = CRect(l,b+h,l+w,b)
		self.fmouse = 0
		self.hueclr = [0,0,0]
		self.huehnd = CGHandle(0,0,0,0,5,5)
		self.huehnd.SetType(1)		
		self.huehnd.MoveTo(l+w/2,b+h)			
		self.boxhnd = CGHandle(0,0,0,0,5,5)
		self.boxhnd.SetType(1)
		x = w/2
		y = h/2
		t = b+h
		r = l+w
		self.colorbox =  CRect(l+x/2,t-y/2,r-x/2,b+y/2)
		self.nullbox = CRect(l-10+x/2,t+10-y/2,r+10-x/2,b-10+y/2)
	def SetPos(self,l,b,w,h):
		self.wndrc.SetRect(l,b+h,l+w,b)
	def setRGB(self,r,g,b):
		self.rgb = [r,g,b]
		self.hsl = rgb2hsb(r,g,b)
		x,y = self.colorbox.Center()
		p = Rot(x/2+20,0,self.hsl[0]+90)
		self.huehnd.MoveTo(x+p[0],y+p[1])	
		p = [int(self.hsl[1]/100.0*self.colorbox.Width()),int(self.hsl[2]/100.0*self.colorbox.Height())]
		self.boxhnd.MoveTo(self.colorbox.L+p[0],self.colorbox.B+3+(p[1]*2))	
		self.hueclr = hsb2rgb(self.hsl[0],100,50)
	def refresh(self):
		self.hueclr = hsb2rgb(self.hsl[0],100,50)
	def setHSL(self,h,s,l):
		self.rgb = hsb2rgb(h,s,l)
		self.hsl = [h,s,l]
		x,y = self.colorbox.Center()
		p = Rot(x/2+20,0,h+90)
		self.huehnd.MoveTo(x+p[0],y+p[1])	
		p = [int(s/100.0*self.colorbox.Width()),int(l/100.0*self.colorbox.Height())]
		self.boxhnd.MoveTo(self.colorbox.L+p[0],self.colorbox.B+3+(p[1]*2))	
	def getRGB(self):
		return [self.rgb[0],self.rgb[1],self.rgb[2]]
	def getHSL(self):
		return [self.hsl[0],self.hsl[1],self.hsl[2]]
	def Draw(self):
		glPushAttrib(GL_LIGHTING_BIT|GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT)
		
		glShadeModel(GL_SMOOTH)
		w = self.wndrc.Width()
		h = self.wndrc.Height()
		x,y = self.colorbox.Center()
		
		factor = 8
		x1 = self.wndrc.R
		x2 = self.wndrc.L
		dx = 0 
		dy = 0 

		glBegin(GL_QUADS)
		glColor3d(1,0,0)
		glVertex2d(x,self.wndrc.T-dy)
		glColor3f(1,1,0)
		glVertex2d(x2,self.wndrc.T-dy)		
		glColor3f(1,1,0)
		glVertex2d(x,y)	
		glColor3f(1,0,0)
		glVertex2d(x,y)	
		glEnd()
		
		glBegin(GL_QUADS)
		glColor3d(1,1,0)
		glVertex2d(x2,self.wndrc.T-dy)		
		glColor3f(0,1,0)
		glVertex2d(x2,self.wndrc.B+dy)	
		glColor3f(1,1,0)
		glVertex2d(x,y)	
		glColor3f(1,1,0)
		glVertex2d(x,y)	
		glEnd()
		
		glBegin(GL_QUADS)
		glColor3d(0,1,0)
		glVertex2d(x2,self.wndrc.B+dy)	
		glColor3f(0,1,1)
		glVertex2d(x,self.wndrc.B+dy)	
		glColor3f(0,1,1)
		glVertex2d(x,y)	
		glColor3f(0,1,0)
		glVertex2d(x,y)	
		glEnd()
							
		glBegin(GL_QUADS)
		glColor3d(0,1,1)
		glVertex2d(x,self.wndrc.B+dy)	
		glColor3f(0,0,1)
		glVertex2d(x1,self.wndrc.B+dy)	
		glColor3f(0,1,1)
		glVertex2d(x,y)	
		glColor3f(0,1,1)
		glVertex2d(x,y)	
		glEnd()
		
		glBegin(GL_QUADS)
		glColor3d(0,0,1)
		glVertex2d(x1,self.wndrc.B+dy)	
		glColor3f(1,0,1)
		glVertex2d(x1,self.wndrc.T-dy)	
		glColor3f(0,0,1)
		glVertex2d(x,y)	
		glColor3f(0,0,1)
		glVertex2d(x,y)	
		glEnd()
		
		glBegin(GL_QUADS)
		glColor3d(1,0,1)
		glVertex2d(x1,self.wndrc.T-dy)	
		glColor3f(1,0,0)
		glVertex2d(x,self.wndrc.T-dy)	
		glColor3f(1,0,0)
		glVertex2d(x,y)	
		glColor3f(1,0,1)
		glVertex2d(x,y)	
		glEnd()
		
		glBegin(GL_QUADS)
		glColor3f(0.75,0.75,0.75)
		glVertex2d(self.colorbox.L-2,self.colorbox.T+2)
		glVertex2d(self.colorbox.R+2,self.colorbox.T+2)
		glVertex2d(self.colorbox.R+2,self.colorbox.B-2)
		glVertex2d(self.colorbox.L-2,self.colorbox.B-2)
		glEnd()	

	
		glBegin(GL_TRIANGLES)
		glColor3f(1,1,1)
		glVertex2d(self.colorbox.L,self.colorbox.T)
		glColor3f(self.hueclr[0]/510.0,self.hueclr[1]/510.0,self.hueclr[2]/510.0)
		glVertex2d(x,y)
		glColor3f(0,0,0)
		glVertex2d(self.colorbox.L,self.colorbox.B)
		glColor3f(1,1,1)
		glVertex2d(self.colorbox.L,self.colorbox.T)
		glColor3f(self.hueclr[0]/510.0,self.hueclr[1]/510.0,self.hueclr[2]/510.0)
		glVertex2d(x,y)
		glColor3f(self.hueclr[0]/255.0,self.hueclr[1]/255.0,self.hueclr[2]/255.0)
		glVertex2d(self.colorbox.R,self.colorbox.T)
		glVertex2d(self.colorbox.R,self.colorbox.T)
		glColor3f(self.hueclr[0]/510.0,self.hueclr[1]/510.0,self.hueclr[2]/510.0)
		glVertex2d(x,y)
		glColor3f(0,0,0)
		glVertex2d(self.colorbox.R,self.colorbox.B)
		glVertex2d(self.colorbox.L,self.colorbox.B)
		glVertex2d(self.colorbox.R,self.colorbox.B)
		glColor3f(self.hueclr[0]/510.0,self.hueclr[1]/510.0,self.hueclr[2]/510.0)
		glVertex2d(x,y)
		glEnd()	
		
		glLineWidth(1.0)
		
		self.huehnd.Draw()			
		self.boxhnd.Draw()
	
		glPopAttrib()

	def HitTest(self,x,y):
		return self.wndrc.PtInRect(x,y)

	def OnMouseMove(self,dx,dy,buttons):
		""" Mouse Move Rutine for this control."""	
		rtn = 0
		if self.HitTest(dx,dy)==0:	return
		if (buttons[0] == 1):	# Left Button Down
			if (self.colorbox.PtInRect(dx,dy)):
				self.setHSL(self.hsl[0],((dx-self.colorbox.L)/self.colorbox.Width())*100,((dy - self.colorbox.B)/(self.colorbox.Height()<<1))*100)
				rtn = 1
			elif (self.nullbox.PtInRect(dx,dy)): 
				pass
			else:
				x,y = self.colorbox.Center()
				v = Vector([dy-y,dx-x])
				angle = (360 - atan2(v[1],v[0])*180.0/pi)%360
				self.setHSL(angle,self.hsl[1],self.hsl[2])
				self.refresh()
				rtn = 1
			self.Draw()
		elif (buttons[0] == 0):	# Left Button Up
			self.fmouse = 0
		elif (buttons[1]==1):	# Middle Button Down
			pass
		elif (buttons[2]==1):	# Right Button Down
			pass
		Draw()
		

		return rtn
		
# --------------------------------------------------------------
# 
# Class CPickPalette
# 
# -------------------------------------------------------------
class CPickPalette:
	"Pick Palette class"
	wndrc = CRect()
	clientrc = CRect()
	palrc = CRect()
	hndlst = []
	curidx = 0
	vs = 0
	maxcolors = 0
	curHandle = None
	fmouse = 0
	visible=1
	def __init__(self,l=0,t=0,w=0,h=0,m=32):
		self.SetPos(l,t,w,h)
		self.maxcolors = m
		self.fmouse = 0
	def SetPos(self,l,t,w,h):
		px = l - self.wndrc.L
		py = t - self.wndrc.T
		self.wndrc.SetRect(l,t,l+w,t-h)
		self.clientrc.SetRect(5,5,self.wndrc.Width()-5,self.wndrc.Height()-5)
		self.vs = float(self.clientrc.Height())/3.0 
		self.palrc.SetRect(self.wndrc.L+5,self.wndrc.T-5-self.vs,self.wndrc.R-5,self.wndrc.B+5+self.vs)
		for hnd in self.hndlst:
			hnd.rc.OffsetRect(px,py)
		del px,py
	def SetMaxColors(self,m):
		self.mascolors = m
	def Draw(self):
		if self.visible == 0:	return
		glColor3f(0.75,0.75,0.75)
		glBegin(GL_QUADS)
		glVertex2d(self.wndrc.L,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.B)
		glVertex2d(self.wndrc.L,self.wndrc.B)
		glEnd()
		glColor3f(0.0,0.0,0.0)
		glBegin(GL_LINE_LOOP)
		glVertex2d(self.wndrc.L,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.T)
		glVertex2d(self.wndrc.R,self.wndrc.B)
		glVertex2d(self.wndrc.L,self.wndrc.B)
		glEnd()	
		glLineWidth(2.0)
		glColor3f(1.0,1.0,1.0)
		glBegin(GL_LINE_STRIP)
		glVertex2d(self.wndrc.L+2,self.wndrc.B+2)
		glVertex2d(self.wndrc.L+2,self.wndrc.T-2)
		glVertex2d(self.wndrc.R-2,self.wndrc.T-2)
		glEnd()
		glColor3f(0.45,0.45,0.45)
		glBegin(GL_LINE_STRIP)
		glVertex2d(self.wndrc.L+2,self.wndrc.B+2)
		glVertex2d(self.wndrc.R-2,self.wndrc.B+2)
		glVertex2d(self.wndrc.R-2,self.wndrc.T-2)
		glEnd()
		glLineWidth(1.0)
		glBegin(GL_LINES)
		for i in range(self.clientrc.R-5):
			c = float(i)/float(self.clientrc.R-5)
			glColor3f(c,c,c)
			glVertex2d(self.wndrc.L+5+i,self.wndrc.B+5+self.vs)
			glVertex2d(self.wndrc.L+5+i,self.wndrc.T-5-self.vs)
		glEnd()
		sz = len(self.hndlst)
		if (sz>0):
			c = (self.clientrc.R-5)/sz
			i = 0		
			for hnd in self.hndlst:
				hnd.Draw()
				glColor3f(hnd.intensity,hnd.intensity,hnd.intensity)
				glBegin(GL_QUADS)
				glVertex2d(self.wndrc.L+5+(i*c),self.wndrc.T-5)
				glVertex2d(self.wndrc.L+5+(i*c)+c,self.wndrc.T-5)
				glVertex2d(self.wndrc.L+5+(i*c)+c,self.wndrc.T-6-self.vs)
				glVertex2d(self.wndrc.L+5+(i*c),self.wndrc.T-6-self.vs)
				glEnd()
				i+=1
		del i,c,sz	
	
	def HitTest(self,x,y):
		return self.wndrc.PtInRect(x,y)

	def PaletteHitTest(self,x,y):
		""" Return None if HitTest over the palette of colors fail
		or the created Handle where the user clicks the mouse."""
		if (self.palrc.PtInRect(x,y)):
			if self.curidx<self.maxcolors:
				i =float(x-self.palrc.L)/float(self.clientrc.R)
				py = self.wndrc.B + (self.vs/2)+5
				self.curidx+=1
				return CGHandle(i,self.curidx,x-3,py+8,x+3,py-8)
			else:	return None
		else:
			return None

	def GetIntensityAt(self,x):
		return float(x-self.palrc.L)/float(self.clientrc.R)

	def HandlerAreaHitTest(self,x,y):
		"""Return 1 if point inside Handler Area, 0 if otherwise"""
		rc = CRect(self.palrc.L,self.palrc.T,self.palrc.R,self.palrc.B)
		rc.OffsetRect(0,-self.vs)
		i = rc.PtInRect(x,y)
		del rc
	 	return i		

	def GetIntenLst(self):
		lst = []
		for h in self.hndlst:	lst.append(h.intensity)
		return lst

	def SetLstfromInten(self,l):
		self.ResetContent()
		self.maxcolors= len(l) 
		delta = self.palrc.Width()
		gPalette.curidx=0
		for i in l:
			px = gPalette.palrc.L+ (delta*i)
			py = gPalette.wndrc.B + (gPalette.vs/2)+5	
			gPalette.curidx+=1
			w = CGHandle(i,gPalette.curidx,px-3,py+8,px+3,py-8)
			gPalette.AddHandle(w)
			del w
		del i,delta
	
	def AddHandle(self,hnd):
		if len(self.hndlst)<self.maxcolors:	self.hndlst.append(hnd)
		return 

	def RemoveHandle(self,hnd):
		i = -1
		for j in range(len(self.hndlst)):
			h = self.hndlst[j]
			if h.id==hnd.id:	i = j
			elif h.id>hnd.id:	h.id-=1
		del self.hndlst[i]
		self.curidx-=1	

	def HndLstHitTest(self,x,y):
		for hnd in self.hndlst:
			if (hnd.rc.PtInRect(x,y)):	return hnd
		return None

	def ResetContent(self):
		for hnd in self.hndlst:
			c = hnd
			hnd = None
			del c
		self.hndlst = []
		self.curidx = 0

	def GetNumColors(self):
		return len(self.hndlst)
		
	def Visible(self,val=1):
		self.visible = val
	
	def OnMouseMove(self,dx,dy,buttons):
		""" Mouse Move Rutine for this control."""
		if self.visible == 0:	return 0	
		rtn = 0
		if self.HitTest(dx,dy)==0:	return
		ViewPort = Buffer(GL_FLOAT,4)
		glGetFloatv(GL_VIEWPORT,ViewPort)

		if (buttons[0]):	# Left Button Down
			self.fmouse = 1
			if self.curHandle!=None:
				#Move handle
				if (self.HandlerAreaHitTest(dx,dy)):
					self.curHandle.MoveTo(dx,dy)
			else:
				# Create a new handle
				hnd = self.PaletteHitTest(dx,dy)
				if (hnd != None): 
					w = CGHandle(hnd.intensity,hnd.id,hnd.rc.L,hnd.rc.T,hnd.rc.R,hnd.rc.B)
					w.SetType(1)
					self.AddHandle(w)
					del w,hnd
				else:
					# Select handle
					self.curHandle=self.HndLstHitTest(dx,dy)
		elif (buttons[0] == 0) and (self.fmouse ==1):	# Left Button Up
			if self.curHandle!=None:
				i = self.GetIntensityAt(dx)
				self.curHandle.SetIntensity(self.GetIntensityAt(dx))
				self.curHandle = None
				rtn = 1
			self.fmouse = 0
		elif (buttons[1]==1):	# Middle Button Down
			pass
		elif (buttons[2]==1):	# Right Button Down
			# Select handle
			self.curHandle=self.HndLstHitTest(dx,dy)
			if self.curHandle:	self.fmouse = 2
	
		elif (buttons[2]==0):	#Right Button Up
			if self.curHandle!=None and (self.fmouse == 2):
				if Blender.Draw.PupMenu("Delete?%t|Yes%x1|No%x0"):
					#Delete handle
					self.RemoveHandle(self.curHandle)
					self.curHandle=None
			self.fmouse = 0
		Draw()
		del ViewPort

		return rtn

# ---------------------------------------------------------------
#
#	Event Definitions
#
# ---------------------------------------------------------------	
EVENT_NONE = 0
EVENT_WIDTH  = 1
EVENT_HEIGHT = 2
EVENT_ASPX   = 3
EVENT_ASPY   = 4
EVENT_CHANGE_MASK = 5
EVENT_LINE_W = 6
EVENT_TOON_LINES=7
EVENT_LINES = 8	
EVENT_RENDER_TYPE = 9
EVENT_PIXELATE=10
EVENT_LEVEL=11
EVENT_SILHOUETTE = 12
EVENT_COLOR = 13
EVENT_STARTFRAME = 14
EVENT_ENDFRAME = 15
EVENT_STEPFRAME = 16
EVENT_CREATE_SWF = 23
EVENT_CREATE_BMP = 24 
EVENT_FILENAME =25
EVENT_MASK = 26
EVENT_REFRESH=27
EVENT_QUIT= 28
EVENT_LOOP=29
EVENT_QLTY=30
EVENT_FPS=31
EVENT_PREVIEW=32
EVENT_CREATE_TIF=33
EVENT_ADD_ITEM = 37
EVENT_DEL_ITEM = 38
EVENT_REMOVE_ALL = 39
EVENT_ADD_ALL = 40
EVENT_GET_FILE = 41
EVENT_PATHNAME = 42
EVENT_SEQUENCE_SWF = 43
EVENT_BROWSE = 44
EVENT_SEQ_FLAG = 45
EVENT_NUM_SEQ_F = 46
EVENT_PARAMS = 47
EVENT_RESETFRAMES = 48
EVENT_VEC_PREVIEW = 49
EVENT_VEC_TYPE = 50
EVENT_TOLERANCE = 51
EVENT_SHADOW = 52
EVENT_LAMP_SHADOW = 53
EVENT_COMPRESS_FLAG = 54
EVENT_MATERIAL_LINES = 55
EVENT_FLARE = 56
EVENT_OK = 57
EVENT_CANCEL = 58
EVENT_LINE_MIN_DISTANCE = 59
EVENT_STROKES = 60
EVENT_INCREMENT = 61
EVENT_DECREMENT = 62
EVENT_NOISE = 63
EVENT_SPACING = 64
EVENT_BRUSH_TYPE = 65

# -------------------------------------------------------------
#
# Constants
#
# -------------------------------------------------------------
SMALL = 0.000001

# -------------------------------------------------------------
#
# Common functions
#
# -------------------------------------------------------------
def sgn(n):	
	if (n>=0):	return 1
	else:	return -1
def sgn0(n):
	if (n>SMALL):	return 1
	elif (n<SMALL):	return -1
	else:	return 0.0

# -------------------------------------------------------------
#
# _Plane class
# 
# -------------------------------------------------------------
class _Plane:
	"""Class _Plane
	   	A plane P is defined by the equation Ax+By+Cz+D = 0
		where A,B,C are the coordinates of the normal vector
		of the plane and D is the distance of the plane to 
		the origin."""
	def __init__(self,_vn = [0,0,0],_d=0,_pts = []):	
		self.d = _d	
		self.vn =  Vector(_vn)
		self.pts = _pts
	def set(self,v):
		if (len(v)==4):	
			self.d = v[-1]
			self.vn = Vector(v[0:3])
		else: print "Error:The vector should be of type [A,B,C,D]"
	def solve(self,v):
		return (DotVecs(self.vn,Vector(v)))+self.d
	def set_d_from_pt(self,p):
		""" Calculate the parameter D of the plane with a given
			point p = [x,y,z] that lies in the surface of the plane.""" 
		self.d = -1 * DotVecs(self.vn,Vector(p))
	def set_from_face(self,f):
		"""	Calculate the normal vector of the plane with the
			vertices from a given polygon.
			face: Polygon face [[x0,y0,z0],[x1,y1,z1],...[xn,yn,zn]]"""
		if (len(f)<3):
			print "Error:The polygon face should have at least 3 points."	
		else:
			self.pts = []
			for i in f:	self.pts.append(i)
			p = Vector([f[1][0]-f[0][0],f[1][1]-f[0][1],f[1][2]-f[0][2]])
			q = Vector([f[2][0]-f[0][0],f[2][1]-f[0][1],f[2][2]-f[0][2]])
			self.vn = CrossVecs(p,q)
			self.vn.normalize()
			self.set_d_from_pt(f[0])
			return _Plane([self.vn.x,self.vn.y,self.vn.z],self.d,self.pts)
	def normalize(self):
		"Normalized plane."
		m = 0.0
		for i in self.vn:
			m = i*i
		m = sqrt(m)			
		self.vn.normalize()
		if (m==0):	self.d = 0
		else:	self.d = self.d/m
		return
	def intersect_line(self,line):
		"""
		Parameters:
				line:  Line ray [P,Q]; P = initial point, Q = end point
				Ray in vector representation: P' = P + t * D
				P' = point in line, t = float number, D = Direction vector of the line ray
		Return values:
				[[x,y,z],t] The point where the plane and the line intersect
	 						and the distance from the origin of the line to the intersection point.
				None - 	if they don't intersect.
		"""
		# Obtain Direction of line (D = ray direction)
		D = Vector([line[1][0]-line[0][0],line[1][1]-line[0][1],line[1][2]-line[0][2]])
		D.normalize()
		# Obtain the Normal vector of the plane
		norm = self.vn
		norm.normalize()
		denom = DotVecs(norm,D)
		if (denom==0): return None
		# Obtain a point in the plane
		if float(norm[2]) == 0:
			if float(norm[0]) == 0:
				if float(norm[1]) == 0:
					p = line[1]
				else:
					p = [0,-self.d/norm[1],0]
			else:
				p = [-self.d/norm[0],0,0]
		else:
			p = [0,0,-self.d/norm[2]]
		# Find distance to collision point
		t = DotVecs(norm,Vector([p[0]-line[0][0],p[1]-line[0][1],p[2]-line[0][2]]))
		t/=denom
		# Return P'
		return  [[(D[0]*t)+line[0][0],(D[1]*t)+line[0][1],(D[2]*t)+line[0][2]],t]
	
	def intersect_plane(self,pl):
		"""Return:
			[Xo,D]	The line where the two planes intersect in 
					vector representation 
					L = Xo + t * D	Xo = Point in the line [x,y,z]
									D = Direction vector
									t = scalar
			None	If Planes are parallel	
		"""		
		# Compute intersection line L of this Plane and Plane T1
		D = CrossVecs(self.vn,pl.vn)	#Direction of the line
		# Test if planes are parallel
		if (reduce(add,D)==0):	return None
		# Compute a point in the intersected line
		if D[0]>=0:	ax = D[0]
		else:	ax = -D[0]
		if D[1]>=0:	ay = D[1]
		else:	ay = -D[1]
		if D[2]>=0:	az = D[2]
		else:	az = -D[2]
		if (ax+ay+az) < SMALL:	return None
		maxc = 0
		if (ax>ay):
			if (ax>az):	maxc =1
			else:	maxc = 3
		else:
			if (ay>az):	maxc =2
			else:	maxc = 3
		#Zero max coordinate and solve other two
		d1 = -1 * DotVecs(self.vn,Vector(self.pts[1]))
		d2 = -1 * DotVecs(pl.vn,Vector(pl.pts[1]))
		x = 0
		y = 0
		z = 0
		if maxc == 1:	# intersect with x=0
			y = (d2*self.vn[2] - d1*pl.vn[2]) / D[0]
			z = (d1*pl.vn[1] - d2*self.vn[1]) / D[0]
 		elif maxc == 2:	# intersect with y=0
			x = (d1*pl.vn[2] - d2*self.vn[2]) / D[1]
			z = (d2*self.vn[0] - d1*pl.vn[0]) / D[1]
		else:			#intersect with z=0
			x = (d2*self.vn[1] - d1*pl.vn[1]) / D[2]
			y = (d1*pl.vn[0] - d2*self.vn[0]) / D[2]
		D.normalize()
		return [[x,y,z],[D.x,D.y,D.z]] 

	def over_under_face(self,ptslst):
		u = map(sgn0,map(self.solve,ptslst))
		count=[0,0,0]	#-1,0,1	
		for item in u:
			if (item==-1):	count[0]+=1
			elif (item==0):	count[1]+=1
			else:	count[2]+=1
		sz = len(ptslst)
		if count[0]>0 and count[2]==0:	return -1		# poly at back
		elif count[2]>0 and count[0]== 0:	return 1	# poly at front
		elif count[1] == sz:	return 0	# poly on plane
		else:	return 2

	def intersect_face(self,ptslst,bsplit=1):
		"""Test if the face is intersecting this plane.
		Parameter: Polygon face [[x0,y0,z0],[x1,y1,z1],...[xn,yn,zn]]

		Return values:
			None 	- If face is on one side of the plane (Not intersection)
			[[face]]  - List containing one face (original given face) when the plane and
					  the face are coplanar (face and plane are the same plane)
			[[face],[face]] - List of two faces (original face splitted) one for the face 
					 infront of the plane and other for the face behind the plane.
		"""
		ans = self.over_under_face(ptslst)
		if (ans==-1 or ans == 1):	return None	#Face is on one side of the plane
		elif (ans == 0):	return [ptslst]		#Coplanar triangles
		else:	# Split
			#No split if flag off
			if bsplit==0:	return [ptslst]
			# Double check the intersection of faces not only planes
			#npl = _Plane().set_from_face(ptslst)
			#ans2 = npl.over_under_face(self.pts)
			#if ans2==-1 or ans2 == 1:	return None
			
			#Split 
			dv1 = map(self.solve,ptslst)
			s1 = map(sgn0,dv1)
			f1 = []
			f2 = []
			sz = len(s1)
			for idx in range(sz):
				i = idx + 1
				if i>=sz:	i = 0
				if (s1[idx]>0):	f1.append(ptslst[idx])
				elif (s1[idx]<0):	f2.append(ptslst[idx])
				else:	
					f1.append(ptslst[idx])
					f2.append(ptslst[idx])
				if s1[i]!=0 and s1[idx]!=0:
					if (s1[i]!=s1[idx]):
						k = self.intersect_line([ptslst[idx],ptslst[i]])
						f1.append(k[0])
						f2.append(k[0])
			return [f1,f2]

#p = _Plane()
#p = p. set_from_face([[0,0,0],[1,0,0],[1,1,0]])
#f = [[1,1,1],[3,1,1],[2,1,-1],[3,1,-1]]
#print p.intersect_face(f)


# --------------------------------------------------------------
# 
# Class _Frustum
# 
# -------------------------------------------------------------
class _Frustum:
	"Frustum class"
	val = []
	def calculate(self,m,p):
		"Calculate frustum bouding box."
		c =	p * m
		q =  c[3]
		self.val[0].set(q+c[0])
	#	self.val[0].normalize()
		self.val[1].set(q-c[1])
	#	self.val[1].normalize()
		self.val[2].set(q-c[0])
	#	self.val[2].normalize()		
		self.val[3].set(q+c[1])
	#	self.val[3].normalize()
		self.val[4].set(q-c[2])
	#	self.val[4].normalize()
		self.val[5].set(q+c[2])
	#	self.val[5].normalize()
	def __init__(self,model,proj):
		"Frustum is a vector of planes."	
		pl = _Plane()	# Left
		pt = _Plane()	# Top
		pr = _Plane()	# Right
		pb = _Plane()	# Bottom
		pk = _Plane()	# bacK
		pf = _Plane()	# Forward
		self.val = [pl,pt,pr,pb,pk,pf]
		self.calculate(model,proj)
	def pt_inside(self,pt):
		"""Check if a point [x,y,z] is inside the frustum.
		(1 = inside, 0 = outside)"""
		for pl in self.val:
			if (pl.solve(pt)<0): return 0
		return 1
	def sphere_inside(self,center,r):
		"""Check if a sphere with the center point at [x,y,z]
		and with a radius r, is inside the frustum. Return 1
		if is inside, 0 if not."""
		for pl in self.val:
			if (pl.solve(center)<=-r):	return 0
		return 1
	def partial_sphere_inside(self,center,r):
		"""Check if a sphere with the center point at [x,y,z]
		and with a radius r, is partial inside the frustum. 
		Return: 0 - Totally outside
				1 - Partially inside
				2 - Totally inside"""
		p = 0
		for pl in self.val:
			d = pl.solve(center)
			if (d<=-r):	return 0
			elif (d>r):	p = p + 1
		if (p == 6):	return 2
		return 1
	def box_inside(self,box):
		"""Check if a box is inside the frustum (qFrustum).
		First check if the center of the box is infront of all
		the planes, if true then return 1, if not check every corner
		to find at least one that is infront of the frustum planes,
	    if such case occurs then return 1 else 0."""
		if (self.pt_inside(box.center)==1):	return 1
		else:
			for pl in self.val:
				found = 0
				for pt in box.val:
					if (pl.solve(pt)>0):
						found = 1
						break
				if (found == 0): return 0
		return 1
	def partial_box_inside(self,box):
		"""Check if a box is partial inside the frustum (qFrustum).
			Return: 0 - Totally outside
				1 - Partially inside
				2 - Totally inside"""
		for pt in box:
			found = 0
			for pl in self.val:
				if (pl.solve(pt))>0:	found+=1
			if found>=3:	return 1
		return 0
	def partial_face_inside(self,face):
		"""Check if a face is partial inside the frustum.
			Return: 0 - Totally outside
				1 - Partially inside
				2 - Totally inside"""
		p = 0	
		sz = len(face)
		for pl in self.val:
			found = 0
			for pt in face:
				if (pl.solve(pt)>=0): found = found + 1
			if (found==0):	return 0
			if (found == sz): p = p + 1
		if (p == 6):	return 2
		return 1

# ---------------------------------------------------------------
# 	Function	: MatrixToBuffer
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def MatrixToBuffer(m):
	return Buffer(GL_FLOAT,16,[m[0][0],m[0][1],m[0][2],m[0][3],
								m[1][0],m[1][1],m[1][2],m[1][3],
								m[2][0],m[2][1],m[2][2],m[2][3],
								m[3][0],m[3][1],m[3][2],m[3][3]])

# ---------------------------------------------------------------
# 	Function	: Perspective
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def Perspective(fovy, aspect, near,far):
	top = near * tan(fovy * pi / 360.0)
	bottom = -top
	left = bottom*aspect
	right= top*aspect
	x = (2.0 * near) / (right-left)
	y = (2.0 * near) / (top-bottom)
	a = (right+left) / (right-left)
	b = (top+bottom) / (top - bottom)
	c = - ((far+near) / (far-near))
	d = - ((2*far*near)/(far-near))
	return Matrix([x,0.0,a,0.0],[0.0,y,b,0.0],[0.0,0.0,c,d],[0.0,0.0,-1.0,0.0])
		
# ---------------------------------------------------------------
# 	Function	f: Ortho
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------			
def Ortho(fovy, aspect ,near,far,scale):
	top = near * tan(fovy * pi / 360.0) * (scale * 10)
	bottom = -top 
	left = bottom * aspect
	right= top * aspect
	rl = right-left
	tb = top-bottom
	fn = near-far 
	tx = -((right+left)/rl)
	ty = -((top+bottom)/tb)
	tz = ((far+near)/fn)
	return Matrix([2.0/rl,0.0,0.0,tx],[0.0,2.0/tb,0.0,ty],[0.0,0.0,2.0/fn,tz],[0.0,0.0,0.0,1.0])
						
	
# ---------------------------------------------------------------
# 	Function	: IntersectLines
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------		
def IntersectLines(l1,l2,flag = 0):
	ua = ((l2[2]-l2[0]) * (l1[1]-l2[1])) - ((l2[3]-l2[1])*(l1[0]-l2[0]))
	ub = ((l1[2]-l1[0]) * (l1[1]-l2[1])) - ((l1[3]-l1[1])*(l1[0]-l2[0]))
	c  = ((l2[3]-l2[1]) * (l1[2]-l1[0])) - ((l2[2]-l2[0])*(l1[3]-l1[1]))
	if c==0:	return None
	if (ua==0 and ub==0 and c==0):	return [l1[0],l1[1]]
	ua/=float(c)
	ub/=float(c)
	if flag:
		if (ua<-0.01 or ua>1.01) and (ub<-0.01 or ub>1.01):
			return None
	return [int(l1[0]+((ua*(l1[2]-l1[0]))+0.5)),int(l1[1]+((ua*(l1[3]-l1[1]))+0.5))]


# ---------------------------------------------------------------
# 	Function	: InsideEdge
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def InsideEdge(pt,e):
	if ((e[2]-e[0])*(pt[1]-e[1])) < ((pt[0]-e[0])*(e[3]-e[1])):	return 1
	return -1

# ---------------------------------------------------------------
# 	Function	: EdgeClip
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def EdgeClip(inlist,edge):
	outlst = []
	if len(inlist)==2:	s = inlist[1]
	else:	s = inlist[-1]
	i=[]
	for p in inlist:
		if InsideEdge(p,edge)>0:
			if InsideEdge(s,edge)<0:
				i = IntersectLines([s[0],s[1],p[0],p[1]],edge,1)
				if i!=None and len(inlist)>2:	outlst.append((i[0],i[1],s[2]))
			outlst.append(p)
		else:
			if InsideEdge(s,edge)>0:
				i = IntersectLines([s[0],s[1],p[0],p[1]],edge,1)
				if i!=None:	outlst.append((i[0],i[1],p[2])) 
		s = p
	return outlst

# ---------------------------------------------------------------
# 	Function	:PolyClip
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def PolyClip(vertexlst,x,y,w,h):
	ClipRgnEdges = [[x,y,x,y+h],[x,y+h,x+w,y+h],[x+w,y+h,x+w,y],[x+w,y,x,y]]
	inlist = vertexlst
	for edge in ClipRgnEdges:
		if inlist==None or inlist == []:	break
		inlist = EdgeClip(inlist,edge)
	return inlist
	
# ---------------------------------------------------------------
# 	Function	: RenderWireFrame
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def RenderWireFrame(tofile):
	global gLineWidth,gGenCol
	global gMsg,gCurrentFrame,gRendering,buffImage

	sc = Blender.Scene.getCurrent()
	context = sc.getRenderingContext()
	w = context.imageSizeX()
	h = context.imageSizeY()
	ax = context.aspectRatioX()
	ay = context.aspectRatioY()
	del sc,context
		
	gRendering = 1
	
	mW = w/2
	mH = h/2
	
	# Set Current Frame
	Blender.Set('curframe',gCurrentFrame)
	Blender.Window.RedrawAll()
	# Get Scene
	sc = Blender.Scene.getCurrent()
	obList = sc.getChildren()

	if tofile:
		sh = bShape()
		sh.Reset()
		movie = []
		gMsg = "Rendering Wireframe"
		oldclr = [-1,-1,-1]
		bChgColor = 0
	else:
		glClearColor(0.0,0.0,0.3,1.0)
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
		glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
		#Draw Background
		glColor3f(gGenCol[4][0],gGenCol[4][1],gGenCol[4][2])
		glBegin(GL_POLYGON)
		glVertex2d(9,50)
		glVertex2d(w+10,50)
		glVertex2d(w+10,h+50)
		glVertex2d(9,h+50)
		glEnd()
		glPolygonMode(GL_FRONT_AND_BACK,GL_LINE)

	# Get Visible Layers
	layerslst = Blender.Window.ViewLayer()
	layerslst.reverse()
	LayerMask = 0
	for l in layerslst:	LayerMask += (2**(l-1))
	del layerslst
	# Calculate Perspective Matrix from the current camera
	obCamera = sc.getCurrentCamera()
	del sc
	cam = obCamera.getInverseMatrix()
	cam.transpose()	

	# Changing the view mode
	cmra = obCamera.getData()
 
	fovy = atan(0.5/(float(w*ax)/float(h*ay))/(cmra.lens/32))
	fovy = fovy *360/pi
	if cmra.type:
		m2 = Ortho(fovy,float(w*ax)/float(h*ay),cmra.clipStart, cmra.clipEnd,17) #cmra.scale) 
	else:
		m2 = Perspective(fovy,float(w*ax)/float(h*ay),cmra.clipStart, cmra.clipEnd) 
	del fovy,cmra
	
	#Create Frustum	
	frustum = _Frustum(cam,m2)
	m1 = Matrix()
	mP = Matrix()
	numobj = 0
	for obMesh in obList:
		if (type(obMesh.data)==NMeshType) and ((obMesh.Layer & LayerMask)>0):
			mhActual = NMesh.GetRawFromObject(obMesh.name) #GetRaw
			#Obtain the colors of the objects in this frame
			colors = []
			if len(mhActual.materials)>0:
				for colsmat in mhActual.materials:
					colors.append([colsmat.R,colsmat.G,colsmat.B,colsmat.alpha])
			else:	colors = [[0.7,0.7,0.7,1.0]]
			m1 = obMesh.matrixWorld #mat
			m1.transpose()
			mP = cam * m1
			mP = m2  * mP

			b = obMesh.getBoundBox()
			bb=[]
			for nb in b:
				nb1 = MatMultVec(m1,Vector([nb[0],nb[1],nb[2],1.0]))
				bb.append([nb1[0],nb1[1],nb1[2]])

			if (frustum.partial_box_inside(bb)>0):
				# Obtain the list of faces
				for f in mhActual.faces:
					tf = []
					t2 = [] 
					for v in f.v:
						#Transform the vertices to global coordinates
						p = MatMultVec(mP,Vector([v.co[0],v.co[1],v.co[2],1.0]))
						tf.append(p)
						p = MatMultVec(m1,Vector([v.co[0],v.co[1],v.co[2],1.0]))
						t2.append([p[0],p[1],p[2]])
						if frustum.partial_face_inside(t2):
							iu = []	
							for p in tf:
								# Create Point
								if p[3]<=0:
									x = int(p[0]*mW)+mW
									y = int(p[1]*mH)+mH
								else:
									x = int((p[0]/p[3])*mW)+mW
									y = int((p[1]/p[3])*mH)+mH
								iu.append([x,y,0])
									
							#clipping
							iu = PolyClip(iu,0.0,0.0,w,h)	
							if len(iu)>0:
								if not tofile:
									glLineWidth(gLineWidth.val)
									glColor3f(colors[f.mat][0],colors[f.mat][1],colors[f.mat][2])	
									glBegin(GL_LINE_LOOP)
									for i in iu:	glVertex2d(i[0]+10,i[1]+50)
									glEnd()
								else:
									# ------------------------------------------------------------- SWF Begin
									clr = [int(colors[f.mat][0]*255),int(colors[f.mat][1]*255),int(colors[f.mat][2]*255),int(colors[f.mat][3]*255)]
									bChgColor = 0
									if (oldclr[0]!=clr[0] or oldclr[1]!=clr[1] or oldclr[2]!=clr[2] or oldclr[3]!=clr[3] ):
										_fsa = FILLSTYLEARRAY([FILLSTYLE(SOLID_FILL,[0,0,0,255])])
										_lsa = LINESTYLEARRAY([LINESTYLE(1,[clr[0],clr[1],clr[2],255])])
										oldclr = [clr[0],clr[1],clr[2],clr[3]]
										sh.SetStyleRecord(SH_MOVE+SH_LINESTYLE+SH_NEWSTYLES,iu[0][0],h-iu[0][1],0,0,1,1,1,_fsa,_lsa)
									else:	
										sh.MoveTo(iu[0][0],(h-iu[0][1]))
									for k in range(len(iu)):
										i = k+1
										if i>=len(iu): i = 0
										sh.LineTo(iu[i][0]-iu[k][0],(h-iu[i][1])-(h-iu[k][1]))
									# ------------------------------------------------------------- SWF End
							del iu
					del tf
		numobj+=1

	del LayerMask

	if tofile:
		# ------------------------------------------------------------- SWF Begin
		sh.EndShape()
		movie = sh.GetShape()
		gPercentage = 0.0
		del sh
		Draw()
		gRendering = 0
		return movie
		# ------------------------------------------------------------- SWF End
	else:
		glPolygonMode(GL_FRONT_AND_BACK,GL_FILL)
		glLineWidth(1.0)
		if buffImage==None:	
			buffImage = Buffer(GL_BYTE,w*h*3)
		# Viewpoint data
		ViewData = Buffer(GL_INT,4)
		glGetIntegerv(GL_VIEWPORT,ViewData)
		glReadBuffer(GL_BACK)
		glReadPixels(ViewData[0]+11,ViewData[1]+50,w-1,h,GL_RGB,GL_UNSIGNED_BYTE,buffImage)
		gRendering = 0
		return 0


def GetNeighboards(faces):
	dic = {}
	for fi in range(len(faces)):
		f = faces[fi]
		for iv in range(len(f.v)):
			i1 = f.v[iv].index
			i2 = f.v[iv-1].index
			if (i1,i2) in dic:
				dic[(i1,i2)].append(fi)
			elif (i2,i1) in dic:
				dic[(i2,i1)].append(fi)
			else:
				dic[(i1,i2)] = [fi]
	return dic
	
def GetSilhouettes(eye,faces,mat,invmat,neigh,cl,ch):
	global	gbLines,gbMaterial
	
	sil_lines = {}
	mat_lines = {}
	shp_lines = {}

	for fi in range(len(faces)):
		f = faces[fi]
		n = f.no
		n =Vector([n[0],n[1],n[2],1.0])
		n = MatMultVec(invmat,n)
		n.normalize()
	
		mverts= []
		for iv in range(len(f.v)):
			pt1 = f.v[iv]
			vtx1 = MatMultVec(mat,Vector([pt1[0],pt1[1],pt1[2],1.0]))
			mverts.append([vtx1[0],vtx1[1],vtx1[2]])

		D = -1 * DotVecs(n,Vector([mverts[0][0],mverts[0][1],mverts[0][2],1.0]))
		visibility = DotVecs(n,Vector([eye[0],eye[1],eye[2],1.0]))+D
			
		if 	(visibility>0):
			for iv in range(len(f.v)):
				v1 = f.v[iv-1].index
				v2 = f.v[iv].index
				
				lstneigh = None
				key = None
				if (v1,v2) in neigh:	key=(v1,v2)
				elif (v2,v1) in neigh:	key = (v2,v1)
				lstneigh = neigh[key]
		
				foundmat = 0
				foundshp = 0	
				if len(lstneigh)>1:
					if lstneigh[0]==fi:	neighface	= lstneigh[1]
					else:	neighface = lstneigh[0]
					
					if (gbMaterial.val>0):	
						if f.materialIndex <> faces[neighface].materialIndex:
							if ((v1,v2) in mat_lines) or ((v2,v1) in mat_lines):
								pass
							else:
								mat_lines[(v1,v2)] = [mverts[iv-1],mverts[iv]]
								foundmat=1
	
					if (gbLines.val>0):
						angle = AngleBetweenVecs(Vector(f.no),Vector(faces[neighface].no))
						if (angle>cl) and (angle<ch):	
							if ((v1,v2) in shp_lines) or ((v2,v1) in shp_lines):
								pass
							else:
								shp_lines[(v1,v2)] = [mverts[iv-1],mverts[iv]]
								foundshp = 1
				# Silhouette Lines	
				if (v1,v2) in sil_lines:	sil_lines[(v1,v2)]=None
				elif (v2,v1) in sil_lines:	sil_lines[(v2,v1)]=None
				else:
					if (foundshp or foundmat):
						pass
					else:	
						sil_lines[(v1,v2)] = [mverts[iv-1],mverts[iv]]
					
	return mat_lines,shp_lines,sil_lines		

# ---------------------------------------------------------------
# 	Function	: DrawObjects
#	Inputs		:
# 	OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def DrawObjects(tofile):
	global gRenderType,	buffImage,framebuff,gEnableMask,gCurrentFrame
	global gFX, gFXType,gLevel,gRendering
	global gLineWidth,gbLines,gbSilhouette,gbMaterial,gSilWidth,gMatWidth
	global gGenCol,gPalette,gDoubleSided
	global gShadow,gSilhouette,gFlare,gFlareObjName,gFlareLoc
	global gColors,gVertexLst,gLineRegions,gColordic
	global gStrokes, gIncrement, gDecrement, gNoise, gSpacing, gBrush

	framebuff = []
	gRendering = 1
	try:
		del gLineRegions
	except:
		pass
	gLineRegions = []
	
	# Set Current Frame
	Blender.Set('curframe',gCurrentFrame)
	Blender.Window.RedrawAll()
	#Get Current Scene
	sc = Blender.Scene.getCurrent()
	# Get Visible Layers
	layerslst = Blender.Window.ViewLayer()
	layerslst.reverse()
	LayerMask = 0
	for l in layerslst:	LayerMask += (2**(l-1))
	del layerslst
	# Get Current camera
	obCamera = sc.getCurrentCamera()
	cmra = obCamera.getData()
	obList = sc.getChildren()
	context = sc.getRenderingContext()
	gW = context.imageSizeX()
	gH = context.imageSizeY()
	gAspX = context.aspectRatioX()
	gAspY = context.aspectRatioY()
	del sc,context

	# Calculate Perspective Matrix from the current camera
	cam = obCamera.getInverseMatrix()
	cam.transpose()	
	fovy = atan(0.5/(float(gW*gAspX)/float(gH*gAspY))/(cmra.lens/32))
	fovy = fovy *360/pi
	if cmra.type:
		m3 = Ortho(fovy,float(gW*gAspX)/float(gH*gAspY),cmra.clipStart, cmra.clipEnd,17) #cmra.scale) 
	else:
		m3 = Perspective(fovy,float(gW*gAspX)/float(gH*gAspY),cmra.clipStart, cmra.clipEnd) 
	# Create Frustum
	frustum = _Frustum(cam,m3)
	LampLst = []
	#Get all lamps positions
	for obj in obList:
		if (obj.getType()=="Lamp"):
			lmp = obj.getData()
			flags = lmp.getMode()
			shdw = 0
			if ((flags & 0x1)<>0):	shdw=1
			loc = obj.loc
			LampLst.append([loc[0],loc[1],loc[2],shdw,lmp.getClipEnd()]) 
			del lmp,loc,shdw,flags
		
	numcolors = 64/gPalette.GetNumColors()
	m = 64 % gPalette.GetNumColors()
	vMaskColors = []
	for hnd in gPalette.hndlst:
		r = [hnd.intensity]
		r *= numcolors 
		vMaskColors.extend(r)
		del r
	if (m>0):
		idx = len(vMaskColors)-1
		r = [vMaskColors[idx-1]] * m
		vMaskColors.extend(r)
		del r,idx
	del hnd

	glPushAttrib(GL_LIGHTING_BIT|GL_ENABLE_BIT|GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT)
	glDisable(GL_SCISSOR_TEST)
	glClearColor(0.0,0.0,0.3,1.0)
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
	glEnable(GL_SCISSOR_TEST)

	if gEnableMask.val and 	tofile>0:
		glColor3f(gGenCol[6][0],gGenCol[6][1],gGenCol[6][2])
	else:
		#Draw Background
		glColor3f(gGenCol[4][0],gGenCol[4][1],gGenCol[4][2])
	
	glBegin(GL_POLYGON)
	glVertex2d(9,50)
	glVertex2d(gW+10,50)
	glVertex2d(gW+10,gH+50)
	glVertex2d(9,gH+50)
	glEnd()

	Viewport = Buffer(GL_INT, 4)
	glGetIntegerv(GL_VIEWPORT, Viewport)
	glViewport(Viewport[0]+10, Viewport[1]+50, gW, gH)

	glEnable(GL_DEPTH_TEST)
	glDisable(GL_LIGHTING)
	glShadeModel(GL_FLAT)
	glDrawBuffer(GL_BACK)

	glMatrixMode(GL_MODELVIEW)
	glPushMatrix()
	glMatrixMode(GL_PROJECTION)
	glPushMatrix()
	glLoadIdentity()
	if cmra.type:
		m3 = Ortho(fovy,float(gW*gAspX)/float(gH*gAspY),cmra.clipStart, cmra.clipEnd,17) #cmra.scale) 
	else:
		m3 = Perspective(fovy,float(gW*gAspX)/float(gH*gAspY), cmra.clipStart, cmra.clipEnd) 
	del cmra,fovy

	m3.transpose()
	proj = MatrixToBuffer(m3)
	glMultMatrixf(proj)
	cam = MatrixToBuffer(obCamera.getInverseMatrix())
	glMultMatrixf(cam)

	glMatrixMode(GL_MODELVIEW)
	glLoadIdentity()

	glPolygonMode(GL_FRONT,GL_FILL)
	if (gRenderType.val>=2):
		glDisable(GL_TEXTURE_2D)
		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_S, GL_REPEAT)
		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_WRAP_T, GL_REPEAT)
		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
		glTexParameteri(GL_TEXTURE_1D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
		glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE, GL_DECAL)

	width = gW
	height = gH
	bsz = width*height*3
	if buffImage==None:	
		buffImage = Buffer(GL_BYTE,bsz)
	buffback = Buffer(GL_BYTE,bsz)
	buff2     = Buffer(GL_BYTE,bsz,[0]*bsz)
	del bsz
		
	gBmpTexture =  Buffer(GL_BYTE,32*3)
	gTextBits=[0]*32
	if (gRenderType.val>3) and (gRenderType.val<7):
		gTextBits = [1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0,1,1,1,1,0,0,0,0]

	w3 = width * 3
	j3 = height*w3
	bj3 = j3-w3


	dictfilter={}
	dictfilter[(0,0,0)]=1
	dictfilter[(255,255,255)]=1
	# __________________________________________________
	# Add Background, lines, silhouette, and mask colors
	# __________________________________________________
	for i in [0,1,2,3,4]:
		ir = int(gGenCol[i][0]*255)
		ig = int(gGenCol[1][1]*255)
		ib = int(gGenCol[1][2]*255)
		if  (ir,ig,ib) in dictfilter:
			pass
		else:
			dictfilter[(ir,ig,ib)]=1
	ObjLst = []
	shadowlines = []
	gSilhouette=[]
	numobj = 0
	for obj in obList:
		if (type(obj.data)==NMeshType) and ((obj.Layer & LayerMask)>0):
			m1 = obj.matrixWorld
			m1.transpose()
			# ------------------------------------------------
			# Set Object Bounding Box
			# ------------------------------------------------
			Box = []
			b = obj.getBoundBox()
			bb=[]
			for nb in b:
				nb1 = MatMultVec(m1,Vector([nb[0],nb[1],nb[2],1.0]))
				bb.append([nb1[0],nb1[1],nb1[2]])
			Box.extend(bb)
			
			m1.transpose()
			m2 = CopyMat(m1)
			m2.transpose()
		
			if (frustum.partial_box_inside(Box)<1) :
				ObjLst.append(0)
			else:
				ObjLst.append(1)
				# ------------------------------------------------
				# Set Mesh
				# ------------------------------------------------
				Mesh = NMesh.GetRawFromObject(obj.name) 
				glPushMatrix()
				mat = MatrixToBuffer(m1)
				glMultMatrixf(mat)
				invmat = obj.getInverseMatrix()
				colors = []
				#Obtain the colors of the objects in this frame
				if len(Mesh.materials)>0:
					for colsmat in Mesh.materials:
						colors.append([colsmat.R,colsmat.G,colsmat.B,colsmat.alpha])
				else:	colors = [[0.7,0.7,0.7,1.0]]

				#Change the colors of the textures 
				textures = []
				for clr in colors:
					tones = []
					for t in range(64):
						ir = int((clr[0]*vMaskColors[t])*255)
						ig = int((clr[1]*vMaskColors[t])*255)
						ib = int((clr[2]*vMaskColors[t])*255)
						if  (ir,ig,ib) in dictfilter:
							pass
						else:
							dictfilter[(ir,ig,ib)]=1
						tones.append(int((clr[0]*vMaskColors[t])*255))
						tones.append(int((clr[1]*vMaskColors[t])*255))
						tones.append(int((clr[2]*vMaskColors[t])*255))
					textures.append(tones)
					del tones
				glLineWidth(1.0)	
	
				if gDoubleSided.val == 0:	glEnable(GL_CULL_FACE)
				
				lampedgedic = {}
				capnear =[]
				capfar = []
			
				if (gbSilhouette.val>0) or (gbLines.val>0) or (gbMaterial.val>0):
					neighboards = GetNeighboards(Mesh.faces)
					matlines, shplines,sillines = GetSilhouettes(obCamera.loc,Mesh.faces,m2,invmat,neighboards,45,360)
					gSilhouette.append([numobj,[sillines,shplines,matlines]])
					matlines,shplines,sillines = None,None,None
					del matlines,shplines,sillines
			
				for face in Mesh.faces:
					n = face.no
					n =Vector([n[0],n[1],n[2],1.0])
					n = MatMultVec(invmat,n)
					n.normalize()
					
					glEnable(GL_CULL_FACE)
					glCullFace(GL_BACK)
					if gDoubleSided.val == 1:	glDisable(GL_CULL_FACE)
					
					clr = colors[face.materialIndex]
					if (gRenderType.val==2) or (gRenderType.val==3):
						texbuff = Buffer(GL_BYTE, 64*3,textures[face.materialIndex])
						glDisable(GL_TEXTURE_1D)
						glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 64, 0, GL_RGB, GL_UNSIGNED_BYTE, texbuff)
						glEnable(GL_TEXTURE_1D)
					elif (gRenderType.val>3):
						r1,g1,b1 = int(gGenCol[2][0]*255),int(gGenCol[2][1]*255),int(gGenCol[2][2]*255)
						r2,g2,b2 = int(clr[0]*255),int(clr[1]*255),int(clr[2]*255)
						j,i = 0,0
						for i in range(0,32*3,3):
							if gTextBits[j]:	
								gBmpTexture[i]=r1
								gBmpTexture[i+1]=g1
								gBmpTexture[i+2]=b1
							else:
								gBmpTexture[i]=r2
								gBmpTexture[i+1]=g2
								gBmpTexture[i+2]=b2
							j+=1
						del i,j,r1,g1,b1,r2,b2,g2
						params=[]
						if (gRenderType.val==4):	params=Buffer(GL_FLOAT,4,[1.0,0.0,0.0,0.0])
						elif (gRenderType.val==5):	params=Buffer(GL_FLOAT,4,[0.0,1.0,0.0,0.0])
						elif (gRenderType.val==6):	params=Buffer(GL_FLOAT,4,[0.0,0.0,1.0,0.0])
						glDisable(GL_TEXTURE_1D)
						glTexImage1D(GL_TEXTURE_1D, 0, GL_RGB, 32, 0, GL_RGB, GL_UNSIGNED_BYTE, gBmpTexture)
						glEnable(GL_TEXTURE_1D)
						glTexGeni(GL_S,GL_TEXTURE_GEN_MODE,GL_OBJECT_LINEAR)
						glTexGenfv(GL_S,GL_OBJECT_PLANE,params)
						glTexGeni(GL_T,GL_TEXTURE_GEN_MODE,GL_EYE_LINEAR)
						glTexGenfv(GL_T,GL_EYE_PLANE,params)
						glEnable(GL_TEXTURE_GEN_S)
					
						del params
					elif (gRenderType.val>-1) :
						glColor3f(clr[0],clr[1],clr[2])
					glPolygonMode(GL_FRONT,GL_FILL)
				
	
					mverts= []
					for iv in range(len(face.v)):
						pt1 = face.v[iv]
						vtx1 = MatMultVec(m2,Vector([pt1[0],pt1[1],pt1[2],1.0]))
						mverts.append([vtx1[0],vtx1[1],vtx1[2]])

					D = -1 * DotVecs(n,Vector([mverts[0][0],mverts[0][1],mverts[0][2],1.0]))
						
					#Create the Shadow Volume for the lamps that cast shadows
					if (len(LampLst)>0) and (gShadow.val>0):
						numlamp=0
						for lamp in LampLst:
							numlamp+=1
							if lamp[3]==0:	continue	#Skip lamps that don't cast shadows
							infinity=lamp[4]					#Lamp's Clip End
							visibility = DotVecs(n,Vector([lamp[0],lamp[1],lamp[2],1.0]))+D
							if visibility>0:
								_cn=[]	# Near Cap
								_cf=[] 	# Far Cap
								for iv in range(len(face.v)):
									# Find silhuette shadow
									v1 = face.v[iv-1].index
									v2 = face.v[iv].index
									if (numlamp,v1,v2) in lampedgedic:	lampedgedic[(numlamp,v1,v2)]=None
									elif (numlamp,v2,v1) in lampedgedic:	lampedgedic[(numlamp,v2,v1)]=None
									else:
										_v1 = Vector([mverts[iv-1][0]-lamp[0],mverts[iv-1][1]-lamp[1],mverts[iv-1][2]-lamp[2],1.0])
										_v1.normalize()
										_v2 = Vector([mverts[iv][0]-lamp[0],mverts[iv][1]-lamp[1],mverts[iv][2]-lamp[2],1.0])
										_v2.normalize()
										lampedgedic[(numlamp,v1,v2)] = [[mverts[iv][0],mverts[iv][1],mverts[iv][2]],
																					   [mverts[iv-1][0],mverts[iv-1][1],mverts[iv-1][2]],
																						 [mverts[iv-1][0]+(_v1[0]*infinity),mverts[iv-1][1]+(_v1[1]*infinity),mverts[iv-1][2]+(_v1[2]*infinity)],
							 															 [mverts[iv][0]+(_v2[0]*infinity),mverts[iv][1]+(_v2[1]*infinity),mverts[iv][2]+(_v2[2]*infinity)]]
									# Find Caps
									_v2 = Vector([mverts[iv][0]-lamp[0],mverts[iv][1]-lamp[1],mverts[iv][2]-lamp[2],1.0])
									_v2.normalize()
									_cn.append([mverts[iv][0]+(_v2[0]*0.001),mverts[iv][1]+(_v2[1]*0.001),mverts[iv][2]+(_v2[2]*0.001)])
									_cf.append([mverts[iv][0]+(_v2[0]*infinity),mverts[iv][1]+(_v2[1]*infinity),mverts[iv][2]+(_v2[2]*infinity)])
					
								_cf.reverse()
								capnear.append([numlamp,_cn])
								capfar.append([numlamp,_cf])	
								
										
														
					if gRenderType.val==2 or gRenderType.val>3:
						p1 = face.v[0]
						p1 = MatMultVec(m2,Vector([p1[0],p1[1],p1[2],1.0]))
						na = 0.0
						if len(LampLst)>0:
							# Obtain the Light Vector (Vertex to light source)
							for lamploc in LampLst:
								vLight =  Vector([lamploc[0]-p1[0],lamploc[1]-p1[1],lamploc[2]-p1[2],1.0])
								vLight.normalize()
								_a = DotVecs(vLight,n)
								if _a<0:	_a*=-1.0
								na+= _a
						else:
							#No lamps, so use camera position as lamp position
							vLight = Vector([obCamera.loc[0]-p1[0],obCamera.loc[1]-p1[1],obCamera.loc[2]-p1[2],1.0])
							vLight.normalize()
							na = max(DotVecs(vLight,n),0.0)
						if na>=1.0:	na = 0.99
						glBegin(GL_POLYGON)
						for v in face.v:
							glTexCoord1f(na) 
							glVertex3f(v[0], v[1], v[2])
						glEnd()	
					elif gRenderType.val==3:
						glBegin(GL_POLYGON)
						for v in face.v:
							p2 = Mesh.verts[v.index]
							p2 = MatMultVec(m2,Vector([p2[0],p2[1],p2[2],1.0]))
							n = Mesh.verts[v.index].no
							n =Vector([n[0],n[1],n[2],1.0])
							n = MatMultVec(invmat,n)
							n.normalize()
							na=0.0
							if len(LampLst)>0:
								# Obtain the Light Vector (Vertex to light source)
								for lamploc in LampLst:
									vLight =  Vector([lamploc[0]-p2[0],lamploc[1]-p2[1],lamploc[2]-p2[2],0.0])
									vLight.normalize()
									na+= (max(DotVecs(vLight,n),0.0)*1.85)
							else:
								#No lamps, so use camera position as lamp position
								vLight =   Vector([obCamera.loc[0]-p2[0],obCamera.loc[1]-p2[1],obCamera.loc[2]-p2[2],0.0])
								vLight.normalize()
								na = (max(DotVecs(vLight,n),0.0)*1.85)	
							if na>=1.0:	na = 0.99
							glTexCoord1f(na) 
							glVertex3f(v[0], v[1], v[2])
						glEnd()	
					else:
						glBegin(GL_POLYGON)
						for v in face.v:	glVertex3f(v[0], v[1], v[2])
						glEnd()	
					glDisable(GL_TEXTURE_1D)
				glPopMatrix()
				shadowlines.append([lampedgedic,capnear,capfar])
				
		numobj=numobj+1
	
	# Save image 
	glReadBuffer(GL_BACK)
	glReadPixels(Viewport[0]+11, Viewport[1]+50,width-1,height,GL_RGB,GL_UNSIGNED_BYTE,buffImage)
	glDisable(GL_TEXTURE_1D)
	
	m3.transpose()
	
	# -------------------------------------------
	# Filter
	# -------------------------------------------
	if (tofile>0):
		for j in range(w3,j3-w3,w3):
			for i in range(3,w3-3,3):
				r = buffImage[j+i]
				g = buffImage[j+i+1]
				b = buffImage[j+i+2]
				for ci in dictfilter:
					if (abs(ci[0]-r)<=8) and (abs(ci[1]-g)<=8) and (abs(ci[2]-b)<=8):
						buffImage[j+i] = ci[0]
						buffImage[j+i+1] = ci[1]
						buffImage[j+i+2] = ci[2]
						r,g,b =  ci[0], ci[1], ci[2]	
						break
		del dictfilter
										
	if (tofile>0) and gRenderType.val==2 or gRenderType.val==3: 
		for j in range(0,j3,w3):
			for i in range(0,w3,3):
				r = buffImage[j+i]
				g = buffImage[j+i+1]
				b = buffImage[j+i+2]
				gdic={}
				for j2 in [j-w3,j,j+w3]:
					for i2 in [i-3,i,i+3]:	
						try:
							ri,rg,rb = buffImage[j2+i2],buffImage[j2+i2+1],buffImage[j2+i2+2]		
							if 	(ri,rg,rb)	in gdic:
								gdic[(ri,rg,rb)]+=1
							else:
								gdic[(ri,rg,rb)]=1	
						except:
								pass
				num = gdic[(r,g,b)]			
				thekey = None	
				if num<3: 
					for key in gdic:
						if gdic[key]>=num: 
							num = gdic[key]
							thekey = key
					buff2[j+i] = thekey[0]
					buff2[j+i+1] =thekey[1]
					buff2[j+i+2] =thekey[2]		
				else:
					buff2[j+i] = r
					buff2[j+i+1] =g
					buff2[j+i+2] =b		 
		for j in range(0,j3,w3):
			for i in range(0,w3,3):
				buffImage[j+i] = buff2[j+i]
				buffImage[j+i+1] =buff2[j+i+1]
				buffImage[j+i+2]=buff2[j+i+2]	
	
				
	
									
	# -------------------------------------------
	# Set Flare obj
	# -------------------------------------------	
	if gFlare.val>0:
		gFlareLoc = [0,0]			
		for obj in obList:				
			if obj.name == gFlareObjName:
				cam =  obCamera.getInverseMatrix()
				cam.transpose()
				m1 = obj.matrixWorld 
				m1.transpose()
				mJ = cam * m1
				mJ = m3  * mJ
				mW = width>>1
				mH = height>>1
				p1 = MatMultVec(mJ,Vector([obj.loc[0],obj.loc[1],obj.loc[2],1.0]))
				px = (((p1[0]/p1[3])*mW)-0.5)+mW
				py = (((p1[1]/p1[3])*mH)-0.5)+mH
				gFlareLoc = [int(px),int(py)]
				del mJ,cam,mW,mH,p1,px,py
				break

		
	EDGE_OFFSET = 0.0001		
	# -------------------------------------------
	# Create black silhouette
	# -------------------------------------------		
	glEnable(GL_CULL_FACE)
	glEnable(GL_DEPTH_TEST)
	glCullFace(GL_BACK)
	glColor3f(0,0,0)
	if gRenderType.val>-1:
		numobj = 0
		for obj in obList:
			if (type(obj.data)==NMeshType) and ((obj.Layer & LayerMask)>0):
				glPushMatrix()
				mat = MatrixToBuffer(obj.matrixWorld)
				Mesh = NMesh.GetRawFromObject(obj.name) 
				glMultMatrixf(mat)
				for face in Mesh.faces:
					glBegin(GL_POLYGON)
					for v in face.v:
						glVertex3f(v[0], v[1], v[2])
					glEnd()		
				glPopMatrix()
			numobj+=1					

	glReadBuffer(GL_BACK)
	glReadPixels(Viewport[0]+11, Viewport[1]+50,width-1,height,GL_RGB,GL_UNSIGNED_BYTE,buffback)
	# Store black 
	gColordic[(0,0,0,255)]=0
	gColors.append([0,0,0,255])
	framebuff.append(buffback)	
	del buffback
	
	
	# Store color regions
	framebuff.append(buffImage)	
	
	# -------------------------------------------
	# Create Silhouettes, Lines, Material Lines
	# -------------------------------------------	
	
	if (gbSilhouette.val>0) or (gbLines.val>0) or (gbMaterial.val>0):
		glClearColor(1.0,1.0,1.0,1.0)
		glClear(GL_COLOR_BUFFER_BIT)
		glDepthRange(0.0,1.0-EDGE_OFFSET)
		glLineWidth(4.0)
		colorsil = 0
		for objmesh in gSilhouette:
			for dic in objmesh[1]:
				for key in dic:
					i = dic[key]
					if i<>None:
						colorsil+=16
						r = (colorsil>>16)
						g = ((colorsil>>8)&0xff)
						b = (colorsil&0xff)
						glColor3f(r/255.0, g/255.0, b/255.0)	
						glBegin(GL_LINES)
						glVertex3f(i[0][0],i[0][1],i[0][2])
						glVertex3f(i[1][0],i[1][1],i[1][2])
						glEnd()
		
		glLineWidth(1.0)
		glReadPixels(Viewport[0]+11, Viewport[1]+50,width-1,height,GL_RGB,GL_UNSIGNED_BYTE,buff2)	
		
		glDepthRange(0.0,1.0)
		
		mP = Matrix()
		cam =  obCamera.getInverseMatrix()
		cam.transpose()
		mP = m3 * cam
		mW = width>>1
		mH = height>>1
		fw = 10.0/float(width)
		fh = 100.0/float(height)
				
		colorsil =0
		numobj=0
		for objmesh in gSilhouette:
			matlines = [[],[],[]]
			linetype = -1	
			quad = [[None]*100,[None]*100,[None]*100]
			for dic in objmesh[1]:
				linetype+=1			
				for key in dic:
					i = dic[key]
					if i<>None:
						colorsil+=16
						hr,hg,hb = (colorsil>>16),((colorsil>>8)&0xff),(colorsil&0xff)
						iu = []
						glColor3f(hr/255.0, hg/255.0, hb/255.0)	
						p1 = MatMultVec(mP,Vector([i[0][0],i[0][1],i[0][2],1.0]))
						px = (((p1[0]/p1[3])*mW))+mW
						py = (((p1[1]/p1[3])*mH))+mH
						iu.append([px,py,0])
						p2 = MatMultVec(mP,Vector([i[1][0],i[1][1],i[1][2],1.0]))
						px = (((p2[0]/p2[3])*mW))+mW
						py = (((p2[1]/p2[3])*mH))+mH
						iu.append([px,py,0])
						#clipping
						iu = PolyClip(iu,0.0,0.0,float(width),float(height))
						if len(iu)>0:			
							vn = Vector([iu[1][0]-iu[0][0],iu[1][1]-iu[0][1]])
							d = int(sqrt((vn[0]*vn[0])+(vn[1]*vn[1])))
							edge1 = None
							edge2 = None
							if (d>3):
								d=d+1
								vn.normalize()						
								sflag = 0				
								edge1 = None
								edge2 = None
								for step in range(0,d):
									x = int(iu[0][0])+int(vn[0]*step)
									y = int(iu[0][1])+int(vn[1]*step)
									if (x>1) and (x<width-1) and (y>1) and (y<height-1):
										found = 0
										for px in [x-1,x,x+1]:
											for py in [y-1,y,y+1]:
												idx = (w3*py)+(px*3)
												ri,gi,bi = buff2[idx],buff2[idx+1],buff2[idx+2]
												if (ri==hr and gi==hg and bi==hb):
													found = 1
													break
											if found:	break
										if found:
											if sflag == 0:								
												edge1 = [int(x),int(y)]			
												sflag = 1
											else:
												edge2 = [int(x),int(y)]		
										else:
											sflag = 0
											if edge1<>None and edge2<>None and (not((edge1[0]==edge2[0]) and (edge1[1]==edge2[1]))):
												id = len(matlines[linetype])
							
												qidx = min(99,int((edge1[1]*fh) + (edge1[0]*fw)))
												if quad[linetype][qidx] == None:	quad[linetype][qidx] = [id]
												elif id not in quad[linetype][qidx]:	quad[linetype][qidx].append(id)
						
												qidx = min(99,int((edge2[1]*fh) + (edge2[0]*fw)))
												if quad[linetype][qidx] == None:	quad[linetype][qidx] = [id]
												elif id not in quad[linetype][qidx]:	quad[linetype][qidx].append(id)
						
												matlines[linetype].append([[edge1[0],edge1[1],edge2[0],edge2[1]],[-1,99],0])
												
											edge1=None
											edge2=None
							else:
								found = 0
								for point in iu:
									x = int(point[0])
									y = int(point[1])
									if (x>1) and (x<width-1) and (y>1) and (y<height-1):
										for px in [x-1,x,x+1]:
											for py in [y-1,y,y+1]:
												idx = (w3*py)+(px*3)
												ri,gi,bi = buff2[idx],buff2[idx+1],buff2[idx+2]
												if (ri==hr and gi==hg and bi==hb):
													found = found + 1
													break
								if found>2:
									edge1 = [int(iu[0][0]),int(iu[0][1])]						
									edge2 = [int(iu[1][0]),int(iu[1][1])]						
															
							if edge1<>None and edge2<>None and (not((edge1[0]==edge2[0]) and (edge1[1]==edge2[1]))):
								id = len(matlines[linetype])
	
								qidx = min(99,int((edge1[1]*fh) + (edge1[0]*fw)))
								if quad[linetype][qidx] == None:	quad[linetype][qidx] = [id]
								elif id not in quad[linetype][qidx]:	quad[linetype][qidx].append(id)
							
								qidx = min(99,int((edge2[1]*fh) + (edge2[0]*fw)))
								if quad[linetype][qidx] == None:	quad[linetype][qidx] = [id]
								elif id not in quad[linetype][qidx]:	quad[linetype][qidx].append(id)			
																					#   segment, id neighboard, angle neighboard, flag
								matlines[linetype].append([[edge1[0],edge1[1],edge2[0],edge2[1]],[-1,99],0])
							
			#Link segments  
			linetype = 0
			for m in matlines:
				for idx in range(len(m)):
					e1 = m[idx][0]
					#Get posible match
					qidx = min(99,int((e1[3]*fh) + (e1[2]*fw)))
					pmatch = []
					if quad[linetype][qidx]<>None:	pmatch.extend(quad[linetype][qidx])
					if qidx>1 and quad[linetype][qidx-1]<>None:	pmatch.extend(quad[linetype][qidx-1])
					if qidx<99 and quad[linetype][qidx+1]<>None:	pmatch.extend(quad[linetype][qidx+1])
					if qidx>9 and quad[linetype][qidx-10]<>None: 	pmatch.extend(quad[linetype][qidx-10])
					if qidx<89 and quad[linetype][qidx+10]<>None: 	pmatch.extend(quad[linetype][qidx+10])	
					box = [e1[2]-2,e1[3]+3,e1[2]+2,e1[3]-3]
										
					for idx2 in pmatch:
						if idx2<>idx:
							e2 = m[idx2][0]
							v1 = Vector([e1[2]-e1[0],e1[3]-e1[1]])
							v2 = Vector([e2[2]-e2[0],e2[3]-e2[1]])
							angle = int(AngleBetweenVecs(v1,v2))
							if angle<135:
								if (e2[0]>=box[0]) and (e2[0]<=box[2]) and (e2[1]>=box[3]) and (e2[1]<=box[1]):
									if m[idx][1][0] <> idx2:
										if angle<m[idx][1][1]:
											m[idx][1][0] = idx2
											m[idx][1][1] = angle
											x = (e1[2]+e2[0])>>1
											y = (e1[3]+e2[1])>>1
											e1[2] = x
											e1[3] = y
											e2[0] = x
											e2[1] = y	
				linetype+=1
			del quad,linetype
														
			# Store colors					
			idx=[0,0,0,0]
			for i in range(3):
				r,g,b = int(gGenCol[i][0]*255),int(gGenCol[i][1]*255),int(gGenCol[i][2]*255)
				if (r,g,b,255) in gColordic:
					idx[i] = gColordic[(r,g,b,255)]
				else:	
					idx[i] = len(gColordic)	
					gColordic[(r,g,b,255)] = idx[i]
					gColors.append([r,g,b,255])	

				
			# Store points
			numx = 0
			numidx = 0
			for linetype in matlines:				
				numx-=1	
				for segment in linetype:
					if segment[2]==0:
						edge = segment[0]
						idvec = len(gVertexLst)
						gVertexLst.append([[edge[0],edge[1]],idx[numidx],9,-1,-1])   #Xi
						gVertexLst.append([[edge[2],edge[3]],idx[numidx],9,-1,-1])  		#Xf 	
						lstpts = [idvec,idvec+1]	
						nextedge = segment[1][0]
						segment[2] = 1
						while (nextedge<>-1 and linetype[nextedge][2]	== 0) :
							p1 = [edge[2],edge[3]]
							edge= linetype[nextedge][0]
							p2 = [edge[0],edge[1]]
							idvec = len(gVertexLst)
							d = int(dist(p1,p2))
							if d<=3:
								p1 = [(p1[0]+p2[0])>>1,(p1[1]+p2[1])>>1]
								gVertexLst[-1][0] = [p1[0],p1[1]]
							else:				
								gVertexLst.append([[edge[0],edge[1]],idx[numidx],9,-1,-1])   #Xi
								lstpts.append(idvec)
								idvec = idvec + 1						
							gVertexLst.append([[edge[2],edge[3]],idx[numidx],9,-1,-1])  		#Xf 								
							lstpts.append(idvec)
							linetype[nextedge][2]	= 1
							nextedge = linetype[nextedge][1][0]	
						
						if len(lstpts)==2:
							p1 = gVertexLst[lstpts[0]][0]
							p2 = gVertexLst[lstpts[1]][0]
							#d = int(dist(p1,p2))
							#if d>5:	
							gLineRegions.append([[numobj,numx],lstpts])
						else:
							lstpts = curve_aprox(lstpts,0) # Curve Optimization	
							gLineRegions.append([[numobj,numx],lstpts])	
																
				numidx+=1
			del numx,numidx
			del idx
			
			numobj = numobj + 1  			
	# -------------------------------------------
	# Create Shadows
	# -------------------------------------------	
	if (gShadow.val>0):
		glClearColor(1.0,1.0,1.0,1.0)
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
		glEnable(GL_CULL_FACE)
		glCullFace(GL_BACK)
		glColor3f(1,1,1)
		if gRenderType.val>-1:
			numobj = 0
			for obj in obList:
				if (type(obj.data)==NMeshType) and ((obj.Layer & LayerMask)>0):
					glPushMatrix()
					mat = MatrixToBuffer(obj.matrixWorld)
					Mesh = NMesh.GetRawFromObject(obj.name) 
					glMultMatrixf(mat)
					for face in Mesh.faces:
						glBegin(GL_POLYGON)
						for v in face.v:
							glVertex3f(v[0], v[1], v[2])
						glEnd()		
					glPopMatrix()
				numobj+=1					
		bsz = width*height*3
		numlamp=0
		# For each lamp that cast shadows do ...
		for lamp in LampLst:
			numlamp+=1
			if lamp[3]==0:	continue	#Skip lamps that don't cast shadows
			glColor3f(1,1,1)
			tempbuff= Buffer(GL_BYTE,bsz,[255]*bsz)
	 		# Clear background and foregound
			glRasterPos2d(10,50)
			glBegin(GL_QUADS)
			glVertex2d(10,50)
			glVertex2d(10+width,50)
			glVertex2d(10+width,50+height)
			glVertex2d(10,50+height)
			glEnd()
			glDrawPixels(width,height,GL_RGB,GL_UNSIGNED_BYTE,tempbuff)
			# Draw the Scene
			glEnable(GL_CULL_FACE)
			glCullFace(GL_BACK)
			
			numobj = 0
			for obj in obList:
				if (type(obj.data)==NMeshType) and ((obj.Layer & LayerMask)>0):
					if ObjLst[numobj]:
						glPushMatrix()
						mat = MatrixToBuffer(obj.matrixWorld)
						Mesh = NMesh.GetRawFromObject(obj.name) 
						glMultMatrixf(mat)
						for face in Mesh.faces:
							glBegin(GL_POLYGON)
							for v in face.v:
								glVertex3f(v[0], v[1], v[2])
							glEnd()		
						glPopMatrix()
					numobj+=1
			# Draw Shadows

			glEnable(GL_BLEND)
			glDepthMask(GL_FALSE)
			glEnable(GL_CULL_FACE)
			
			for triplet in shadowlines:
				edgelst= triplet[0]
				glCullFace(GL_BACK)
				glBlendFunc(GL_DST_COLOR,GL_ZERO)		
				glColor4f(0.5,0.5,0.5,1)
				for key in edgelst:
					if key[0] == numlamp:
						edge = edgelst[key]
						if edge<>None:
							i = edge
							glBegin(GL_QUADS)
							glVertex3f(i[0][0],i[0][1],i[0][2])
							glVertex3f(i[1][0],i[1][1],i[1][2])
							glVertex3f(i[2][0],i[2][1],i[2][2])
							glVertex3f(i[3][0],i[3][1],i[3][2])
							glEnd()
		
				for cap in triplet[1]:
					if cap[0] == numlamp:
						glBegin(GL_POLYGON)
						for i in cap[1]:
							vk = Vector([i[0]-obCamera.loc[0],i[1]-obCamera.loc[1],i[2]-obCamera.loc[2]])
							vk.normalize()
							vk *=2 
							glVertex3f(i[0]+vk[0],i[1]+vk[1],i[2]+vk[2])
						glEnd()
				for cap in triplet[2]:
					if cap[0] == numlamp:
		 				glBegin(GL_POLYGON)
						for i in cap[1]:
							glVertex3f(i[0],i[1],i[2])
						glEnd()		
				
				glCullFace(GL_FRONT)
				glBlendFunc(GL_DST_COLOR,GL_ONE)
				glColor4f(1,1,1,0.5)
				for key in edgelst:
					if key[0] == numlamp:
						edge = edgelst[key]
						if edge<>None:
							i = edge
							glBegin(GL_QUADS)
							glVertex3f(i[0][0],i[0][1],i[0][2])
							glVertex3f(i[1][0],i[1][1],i[1][2])
							glVertex3f(i[2][0],i[2][1],i[2][2])
							glVertex3f(i[3][0],i[3][1],i[3][2])
							glEnd()
				
				for cap in triplet[1]:
					if cap[0] == numlamp:
						glBegin(GL_POLYGON)
						for i in cap[1]:
							vk = Vector([i[0]-obCamera.loc[0],i[1]-obCamera.loc[1],i[2]-obCamera.loc[2]])
							vk.normalize()
							vk *=2 
							glVertex3f(i[0]+vk[0],i[1]+vk[1],i[2]+vk[2])
						glEnd()
				for cap in triplet[2]:
					if cap[0] == numlamp:
		 				glBegin(GL_POLYGON)
						for i in cap[1]:
							glVertex3f(i[0],i[1],i[2])
						glEnd()	
							
			glDepthMask(GL_TRUE)
			glDisable(GL_BLEND)
			glCullFace(GL_BACK)
			
			glReadBuffer(GL_BACK)
			glReadPixels(Viewport[0]+11, Viewport[1]+50,width-1,height,GL_RGB,GL_UNSIGNED_BYTE,tempbuff)
		
			#Binarize (W&B)	
			for j in range(0,j3,w3):
				for i in range(0,w3,3):
					if ((tempbuff[j+i]<255) or (tempbuff[j+i+1]<255) or (tempbuff[j+i+1]<255)):
						tempbuff[j+i] = int(gGenCol[5][0]*255)
						tempbuff[j+i+1] = int(gGenCol[5][1]*255)
						tempbuff[j+i+2] = int(gGenCol[5][2]*255)
						
			# Save shadow for lamp n
			framebuff.append(tempbuff)

	glPopAttrib()
	glMatrixMode(GL_PROJECTION)
	glPopMatrix()
	glMatrixMode(GL_MODELVIEW)
	glPopMatrix()
	glViewport(Viewport[0]+10, Viewport[1]+51, Viewport[2],Viewport[3])	
	
	
	# -------------------------------------------
	# FX Pixelate and voronoi
	# -------------------------------------------		
	if gFX.val:
		mr = int(gGenCol[6][0]*255.0)	# Mask color
		mg = int(gGenCol[6][1]*255.0)
		mb = int(gGenCol[6][2]*255.0)	
		kr = int(gGenCol[4][0]*255.0)	# BackColor color
		kg = int(gGenCol[4][1]*255.0)
		kb = int(gGenCol[4][2]*255.0)		
		if gFXType.val == 0:
			#__________________________________
			# Pixelate 
			#__________________________________
			l1 = width/gLevel.val
			l2 = height/gLevel.val
			lw = l2 * w3
			l3 = l1 * 3
			ll = l1 * l2
			for j in range(0,j3,lw):
				for i in range(0,w3,l3):
					r = 0
					g = 0
					b = 0
					count = 0
					for bj in range(j,j+lw,w3):
						for bi in range(i,i+l3,3):
							try:
								wr= buffImage[bj+bi] 
								wg= buffImage[bj+bi+1] 
								wb= buffImage[bj+bi+2]
								if (wr==mr) and (wg==mg) and (wb==mb):
									r+= kr
									g+= kg
									b+= kb
								else: 
									r+= wr
									g+= wg
									b+= wb
							except:
								r += 128
								g += 128
								g += 128
					r /=ll
					g /=ll
					b /=ll

					for bj in range(j,j+lw,w3):
						for bi in range(i,i+l3,3):
							try:
								buffImage[bj+bi]   = r
								buffImage[bj+bi+1] = g
								buffImage[bj+bi+2] = b 
							except:	pass
		elif gFXType.val == 1:
			#__________________________________
			# Voronoi
			#__________________________________
			if gEnableMask.val:
				r,g,b = kr,kg,kb	#Background color
			else:
				r,g,b = int(gGenCol[5][0]*255.0),int(gGenCol[5][1]*255.0),int(gGenCol[5][2]*255.0)	#Shadow color
			denom = max(gLevel.val*1.0,10.0)
			j,j1,i,i1 = 0,0,0,0
			for j in range(0,j3,w3):
				i1 = 0
				for i in range(0,w3,3):
					if (noise([i1/denom,j1/denom,0.0],NoiseTypes.VORONOI_CRACKLE)<0.5):
						buffImage[j+i]   = r
						buffImage[j+i+1] = g
						buffImage[j+i+2] = b
					i1+=1
	 			j1+=1

			del j,i,j1,i1
			
		del kr,kg,kb,mr,mb,mg
							
#	glEnable(GL_LINE_SMOOTH)
			
	# -------------------------------------------
	# Draw shadows
	# -------------------------------------------	
	if (tofile==0) and (gShadow.val>0) and (len(framebuff)>2): 
		mr = int(gGenCol[5][0]*255.0)
		mg = int(gGenCol[5][1]*255.0)
		mb = int(gGenCol[5][2]*255.0)
		for j in range(0,j3,w3):
				for i in range(0,w3,3):
					for numbuff in range(2,len(framebuff)):
						buff = framebuff[numbuff]
						if (buff[j+i]==mr) and  (buff[j+i+1]==mg) and (buff[j+i+2]==mb):
							buffImage[j+i]   = (buffImage[j+i] >> 1) + (mr >> 1)
							buffImage[j+i+1] = (buffImage[j+i+1] >> 1) + (mg >> 1)
							buffImage[j+i+2] = (buffImage[j+i+2] >> 1) + (mb >> 1)
		del mr,mg,mb
							
	# -------------------------------------------
	# Draw silhouette and lines
	# -------------------------------------------		
	if (tofile==0 or gStrokes.val) and ((gbLines.val>0) or (gbSilhouette.val>0) or (gbMaterial.val>0)):
		bsz = width*height*3
		buff2 = Buffer(GL_BYTE,bsz,[0]*bsz)
		del bsz
		glClearColor(1.0,1.0,1.0,1.0)
		glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

		if gStrokes.val == 0:
			flst = [0.0,0.2,0.4,0.6,0.8,1.0]
			for i in	gLineRegions:
				linedraw = 1
				if (i[0][1]==-1) and (gbSilhouette.val>0):
					glColor3f(gGenCol[3][0],gGenCol[3][1],gGenCol[3][2])
					glLineWidth(gSilWidth.val)
				elif (i[0][1] == -2) and (gbLines.val>0) :
					glColor3f(gGenCol[2][0],gGenCol[2][1],gGenCol[2][2])
					glLineWidth(gLineWidth.val)	
				elif (i[0][1] == -3) and (gbMaterial.val>0):
					glColor3f(gGenCol[1][0],gGenCol[1][1],gGenCol[1][2])
					glLineWidth(gMatWidth.val)	
				else:
					linedraw=0	
			
				if linedraw:	
					glBegin(GL_LINE_STRIP)
					for j in i[1]:
						if str(type(j))=="<type 'list'>":
							for fix in flst:
								p1 = bez3(j[0],j[1],j[2],fix)
								glVertex2d(p1[0],p1[1])	
						else:
							p1 = 	gVertexLst[j][0]
							glVertex2d(p1[0],p1[1])
					glEnd()
			del flst
			glLineWidth(1.0)	
		
		else:
			for stk in	gLineRegions:
				lst = stk[1]
				sz = len(lst)
				midsz = sz/2
				szline = 0
				
				if (stk[0][1]==-1) and (gbSilhouette.val>0):	szline=float(gSilWidth.val)
				elif (stk[0][1] == -2) and (gbLines.val>0) :	szline=float(gLineWidth.val)
				elif (stk[0][1] == -3) and (gbMaterial.val>0):	szline=float(gMatWidth.val)
				for i in range(sz-1):
					currsz = float(szline)
					perc = i/float(sz)
					if (gIncrement.val) and (gDecrement.val):
						if i< midsz:	currsz *= perc
						else:	currsz *= (1.0-perc)
					elif (gIncrement.val):	currsz *= perc
					elif (gDecrement.val):	currsz *= (1.0-perc)
					halfsz = int((currsz/2.0)+0.5)
					if halfsz<=0: halfsz=1
						
					if (str(type(lst[i]))<>"<type 'list'>"):
						p = gVertexLst[lst[i]][0]
						q = []
						if (i+1==sz):	j=i-1
						else:	j=i+1
						if (str(type(lst[j]))<>"<type 'list'>"):
							q = gVertexLst[lst[j]][0]
						else:
							q = lst[j][0]
						v = Vector([q[0]-p[0],q[1]-p[1]])
						v.normalize()
						d = int(dist(p,q))
						midsz = d/2.0	
						for j in range(0,d,gSpacing.val):
							rv =[0,0]
							if (gNoise.val):	rv = Blender.Noise.randuvec()
							dx = int(p[0]+(v[0]*j)+rv[0]*gSpacing.val)
							dy = int(p[1]+(v[1]*j)+rv[1]*gSpacing.val)
							k = 4 + stk[0][1]
							glColor3f(gGenCol[k][0],gGenCol[k][1],gGenCol[k][2])
							drawBrush(dx,dy,halfsz)
					else:
						j = lst[i]
						d = dist(j[0],j[1])	
						d += dist(j[1],j[2])
						delta =float(gSpacing.val)/d
						numdiv = int(d)/gSpacing.val
						flst = []
						for xi in range(numdiv+1):
							r = xi*delta
							if r>1.0:	r=1.0
							elif r<0:	r=0.0
							flst.append(r)
						for u in flst:
							p = bez3(j[0],j[1],j[2],u)
							q = bez3(j[0],j[1],j[2],u+delta)
							v = Vector([q[0]-p[0],q[1]-p[1]])
							v.normalize()	
							rv =[0,0]
							if (gNoise.val):	rv = Blender.Noise.randuvec()
							dx = int(p[0]+rv[0]*gSpacing.val)
							dy = int(p[1]+rv[1]*gSpacing.val)
							k = 4 + stk[0][1]
							glColor3f(gGenCol[k][0],gGenCol[k][1],gGenCol[k][2])
							drawBrush(dx,dy,halfsz)
						k = i+1
						if (k<>sz):
							p = [j[2][0],j[2][1]]
							if (str(type(lst[k]))<>"<type 'list'>"):
								q = gVertexLst[lst[k]][0]
							else:
								q = lst[k][0]	
							v = Vector([q[0]-p[0],q[1]-p[1]])
							v.normalize()
							d = int(dist(p,q))
							for j in range(0,d,gSpacing.val):
								rv =[0,0]
								if (gNoise.val):	rv = Blender.Noise.randuvec()
								dx = int(p[0]+(v[0]*j)+rv[0]*gSpacing.val)
								dy = int(p[1]+(v[1]*j)+rv[1]*gSpacing.val)
								k = 4 + stk[0][1]
								glColor3f(gGenCol[k][0],gGenCol[k][1],gGenCol[k][2])
								drawBrush(dx,dy,halfsz)
			del gLineRegions
							
		glReadPixels(Viewport[0]+11, Viewport[1]+50,width-1,height,GL_RGB,GL_UNSIGNED_BYTE,buff2)	
		for j in range(0,j3,w3):
			for i in range(0,w3,3):
				if (buff2[j+i]==255) and  (buff2[j+i+1]==255) and (buff2[j+i+2]==255):
					pass
				else:
						buffImage[j+i]   = buff2[j+i] 
						buffImage[j+i+1] = buff2[j+i+1]
						buffImage[j+i+2] = buff2[j+i+2] 
	
#	glDisable(GL_LINE_SMOOTH)			
			
	del buff2,w3,j3,bj3
	del LayerMask
	del gSilhouette
		
	gRendering = 0
	return	0			

# ---------------------------------------------------------------
# Function	: linear_aprox
#	Inputs		:
# OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def linear_aprox(lst):
	global	gVertexLst,gMinDistance

	e = 0.0; idxe = 0
		
	if ((lst[0]==lst[-1]) and len(lst)>2):
		e = 10.0
		idxe = len(lst)/2
	else:
		pi = gVertexLst[lst[0]][0]
		pf = gVertexLst[lst[-1]][0]
		v = Vector([pf[0]-pi[0],pf[1]-pi[1]])
		v.normalize()
		mv = abs((v[0]*v[0])+(v[1]*v[1]))

		for i in range(1,len(lst)-1):
			p = gVertexLst[lst[i]][0]
			u = Vector([p[0]-pi[0],p[1]-pi[1]])
			dv = DotVecs(u,v)
			if mv==0.0:	d = 0
			else:
				try:
					fat=(dv/mv)
					proyu = Vector([v[0]*fat,v[1]*fat])
					proyu = [proyu[0]+pi[0],proyu[1]+pi[1]]
					w = [p[0]-proyu[0], p[1]-proyu[1]]
					d = sqrt((w[0]*w[0])+(w[1]*w[1]))
				except:
					d = 0
			if d>=e:
				e = d
				idxe = i
	if (e<gMinDistance.val):
		return [lst[0],lst[-1]]
	else:
		if len(lst)>2:
			l1 = lst[0:idxe+1]
			l2 = lst[idxe:]
			l1 = linear_aprox(l1)
			l2 = linear_aprox(l2)
			l2 = l2[1:]
			l1.extend(l2)
			return l1
		else:	return lst
			
# ---------------------------------------------------------------
# Function	: curve_aprox
#	Inputs		:
# OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	

def curve_aprox(lst,cycle=1): 
	global	gVertexLst,gCurveMax
	sz = len(lst)
	if sz<3:	return lst
	start = 0
	end = sz
	outlst = []
	if cycle<1:
		outlst.append(lst[0])
		start = 1
		end = sz - 1
	item = 0		
	for i in range(start,end):
		p1 = gVertexLst[lst[i-1]][0]
		p2 = gVertexLst[lst[i]][0]
		if (i+1)==sz:	j = 0
		else: j = i+1
		p3 = gVertexLst[lst[j]][0]
		v1 = Vector([p1[0]-p2[0],p1[1]-p2[1]])
		v2 = Vector([p3[0]-p2[0],p3[1]-p2[1]])
		angle = int(AngleBetweenVecs(v1,v2))
		q1 = getMid(p1,p2)
		q2 = getMid(p2,p3)
		v = [q1[0]-q2[0],q1[1]-q2[1]]
		ptv = getMid(q1,q2)
		tv = Vector([ptv[0]-p2[0],ptv[1]-p2[1]])
		if (tv[0]<>0 or tv[1]<>0):	tv.normalize()
		r1 = [p2[0]+(tv[0]*1.2),p2[1]+(tv[1]*1.2)]
		L1 = [p2[0],p2[1],q1[0],q1[1]]
		L2 = [r1[0],r1[1],r1[0]+v[0],r1[1]+v[1]]
		pt1 = IntersectLines(L1,L2)
		item = lst[i]
		if pt1<>None and (str(pt1[0])<>sNAN) and  (str(pt1[1])<>sNAN):
			d1 = dist(q1,p2)
			d2 = dist(q1,pt1)
			g = d2/d1
			a = (4*g)/3
			sa = str(a)
			if sa==sNAN or sa==sINF:
				print "NaN!"
			else:	
				if a>=0.25 and a<=gCurveMax.val:
					item = [[q1[0],q1[1]],[p2[0],p2[1]],[q2[0],q2[1]]]
		outlst.append(item)
	if (cycle<1):	outlst.append(lst[-1])
	return outlst

# ---------------------------------------------------------------
# Function	: ScanImage
#	Inputs		:
# OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def ScanImage(width,height,framebuff):
	global gVertexLst,gColordic, gColors, gGenCol,gEnableMask
	mr = int(gGenCol[6][0]*255.0)	# Mask color
	mg = int(gGenCol[6][1]*255.0)
	mb = int(gGenCol[6][2]*255.0)								
	for numbuff in range(len(framebuff)):
		buff = framebuff[numbuff]	
		#__________________________________
		# Scanning image 
		#__________________________________
		rb,gb,bb=-10,-10,-10
		sz = 0
		# 			   				 0     1     2    3    4   
		# gVertexLst = ((x,y),clridx,flag,prev,next)
		r0 = []
		r1 = []
		xi= 0
		w3 = width * 3
		top = w3-3
		idx = 0
		first = 0
		xf = 0
		for j in range(0,height,1):
			flag=0
			rb,gb,bb,ab=-10,-10,-10,-10
			jw = j*w3
			for i in range(0,w3,3):
					if numbuff > 1:	# shadows
						a = 127 - numbuff
					else:						# colors
						a = 255
					r=buff[jw+i]
					g=buff[jw+i+1]
					b=buff[jw+i+2]
					if abs(r-rb)>9 or abs(g-gb)>9 or abs(b-bb)>9 or abs(a-ab)>9 or i==top or j==height-1: 
						if flag==0:	flag = 1
						else:
							if (rb,gb,bb,ab) in gColordic:
								idx = gColordic[(rb,gb,bb,ab)]
							else:	
								idx = len(gColordic)	
								gColordic[(rb,gb,bb,ab)]=idx
								gColors.append([rb,gb,bb,ab])
							if (numbuff == 1) and (rb==0 and gb==0 and bb == 0):
								pass
							elif (numbuff > 1) and (rb==255 and gb==255 and bb == 255):
								pass
							elif (gEnableMask.val) and (rb==mr and gb==mg and bb == mb):
								pass
							else:
								xf = i/3
								sz = len(gVertexLst)
								if sz<0:	sz = 0
								gVertexLst.append([[xi-0.5,j+0.5],idx,0,sz+3,sz+1]) #Xi'
								gVertexLst.append([[xi-0.5,j-0.5],idx,0,sz,sz+2])   #Xi"
								gVertexLst.append([[xf+0.5,j-0.5],idx,0,sz+1,sz+3])	#Xf'
								gVertexLst.append([[xf+0.5,j+0.5],idx,0,sz+2,sz])	#Xf"
								r1.append([[xi,j],[xf,j],sz,idx]) #(Xi,Xf,idxXi',coloridx)
							
						xi= i/3
						rb,gb,bb,ab = r,g,b,a
				
			if first == 0:
				first = 1
			else:
				for _f in r1:
					dyi = _f[0]
					dyf = _f[1]
					for _i in r0:
						# Check intersect range of pairs
						dxi = _i[0]
						dxf = _i[1]
						if (_f[3]==_i[3]): #Same color
							if (((dyi<=dxf) and (dyi>=dxi)) or ((dyf<=dxf) and (dyf>=dxi))) or (((dxi>=dyi) and (dxi<=dyf)) or ((dxf>=dyi) and (dxf<=dyf))):
								# intersection
								z0 = gVertexLst[_f[2]+2][3]
								z1 = gVertexLst[_i[2]+3][4]
								z2 = _f[2]+2
								z3 = _i[2]+3
								gVertexLst[z0][4] = z1
								gVertexLst[z1][3] = z0
								gVertexLst[z3][4] = z2
								gVertexLst[z2][3] = z3
			r0 = r1
			r1 = []
		
	del r0,r1
	del	rb,gb,bb,xi,xf,idx,sz
	del w3,top,first

	framebuff[0]=None
	for i in range(1,len(framebuff)):
		buff = framebuff[i]
		del buff
		buff = 0
	del framebuff
	framebuff = []


# ---------------------------------------------------------------
# Function	: StrokeGeneration
#	Inputs		:
# OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def StrokeGeneration(stroke):
	global gSilWidth,LineWidth,gMatWidth,gIncrement,gDecrement,gNoise
	global gVertexLst
	
	lst = stroke[1]
	sz = len(lst)
	midsz = float(sz/2)
	szline = 0
	if (stroke[0][1]==-1):	szline=gSilWidth.val
	elif (stroke[0][1]==-2):	szline=gLineWidth.val
	elif (stroke[0][1]==-3):	szline=gMatWidth.val
	noisediv = 3 	#pixels
	outlst1 = []
	outlst2 = []
	lastv=[0,0]
	for i in range(sz-1):
		currsz = szline
		if (gIncrement.val == 1) and (gDecrement.val==1):
			if i==midsz: currsz = szline
			elif i< midsz:	currsz = (i/midsz)*szline
			else:	currsz = szline - ((i/midsz)*szline)
		elif (gIncrement.val == 1):	currsz = (i/float(sz))*szline
		elif (gDecrement.val==1):	currsz = szline - ((i/float(sz))*szline)			
		w = currsz/2	
		if (str(type(lst[i]))<>"<type 'list'>"):
			p = gVertexLst[lst[i]][0]
			q = []
			if (str(type(lst[i+1]))<>"<type 'list'>"):
				q = gVertexLst[lst[i+1]][0]
			else:
				q = lst[i+1][0]
			d = dist(p,q)
			v = Vector([q[0]-p[0],q[1]-p[1]])
			v.normalize()
			t1 = [-(v[1]*w),v[0]*w]
			t2 = [v[1]*w,-(v[0]*w)]
			outlst1.append([p[0]+t1[0],p[1]+t1[1]])
			outlst2.append([p[0]+t2[0],p[1]+t2[1]])
			if (gNoise.val) and ((i+1)<sz):
				for j in range(0,d,noisediv):
					rv = Blender.Noise.randuvec()
					outlst1.append([int(p[0]+(v[0]*j)+(t1[0]+rv[0])),int(p[1]+(v[1]*j)+(t1[1]+rv[1]))])
					outlst2.append([int(p[0]+(v[0]*j)+(t2[0]+rv[0])),int(p[1]+(v[1]*j)+(t2[1]+rv[1]))])
		else:
			if (gNoise.val):
				for u in [0.0,0.2,0.4,0.6,0.8,1.0]:
					if u>0.8:	v = Vector(lastv)
					else:
						j = lst[i]
						p = bez3(j[0],j[1],j[2],u)
						q = bez3(j[0],j[1],j[2],u+0.2)
						d = dist(p,q)
						v = Vector([q[0]-p[0],q[1]-p[1]])
						v.normalize()
					t1 = [-(v[1]*w),v[0]*w]
					t2 = [v[1]*w,-(v[0]*w)]
					rv = Blender.Noise.randuvec()
					outlst1.append([int(p[0]+v[0]+(t1[0]+rv[0])),int(p[1]+v[1]+(t1[1]+rv[1]))])
					outlst2.append([int(p[0]+v[0]+(t2[0]+rv[0])),int(p[1]+v[1]+(t2[1]+rv[1]))])
			else:
				p = lst[i][0]
				q = lst[i][2]
				v = Vector([q[0]-p[0],q[1]-p[1]])
				v.normalize()
				t1 = [-(v[1]*w),v[0]*w]
				t2 = [v[1]*w,-(v[0]*w)]
				outlst1.append([p[0]+t1[0],p[1]+t1[1]])
				outlst2.append([p[0]+t2[0],p[1]+t2[1]])
				r =  bez3(i[0],i[1],i[2],0.5)
				outlst1.append([r[0]+t1[0],r[1]+t1[1]])
				outlst2.append([r[0]+t2[0],r[1]+t2[1]])
				outlst1.append([q[0]+t1[0],q[1]+t1[1]])
				outlst2.append([q[0]+t2[0],q[1]+t2[1]])

	outlst2.reverse()
	outlst1.extend(outlst2)
	ans = [[1,stroke[0][1]],outlst1]
	return ans
	
# ---------------------------------------------------------------
# Function	: Vectorize
#	Inputs		:
# OutPuts 	:
#	Description	:
# ---------------------------------------------------------------	
def Vectorize(width,height,colors):
	global gGenCol,gCurrentFrame,gLineWidth,gVertexLst
	global gbLines,gFlare
	global gSilWidth,gMatWidth,gbToonLines,gToonWidth
	global buffImage,gLineRegions,gbSilhouette,gbLines,gbMaterial,gStrokes
	
	sh = bShape()
	sh.Reset()
	movie = []
	
	#_________________________________
	# Optimize links
	#__________________________________	
	RegionVectors=[]				
	sz = len(gVertexLst)
	
	for numv in range(sz):
		area = 0
		v = gVertexLst[numv]
		lstpts = []
		idx = numv
		while v[2]==0:
			v[2] = 1
			lstpts.append(idx)	
			idx = v[4]
			v = gVertexLst[v[4]]
			if idx == numv:	lstpts.append(idx)
				
		if len(lstpts)>3:
			v = gVertexLst[lstpts[0]][1]
			lstpts = linear_aprox(lstpts)		# Linear Optimization
			lstpts.pop()
			if len(lstpts)>3:				
				lstpts = curve_aprox(lstpts) # Curve Optimization	
				if len(lstpts)>3:					
					RegionVectors.append([v,lstpts])
		del lstpts
	# Sort by color idx		
	RegionVectors.sort()	

	#Add lines
	if gStrokes.val==0:
		if len(gLineRegions)>0:
			for i in gLineRegions:
			#	i = StrokeGeneration(i)
				RegionVectors.append(i)
	
	#__________________________________
	# Create SWF file
	#__________________________________	

	h = height
	a = FILLSTYLEARRAY([FILLSTYLE(SOLID_FILL,[255,0,0,255])])
	b = LINESTYLEARRAY([LINESTYLE(1,[0,0,0,255])])
	
	oldcoloridx=-1
	coloridx =-1
	colorflag=0
	linetrans = 1
	fillshape = 1
	stroke = 0
	for q in RegionVectors:
		region = q[1]
		
		sz = len(region)
		stroke = 0
		if sz>0:
			if (str(type(q[0]))<>"<type 'list'>"):
				coloridx = q[0]
				color=colors[coloridx]
				# Set color flag that identify when a color idx has change	
				if (coloridx==oldcoloridx):	colorflag=0
				else:	
					colorflag=1
				 	oldcoloridx = coloridx
				fillshape = 1
				# Set Fillstyle and line style	
				if (gFlare.val>0):
					ctr = [gFlareLoc[0],gFlareLoc[1]]
					a = FILLSTYLEARRAY([FILLSTYLE(RADIAL_GRADIENT_FILL,[2.0,2.0,0,0,ctr[0],h-ctr[1]],[3,[GRADRECORD(0,[255,255,255,color[3]]),GRADRECORD(30,[color[0],color[1],color[2],color[3]]),GRADRECORD(255,[0,0,0,color[3]])]])])
				else:
					a = FILLSTYLEARRAY([FILLSTYLE(SOLID_FILL,[color[0],color[1]