#!BPY

"""
Name: 'Blender Analytical Geometry'
Blender: 248
Group: 'Object'
Tooltip: 'Draw parametric curves/surfaces'
"""
__author__ = 'Stefano <S68> Selleri '
__version__ = '0.6 18-03-06'
__url__ = ["Author's site, http://www.selleri.org/Blender/scripts/text.html", "http://wiki.blender.org/index.php/Extensions:Py/Scripts/Manual/Mesh/BAG"]

__bpydoc__ = """\
This script Draws parametric curves/surfaces.

This can be done either using presets or entering math values.

"""

#############################################################
#                                                           #
# Blender Analytical Geometry Tool                          #
#                                                           #
# (C) May 2004 Stefano <S68> Selleri                        #
# Originally Released under the Blender Artistic Licence (BAL)
# See www.blender.org                                       #
# --------------------------------------------------------------------------
# ***** BEGIN GPL LICENSE BLOCK *****
#
# 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.
#
# ***** END GPL LICENCE BLOCK *****
# --------------------------------------------------------------------------
#############################################################
# History                                                   #
# V: 0.0.0 - 09-05-04 - The script starts to take shape, an #
#                       history is now deserved :)          #
# V: 0.0.1 - 14-05-04 - First public release                #
# V: 0.0.2 - 15-05-04 - Hey! Who needs 'Curve' option?      #
#                       You can use surface with Nu=1 or    #
#                       Nv=1 !!! And you might need to      #
#                       Load and Save and user parameters!  #
#            16-05-04 - Load and save works, now, error     #
#                       check!                              #
# V: 0.0.3 - 17-05-04 - Added 'pi' added the possibility    #
#                       to have parametric Umin Umax, Vmin  #
#                       Vmax, changed XML a bit             #
# V: 0.0.4 - 18-05-04 - Added MACROS, GUI Splitted in two   #
#                       panels, EditMode added :)           #
# V: 0.0.5 - 28-05-04 - Bugfix release, after reports by:   #
#                       jms: Relocate Load/Save buttons     #
#                       macbuse: UV coords, better errors   #
#                       phlip: GUI bug                      #
#            31-05-04 - Last (?!) bug removed               #
# V: 0.0.6 - 18-03-06 - It does not work with 2.43 API!!    #
#############################################################

import Blender
from Blender import *
from math import *
import os
import re
import string

#############################################################
# GLOBALS                                                   #
#############################################################
VERSION         ='0.0.6'

#############################################################
# INTERFACE EVENTS                                          #
#############################################################
EXIT        = 1
NOOP        = 2
COMPUTE     = 3
ACTION_SAVE = 4
ACTION_LOAD = 5
REDRAW      = 6

ACTION_CON  = 10
ACTION_PARA = 11

CART_ON     = 21
CYL_ON      = 22
SPH_ON      = 23

TYPE_MESH   = 201
TYPE_CURVE  = 202

ADD_UP      = 300
REM_UP      = [301, 302, 303, 304]

ADD_M       = 400
REM_M       = [401]

DLG_OK      = 500

#############################################################
# SURFACE GLOBALS                                           #
#############################################################
TSRefCart   = Draw.Create(0)
TSRefCyl    = Draw.Create(1)
TSRefSph    = Draw.Create(0)

TSLabel     = Draw.Create('Logarithmic Spiral')

TSConst     = Draw.Create(1)
TSPara      = Draw.Create(0)

TS1fun      = Draw.Create('r0*E+r1*E*cos(2*pi*u)')
TS2fun      = Draw.Create('2*pi*v')
TS3fun      = Draw.Create('d*E+r1*E*sin(2*pi*u)')

TSumin      = Draw.Create('0.0')
TSumax      = Draw.Create('1.0')
TSuN        = Draw.Create('16')

TSvmin      = Draw.Create('0.0')
TSvmax      = Draw.Create('1.0')
TSvN        = Draw.Create('24')

TSEditMode  = Draw.Create(0)

TSUPNames   = [Draw.Create('r0'),
               Draw.Create('r1'),
               Draw.Create('alpha0'),
               Draw.Create('d')]
TSUPValues  = [Draw.Create(1.0),
               Draw.Create(0.25),
               Draw.Create(0.15),
               Draw.Create(0.75)]
TSUPDescr   = [Draw.Create('Spiral initial radius'),
               Draw.Create('Bevel initial radius'),
               Draw.Create('Exponential factor'),
               Draw.Create('Step along z')]
TSUPNumber  = 4

TSMNames    = [Draw.Create('E')]
TSMValues   = [Draw.Create('exp(alpha0*2*pi*v)')]
TSMDescr    = [Draw.Create('Exponential behavior')]
TSMNumber   = 1

ErrorMessage=''

#############################################################
# ERRORDIALOG                                               #
#############################################################
def ErrorDialog():
    global ErrorMessage

    global DLG_OK
    
    BGL.glClearColor(0.5, 0.5, 0.5, 0.0)
    BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
    BGL.glColor3f(0, 0, 0) 			# Black
    BGL.glRectf(2, 100, 482, 320)
    BGL.glColor3f(0.6, 0.1, 0.1) 		# Dark Red
    BGL.glRectf(4, 282, 480, 318)
    BGL.glRectf(4, 102, 480, 262)

    #############################################################
    # Common Header                                             #
    #############################################################

    BGL.glColor3f(1., 1., 0.6)
    BGL.glRasterPos2d(10, 305)
    Draw.Text("Blender Analytical Geometry v. "+VERSION)
    BGL.glRasterPos2d(10, 289)
    Draw.Text("(C) May 2004 Stefano Selleri <a.k.a. S68>")
    BGL.glColor3f(1.0, 1.0, 0.4)
    w = Draw.GetStringWidth('ERROR','normal')
    BGL.glRasterPos2d(240-w/2, 269)
    Draw.Text("ERROR")
    Draw.Button("OK", DLG_OK, 407, 287, 70, 24)

    EM = ErrorMessage
    i = 0
    BGL.glColor3f(1., 1., 0.6)
    while (EM != ''):
        s = EM[0:64]
        EM = EM[64:]
        try:
            cr = re.search(r'\n',s).start()
        except:
            cr = -1

        if( cr >- 1 ):
            EM = s[cr+1:]+EM
            s = s[0:cr]
        
        BGL.glRasterPos2d(10, 249-i*15)
        Draw.Text(s)
        i = i + 1
        
#############################################################
# XML Parser                                                #
#############################################################
from xml.sax.handler import ContentHandler
import xml.sax
import sys

def safe_eval(str):
    try:
        return int(str)
    except:
        try:
            return float(str)
        except:
            return repr(str)
        
class BAGHandler(ContentHandler):
        
    def __init__(self):
        self.in_Ref    = 0
        self.in_Label  = 0
        self.in_F1     = 0
        self.in_F2     = 0
        self.in_F3     = 0
        self.in_U      = 0
        self.in_V      = 0
        self.in_UP     = 0
        self.in_M     = 0

        self.UPNames   = []
        self.UPValues  = []
        self.UPIndex   = []
        self.UPDescr   = []
        self.UPNumber  = 0

        self.MNames   = []
        self.MValues  = []
        self.MIndex   = []
        self.MDescr   = []
        self.MNumber  = 0

    def startDocument(self):
	print'--- Reading BAG XML file ---'

    def startElement(self, name, attrs):
        self.arg = ""
        if name=='BAG':
            for k in attrs.keys():
                if k=='version':
                    self.version  = str(attrs.getValue(k))
        if name=='Reference':
            self.in_Ref=1
        if name=='Label':
            self.in_Label=1
        if name=='F1':
            self.in_F1=1
        if name=='F2':
            self.in_F2=1
        if name=='F3':
            self.in_F3=1
        if name=='ParU':
            for k in attrs.keys():
                if k=='Min':
		    par = re.sub(r'\n','',attrs.getValue(k))
                    self.UMin  = str(par)
                if k=='Max':
		    par = re.sub(r'\n','',attrs.getValue(k))
                    self.UMax  = str(par)
		self.in_U=1
        if name=='ParV':
            for k in attrs.keys():
                if k=='Min':
		    par = re.sub(r'\n','',attrs.getValue(k))
                    self.VMin  = str(par)
                if k=='Max':
		    par = re.sub(r'\n','',attrs.getValue(k))
                    self.VMax  = str(par)
		self.in_V=1
        if name=='UserPara':
            for k in attrs.keys():
                if k=='Name':
		    nam = re.sub(r'\n','',attrs.getValue(k))
                    self.UPNames.append(nam)
                if k=='Value':
                    self.UPValues.append(safe_eval(attrs.getValue(k)))
                if k=='Index':
                    self.UPIndex.append(safe_eval(attrs.getValue(k)))
		self.in_UP=1
        if name=='Macro':
            for k in attrs.keys():
                if k=='Name':
		    nam = re.sub(r'\n','',attrs.getValue(k))
                    self.MNames.append(nam)
                if k=='Value':
                    nam = re.sub(r'\n','',attrs.getValue(k))
                    self.MValues.append(nam)
                if k=='Index':
                    self.MIndex.append(safe_eval(attrs.getValue(k)))
		self.in_M=1

    def endElement(self, name):
        if name=='Reference':
            self.Reference = string.strip(self.arg)
            self.in_Ref=0
        if name=='Label':
	    fun = re.sub(r'\n','',self.arg)	
            self.Label = fun
            self.in_Label=0
        if name=='F1':
	    fun = re.sub(r'\n','',self.arg)	
            self.F1 = str(fun)
            self.in_F1=0
        if name=='F2':    
	    fun = re.sub(r'\n','',self.arg)	
            self.F2 = str(fun)
            self.in_F2=0
        if name=='F3':
	    fun = re.sub(r'\n','',self.arg)	
            self.F3 = str(fun)
            self.in_F3=0
        if name=='ParU':
            un = re.sub(r'\n','',self.arg)
            self.UN = str(un)
            self.in_U=0
        if name=='ParV':    
            vn = re.sub(r'\n','',self.arg)
            self.VN = str(vn)
            self.in_V=0
        if name=='UserPara':    
	    descr = re.sub(r'\n','',self.arg)
            self.UPDescr.append(descr)
            self.UPNumber = self.UPNumber + 1
            self.in_UP=0
        if name=='Macro':    
	    descr = re.sub(r'\n','',self.arg)
            self.MDescr.append(descr)
            self.MNumber = self.MNumber + 1
            self.in_M=0

    def characters(self, ch):
        self.arg = self.arg + ch

#############################################################
# FILE FUNCTIONS                                            #
#############################################################
def writeln(f,x):
	try:
		if (type(x).__name__ == 'string'):
			nn = string.find(x, '\n')
			if (nn > 0):
				x = x[:nn] + x[nn + 1:]
		f.write(str(x))
		f.write('\n')
	except:
		pass

def BAGSave(filename):
    global VERSION
    
    global TSRefCart, TSRefCyl, TSRefSph, TSLabel
    global TS1fun, TS2fun, TS3fun
    global TSumin, TSumax, TSuN, TSvmin, TSvmax, TSvN

    global TSUPNames, TSUPValues, TSUPDescr, TSUPNumber
    global TSMNames, TSMValues, TSMDescr, TSMNumber

    splitted = os.path.splitext(filename)
    if(splitted[1]==''):
	filename = string.join((filename,'bag'),'.')

    if os.path.exists(filename):
	print "We will overwrite without warning!"

    FD = open(filename,"w")

    writeln(FD,"<BAG version=\""+VERSION+"\">")
    if (TSRefCart.val==1):
	writeln(FD,"<Reference>Cartesian</Reference>")
    elif(TSRefCyl.val==1):
	writeln(FD,"<Reference>Cylindrical</Reference>")
    else:
	writeln(FD,"<Reference>Spherical</Reference>")

    writeln(FD,"<Label>")
    writeln(FD,TSLabel.val)
    writeln(FD,"</Label>")

    writeln(FD,"<F1>")
    writeln(FD,TS1fun.val)
    writeln(FD,"</F1>")

    writeln(FD,"<F2>")
    writeln(FD,TS2fun.val)
    writeln(FD,"</F2>")
		
    writeln(FD,"<F3>")
    writeln(FD,TS3fun.val)
    writeln(FD,"</F3>")

    writeln(FD,"<ParU Min=\""+str(TSumin.val)+"\" Max=\""+str(TSumax.val)+"\">")
    writeln(FD,TSuN.val)
    writeln(FD,"</ParU>")

    writeln(FD,"<ParV Min=\""+str(TSvmin.val)+"\" Max=\""+str(TSvmax.val)+"\">")
    writeln(FD,TSvN.val)
    writeln(FD,"</ParV>");

    for i in range(TSUPNumber):
	writeln(FD,"<UserPara Name=\""+TSUPNames[i].val+"\" Value=\""+str(TSUPValues[i].val)+"\" Index=\""+str(i)+"\">")
	writeln(FD,TSUPDescr[i].val)
	writeln(FD,"</UserPara>");

    for i in range(TSMNumber):
	writeln(FD,"<Macro Name=\""+TSMNames[i].val+"\" Value=\""+str(TSMValues[i].val)+"\" Index=\""+str(i)+"\">")
	writeln(FD,TSMDescr[i].val)
	writeln(FD,"</Macro>");

    writeln(FD,"</BAG>");
    FD.close()
    
def BAGLoad(filename):
    global VERSION

    global REM_UP
    global REM_M
    
    global TSRefCart, TSRefCyl, TSRefSph, TSLabel
    global TS1fun, TS2fun, TS3fun
    global TSumin, TSumax, TSuN, TSvmin, TSvmax, TSvN

    global TSUPNames, TSUPValues, TSUPDescr, TSUPNumber
    global TSMNames, TSMValues, TSMDescr, TSMNumber

    TSUPNames  = []
    TSUPValues = []
    TSUPDescr  = []
    TSUPNumber = 0
    REM_UP     = []
    
    TSMNames  = []
    TSMValues = []
    TSMDescr  = []
    TSMNumber = 0
    REM_M     = []

    if not os.path.exists(filename):
	print "Well... where is the file?";
    else:
	parser = xml.sax.make_parser()
	handler = BAGHandler()
	parser.setContentHandler(handler)
	parser.parse(filename)

	TSRefCart.val=0
	TSRefCyl.val=0
	TSRefSph.val=0

	### Version Check
	if (handler.version != VERSION):
	    print "*** WARNING *** This is BAG v."+VERSION+" while the "+filename+" file looks like being saved by BAG v."+handler.version
			
	### Mapping TAG
	try:
	    Para=handler.Reference
	except:
	    Para="Cartesian"
			
	if (Para=="Cartesian"):
	    TSRefCart.val=1
	elif (Para=="Cylindrical"):
	    TSRefCyl.val=1
	else:
	    TSRefSph.val=1

	### Functions	
	try:
 	    TSLabel.val=handler.Label
	except:
	    TSLabel.val=''

	### Functions
	print handler
	print handler.F1	
#	try:
	TS1fun.val=handler.F1
#	except:
#	    TS1fun.val='u'

	try:
 	    TS2fun.val=handler.F2
	except:
	    TS2fun.val='v'

	try:
 	    TS3fun.val=handler.F3
	except:
	    TS3fun.val='0'

	### UV parameters TAG	
	try:
	    TSumin.val=handler.UMin
	except:
	    TSumin.val=str(0.0)
	try:
	    TSumax.val=handler.UMax
	except:
	    TSumax.val=str(1.0)
	try:
	    TSuN.val=handler.UN
	except:
	    TSuN.val=str(10)

	try:
	    TSvmin.val=handler.VMin
	except:
	    TSvmin.val=str(0.0)
	try:
	    TSvmax.val=handler.VMax
	except:
	    TSvmax.val=str(1.0)
	try:
	    TSvN.val=handler.VN
	except:
	    TSvN.val=str(10)

	if (handler.UPNumber>0):
	    TSUPNumber = handler.UPNumber
	    for i in range (handler.UPNumber):
         	TSUPNames.insert (handler.UPIndex[i],Draw.Create(str(handler.UPNames[i])))
		TSUPValues.insert(handler.UPIndex[i],Draw.Create(handler.UPValues[i]))
		TSUPDescr.insert(handler.UPIndex[i],Draw.Create(str(handler.UPDescr[i])))
		REM_UP.append(300+i+1)

	if (handler.MNumber>0):
	    TSMNumber = handler.MNumber
	    for i in range (handler.MNumber):
         	TSMNames.insert (handler.MIndex[i],Draw.Create(str(handler.MNames[i])))
		TSMValues.insert(handler.MIndex[i],Draw.Create(str(handler.MValues[i])))
		TSMDescr.insert(handler.MIndex[i],Draw.Create(str(handler.MDescr[i])))
		REM_M.append(400+i+1)

	Draw.Redraw()
		
#############################################################
# Surfaces                                                  #
#############################################################
def ComputeSurface():
    global ErrorMessage

    global TSRefCart, TSRefCyl,TSRefSph
    global TS1fun, TS2fun, TS3fun
    global TSumin, TSumax, TSuN, TSvmin, TSvmax, TSvN

    global TSUPNames, TSUPValues, TSUPDescr, TSUPNumber
    global TSMNames, TSMValues, TSMDescr, TSMNumber

    SurfaceMesh = NMesh.GetRaw()

    pc1 = TS1fun.val
    pc2 = TS2fun.val
    pc3 = TS3fun.val

    umin = TSumin.val
    umax = TSumax.val

    vmin = TSvmin.val
    vmax = TSvmax.val

    uN = TSuN.val
    vN = TSvN.val
    
    ########## Handles Macros
    for i in range(TSMNumber):
       replacement = r'\b'+TSMNames[i].val+r'\b'
       pc1 = re.sub(replacement,TSMValues[i].val,pc1)
       pc2 = re.sub(replacement,TSMValues[i].val,pc2)
       pc3 = re.sub(replacement,TSMValues[i].val,pc3)

       umin = re.sub(replacement,TSMValues[i].val,umin)
       umax = re.sub(replacement,TSMValues[i].val,umax)

       vmin = re.sub(replacement,TSMValues[i].val,vmin)
       vmax = re.sub(replacement,TSMValues[i].val,vmax)

       uN = re.sub(replacement,TSMValues[i].val,uN)
       vN = re.sub(replacement,TSMValues[i].val,vN)

    ########## Handles User Constants
    for i in range(TSUPNumber):
       replacement = r'\b'+TSUPNames[i].val+r'\b' 
       pc1 = re.sub(replacement,str(TSUPValues[i].val),pc1)
       pc2 = re.sub(replacement,str(TSUPValues[i].val),pc2)
       pc3 = re.sub(replacement,str(TSUPValues[i].val),pc3)

       umin = re.sub(replacement,str(TSUPValues[i].val),umin)
       umax = re.sub(replacement,str(TSUPValues[i].val),umax)

       vmin = re.sub(replacement,str(TSUPValues[i].val),vmin)
       vmax = re.sub(replacement,str(TSUPValues[i].val),vmax)

       uN = re.sub(replacement,str(TSUPValues[i].val),uN)
       vN = re.sub(replacement,str(TSUPValues[i].val),vN)

    ########## pi and similar constants
    pc1 = re.sub(r'\bpi\b',str(3.1415926535897932),pc1)
    pc2 = re.sub(r'\bpi\b',str(3.1415926535897932),pc2)
    pc3 = re.sub(r'\bpi\b',str(3.1415926535897932),pc3)
    
    try:
        umin = eval(umin)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating UMIN ' + str(sys.exc_value) + '\n' 
        umin = 0
                
    try:
        umax = eval(umax)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating UMAX ' + str(sys.exc_value) + '\n' 
        umax = 1

    try:
        vmin = eval(vmin)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating VMIN \n' + str(sys.exc_value) + '\n' 
        vmin = 0

    try:
        vmax = eval(vmax)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating VMAX \n' + str(sys.exc_value) + '\n'
        vmax = 1

    try:
        uN = eval(uN)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating N \n' + str(sys.exc_value) + '\n'
        uN = 1

    try:
        vN = eval(vN)
    except:
        ErrorMessage = ErrorMessage + 'Error Evaluating M \n' + str(sys.exc_value) + '\n'
        vN = 1

    uN = int(uN)
    vN = int(vN)

    warn1 = 0
    warn2 = 0
    warn3 = 0
    
    for i in range(uN):
        for j in range(vN):

            if (uN == 1):
                u = umin
            else:    
                u = (umax-umin)*i/(uN-1)+umin

            if (vN == 1):
                v = TSvmin.val
            else:    
                v = (vmax-vmin)*j/(vN-1)+vmin

            c1 = re.sub(r'\bu\b',str(u),pc1)
            c1 = re.sub(r'\bv\b',str(v),c1)
	    try:
		c1 = eval(c1)
            except:
                if(warn1==0):
                    ErrorMessage = ErrorMessage + 'Error Evaluating F1 \n' + str(sys.exc_value) + '\n'
                    warn1 = 1
		c1 = 0
            
            c2 = re.sub(r'\bu\b',str(u),pc2)
            c2 = re.sub(r'\bu\b',str(v),c2)
	    try:
                c2 = eval(c2)
            except:
                if(warn2==0):
                    ErrorMessage = ErrorMessage + 'Error Evaluating F2 \n' + str(sys.exc_value) + '\n'
                    warn2 = 1
		c2 = 0               
            
            c3 = re.sub(r'\bu\b',str(u),pc3)
            c3 = re.sub(r'\bv\b',str(v),c3)
	    try:
                c3 = eval(c3)
            except:
                if(warn3==0):
                    ErrorMessage = ErrorMessage + 'Error Evaluating F3 \n' + str(sys.exc_value) + '\n'
                    warn3 = 1
                c3 = 0              

            if (ErrorMessage != ''):
                break
            
            if (TSRefCart.val==1):
                x = c1
                y = c2
                z = c3
            elif (TSRefCyl.val==1):
                x = c1 * cos(c2)
                y = c1 * sin(c2)
                z = c3
            else:
                x = c1 * sin(c2) * cos(c3)
                y = c1 * sin(c2) * sin(c3)
                z = c1 * cos(c2)

            ve = NMesh.Vert(x,y,z)
            
            SurfaceMesh.verts.append(ve)
            
            nf = NMesh.Face()
            idx = i*vN + j
#            print SurfaceMesh.verts[idx].uvco
            
            if (uN>1 and vN>1):
                if (i>0):
                    if (j>0):
                        nf.v.append(SurfaceMesh.verts[idx])
                        nf.v.append(SurfaceMesh.verts[idx-1])
                        nf.v.append(SurfaceMesh.verts[idx-vN-1])
                        nf.v.append(SurfaceMesh.verts[idx-vN])
                        nf.uv = list([
                            tuple([1.0*i/(uN-1),1.0*j/(vN-1)]),
                            tuple([1.0*i/(uN-1),1.0*(j-1)/(vN-1)]),
                            tuple([1.0*(i-1)/(uN-1),1.0*(j-1)/(vN-1)]),
                            tuple([1.0*(i-1)/(uN-1),1.0*j/(vN-1)])])
#                        print nf.uv
                        SurfaceMesh.faces.append(nf)
            else:
                if (i+j>0):
                    nf.v.append(SurfaceMesh.verts[idx])
                    nf.v.append(SurfaceMesh.verts[idx-1])

#            SurfaceMesh.faces.append(nf)

	    
    NMesh.PutRaw(SurfaceMesh)
    Draw.Redraw()
    
#############################################################
# MAIN WINDOW                                               #
#############################################################
def MainWindow():        
    global EXIT, NOOP, COMPUTE, ACTION_SAVE, ACTION_LOAD, REDRAW
    global ACTION_CON,ACTION_PARA
    global CART_ON,CYL_ON,SPH_ON
    global TYPE_MESH, TYPE_CURVE
    global ADD_UP, REM_UP
    global ADD_M, REM_M

    global TSEditMode,TSConst, TSPara, TSLabel
    global TSRefCart, TSRefCyl,TSRefSph
    global TS1fun, TS2fun, TS3fun
    global TSumin, TSumax, TSuN, TSvmin, TSvmax, TSvN

    global TSUPNames, TSUPValues, TSUPDescr, TSUPNumber
    global TSMNames, TSMValues, TSMDescr, TSMNumber

    #############################################################
    # Backgrounds                                               #
    #############################################################

    BGL.glClearColor(0.5, 0.5, 0.5, 0.0)
    BGL.glClear(BGL.GL_COLOR_BUFFER_BIT)
    BGL.glColor3f(0, 0, 0) 			# Black
    BGL.glRectf(2, 2, 482, 520)
    BGL.glColor3f(0.48, 0.4, 0.57) 		# Light Purple
    BGL.glRectf(4, 479, 480, 510)
    BGL.glRectf(4, 34, 480, 450)
    BGL.glColor3f(0.3, 0.27, 0.35) 		# Dark purple
    BGL.glRectf(4, 451,480, 478)
    BGL.glRectf(4, 4, 480, 33)

    #############################################################
    # Common Header                                             #
    #############################################################

    BGL.glColor3f(0.9, 0.8, 1)
    BGL.glRasterPos2d(10, 500)
    Draw.Text("Blender Analytic Geometry v. "+VERSION)
    BGL.glRasterPos2d(10, 484)
    Draw.Text("(C) May 2004 Stefano Selleri <a.k.a. S68>")
    Draw.Button("Save", ACTION_SAVE, 267, 482, 70, 24,
        	"Save currents settings to a file")
    Draw.Button("Load", ACTION_LOAD, 337, 482, 70, 24,
                "Loads Previously saved Settings form a file")
    Draw.Button("Exit", EXIT, 407, 482, 70, 24)
 
        
    TSEditMode = Draw.Toggle("EditMode", REDRAW, 7, 455, 76, 18, TSEditMode.val,
                                 "Enters/Exits Edit Mode")
    if (TSEditMode.val==0):
        TSConst.val = 1
        TSPara.val  = 0
    else:
        TSConst = Draw.Toggle("Constants",ACTION_CON,130,455,120,18,TSConst.val,
                              "Uses defined constants")
        TSPara  = Draw.Toggle("Parameters",ACTION_PARA,253,455,120,18,TSPara.val,
               	              "Parametrical functions and macros")

    Draw.Button("GENERATE", COMPUTE, 7, 7, 470, 24)
    BGL.glColor3f(0.9, 0.9, 0.9)

    #############################################################
    # Screen                                                    #
    #############################################################

    if (TSConst.val == 1):
        ####################################################
        # User Parameters                                  #
        ####################################################
        BGL.glRasterPos2d(8, 430)
        Draw.Text("Constants:")

        if (TSEditMode.val==1):
            TSLabel = Draw.String("Label: ", NOOP, 110, 425, 300, 18, TSLabel.val, 128 , 
                     	          "Label of the Formula")
            
            Draw.Button("Add", ADD_UP, 392, 405-TSUPNumber*20, 76, 18)
        else:
            BGL.glColor3f(1., 1.0, 0.8)
            BGL.glRasterPos2d(110, 430)
            Draw.Text(TSLabel.val)
            BGL.glColor3f(0.9, 0.9, 0.9)
            
        for i in range(TSUPNumber):
            TSUPValues[i]= Draw.Number("", NOOP, 110, 405-i*20, 76, 18, TSUPValues[i].val, -10000.0, 10000.0, 
                	               TSUPDescr[i].val)
            if (TSEditMode.val==1):
                TSUPNames[i] = Draw.String("Name: ", NOOP, 7, 405-i*20, 100, 18, TSUPNames[i].val, 8 , 
                     	               "Constant Symbolic Name")
                TSUPDescr[i] = Draw.String("Descr: ", NOOP, 189, 405-i*20, 200, 18, TSUPDescr[i].val, 128 , 
                     	               "Constant Description")
                Draw.Button("Remove", REM_UP[i], 392, 405-i*20, 76, 18)
            else:
                BGL.glRasterPos2d(189, 410-i*20)
                Draw.Text(TSUPDescr[i].val)
                BGL.glColor3f(1., 1.0, 0.8)
                w = Draw.GetStringWidth(TSUPNames[i].val,'normal')
                BGL.glRasterPos2d(107-w, 410-i*20)
                Draw.Text(TSUPNames[i].val)
                BGL.glColor3f(0.9, 0.9, 0.9)
                

    else:    
        BGL.glRasterPos2d(8, 425)
        Draw.Text("Reference:")
        
        TSRefCart = Draw.Toggle("Cartesian",CART_ON,100,420,76,18,TSRefCart.val,
                                "Uses Cartesian Coordinates")
        TSRefCyl  = Draw.Toggle("Cylindrical",CYL_ON,180,420,76,18,TSRefCyl.val,
                   	            "Uses Cylindrical Coordinates")
        TSRefSph  = Draw.Toggle("Spherical",SPH_ON,260,420,76,18,TSRefSph.val,
                  	            "Uses Spherical Coordinates")

        BGL.glRasterPos2d(8, 395)
        Draw.Text("Parametric law:")

        if (TSRefCart.val == 1):
        ####################################################
        # CartLabels                                       #
        ####################################################
            TS1fun    = Draw.String("x(u,v) = ", NOOP, 100, 390, 360, 18, TS1fun.val, 399 , 
                          		"X coordinate parametric (u,v) law")
            TS2fun    = Draw.String("y(u,v) = ", NOOP, 100, 370, 360, 18, TS2fun.val, 399 , 
                                    "Y coordinate parametric (u,v) law")
            TS3fun    = Draw.String("z(u,v) = ", NOOP, 100, 350, 360, 18, TS3fun.val, 399 ,
                        		"Z coordinate parametric (u,v) law")
        elif (TSRefCyl.val == 1):
        ####################################################
        # Cyl Labels                                       #
        ####################################################
            TS1fun    = Draw.String("rho(u,v) = ", NOOP, 100, 390, 360, 18, TS1fun.val, 399 , 
                           		"RHO coordinate parametric (u,v) law")
            TS2fun    = Draw.String("phi(u,v) = ", NOOP, 100, 370, 360, 18, TS2fun.val, 399 , 
    	        		"PHI coordinate parametric (u,v) law")
            TS3fun    = Draw.String("z(u,v) = ", NOOP, 100, 350, 360, 18, TS3fun.val, 399 ,
    	        		"Z coordinate parametric (u,v) law")	 

        else:
        ####################################################
        # Sph Labels                                       #
        ####################################################
            TS1fun    = Draw.String("r(u,v) = ", NOOP, 100, 390, 360, 18, TS1fun.val, 399 , 
                         	        "R coordinate parametric (u,v) law")
            TS2fun    = Draw.String("theta(u,v) = ", NOOP, 100, 370, 360, 18, TS2fun.val, 399 , 
    	        		"THETA coordinate parametric (u,v) law")
            TS3fun    = Draw.String("phi(u,v) = ", NOOP, 100, 350, 360, 18, TS3fun.val, 399 ,
    	        		"PHI coordinate parametric (u,v) law")	 

        ####################################################
        # UV parameters                                    #
        ####################################################
        BGL.glRasterPos2d(8, 325)
        Draw.Text("Parameter u,v:")
        TSumin = Draw.String("u min: ", NOOP, 100, 320, 100, 18, TSumin.val, 399, 
                 	                "Minimum (starting) value for parameter u")
        TSumax = Draw.String("u max: ", NOOP, 205, 320, 100, 18, TSumax.val, 399, 
                    	        "Maximum (ending) value for parameter u")
        TSuN   = Draw.String("N: ", NOOP, 310, 320, 100, 18, TSuN.val, 399,
                    	        "Number of points")

        TSvmin = Draw.String("v min: ", NOOP, 100, 300, 100, 18, TSvmin.val, 399,
                    	        "Minimum (starting) value for parameter u")
        TSvmax = Draw.String("v max: ", NOOP, 205, 300, 100, 18, TSvmax.val, 399,
                	        "Maximum (ending) value for parameter u")
        TSvN   = Draw.String("M: ", NOOP, 310, 300, 100, 18, TSvN.val, 399, 
                	        "Number of points")

        ####################################################
        # MACROS                                           #
        ####################################################
        BGL.glRasterPos2d(8, 275)
        Draw.Text("Macros:")

        Draw.Button("Add", ADD_M, 415, 250-TSMNumber*20, 56, 18)
        
        for i in range(TSMNumber):
            TSMNames[i] = Draw.String("Name: ", NOOP, 7, 250-i*20, 100, 18, TSMNames[i].val, 8 , 
                     	               "Macro Name")
                
            TSMValues[i]= Draw.String("Val:", NOOP, 110, 250-i*20, 150, 18, TSMValues[i].val, 399 , 
                	               TSMDescr[i].val)

            TSMDescr[i] = Draw.String("De: ", NOOP, 263, 250-i*20, 150, 18, TSMDescr[i].val, 128 , 
                     	               "Macro Description")

            Draw.Button("Remove", REM_M[i], 415, 250-i*20, 56, 18)

    
#############################################################
# Graphics                                                  #
#############################################################
def draw():
    global ErrorMessage
    if (ErrorMessage==''):
        MainWindow()
    else:
        ErrorDialog()

#############################################################
# Event Handler                                             #
#############################################################
def event(evt, val): 
	if (evt== Draw.QKEY and not val):
		Draw.Exit()

def bevent(evt):
    global ErrorMessage
    
    global EXIT, NOOP, COMPUTE, ACTION_SAVE, ACTION_LOAD, REDRAW
    global ACTION_CON,ACTION_PARA
    global CART_ON,CYL_ON,SPH_ON
    global TYPE_MESH, TYPE_CURVE
    global ADD_UP, REM_UP
    global DLG_OK
    
    global TSConst, TSPara
    global TSRefCart, TSRefCyl,TSRefSph
    global TS1fun, TS2fun, TS3fun
    global TSumin, TSumax, TSuN, TSvmin, TSvmax, TSvN

    global TSUPNames, TSUPValues, TSUPDescr, TSUPNumber
    global TSMNames, TSMValues, TSMDescr, TSMNumber

    if   (evt == EXIT):
        # EXIT
        Draw.Exit()
        # 2 = NOOP
    elif (evt == COMPUTE):
        ComputeSurface()
	Draw.Redraw()
    elif (evt == ACTION_SAVE):
	Window.FileSelector (BAGSave, 'SAVE FILE:')        
    elif (evt == ACTION_LOAD):
	Window.FileSelector (BAGLoad, 'LOAD FILE:')        
        
    elif (evt == ACTION_CON):
	TSConst.val  = 1
	TSPara.val   = 0
        # REDRAW INTERFACE
	Draw.Redraw()
    elif (evt == ACTION_PARA):
	TSConst.val  = 0
	TSPara.val   = 1
        # REDRAW INTERFACE
	Draw.Redraw()
    elif (evt == REDRAW):
	Draw.Redraw()

    #############################################################
    # COORDINATE SWAPPING                                       #
    #############################################################
    elif (evt == CART_ON):
	TSRefCart.val  = 1
	TSRefCyl.val   = 0
	TSRefSph.val   = 0
        # REDRAW INTERFACE
	Draw.Redraw()
    elif (evt == CYL_ON):
	TSRefCart.val  = 0
	TSRefCyl.val   = 1
	TSRefSph.val   = 0
        # REDRAW INTERFACE
	Draw.Redraw()
    elif (evt == SPH_ON):
	TSRefCart.val  = 0
	TSRefCyl.val   = 0
	TSRefSph.val   = 1
        # REDRAW INTERFACE
	Draw.Redraw()
  	    
    elif (evt == ADD_UP):
        TSUPNames.append(Draw.Create('a'))
        TSUPValues.append(Draw.Create(0.0))
        TSUPDescr.append(Draw.Create('Descr'));
        TSUPNumber = TSUPNumber + 1
        REM_UP.append(300+TSUPNumber)
        Draw.Redraw()
    elif (evt > ADD_UP and evt < ADD_M):
        for i in range(TSUPNumber):
            if (evt == REM_UP[i]):
                TSUPNames.pop(i)
                TSUPValues.pop(i)
                TSUPDescr.pop(i)
                TSUPNumber = TSUPNumber - 1
                break
        Draw.Redraw()

    elif (evt == ADD_M):
        TSMNames.append(Draw.Create('A'))
        TSMValues.append(Draw.Create('u'))
        TSMDescr.append(Draw.Create('Descr'));
        TSMNumber = TSMNumber + 1
        REM_M.append(400+TSMNumber)
        Draw.Redraw()
    elif (evt > ADD_M and evt < DLG_OK):
        for i in range(TSMNumber):
            if (evt == REM_M[i]):
                TSMNames.pop(i)
                TSMValues.pop(i)
                TSMDescr.pop(i)
                TSMNumber = TSMNumber - 1
                break
        Draw.Redraw()

    elif (evt == DLG_OK):
        print '-'+ErrorMessage+'-'
        ErrorMessage=''
        print '-'+ErrorMessage+'-'
        Draw.Redraw()
        
#############################################################
# Registering all functions                                 #
#############################################################

Draw.Register(draw, event, bevent)
