"""
     qtgui/MGGLWidgetCore.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC
     Copyright (C) 2009-2011 University of York
     Copyright (C) 2012 STFC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     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 Lesser General Public License for more details.
"""
import sys
import os
import math
import time
import image_info
if sys.argv.count('-osmesa'):
  import mgOSMesa as opengl
else:
  import opengl
from PyQt4 import QtCore, QtGui, QtOpenGL
import pygl_coord
import cprim

import global_definitions

class MGGLWidgetCore:

    viewsize = 12.0
    nframes = 0
    previous_frames = nframes
    initial_time = time.time()
    previous_time = initial_time
    rolling = 0
    recording = 0


    def setAmbientOcclusionPrefs(self, params):
		if params.has_key("ambocc_znear"):
			self.ambientOcclusionZNear = params["ambocc_znear"]
		if params.has_key("ambocc_zfar"):
			self.ambientOcclusionZFar = params["ambocc_zfar"]
		if params.has_key("ambocc_radius"):
			self.ambientOcclusionRadius = params["ambocc_radius"]
		if params.has_key("ambocc_bias"):
			self.ambientOcclusionBias = params["ambocc_bias"]
		if params.has_key("ambocc_scale"):
			self.ambientOcclusionScale = params["ambocc_scale"]
		self.updateGL()

    def setSize(self, size):
	self._size = size

    def size(self):
	return self._size

    def BindOffScreenBufferFBO(self):
        self.pbuffer.bind()

    def BindOffScreenBuffer(self):
        self.pbuffer.makeCurrent()

    def width(self):
	return self._size.width()

    def height(self):
	return self._size.height()

    def bindTexture(self, image=None,pixmap=None,target=None,format=None,fileName=None,options=None):
        return 0

    def __init__(self, parent=None,share=None,format=None):
	self.use_pbuffer = False
	self.displayListsRebuilt = 1
	self.isTransparent =  False
        self.visibility_list = []
        self.alpha_list = []

        self.doStereo = 0
        self.doZalmanStereo = False

        self.object = 0
	self.RADIUS= 60.0 
        self.quat = pygl_coord.Quat(0.0,0.0,0.0,0)
        self.extra_quat = pygl_coord.Quat(0.0,0.0,0.0,0)
        self.extra_matrix=None
        self.rpos = [0,0,-10.0]

	self.keys_down = {}

        self.lastPos = QtCore.QPoint()
        self.mouseDownPos = QtCore.QPoint()

        self.bgcolour = QtGui.QColor(255, 255, 255, 255)
        #self.bgcolour = QtGui.QColor(0, 0, 0, 0)

        self.go = []
        self.listids = []
        self.DISPLAYLISTS = 0
        self.IMMEDIATE = 1
        self.SetRenderMode(self.DISPLAYLISTS)

	self.drawTextSeparately = True
	self.fontScaling = 1.0

        self.NEAR=1
        self.FAR=1000
        self.slab_width = 10
        self.slab_offset = 0
        self.fog_strength = 0
        self.fog_enabled = True
        self.slab_enabled = False
        self.clip_cap = False

	self.fog_near = -0.
	self.fog_far = 20.

        self.show_axes = 0
        self.show_scale = 0
        self.shaders_on = 0
        self.vertexShader = ''
        self.fragmentShader = ''
        self.textVertexShader = ''
        self.textFragmentShader = ''
        self.normalAsColourVertexShader = ''
        self.normalAsColourFragmentShader = ''
        self.edgeDetectVertexShader = ''
        self.edgeDetectFragmentShader = ''
        self.blurVertexShader = ''
        self.blurXFragmentShader = ''
        self.blurYFragmentShader = ''
        self.depthVertexShader = ''
        self.depthFragmentShader = ''
        self.textBackgroundVertexShader = ''
        self.textBackgroundFragmentShader = ''
        self.circleShadowVertexShader = ''
        self.circleShadowFragmentShader = ''
        self.circleVertexShader = ''
        self.circleFragmentShader = ''
        self.ssaoVertexShader = ''
        self.ssaoFragmentShader = ''
        self.shadowVertexShader = ''
        self.shadowFragmentShader = ''

        self.shadowCentre = (0,0,0)
        self.shadowExtent = 45. # Random number. Anything will do until we have something to view.
        self.axes_position = (0.75,0.75)

        self.doMirror = False

        self.doShadow = False
        self.inShadow = False

        self.doAmbient = False
        self.inAmbient = False
        self.doOutline = False

        self.ambientOcclusionZNear  = 100.0
        self.ambientOcclusionZFar   = 150.0
        self.ambientOcclusionRadius = 15.0
        self.ambientOcclusionBias   = 0.3
        self.ambientOcclusionScale  = 1.0
        self.customClipPlanes= []

        self.line_scaling = 1.0

    def GetRenderMode(self):
        return self.renderMode

    def SetRenderMode(self,mode):
        self.renderMode = mode

    def SetupSymmetry(self):
        i=0
        for id in self.listids:
          if self.go[i].obj.GetDrawSymmetry():
             self.go[i].SetupSymmetry(self.rpos,self.extents())
          i=i+1

    def getBackground(self):
      col = [ self.bgcolour.red(), self.bgcolour.green(), self.bgcolour.blue()]
      return col

    def setPositionNoUpdate(self, rpos):
	self.rpos = rpos
        self.SetupSymmetry()

    def setPosition(self, rpos):
	self.rpos = rpos
        self.updateGL()
        self.emit(QtCore.SIGNAL("PositionChanged"),(self))
        self.SetupSymmetry()

    def setQuatNoUpdate(self, quat):
	self.quat = quat

    def setQuat(self, quat):
	self.quat = quat
        self.updateGL()
        self.emit(QtCore.SIGNAL("QuatChanged"),(self))

    def setRotationNoUpdate(self, dx,dy,dz):
        cart = self.extra_quat.getInvMatrix()*pygl_coord.Cartesian(dx,dy,dz)
        dx, dy,dz = cart.get_x(), cart.get_y(), cart.get_z()
        rotQ = pygl_coord.Quat(dx,dy,dz,0)
        self.quat.postMult(rotQ)
        self.emit(QtCore.SIGNAL("QuatChanged"),(self))

    def setRotation(self, dx,dy,dz):
        cart = self.extra_quat.getInvMatrix()*pygl_coord.Cartesian(dx,dy,dz)
        dx, dy,dz = cart.get_x(), cart.get_y(), cart.get_z()
        rotQ = pygl_coord.Quat(dx,dy,dz,0)
        self.quat.postMult(rotQ)
        self.updateGL()
        self.emit(QtCore.SIGNAL("QuatChanged"),(self))

    def transparency(self):
	    return self.isTransparent

    def setTransparency(self,transparent=True):
	    self.isTransparent = transparent

    def nofTransparentObjects(self):
            nn = 0
            for go in self.go:
               if go.obj.GetAlpha()<0.99: nn = nn+1
            return nn

    def recentre(self):
      origin = self.go.obj.get_origin()
      if type(origin) == type(""):
        origin = pygl_coord.CartesianPtr(self.go.obj.get_origin())
        origin = (origin.get_x(),origin.get_y(),origin.get_z())
      self.centreOn(origin)

    def SetOrigin(self, o_in=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        self.rpos=o_in
        self.updateGL()
	self.emit(QtCore.SIGNAL("ViewChanged"),(self))
        self.SetupSymmetry()

    def setZoomNoUpdate(self, RADIUS):
	self.RADIUS = RADIUS
	if self.RADIUS < 1: self.RADIUS = 1

    def setZoom(self, RADIUS):
	self.RADIUS = RADIUS
	if self.RADIUS < 1: self.RADIUS = 1
        self.updateGL()
        self.emit(QtCore.SIGNAL("ZoomChanged"),(self))

    def setViewsize(self,viewsize):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        self.viewsize = viewsize
        self.resizeGL(self.size().width(),self.size().height())
        self.updateGL()

    def setDoZalmanStereo(self,doZalmanStereo):
        self.doZalmanStereo = doZalmanStereo
        if not doZalmanStereo:
          if hasattr(self,"format") and callable(self.format) and hasattr(self.format(),"samples") and callable(self.format().samples) and self.format().samples()>1:
            opengl.glEnable(0x809D); #/* GL_MULTISAMPLE_ARB */

    def setStereo(self,stereo):
        self.doStereo = stereo

    def getDoZalmanStereo(self):
        return self.doZalmanStereo

    def getStereo(self):
        return self.doStereo

    def getFontScaling(self):
        return self.fontScaling

    def setFontScaling(self,fontScaling):
        self.fontScaling = fontScaling

    def getExtraMatrixCopy(self):
	    if self.extra_matrix:
		    try:
	    		import pygl_coord
	    		extra_matrix_copy = pygl_coord.matrix(4,4,self.extra_matrix)
			return extra_matrix_copy
		    except:
			    return None
	    return None

    def getExtraMatrix(self):
        return self.extra_matrix

    def setExtraMatrix(self,matrix):
        self.extra_matrix=matrix

    def setup_colour_pointers(self):
        import COLOUR
        dum = COLOUR.COLOUR()
        white = COLOUR.COLOUR.insts.RGB("white")
        self.whitep = pygl_coord.doublea(4)
        self.whitep[0] = white[0]; self.whitep[1] = white[1]; self.whitep[2] = white[2]; self.whitep[3] = white[3]; 
        self.symcolp = []
        excludes = ['green','red','blue','white','black','yellow']

        exclude = []
        next = COLOUR.COLOUR.insts.next('default')
        while exclude.count(next) == 0:
                  exclude.append(next)
                  next = COLOUR.COLOUR.insts.next(next)

        final = []
        for col in exclude:
          if not excludes.count(col):
             rgb =  COLOUR.COLOUR.insts.RGB(col)
             symcolp = pygl_coord.doublea(4)
             symcolp[0] = rgb[0]; symcolp[1] = rgb[1]; symcolp[2] = rgb[2]; symcolp[3] = rgb[3]; 
             self.symcolp.append(symcolp)

    def setAxes(self,state):
        self.show_axes = state

    def getAxes(self):
        return self.show_axes
    
    def setShowScale(self,state):
        self.show_scale = state

    def getShowScale(self):
        return self.show_scale
    
    def setFogNearAndFar(self,near,far):
	self.fog_near = near
	self.fog_far = far

    def setFog(self,state,strength=-1):
        self.fog_enabled = state
        if strength>=0.0: self.fog_strength = strength
        self.emit(QtCore.SIGNAL("FogChanged"),(self))

    def setSlab(self,state,width=-1,position=None,clip_cap=None):
        self.slab_enabled = state
        if clip_cap != None:self.clip_cap = clip_cap
        if width>=0.0: self.slab_width = width
        if position != None: self.slab_offset = position
        self.emit(QtCore.SIGNAL("SlabChanged"),(self))
 
class MGGLWidgetSimple(MGGLWidgetCore,QtCore.QObject):

    def setMouseBindings(self,bindings={}):
	pass

    def setBackground(self,r,g,b,a=255):
        self.bgcolour = QtGui.QColor(r,g,b,a)
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	self.updateGL()
	cprim.RGBReps().SetBackgroundColour([r/255.,g/255.,b/255.,a/255.])

    def removeDisplayObject(self, go_in=None,redraw=0):
        i=0
        for go in self.go[:]:
           if go is go_in:
              #print "get rid of", go,i
              self.go.pop(i)
           i=i+1

    def addDisplayObject(self, go=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        if redraw and go:
          self.go.append(go)
	  self.displayListsRebuilt = 1
          self.updateGL()
        self.SetupSymmetry()

    def rebuildAllDisplayObjects(self,redraw=0):
        print "rebuildAllDisplayObjects Simple "
	pass

    def rebuildDisplayObject(self, go=None,redraw=0):
	pass

    def centreOn(self,origin,glide=1):
        rpos_new = (-origin[0],-origin[1],-origin[2])
	self.rpos = rpos_new

    def DrawInThread(self):
	pass

    def __init__(self, parent=None,share=None,format=None):
	QtCore.QObject.__init__(self,parent)
        MGGLWidgetCore.__init__(self,parent,share,format)
	self._size = QtCore.QSize(640,480)
	self._lights = []
        self.atom_font = QtGui.QFont("times",12)
        self.font = QtGui.QFont("times",18)
	self.fm	 = QtGui.QFontMetrics(self.font)

    def SetGO(self, go_in=None,redraw=0):
        self.go=go_in

    def resizeGL(self,w,h):
	self.setSize(QtCore.QSize(w,h))

    def paintGL(self):
	pass

    def updateGL(self):
	pass

    def makeCurrent(self):
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	pass

    def setLights(self,lights):
	self._lights = lights

    def getLights(self):
	ls = []
	i = 0
	for l in self._lights:
		params = {}
		params[opengl.GL_AMBIENT] = l.ambient
		params[opengl.GL_SPECULAR] = l.specular
		params[opengl.GL_DIFFUSE] = l.diffuse
		newl = {}
		newl["params"] = params
		newl["pos"] = QtCore.QPointF(l.position[0],l.position[1])
		newl["depth"] = l.position[2]
		lightName="GL_LIGHT"+str(i)
		exec "lightID=opengl."+lightName
		newl["id"] = lightID
		ls.append(newl)
		i = i+1

	while i < 8:
		ls.append(None)
		i = i+1

	return ls

		

    def extents(self):
	# To be implemented
	xaxis = pygl_coord.Cartesian(1,0,0)
	yaxis = pygl_coord.Cartesian(0,1,0)
	zaxis = pygl_coord.Cartesian(0,0,1)

	# Rest should be OK
	win_w = self.size().width()
	win_h = self.size().height()
        ratio = 1.0* win_w / win_h

        tr = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        tl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        bl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        br = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        return [tl,tr,br,bl]

class MGGLWidgetGL(MGGLWidgetCore):

    def updateGL(self):
	# To be implemented
	pass

    def makeCurrent(self):
	# To be implemented
	pass

    def __init__(self,parent=None,share=None,format=None,use_pbuffer=False,pbuffer_size=QtCore.QSize(600,600)):
        MGGLWidgetCore.__init__(self,parent,share,format)
	self.numberOfLightsOn = 0
        self.setup_colour_pointers()
        self.shader = None
        self.furtherMatrix=None
        self.furtherQuat=None

    def setBackground(self,r,g,b,a=255):
        self.bgcolour = QtGui.QColor(r,g,b,a)
        opengl.glClearColor(self.bgcolour.redF(),self.bgcolour.greenF(),self.bgcolour.blueF(),a)
	self.updateGL()
	cprim.RGBReps().SetBackgroundColour([r/255.,g/255.,b/255.,a/255.])

    def extents(self):
        xaxis,yaxis,zaxis = self.xaxis,self.yaxis,self.zaxis
	win_w = self.size().width()
	win_h = self.size().height()
        ratio = 1.0* win_w / win_h

        tr = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        tl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        bl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        br = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        return [tl,tr,br,bl]

    def DrawAxes(self):
	y = self.bgcolour.redF()*0.299 + self.bgcolour.greenF()*0.587 + self.bgcolour.blueF()*0.114;
        quat = pygl_coord.Quat(self.quat)
        quat.postMult(self.extra_quat)
        tex_id_x_0 = self.bindTexture(self.tex_image_x[0])
        tex_id_x_1 = self.bindTexture(self.tex_image_x[1])
        tex_id_y_0 = self.bindTexture(self.tex_image_y[0])
        tex_id_y_1 = self.bindTexture(self.tex_image_y[1])
        tex_id_z_0 = self.bindTexture(self.tex_image_z[0])
        tex_id_z_1 = self.bindTexture(self.tex_image_z[1])
        opengl.DrawAxes(y,self.size().width(),self.size().height(),quat,self.viewsize,self.axes_position,tex_id_x_0, tex_id_x_1, tex_id_y_0, tex_id_y_1, tex_id_z_0, tex_id_z_1,self.tex_image_x[0].width(),self.tex_image_x[0].height(),self.tex_image_y[0].width(),self.tex_image_y[0].height(),self.tex_image_z[0].width(),self.tex_image_z[0].height(),self.fm.descent())
        opengl.DrawAxesText(y,self.size().width(),self.size().height(),quat,self.viewsize,self.axes_position,tex_id_x_0, tex_id_x_1, tex_id_y_0, tex_id_y_1, tex_id_z_0, tex_id_z_1,self.tex_image_x[0].width(),self.tex_image_x[0].height(),self.tex_image_y[0].width(),self.tex_image_y[0].height(),self.tex_image_z[0].width(),self.tex_image_z[0].height(),self.fm.descent())

    def DrawScale(self):
        y = self.bgcolour.redF()*0.299 + self.bgcolour.greenF()*0.587 + self.bgcolour.blueF()*0.114;
        if y>0.5:
          opengl.glColor3f(0.0,0.0,0.0)
        else:
          opengl.glColor3f(1.0,1.0,1.0)

	win_w = self.size().width()
	win_h = self.size().height()
        ratio = 1.0* win_w / win_h
        dist = u"%.1f \u212B" % (ratio*self.viewsize/2.*self.RADIUS/60.)
        #self.renderText(0.815*self.width(),0.925*self.height(),QtCore.QString(dist))
        import TextLabel
	tex_image_z,twandh = TextLabel.renderStringToPixmap(dist,self.font)
        if hasattr(self,"dist_tex_0"):
          self.deleteTexture(self.dist_tex_0)
          self.deleteTexture(self.dist_tex_1)
        self.dist_tex_0 = self.bindTexture(tex_image_z[0])
        self.dist_tex_1 = self.bindTexture(tex_image_z[1])
        opengl.DrawScale(y,self.size().width(),self.size().height(),self.viewsize,self.dist_tex_0,self.dist_tex_1,tex_image_z[0].width(),tex_image_z[0].height(),self.fm.descent())
        opengl.DrawScaleText(y,self.size().width(),self.size().height(),self.viewsize,self.dist_tex_0,self.dist_tex_1,tex_image_z[0].width(),tex_image_z[0].height(),self.fm.descent())

    def reInitializeTextPrims(self):
        for go in self.go:
           go.obj.reInitializeTextPrims()

    def rebuildAllDisplayObjects(self,redraw=0):
        #print "rebuildAllDisplayObjects GL"
        for go in self.go:
           self.rebuildDisplayObject(go,redraw)
        self.SetupSymmetry()

    def rebuildDisplayObject(self, go=None,redraw=0):
	redrawn = False
        i=0
        for old_go in self.go:
           if go is old_go:
              self.buildlist(go,self.listids[i])
	      redrawn = True
           i = i + 1
        if redraw and go and (not redrawn) and not go.IsAnchored():
          go.obj.draw_solids()
          go.obj.draw_lines(None,0,0,self.line_scaling)
        if redraw:
	  self.displayListsRebuilt = 1
          self.updateGL()
        self.SetupSymmetry()

    def removeDisplayObject(self, go_in=None,redraw=0):
        i=0
        for go in self.go[:]:
           if go is go_in:
              #print "get rid of", go,i
              self.go.pop(i)
              id = self.listids.pop(i)
              opengl.glDeleteLists(id,1)
           i=i+1
        if redraw and self.go:
	  self.displayListsRebuilt = 1
          self.updateGL()
        self.SetupSymmetry()

    def addDisplayObject(self, go=None,redraw=0):
        if redraw and go:
          listid = opengl.glGenLists(1)
          self.go.append(go)
          self.listids.append(listid)
          self.buildlist(go,listid)
	  self.displayListsRebuilt = 1
          self.updateGL()
        self.xaxis,self.yaxis,self.zaxis = self.getaxes()
        self.SetupSymmetry()

    def setLights(self,lights):
#	print "Setting lights",lights
	non = 0
	for light in lights:
		if light.on:
			non = non + 1
	#print "There are",non,"lights turned on"
	self.numberOfLightsOn = non
	maxLights = opengl.intp()
	thisName = ''
	opengl.glGetIntegerv(opengl.GL_MAX_LIGHTS,maxLights)
	for i in range(maxLights.value()):
		lightName="GL_LIGHT"+str(i)
		if hasattr(opengl,lightName):
			exec "lightID=opengl."+lightName
			opengl.glDisable(lightID)
        opengl.glPushMatrix()
	opengl.glLoadIdentity()
        for light in lights:
        	light.apply()
        if self.shaders_on and self.shader:
           self.shader.setNumberOfLights(non)
           if hasattr(self,"circleShader"):
             self.circleShader.setNumberOfLights(non)
        opengl.glPopMatrix()
	self.updateGL()
        self.lights = lights

    def getOpenGLLightParameters(self,lightID):
		import opengl
		lightOn = opengl.intp()
		lightPosition = opengl.floata(4)
		lightParams = opengl.floata(4)
		opengl.glGetIntegerv(lightID,lightOn)
		opengl.glGetLightfv(lightID,opengl.GL_POSITION,lightPosition)
		params = {}
		for parameter in opengl.GL_AMBIENT,opengl.GL_DIFFUSE,opengl.GL_SPECULAR:
			opengl.glGetLightfv(lightID,parameter,lightParams)
			params[parameter] = (lightParams[0],lightParams[1],lightParams[2],lightParams[3])
		light = None
		if lightOn.value()>0: 
			light = {}
			light["pos"] = QtCore.QPointF(lightPosition[0],-lightPosition[1])
			light["depth"] = lightPosition[2]
			light["id"] = lightID
			light["params"] = params
		del lightOn
		del lightPosition
		del lightParams
		return light

    def getLights(self):
		import opengl
		maxLights = opengl.intp()
		opengl.glGetIntegerv(opengl.GL_MAX_LIGHTS,maxLights)
		mylights = []
		for i in range(maxLights.value()):
			lightName="GL_LIGHT"+str(i)
			if hasattr(opengl,lightName):
				exec "lightID=opengl."+lightName
				mylights.append(self.getOpenGLLightParameters(lightID))
		return mylights

    def initializeGL(self):
        # This needs to be called from somewhere ...

        opengl.glClearColor(self.bgcolour.redF(),self.bgcolour.greenF(),self.bgcolour.blueF(),1)
        opengl.glEnableClientState(opengl.GL_VERTEX_ARRAY);
        opengl.glEnableClientState(opengl.GL_NORMAL_ARRAY);
        stereo_availablep = pygl_coord.intp()
        opengl.glGetIntegerv(opengl.GL_STEREO,stereo_availablep)
        self.stereoAvailable = stereo_availablep.value()
        del stereo_availablep
        #print "initializeGL",self.stereoAvailable
	self.drawText = True
	self.drawImages = True
        rq = cprim.RenderQuality()
        rq.SetRenderQuality(0)

        opengl.glLightModeli(opengl.GL_LIGHT_MODEL_LOCAL_VIEWER,opengl.GL_TRUE)
        opengl.glEnable(opengl.GL_NORMALIZE)
        opengl.glEnable(opengl.GL_LIGHTING)
        opengl.glShadeModel(opengl.GL_SMOOTH)
        opengl.glEnable(opengl.GL_DEPTH_TEST)
        opengl.glPolygonMode(opengl.GL_FRONT,opengl.GL_FILL);
        opengl.glPolygonMode(opengl.GL_BACK,opengl.GL_FILL);
        opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)
        opengl.glEnable(opengl.GL_COLOR_MATERIAL)
        #opengl.glEnable(opengl.GL_LINE_SMOOTH)
        opengl.glEnable(opengl.GL_BLEND)
        opengl.glBlendFunc(opengl.GL_SRC_ALPHA,opengl.GL_ONE_MINUS_SRC_ALPHA);
        opengl.SetupFBOBlending()
        #opengl.glHint(opengl.GL_LINE_SMOOTH_HINT, opengl.GL_NICEST);
        opengl.glHint(opengl.GL_FOG_HINT, opengl.GL_NICEST);

        #This is how we create some text, fonts need to be created, oe else PyQt crashes on exit ...
        self.hello = QtCore.QString("Hello World")
        self.atom_font = QtGui.QFont("times",12)
        #print "self.atom_font",self.atom_font
        self.font = QtGui.QFont("times",18)
	self.fm	 = QtGui.QFontMetrics(self.font)

        #This is how we create some image
        piccy_vertices = pygl_coord.CartesianVector(1)
        p1 = pygl_coord.Cartesian(0.0,0.1,0)
        piccy_vertices[0] = p1
        opengl.glPixelStorei(opengl.GL_UNPACK_ALIGNMENT, 1)
        opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_S, opengl.GL_CLAMP);
        opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_T, opengl.GL_CLAMP);
        opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MAG_FILTER, opengl.GL_LINEAR);
        opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MIN_FILTER, opengl.GL_LINEAR);
	import TextLabel
        # We convert to QPixmap, because QGLWidget.bindTexture(QImage) seems to have a bad memory leak.
	tex_image_x,twandh = TextLabel.renderStringToPixmap("x",self.font)
        tex_image_y,twandh = TextLabel.renderStringToPixmap("y",self.font)
	tex_image_z,twandh = TextLabel.renderStringToPixmap("z",self.font)
        self.tex_image_x = QtGui.QPixmap.fromImage(tex_image_x[0]), QtGui.QPixmap.fromImage(tex_image_x[1])
        self.tex_image_y = QtGui.QPixmap.fromImage(tex_image_y[0]), QtGui.QPixmap.fromImage(tex_image_y[1])
        self.tex_image_z = QtGui.QPixmap.fromImage(tex_image_z[0]), QtGui.QPixmap.fromImage(tex_image_z[1])
	self.doMultiTextureBillboards = True
	self.multiTextureAvailable = True
	if sys.platform == "win32":
          import glewInfo
	  self.multiTextureAvailable = glewInfo.check_GL_ARB_multitexture()
	  vendor = opengl.glGetString(opengl.GL_VENDOR)
	  renderer = opengl.glGetString(opengl.GL_RENDERER)
	  if 'Humper' in vendor and 'Chromium' in renderer:
	    self.doMultiTextureBillboards = False
        """
        fill_no_fill_pix = QtGui.QPixmap(os.path.join(os.environ["CCP4MG"],"qticons","fill_and_no_fill.png"))
        fill_no_fill_tex = self.bindTexture(fill_no_fill_pix)
        cprim.Primitive.SetFillNoFillTextureID(fill_no_fill_tex);
        """
        self.circle_tex_id = None
        self.circle_tex_id2 = None
        return

    def loadCircleTextures(self,width=2048,height=2048,line_width=50,circle_width=18,fontFamily="Helvetica",bold=True,italic=False,fontSize=0.5):
        import tempfile
        import CircleTextures
        im = CircleTextures.getTextureImage(width,height,line_width,circle_width,fontFamily,bold,italic,fontSize)
        f = tempfile.NamedTemporaryFile(suffix=".png",prefix="ccp4mg"+str(os.getpid()))
        fn = f.name
        f.close()
        im.save(fn)
        ii = image_info.image_info(fn)
        self.circle_tex_id = opengl.load_texture(ii,opengl.MIPMAP);
        self.circle_tex_id2 = opengl.load_texture(ii,opengl.MIPMAP);
        os.unlink(fn)

    def copyShaders(self,otherGLWidget):
        self.setShadowShader(otherGLWidget.shadowVertexShader,otherGLWidget.shadowFragmentShader)
        self.setSSAOShader(otherGLWidget.ssaoVertexShader,otherGLWidget.ssaoFragmentShader)
        self.setCircleShader(otherGLWidget.circleVertexShader,otherGLWidget.circleFragmentShader)
        self.setCircleShadowShader(otherGLWidget.circleShadowVertexShader,otherGLWidget.circleShadowFragmentShader)
        self.setTextBackgroundShader(otherGLWidget.textBackgroundVertexShader,otherGLWidget.textBackgroundFragmentShader)
        self.setDepthShader(otherGLWidget.depthVertexShader,otherGLWidget.depthFragmentShader)
        self.setEdgeDetectShader(otherGLWidget.edgeDetectVertexShader,otherGLWidget.edgeDetectFragmentShader)
        self.setNormalShader(otherGLWidget.normalAsColourVertexShader,otherGLWidget.normalAsColourFragmentShader)
        self.setTextShader(otherGLWidget.textVertexShader,otherGLWidget.textFragmentShader)
        self.setShader(otherGLWidget.vertexShader,otherGLWidget.fragmentShader)
        self.setBlurShaders(otherGLWidget.blurVertexShader,otherGLWidget.blurXFragmentShader,otherGLWidget.blurYFragmentShader)
        self.setShaderState(otherGLWidget.getShaderState())
        self.setShadowState(otherGLWidget.doShadow)
        self.setAmbientOcclusionState(otherGLWidget.doAmbient)
        self.calculateShadowExtents()

    def getShaderState(self):
	return self.shaders_on

    def setShaderState(self,state):
        if type(state) == tuple:
           dum,state = state
	self.shaders_on = state
        if self.shader:
           self.shader.setNumberOfLights(self.numberOfLightsOn)
           if hasattr(self,"circleShader"):
             self.circleShader.setNumberOfLights(self.numberOfLightsOn)
        w,h = self.width(),self.height()
        self.resizeGL(w,h)
        self.emit(QtCore.SIGNAL("ShaderStateChanged"), (self,state))

    def getShader(self):
        return (self.vertexShader,self.fragmentShader)

    def setShadowShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.shadowShader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.shadowVertexShader = vertexShader
                self.shadowFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setSSAOShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.ssaoShader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.ssaoVertexShader = vertexShader
                self.ssaoFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setCircleShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.circleShader = glShaders.MGGLShader(vertexShader,fragmentShader)
		nCustomClipPlanesLoc = self.circleShader.getUniformLocation("nCustomClipPlanes")
		self.circleShader.Uniform1i(nCustomClipPlanesLoc,0)
                self.circleVertexShader = vertexShader
                self.circleFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setCircleShadowShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.circleShadowShader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.circleShadowVertexShader = vertexShader
                self.circleShadowFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setTextBackgroundShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.textBackgroundShader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.textBackgroundVertexShader = vertexShader
                self.textBackgroundFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setDepthShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.depthShader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.depthVertexShader = vertexShader
                self.depthFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setBlurShaders(self,vertexShader,blurXFragmentShader,blurYFragmentShader):
	try:
		import glShaders
		self.blurXShader = glShaders.MGGLShader(vertexShader,blurXFragmentShader)
		self.blurXShader.setSamplerUniforms()
		self.blurXShader.turnOff()
		import glShaders
		self.blurYShader = glShaders.MGGLShader(vertexShader,blurYFragmentShader)
		self.blurYShader.setSamplerUniforms()
		self.blurYShader.turnOff()
                self.blurVertexShader = vertexShader
                self.blurXFragmentShader = blurXFragmentShader
                self.blurYFragmentShader = blurYFragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setEdgeDetectShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.edgeDetectShader = glShaders.MGGLShader(vertexShader,fragmentShader)
		self.edgeDetectShader.setSamplerUniforms()
		self.edgeDetectShader.turnOff()
                self.edgeDetectVertexShader = vertexShader
                self.edgeDetectFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setNormalShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.normalAsColourShader = glShaders.MGGLShader(vertexShader,fragmentShader)
		self.normalAsColourShader.setSamplerUniforms()
		self.normalAsColourShader.turnOff()
                self.normalAsColourVertexShader = vertexShader
                self.normalAsColourFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setTextShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.textShader = glShaders.MGGLShader(vertexShader,fragmentShader)
		self.textShader.setSamplerUniforms()
		self.textShader.turnOff()
                self.textVertexShader = vertexShader
                self.textFragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setShader(self,vertexShader,fragmentShader):
	try:
		import glShaders
		self.shader = glShaders.MGGLShader(vertexShader,fragmentShader)
		self.shader.setSamplerUniforms()
		self.shader.turnOff()
                self.vertexShader = vertexShader
                self.fragmentShader = fragmentShader
	except:
		print "This version of ccp4mg does not have shader support."

    def setCustomClipPlanes(self,planes):
        self.customClipPlanes= planes

    def setup_clipping(self):
        opengl.glEnable(opengl.GL_CLIP_PLANE0)
        opengl.glEnable(opengl.GL_CLIP_PLANE1)
        if self.inShadow:
          opengl.glDisable(opengl.GL_CLIP_PLANE1)
          opengl.glClipPlane(opengl.GL_CLIP_PLANE0,opengl.newdv4(0,0,-1,-(self.slab_offset-self.slab_width/2.)-0.5))
        if not self.inShadow:
          opengl.glClipPlane(opengl.GL_CLIP_PLANE0,opengl.newdv4(0,0,1,self.slab_offset+self.slab_width/2.))
          opengl.glClipPlane(opengl.GL_CLIP_PLANE1,opengl.newdv4(0,0,-1,-(self.slab_offset-self.slab_width/2.)))

        customClipPlanes = []

        for pl in self.customClipPlanes:
          if hasattr(pl,"has_key") and pl.has_key("visible") and pl["visible"] and pl.has_key("plane"):
             customClipPlanes.append(pl["plane"])
             
        # Plane "normal" vectors are normalized but the offset is not.
        # This allows user to specify a normal as a direction and offset in angstroms
        # without worrying about normalization. This could be a problem if we use planes
        # generated automatically from atom positions, etc. May need to rethink this.
        z = pygl_coord.Cartesian(0,0,-1)
        nplanes = 0
        opengl.glDisable(opengl.GL_CLIP_PLANE2)
        opengl.glDisable(opengl.GL_CLIP_PLANE3)
        opengl.glDisable(opengl.GL_CLIP_PLANE4)
        opengl.glDisable(opengl.GL_CLIP_PLANE5)
        for iPlane in range(len(customClipPlanes)):
          thePlane = customClipPlanes[iPlane]
          myvec = pygl_coord.Cartesian(thePlane[0],thePlane[1],thePlane[2])
          if abs(myvec.length())<1e-5:
            break
          myvec.normalize()
          opengl.glEnable(opengl.GL_CLIP_PLANE0+nplanes+2)
          opengl.glClipPlane(opengl.GL_CLIP_PLANE0+nplanes+2,opengl.newdv4(myvec.get_x(),myvec.get_y(),myvec.get_z(),thePlane[3]))
          if self.shaders_on and hasattr(self,"circleShader") and hasattr(self.circleShader,"getUniformLocation") :
            angle = math.acos(pygl_coord.Cartesian.DotProduct(myvec,z))
            glslMult =  60./float(self.RADIUS)
            a = math.cos(angle)*(self.NEAR+self.FAR)/2.-thePlane[3]*glslMult
            otherClip = opengl.newfv4(myvec.get_x(),myvec.get_y(),myvec.get_z(),-a)
            self.circleShader.setClipPlane(nplanes+2,otherClip);
          nplanes = nplanes + 1
        if self.shaders_on and hasattr(self.circleShader,"getUniformLocation") :
          nCustomClipPlanesLoc = self.circleShader.getUniformLocation("nCustomClipPlanes")
          self.circleShader.Uniform1i(nCustomClipPlanesLoc,nplanes)

        if self.shaders_on and self.shader:
           glslMult =  60./float(self.RADIUS)
           nearClip = opengl.newfv4(0,0,1,(self.NEAR+self.FAR)/2.+glslMult*(self.slab_offset+self.slab_width/2.))
           farClip = opengl.newfv4(0,0,-1,-((self.NEAR+self.FAR)/2.+glslMult*(self.slab_offset-self.slab_width/2.)))
           self.shader.setClipPlanes(nearClip,farClip);
           if hasattr(self,"circleShader"):
             self.circleShader.setClipPlanes(nearClip,farClip);
             self.circleShader.turnOff()
             clipCapLoc = self.circleShader.getUniformLocation("clipCap")
             self.circleShader.Uniform1i(clipCapLoc,self.clip_cap)
           opengl.delcGLfp(nearClip)
           opengl.delcGLfp(farClip)

    def setup_fog(self):
        self.FOG_START = self.NEAR # Temporary
        self.FOG_END = self.FAR
        dist = .5*(self.FOG_START+self.FOG_END)

	fog_near = dist + ((60.*self.fog_near)/self.RADIUS)
        fog_far = dist + ((60.*self.fog_far)/self.RADIUS)

        if(fog_far<=fog_near): fog_far = fog_near+0.1
        opengl.glEnable(opengl.GL_FOG)
        if hasattr(self,"fogcolour") and self.fogcolour != None:
	  fogcolour = opengl.newfv4(self.fogcolour.red()/255.,self.fogcolour.green()/255.,self.fogcolour.blue()/255.,self.fogcolour.alpha()/255.)
        else:
	  fogcolour = opengl.newfv4(self.bgcolour.red()/255.,self.bgcolour.green()/255.,self.bgcolour.blue()/255.,self.bgcolour.alpha()/255.)
        opengl.glFogi(opengl.GL_FOG_MODE,opengl.GL_LINEAR)
        opengl.glFogfv(opengl.GL_FOG_COLOR, fogcolour)
        opengl.glFogf(opengl.GL_FOG_START,fog_near)
        opengl.glFogf(opengl.GL_FOG_END,fog_far)
        opengl.delcGLfp(fogcolour)

    def calculateShadowExtents(self):
        import mmdb2 as mmdb
        dobj = global_definitions.get_dataobj(object_type='MolData')
        if len(dobj)<1: return
        selection = 'all'
        total_maxe = [1e-7,1e-7,1e-7]
        total_mine = [1e+7,1e+7,1e+7]
        for obj in dobj:
          rv = obj.parse_selection(command=selection)
          if rv[0] == 0 and rv[1] > 0:
            import pygl_coord
            selHnd = rv[1]
            tmp = pygl_coord.doublea(1)
            rtde =  tmp.frompointer(mmdb.realtype_to_double(obj.molHnd.Extent(selHnd)))
            mine,maxe = (rtde[0],rtde[1],rtde[2]),(rtde[3],rtde[4],rtde[5])
            mide = ((mine[0]+maxe[0])/2.,(mine[1]+maxe[1])/2.,(mine[2]+maxe[2])/2.)
            theSize = max(abs(mine[0]-maxe[0]),abs(mine[1]-maxe[1]),abs(mine[2]-maxe[2]))
            if (mine[0]) < total_mine[0]: total_mine[0] = mine[0]
            if (mine[1]) < total_mine[1]: total_mine[1] = mine[1]
            if (mine[2]) < total_mine[2]: total_mine[2] = mine[2]
            if (maxe[0]) > total_maxe[0]: total_maxe[0] = maxe[0]
            if (maxe[1]) > total_maxe[1]: total_maxe[1] = maxe[1]
            if (maxe[2]) > total_maxe[2]: total_maxe[2] = maxe[2]
        total_mide = (-(total_mine[0]+total_maxe[0])/2.,-(total_mine[1]+total_maxe[1])/2.,-(total_mine[2]+total_maxe[2])/2.)
        theTotalSize = max(abs(total_mine[0]-total_maxe[0]),abs(total_mine[1]-total_maxe[1]),abs(total_mine[2]-total_maxe[2]))
        #print "theTotalSize",theTotalSize
        #print "theTotalCom",total_mide
        self.shadowExtent = theTotalSize+10
        self.shadowCentre = total_mide


    def setupModelviewCore(self):
        opengl.glMatrixMode(opengl.GL_MODELVIEW);
        opengl.glLoadIdentity()

        if self.NEAR> 60 or self.FAR < 60 or (self.FAR-self.NEAR)<60 or 1:
          dist = .5*(self.NEAR+self.FAR)
        else:
          dist = 60
        #opengl.glTranslatef(0,0,-dist+self.slab_offset)
        if self.inShadow:
          opengl.glTranslatef(0,0,-self.shadowExtent/2.)
          opengl.glScalef(1,1,1)
          pass
        else:
          opengl.glTranslatef(0,0,-dist)
          opengl.glScalef(60.0/float(self.RADIUS),60.0/float(self.RADIUS),60.0/float(self.RADIUS))

    def setupModelview(self,furtherQuat=None,furtherMatrix=None):
        self.setupModelviewCore()

        if self.fog_enabled:
          self.setup_fog()
        else:
          if hasattr(self,"fogcolour") and self.fogcolour != None:
	    fogcolour = opengl.newfv4(self.fogcolour.red()/255.,self.fogcolour.green()/255.,self.fogcolour.blue()/255.,self.fogcolour.alpha()/255.)
          else:
	    fogcolour = opengl.newfv4(self.bgcolour.red()/255.,self.bgcolour.green()/255.,self.bgcolour.blue()/255.,self.bgcolour.alpha()/255.)
          opengl.glFogfv(opengl.GL_FOG_COLOR, fogcolour)
          opengl.glDisable(opengl.GL_FOG)
          # We do the folowing so that we do not have to compile separate shaders with fog on/off.
          opengl.glFogi(opengl.GL_FOG_MODE,opengl.GL_LINEAR)
          opengl.glFogf(opengl.GL_FOG_START,self.FAR)
          opengl.glFogf(opengl.GL_FOG_END,self.FAR+1.0)

        if self.slab_enabled:
          self.setup_clipping()
        else:
          opengl.glDisable(opengl.GL_CLIP_PLANE0)
          opengl.glDisable(opengl.GL_CLIP_PLANE1)
          opengl.glDisable(opengl.GL_CLIP_PLANE2)
          opengl.glDisable(opengl.GL_CLIP_PLANE3)
          opengl.glDisable(opengl.GL_CLIP_PLANE4)
          opengl.glDisable(opengl.GL_CLIP_PLANE5)
          glslMult =  60./float(self.RADIUS)
	  if self.inShadow:
            #FIXME ????? Really
            self.shader.setClipPlanes(opengl.newfv4(0,0,1,(self.NEAR+self.FAR)/2.+glslMult*(500.)),opengl.newfv4(0,0,-1,-((self.NEAR+self.FAR)/2.+glslMult*(-500.))));
            if hasattr(self,"circleShader"):
              self.circleShader.setClipPlanes(opengl.newfv4(0,0,1,(self.NEAR+self.FAR)/2.+glslMult*(500.)),opengl.newfv4(0,0,-1,-((self.NEAR+self.FAR)/2.+glslMult*(-500.))));
            self.shadowShader.setClipPlanes(opengl.newfv4(0,0,1,(self.NEAR+self.FAR)/2.+glslMult*(500.)),opengl.newfv4(0,0,-1,-((self.NEAR+self.FAR)/2.+glslMult*(-500.))));
          else:
            nearClip = opengl.newfv4(0,0,1,(self.FAR))
            farClip = opengl.newfv4(0,0,-1,((self.NEAR)))
            if hasattr(self,"circleShader") and hasattr(self.circleShader,"setClipPlanes") and hasattr(self.circleShader,"turnOff"):
              self.circleShader.setClipPlanes(nearClip,farClip)
              self.circleShader.turnOff()
            opengl.delcGLfp(nearClip)
            opengl.delcGLfp(farClip)

        quat = pygl_coord.Quat(self.quat)
        quat.postMult(self.extra_quat)
	if self.extra_matrix:
		opengl.glMultMatrixd(self.extra_matrix)
	if furtherMatrix:
		opengl.glMultMatrixd(furtherMatrix)
        if furtherQuat:
          quat.postMult(furtherQuat)
        glrotmat = quat.getInvMatrix().to_dp()
        opengl.glMultMatrixd(glrotmat)
        
        self.xaxis,self.yaxis,self.zaxis = self.getaxes()
        if self.inShadow:
          opengl.glTranslated(self.shadowCentre[0],self.shadowCentre[1],self.shadowCentre[2])
        else:
          opengl.glTranslated(self.rpos[0],self.rpos[1],self.rpos[2])
        opengl.delcdp(glrotmat)
       
    def showMessage(self,message):
	pass

    def paintGL(self):
        opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT)
        self.setupModelview()
        self.paintGLMain()
        opengl.glFlush()

    def drawOpaque(self,solids=True,anchored=True):
            defaultColour = False
            i=0
            for id in self.listids:
              if self.go[i].obj.visible>0 and self.go[i].obj.GetAlpha()>=0.99 and self.go[i].obj.IsAnchored()==anchored:
                opengl.glEnable(opengl.GL_CULL_FACE)
                if hasattr(self.go[i],"ui") and not self.inShadow:
                  if hasattr(self.go[i].ui,"isDoubleSided") and callable(self.go[i].ui.isDoubleSided):
                     shiny = False
                     if self.go[i].ui.isDoubleSided() and solids:
                       if hasattr(self.go[i].ui,"insideShiny") and callable(self.go[i].ui.insideShiny):
                          shiny = self.go[i].ui.insideShiny()
                       if shiny:
                         opengl.glDisable(opengl.GL_CULL_FACE)
                         opengl.glLightModeli(opengl.GL_LIGHT_MODEL_TWO_SIDE,1)
                       else:
                         opengl.glCullFace(opengl.GL_FRONT)
                         opengl.glLightModeli(opengl.GL_LIGHT_MODEL_TWO_SIDE,0)
                       if hasattr(self.go[i].ui,"insideColour") and callable(self.go[i].ui.insideColour):
                         inside_col = self.go[i].ui.insideColour()
                         if inside_col != "default":
                           colv = cprim.RGBReps().GetColour(inside_col)
                           insColour = opengl.newfv4(colv[0],colv[1],colv[2],1)
                           if shiny or (self.shaders_on and self.shader):
                             if self.shaders_on and self.shader:
                               self.shader.setBackSurfaceLightProperties(bool(shiny),False)
                               defaultColour = False
                             opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_NONE)
                             opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)
                             opengl.glMaterialfv(opengl.GL_BACK,opengl.GL_AMBIENT_AND_DIFFUSE,insColour)
                           else:
                             if self.shaders_on and self.shader:
                               self.shader.setBackSurfaceLightProperties(bool(shiny),False)
                               defaultColour = False
                             opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_AMBIENT)
                             opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_NONE)
                             opengl.glLightModelfv(opengl.GL_LIGHT_MODEL_AMBIENT,insColour)
                           opengl.delGLfp(insColour)
                         else:
                           if self.shaders_on and self.shader:
                              self.shader.setBackSurfaceLightProperties(bool(shiny),True)
                              defaultColour = True
                           opengl.glColorMaterial(opengl.GL_FRONT_AND_BACK,opengl.GL_AMBIENT_AND_DIFFUSE)
                         if not shiny:
                           # FIXME: glCallList was it seems only needed by HBonds, Contacts and Geometry, maybe others.
                           # but it breaks shader state of depthShadow, maybe we can turn it on again when required
                           # Does this one ever get called?
                           if not self.inShadow and not self.go[i].obj.IsAnchored():opengl.glCallList(id)
                           if self.go[i].obj.IsAnchored():
                             self.go[i].obj.draw_solids()
                       if not shiny:
                         opengl.glCullFace(opengl.GL_BACK)
                         ambColour = opengl.newfv4(0.2,0.2,0.2,1)
                         opengl.glLightModelfv(opengl.GL_LIGHT_MODEL_AMBIENT,ambColour)
                         opengl.delGLfp(ambColour)
                     if not shiny:
                       opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_NONE)
                       opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)
                       opengl.glLightModeli(opengl.GL_LIGHT_MODEL_TWO_SIDE,0)
                # FIXME: glCallList was it seems only needed by HBonds, Contacts and Geometry, maybe others.
                # but it breaks shader state of depthShadow, maybe we can turn it on again when required
                if self.shaders_on and self.shader and solids:
                  self.shader.setBackSurfaceLightProperties(True,defaultColour)
                if not self.inShadow and not self.go[i].obj.IsAnchored():
                  pass
                  # NEED TO TURN OFF SHADER HERE, tricky...
                  #opengl.glCallList(id)
                  self.go[i].obj.draw_solids()
                  #self.shader.turnOff()
                  self.go[i].obj.draw_lines(None,0,0,self.line_scaling)
                  #self.shader.turnOff()
                  if self.doShadow and not self.inShadow and solids:
                    opengl.glEnable( opengl.GL_TEXTURE_2D);
                opengl.glLineWidth(2.0);
                if not solids: self.go[i].obj.DrawUnitCell()
                if self.go[i].obj.GetDrawSymmetry():
                   #self.go[i].SetupSymmetry(self.rpos,self.extents())
                   nsym = self.go[i].obj.GetNumSymmetryMatrices()
                   symm_mat = pygl_coord.MatrixVector(self.go[i].obj.symm_mat)
                   for isym in range(nsym):
		      colindex = self.go[i].obj.GetSymmetryMatrixNumber(isym)
                      opengl.glPushMatrix()
                      glrotmat = symm_mat[isym].Transpose().to_dp()
                      opengl.glMultMatrixd(glrotmat)
                      opengl.delcdp(glrotmat)
                      if self.go[i].obj.GetDrawSymmetryColoured():
                        if colindex < len(self.symcolp):
			  if solids: self.go[i].obj.draw_solids(self.symcolp[colindex],0,1)
                        else:
                          if solids: self.go[i].obj.draw_solids(self.whitep,0,1)
                      else:
                        if solids: self.go[i].obj.draw_solids()
                      if self.go[i].obj.GetDrawSymmetryColoured():
                        if colindex < len(self.symcolp):
                          if not solids: self.go[i].obj.draw_lines(self.symcolp[colindex],1,1)
                        else:
                          if not solids: self.go[i].obj.draw_lines(self.whitep,1,1,self.line_scaling)
                      else:
                        if not solids: self.go[i].obj.draw_lines(None,0,0,self.line_scaling)
                      opengl.glPopMatrix()
                if self.go[i].obj.IsAnchored():
                  if (not self.go[i].obj.GetDrawSymmetry()) or self.go[i].doCentralSymmetry:
                    if solids: self.go[i].obj.draw_solids()
                    if not solids: self.go[i].obj.draw_lines(None,0,0,self.line_scaling)
              i=i+1

    def drawTransparent(self,solids=True,anchored=True):
            quat = pygl_coord.Quat(self.quat)
            i=0
            for id in self.listids:
              if self.go[i].obj.visible>0 and self.go[i].obj.GetAlpha()<0.99 and self.go[i].obj.IsAnchored()==anchored:
                if not self.inShadow:
       	          opengl.glCullFace(opengl.GL_BACK)
                if hasattr(self.go[i],"ui") and not self.inShadow:
                  if hasattr(self.go[i].ui,"isDoubleSided") and callable(self.go[i].ui.isDoubleSided):
                     if self.go[i].ui.isDoubleSided() and solids:
                       opengl.glDisable(opengl.GL_CULL_FACE)
                       opengl.glLightModeli(opengl.GL_LIGHT_MODEL_TWO_SIDE,1)
                       if hasattr(self.go[i].ui,"insideColour") and callable(self.go[i].ui.insideColour):
                         inside_col = self.go[i].ui.insideColour()
                         if inside_col != "default":
                           colv = cprim.RGBReps().GetColour(inside_col)
                           insColour = opengl.newfv4(colv[0],colv[1],colv[2],self.go[i].obj.GetAlpha())
                           opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_NONE)
                           opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)
                           opengl.glMaterialfv(opengl.GL_BACK,opengl.GL_AMBIENT_AND_DIFFUSE,insColour)
                           opengl.delGLfp(insColour)
                         else:
                           opengl.glColorMaterial(opengl.GL_FRONT_AND_BACK,opengl.GL_AMBIENT_AND_DIFFUSE)
                         if self.shaders_on and self.shader:
                            # Hmm, seems we do only shiny when transparent without shaders !!!!
                            shiny = False
                            if hasattr(self.go[i].ui,"insideShiny") and callable(self.go[i].ui.insideShiny):
                               shiny = self.go[i].ui.insideShiny()
                            self.shader.setBackSurfaceLightProperties(bool(shiny),inside_col=="default")
                # FIXME: glCallList was it seems only needed by HBonds, Contacts and Geometry, maybe others.
                # but it breaks shader state of depthShadow, maybe we can turn it on again when required
                if  not self.inShadow and not self.go[i].obj.IsAnchored():opengl.glCallList(id)
                opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_NONE)
                opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)
                opengl.glLightModeli(opengl.GL_LIGHT_MODEL_TWO_SIDE,0)
                if not solids: self.go[i].obj.DrawUnitCell()
                if self.go[i].obj.GetDrawSymmetry():
                   #self.go[i].SetupSymmetry(self.rpos,self.extents())
                   nsym = self.go[i].obj.GetNumSymmetryMatrices()
                   symm_mat = pygl_coord.MatrixVector(self.go[i].obj.symm_mat)
                   for isym in range(nsym):
		      colindex = self.go[i].obj.GetSymmetryMatrixNumber(isym)
                      opengl.glPushMatrix()
                      glrotmat = symm_mat[isym].Transpose().to_dp()
                      opengl.glMultMatrixd(glrotmat)
                      opengl.delcdp(glrotmat)
	              if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
                         self.shader.turnOn()
                         #self.shader.setDefaultDataAttrib1f("occData",1.0)
                      if solids: self.go[i].obj.draw_solids()
	              if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
                      # This is broken, need longer section like for alpha==1
                      self.go[i].obj.draw_billboards(quat,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
                      if self.go[i].obj.GetDrawSymmetryColoured():
                        if colindex < len(self.symcolp):
                          if not solids: self.go[i].obj.draw_lines(self.symcolp[colindex],1,1,self.line_scaling)
                        else:
                          if not solids: self.go[i].obj.draw_lines(self.whitep,1,1,self.line_scaling)
                      else:
                        if not solids: self.go[i].obj.draw_lines(None,0,0,self.line_scaling)
                      opengl.glPopMatrix()
                if self.go[i].obj.IsAnchored():
	          if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
                     self.shader.turnOn()
                     #self.shader.setDefaultDataAttrib1f("occData",1.0)
                  if (not self.go[i].obj.GetDrawSymmetry()) or self.go[i].doCentralSymmetry:
                    if solids: self.go[i].obj.draw_solids()
	            if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
                    if not solids: self.go[i].obj.draw_lines(None,0,0,self.line_scaling)
              i=i+1

    def drawSphereBillboards(self,quat):
        prims2 = cprim.BillboardPrimitivePointerVector()
        for go in self.go:
          if go.obj.visible:
            ps = go.obj.GetImposterPrimitives()
            primsnew = cprim.BillboardPrimitivePointerVector(len(prims2))
            primsnew[:len(prims2)] = prims2
            primsnew[len(prims2):len(prims2)+len(ps)] = ps
            prims2 = primsnew
        if hasattr(self,"circleShader"):
          if self.slab_enabled and not self.inShadow:
            glslMult =  60./float(self.RADIUS)
            opengl.glEnable(opengl.GL_CLIP_PLANE0)
            opengl.glEnable(opengl.GL_CLIP_PLANE1)
            # Here,I am stretching the "fixed function clipping" by 2 angstroms front and back to 
            # enable imposter spheres to be more likely (i.e. unless R>2) to be clipped nicely.
            # Then I do the fancier clipping in the shader.
            nearClip = opengl.doublea(4)
            opengl.glGetClipPlane(opengl.GL_CLIP_PLANE0,nearClip);
            farClip = opengl.doublea(4)
            opengl.glGetClipPlane(opengl.GL_CLIP_PLANE1,farClip);
            opengl.glPushMatrix()
            self.setupModelviewCore()
            # But why is this so complicated? Why is all this scaling necessary after above 2 lines?
            opengl.glScalef(float(self.RADIUS)/60.,float(self.RADIUS)/60.,float(self.RADIUS)/60.)
            nearClip[3] = nearClip[3] - 498.5 / 60.0*float(self.RADIUS)
            farClip[3] = farClip[3] + 502.5 / 60.0*float(self.RADIUS)
            opengl.glClipPlane(opengl.GL_CLIP_PLANE0,nearClip)
            opengl.glClipPlane(opengl.GL_CLIP_PLANE1,farClip)
            otherClip = opengl.doublea(4)
            # This is sufficient for e.g. GL version: 3.3.0 NVIDIA 295.59 (GeForce 8600 GT)/ Shader 3.30 NVIDIA via Cg compiler
            # But may need to set custom clip planes with adjustment above for older shader versions/ATI, Intel.
            opengl.glDisable(opengl.GL_CLIP_PLANE2)
            opengl.glDisable(opengl.GL_CLIP_PLANE3)
            opengl.glDisable(opengl.GL_CLIP_PLANE4)
            opengl.glDisable(opengl.GL_CLIP_PLANE5)
            opengl.glPopMatrix()
          if self.fog_enabled:
            self.setup_fog()
          else:
            if hasattr(self,"fogcolour") and self.fogcolour != None:
	      fogcolour = opengl.newfv4(self.fogcolour.red()/255.,self.fogcolour.green()/255.,self.fogcolour.blue()/255.,self.fogcolour.alpha()/255.)
            else:
	      fogcolour = opengl.newfv4(self.bgcolour.red()/255.,self.bgcolour.green()/255.,self.bgcolour.blue()/255.,self.bgcolour.alpha()/255.)
            opengl.glFogfv(opengl.GL_FOG_COLOR, fogcolour)
            opengl.glDisable(opengl.GL_FOG)
            # We do the folowing so that we do not have to compile separate shaders with fog on/off.
            opengl.glFogi(opengl.GL_FOG_MODE,opengl.GL_LINEAR)
            opengl.glFogf(opengl.GL_FOG_START,self.FAR)
            opengl.glFogf(opengl.GL_FOG_END,self.FAR+1.0)
          right = quat.getInvMatrix() * pygl_coord.Cartesian(1,0,0)
          up = quat.getInvMatrix() * pygl_coord.Cartesian(0,1,0)
          if self.inShadow or self.inAmbient:
            self.circleShader.setNumberOfLights(1)
          if not self.inShadow and not self.inAmbient:
            self.circleShader.setNumberOfLights(self.numberOfLightsOn)
            self.circleShader.turnOn()
            upX = self.circleShader.getUniformLocation("upX")
            upY = self.circleShader.getUniformLocation("upY")
            upZ = self.circleShader.getUniformLocation("upZ")
            self.circleShader.Uniform1f(upX,up.get_x())
            self.circleShader.Uniform1f(upY,up.get_y())
            self.circleShader.Uniform1f(upZ,up.get_z())
            rightX = self.circleShader.getUniformLocation("rightX")
            rightY = self.circleShader.getUniformLocation("rightY")
            rightZ = self.circleShader.getUniformLocation("rightZ")
            self.circleShader.Uniform1f(rightX,right.get_x())
            self.circleShader.Uniform1f(rightY,right.get_y())
            self.circleShader.Uniform1f(rightZ,right.get_z())
            scaling = self.circleShader.getUniformLocation("scaling")
            self.circleShader.Uniform1f(scaling,60.0/self.RADIUS)
          elif self.inShadow:
            opengl.glCullFace(opengl.GL_BACK)
            self.circleShadowShader.turnOn()
            upX = self.circleShadowShader.getUniformLocation("upX")
            upY = self.circleShadowShader.getUniformLocation("upY")
            upZ = self.circleShadowShader.getUniformLocation("upZ")
            self.circleShadowShader.Uniform1f(upX,up.get_x())
            self.circleShadowShader.Uniform1f(upY,up.get_y())
            self.circleShadowShader.Uniform1f(upZ,up.get_z())
            rightX = self.circleShadowShader.getUniformLocation("rightX")
            rightY = self.circleShadowShader.getUniformLocation("rightY")
            rightZ = self.circleShadowShader.getUniformLocation("rightZ")
            self.circleShadowShader.Uniform1f(rightX,right.get_x())
            self.circleShadowShader.Uniform1f(rightY,right.get_y())
            self.circleShadowShader.Uniform1f(rightZ,right.get_z())
            scaling = self.circleShadowShader.getUniformLocation("scaling")
            self.circleShadowShader.Uniform1f(scaling,60.0/self.RADIUS)
          for go in self.go:
            if go.obj.visible:
              go.obj.draw_imposters()
              symm_mat = []

              if go.obj.GetDrawSymmetry():
                nsym = go.obj.GetNumSymmetryMatrices()
                symm_mat = pygl_coord.MatrixVector(go.obj.symm_mat)
  
                for isym in range(nsym):
                  opengl.glPushMatrix()
                  glrotmat =  symm_mat[isym].Transpose().to_dp()
                  opengl.glMultMatrixd(glrotmat)
                  opengl.delcdp(glrotmat)
                  qorig = pygl_coord.Quat(quat)
                  qsym = pygl_coord.Quat(symm_mat[isym])
                  q = pygl_coord.Quat()
                  q.postMult(qsym)
                  q.postMult(qorig)
                  right = q.getInvMatrix() * pygl_coord.Cartesian(1,0,0)
                  up = q.getInvMatrix() * pygl_coord.Cartesian(0,1,0)
                  if not self.inShadow and not self.inAmbient:
                    self.circleShader.Uniform1f(upX,up.get_x())
                    self.circleShader.Uniform1f(upY,up.get_y())
                    self.circleShader.Uniform1f(upZ,up.get_z())
                    self.circleShader.Uniform1f(rightX,right.get_x())
                    self.circleShader.Uniform1f(rightY,right.get_y())
                    self.circleShader.Uniform1f(rightZ,right.get_z())
                  elif self.inShadow:
                    self.circleShadowShader.Uniform1f(upX,up.get_x())
                    self.circleShadowShader.Uniform1f(upY,up.get_y())
                    self.circleShadowShader.Uniform1f(upZ,up.get_z())
                    self.circleShadowShader.Uniform1f(rightX,right.get_x())
                    self.circleShadowShader.Uniform1f(rightY,right.get_y())
                    self.circleShadowShader.Uniform1f(rightZ,right.get_z())
                  go.obj.draw_imposters()
                  opengl.glPopMatrix()

        if hasattr(self,"circleShader"):
          if not self.inShadow and not self.inAmbient:
            self.circleShader.turnOff()
          elif self.inShadow:
            self.circleShadowShader.turnOff()


    def paintGLMain(self,smooth_line=1):
        opengl.glColorMaterial(opengl.GL_BACK,opengl.GL_NONE)
        opengl.glColorMaterial(opengl.GL_FRONT,opengl.GL_AMBIENT_AND_DIFFUSE)

        opengl.glDepthFunc(opengl.GL_LESS);
        opengl.glBlendFunc(opengl.GL_SRC_ALPHA,opengl.GL_ONE_MINUS_SRC_ALPHA);
        opengl.SetupFBOBlending()
        opengl.glDisable(opengl.GL_TEXTURE_2D)
        opengl.glEnableClientState(opengl.GL_VERTEX_ARRAY)
        opengl.glEnableClientState(opengl.GL_NORMAL_ARRAY)
        opengl.glEnableClientState(opengl.GL_COLOR_ARRAY)

        nplanes = 0
	if self.transparency() and self.nofTransparentObjects()>0:
          axes = self.getaxes()
          # Hack needed because swig isn't up to converting [] to std::vector with derived objects it seems.
	  import xmapview
          cobjs = xmapview.DisplayobjectVector()
          for ob in self.go:
            cobjs.append(ob.obj)
          v = cprim.DoubleDoubleVector()

	  if self.displayListsRebuilt == 1:
	    rebuilt = 1
	    self.displayListsRebuilt = 0
          else:
	    rebuilt = 0
          if len(self.visibility_list)!=len(self.go):
             self.visibility_list = []
             rebuilt = 1
             for go in self.go:
               self.visibility_list.append(go.obj.visible)
          else:
            iob=0
            for go in self.go:
               if self.visibility_list[iob] != go.obj.visible:
                  rebuilt = 1
                  break
               iob = iob + 1
            if rebuilt:
               self.visibility_list = []
               for go in self.go:
                 self.visibility_list.append(go.obj.visible)
          if len(self.alpha_list)!=len(self.go):
             self.alpha_list = []
             rebuilt = 1
             for go in self.go:
               self.alpha_list.append(go.obj.GetAlpha())
          else:
            iob=0
            for go in self.go:
               if go.obj.visible:
                 if self.alpha_list[iob] != go.obj.GetAlpha():
                    rebuilt = 1
                    break
               iob = iob + 1
            if rebuilt:
               self.alpha_list = []
               for go in self.go:
                 self.alpha_list.append(go.obj.GetAlpha())

          cprim.DrawSortedTransparentPrimitives(cobjs, 1, 0, 0, v, axes, False, bool(rebuilt))
          opengl.glDisable(opengl.GL_LIGHTING);
	else: # Transparency...?
	  if smooth_line:
        	opengl.glBlendFunc(opengl.GL_SRC_ALPHA,opengl.GL_ONE_MINUS_SRC_ALPHA);
                opengl.SetupFBOBlending()
		opengl.glEnable(opengl.GL_BLEND)
		#opengl.glEnable(opengl.GL_LINE_SMOOTH)
	  else:
		opengl.glDisable(opengl.GL_BLEND)
		#opengl.glDisable(opengl.GL_LINE_SMOOTH)

       	  opengl.glBlendFunc(opengl.GL_SRC_ALPHA,opengl.GL_ONE_MINUS_SRC_ALPHA);
          opengl.SetupFBOBlending()
	  opengl.glEnable(opengl.GL_BLEND)
       	  opengl.glEnable(opengl.GL_CULL_FACE)
       	  if not self.inShadow:
            opengl.glCullFace(opengl.GL_BACK)

          quat = pygl_coord.Quat(self.quat)
          extra_quat = pygl_coord.Quat(self.extra_quat)
          quat.postMult(extra_quat)
          if self.GetRenderMode()==self.DISPLAYLISTS:
            self.drawOpaque(True,False)
	    if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
              self.shader.turnOn()
              #self.shader.setDefaultDataAttrib1f("occData",1.0)
	    if self.multiTextureAvailable:
              opengl.SetMyTextureUnit(opengl.GL_TEXTURE2)
              opengl.glDisable(opengl.GL_TEXTURE_2D)
            self.drawOpaque(True)
            self.drawSphereBillboards(quat)
            if hasattr(self,"circleShader"):
              if self.slab_enabled and not self.inShadow:
                self.setupModelview(self.furtherMatrix,self.furtherQuat)

            if self.slab_enabled:
              customClipPlanes = []
              for pl in self.customClipPlanes:
                if hasattr(pl,"has_key") and pl.has_key("visible") and pl["visible"] and pl.has_key("plane"):
                   customClipPlanes.append(pl["plane"])
              for iPlane in range(len(customClipPlanes)):
                thePlane = customClipPlanes[iPlane]
                myvec = pygl_coord.Cartesian(thePlane[0],thePlane[1],thePlane[2])
                if abs(myvec.length())<1e-5:
                  break
                opengl.glEnable(opengl.GL_CLIP_PLANE0+nplanes+2)
                nplanes = nplanes + 1

            if self.shaders_on and hasattr(self.circleShader,"getUniformLocation") :
              nCustomClipPlanesLoc = self.circleShader.getUniformLocation("nCustomClipPlanes")
              self.circleShader.Uniform1i(nCustomClipPlanesLoc,nplanes)

            self.drawOpaque(False,False)
	    if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
            self.drawOpaque(False)
            self.drawTransparent(True,False)
	    if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
              self.shader.turnOn()
              #self.shader.setDefaultDataAttrib1f("occData",1.0)
            self.drawTransparent(True)
	    if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
            self.drawTransparent(False)
          else: # Symmetry, transparency...?
            if len(self.go)>1: 
              for go in self.go:
	        if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
                   self.shader.turnOn()
                   #self.shader.setDefaultDataAttrib1f("occData",1.0)
                go.obj.draw_solids()
	        if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
                go.obj.draw_lines(None,0,0,self.line_scaling)

        needDoMultiTextureBillboards = False
        for go in self.go:
          if go.obj.visible:
            if go.obj.GetNumberOfBillboardPrimitives()>0:
               needDoMultiTextureBillboards = True
               break

        """
	if self.multiTextureAvailable:
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D);
        """

        if self.inShadow or self.inAmbient:
          return

	if True:# we need to know when to do this ....
          opengl.glEnable(opengl.GL_TEXTURE_2D);
          opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
          opengl.glDisable(opengl.GL_TEXTURE_2D);
	  if self.multiTextureAvailable:
            opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
            opengl.glEnable(opengl.GL_TEXTURE_2D);
            opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
            opengl.glDisable(opengl.GL_TEXTURE_2D);

	if self.multiTextureAvailable and needDoMultiTextureBillboards and self.doMultiTextureBillboards:
          # This does not work, for symmetry, yet
          opengl.glDisable(opengl.GL_LIGHTING);
          y = self.bgcolour.redF()*0.299 + self.bgcolour.greenF()*0.587 + self.bgcolour.blueF()*0.114;
          if self.circle_tex_id == None or self.circle_tex_id2 == None:
            self.loadCircleTextures()
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D);
          opengl.glBindTexture( opengl.GL_TEXTURE_2D, self.circle_tex_id );
          opengl.glTexEnvf(opengl.GL_TEXTURE_ENV, opengl.GL_TEXTURE_ENV_MODE, opengl.GL_MODULATE);
          if y<0.5: 
             opengl.SetMyTextureUnit(opengl.GL_TEXTURE1);
             opengl.glEnable(opengl.GL_TEXTURE_2D);
             opengl.glBindTexture( opengl.GL_TEXTURE_2D, self.circle_tex_id2 );
             opengl.glTexEnvf(opengl.GL_TEXTURE_ENV, opengl.GL_TEXTURE_ENV_MODE, opengl.GL_DECAL);
          else:
             opengl.SetMyTextureUnit(opengl.GL_TEXTURE1);
             opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
             opengl.glDisable(opengl.GL_TEXTURE_2D);
          """
          for go in self.go:
            if go.obj.visible:
              go.obj.draw_billboards(quat,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
          """
          prims = cprim.BillboardPrimitivePointerVector()
          for go in self.go:
            if go.obj.visible:
              ps = go.obj.GetBillboardPrimitives()
              primsnew = cprim.BillboardPrimitivePointerVector(len(prims))
              primsnew[:len(prims)] = prims
              primsnew[len(prims):len(prims)+len(ps)] = ps
              prims = primsnew
          cprim.draw_billboards(prims,quat,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2]);
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D);
          opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
          opengl.glDisable(opengl.GL_TEXTURE_2D);
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE1);
          opengl.glEnable(opengl.GL_TEXTURE_2D);
          opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
          opengl.glDisable(opengl.GL_TEXTURE_2D);
  
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D);
  
        opengl.glDisable(opengl.GL_CLIP_PLANE2)
        opengl.glDisable(opengl.GL_CLIP_PLANE3)
        opengl.glDisable(opengl.GL_CLIP_PLANE4)
        opengl.glDisable(opengl.GL_CLIP_PLANE5)

        opengl.glEnable(opengl.GL_LIGHTING)

        opengl.glColor4f(1.0-self.bgcolour.redF(),1.0-self.bgcolour.greenF(),1.0-self.bgcolour.blueF(),1)

        opengl.glEnable(opengl.GL_BLEND);
        opengl.glBlendFunc(opengl.GL_ONE, opengl.GL_ONE_MINUS_SRC_ALPHA);
        opengl.glEnable(opengl.GL_TEXTURE_2D)

        misco = global_definitions.PM('miscell_prefs')
        depth_text = misco.get('depth_text')
        if not depth_text:
          opengl.glDepthFunc(opengl.GL_ALWAYS);
        fog_text = misco.get('fog_text')

        if fog_text and self.fog_enabled:
          opengl.SetupFBOBlending()
          opengl.glEnable(opengl.GL_FOG)
        else:
          opengl.glDisable(opengl.GL_FOG)

        if self.drawText == True:
          quat = pygl_coord.Quat(self.quat)
          quat.postMult(self.extra_quat)
          for go in self.go:
             if go.obj.visible>0:
                 opengl.glColor4f(1.0-self.bgcolour.redF(),1.0-self.bgcolour.greenF(),1.0-self.bgcolour.blueF(),1)
        	 opengl.glPixelStorei(opengl.GL_UNPACK_ALIGNMENT, 1)
        	 opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_S, opengl.GL_CLAMP);
        	 opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_T, opengl.GL_CLAMP);
        	 opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MAG_FILTER, opengl.GL_LINEAR);
        	 opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MIN_FILTER, opengl.GL_LINEAR);
        	 opengl.glDisable(opengl.GL_LIGHTING)
                 if hasattr(go,"symmetry_dependent") and go.symmetry_dependent and go.symmetry_dependent.draw_symmetry and hasattr(go.symmetry_dependent.obj,"GetNumSymmetryMatrices"):
                   if (not go.symmetry_dependent.obj.GetDrawSymmetry()) or go.symmetry_dependent.doCentralSymmetry:
                     self.drawTheText(quat,fog_text,go,misco,nCustomPlanes=nplanes)
                 else:
                   self.drawTheText(quat,fog_text,go,misco,nCustomPlanes=nplanes)
                 symm_mat = []
		 if hasattr(go,"symmetry_dependent") and go.symmetry_dependent and go.symmetry_dependent.draw_symmetry and hasattr(go.symmetry_dependent.obj,"GetNumSymmetryMatrices"):
			 if go.symmetry_dependent.symmetry_labels:
			   nsym = go.symmetry_dependent.obj.GetNumSymmetryMatrices()
               		   symm_mat = pygl_coord.MatrixVector(go.symmetry_dependent.obj.symm_mat)

		 if hasattr(go,"draw_symmetry") and go.draw_symmetry and hasattr(go.obj,"GetNumSymmetryMatrices"):
			 nsym = go.obj.GetNumSymmetryMatrices()
               		 symm_mat = pygl_coord.MatrixVector(go.obj.symm_mat)

                 for mat in symm_mat:
                      		opengl.glPushMatrix()
                                glrotmat = mat.Transpose().to_dp()
                      		opengl.glMultMatrixd(glrotmat)
                                opengl.delcdp(glrotmat)
				qorig = pygl_coord.Quat(quat)
				qsym = pygl_coord.Quat(mat)
				q = pygl_coord.Quat()
				q.postMult(qsym)
				q.postMult(qorig)
                 		opengl.glColor4f(1.0-self.bgcolour.redF(),1.0-self.bgcolour.greenF(),1.0-self.bgcolour.blueF(),1)
        			opengl.glPixelStorei(opengl.GL_UNPACK_ALIGNMENT, 1)
        			opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_S, opengl.GL_CLAMP);
        			opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_T, opengl.GL_CLAMP);
        			opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MAG_FILTER, opengl.GL_LINEAR);
        			opengl.glTexParameteri(opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_MIN_FILTER, opengl.GL_LINEAR);
        			opengl.glDisable(opengl.GL_LIGHTING)
                 		#go.obj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
                                self.drawTheText(q,fog_text,go,misco,nCustomPlanes=nplanes)
                      		opengl.glPopMatrix()

        if hasattr(self,"textShader"): self.textShader.turnOff()
        opengl.glDisable(opengl.GL_FOG)

        self.DrawAxes()
        self.DrawScale()

        if self.drawImages == True:
          for go in self.go:
             if go.obj.visible>0:
                go.obj.draw_images()
	#print self.viewsize,self.size().height(),self.tex_image_z.width(),self.tex_image_z.height()

    def drawTheText(self,quat,fog_text,go,misco,nCustomPlanes=0):
                 tlb = misco.get('text_label_background')
                 if tlb:
                   text_label_background_colour =  misco.get('text_label_background_colour')
                   if text_label_background_colour:
                     if text_label_background_colour == "default":
                       bgcol = (self.bgcolour.redF(),self.bgcolour.greenF(),self.bgcolour.blueF())
                     else:
                       bgcol =  cprim.RGBReps.GetColour(text_label_background_colour.replace('_',' '))
                     opengl.glColor4f(bgcol[0],bgcol[1],bgcol[2],1)
                   opengl.glDisable(opengl.GL_TEXTURE_2D)
                   if fog_text and self.shaders_on and hasattr(self,"textBackgroundShader"): self.textBackgroundShader.turnOn()
                   go.obj.draw_text_background(quat,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2],self.fontScaling)
                   if fog_text and self.shaders_on and hasattr(self,"textBackgroundShader"): self.textBackgroundShader.turnOff()
                   opengl.glEnable(opengl.GL_TEXTURE_2D)
                   opengl.glColor4f(1.0-self.bgcolour.redF(),1.0-self.bgcolour.greenF(),1.0-self.bgcolour.blueF(),1)
                   opengl.glColor4f(1.0,1,1,1)
                 if fog_text and self.shaders_on and hasattr(self,"textShader"): self.textShader.turnOn()
                 go.obj.draw_text(quat,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2],self.fontScaling,nCustomPlanes)
                 if fog_text and self.shaders_on and hasattr(self,"textShader"): self.textShader.turnOff()

    def resizeGL(self, w, h):
	# This needs to be called from somewhere.
        if h == 0:
            h = 1
        if w == 0:
            w = 1
        ratio = 1.0*w / h

        opengl.glMatrixMode(opengl.GL_PROJECTION);
        opengl.glLoadIdentity();
        opengl.glViewport(0, 0, w, h);
	viewport = pygl_coord.inta(4)
        opengl.glGetIntegerv(opengl.GL_VIEWPORT,viewport);
        opengl.glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,self.NEAR,self.FAR);
        opengl.glMatrixMode(opengl.GL_MODELVIEW)
        cprim.BillBoardText().SetMatrices()

    def GetXYZBox(self, x, y):
        xyzs = [ self.getxyz(x-10,y+10),self.getxyz(x-10,y-10), self.getxyz(x+10,y-10), self.getxyz(x+10,y+10) ]
        xyzbox = pygl_coord.CartesianVector()
        xyzbox.append(xyzs[0][0]); xyzbox.append(xyzs[0][1]); xyzbox.append(xyzs[1][0]); xyzbox.append(xyzs[1][1]);
        xyzbox.append(xyzs[2][0]); xyzbox.append(xyzs[2][1]); xyzbox.append(xyzs[3][0]); xyzbox.append(xyzs[3][1]);
        return xyzbox

    def getxyz(self,x,y): 
        """
        Work out world x,y,z at near and far clipping planes.
        """
	viewport = pygl_coord.inta(4)
	mvmatrix = pygl_coord.doublea(16)
	projmatrix = pygl_coord.doublea(16)
	wx = pygl_coord.doublep()
	wy = pygl_coord.doublep()
	wz = pygl_coord.doublep()

        opengl.glGetIntegerv(opengl.GL_VIEWPORT,viewport);
        opengl.glGetDoublev(opengl.GL_PROJECTION_MATRIX,projmatrix);
        opengl.glGetDoublev(opengl.GL_MODELVIEW_MATRIX,mvmatrix);
        realy = viewport[3] - y - 1;
        opengl.gluUnProject(x,realy,0.0,mvmatrix,projmatrix,viewport,wx,wy,wz);
	cart1 = pygl_coord.Cartesian(wx.value(), wy.value(), wz.value())
        opengl.gluUnProject(x,realy,1.0,mvmatrix,projmatrix,viewport,wx,wy,wz);
	cart2 = pygl_coord.Cartesian(wx.value(), wy.value(), wz.value())
        cv = pygl_coord.CartesianVector()
	cv.append(cart1)
	cv.append(cart2)
        del viewport
        del mvmatrix
        del projmatrix

        del wx
        del wy
        del wz
	return cv;

    def getaxes(self):
        """
        Return the eyes' x,y and z axes.
        """
        mat = self.quat.getInvMatrix()
        dumX = mat*pygl_coord.Cartesian(1,0,0)
        dumY = -(mat*pygl_coord.Cartesian(0,1,0))
        dumZ = mat*pygl_coord.Cartesian(0,0,1)

        return dumX,dumY,dumZ

    def BuildPrimitiveDisplayList(self):
      self.makeCurrent()
      col = pygl_coord.doublea(4); col[0] = col[1] = col[2] = col[3] = 0.0
      cprim.sphere(0,1.0,True)
      cprim.sphere(1,1.0,True)
      cprim.sphere(2,1.0,True)
      cprim.sphere(3,1.0,True)
      cprim.sphere(4,1.0,True)
      carts = pygl_coord.CartesianVector()
      carts.append(pygl_coord.Cartesian(0,0,0))
      carts.append(pygl_coord.Cartesian(0,0,1))
      cprim.draw_cylinder(carts,1.0,4,0,True)
      cprim.draw_cylinder(carts,1.0,8,0,True)
      cprim.draw_cylinder(carts,1.0,16,0,True)
      cprim.draw_cylinder(carts,1.0,32,0,True)

    def SetGO(self, go_in=None,redraw=0):
        self.go=go_in
	self.listids=[]
        if redraw:
          for go in self.go:
            if go:
              listid = opengl.glGenLists(1)
              self.listids.append(listid)
              self.buildlist(go,listid)
              self.updateGL()
        self.SetupSymmetry()

    def buildlist(self,go,listid):
        self.BuildPrimitiveDisplayList()
        opengl.glNewList(listid, opengl.GL_COMPILE_AND_EXECUTE)
        if go and not go.obj.IsAnchored(): 
          if self.shaders_on and hasattr(self,"shader") and hasattr(self.shader,"turnOn") and callable(self.shader.turnOn):
             self.shader.turnOn()
             #self.shader.setDefaultDataAttrib1f("occData",1.0)
          go.obj.draw_solids()
          if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
          go.obj.draw_lines(None,0,0,self.line_scaling)
        opengl.glEndList()
	
