"""
     qtgui/MGGLWidget.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.
"""



"""PyQt4 port of the opengl/hellogl example from Qt v4.x"""

import sys
import os
import time
import types
import math
import operator

from PyQt4 import QtCore, QtGui, QtOpenGL, QtSvg
import sip
from global_definitions import PM, MAINWINDOW, get_dispobj
import MGPickEvent
import opengl

from MGGLWidgetCore import MGGLWidgetCore, MGGLWidgetSimple, MGGLWidgetGL

try:
    import opengl
    import pygl_coord
    import cprim
    import surface
    import image_info
except ImportError:
    exc_type, exc_value,exc_tb = sys.exc_info()[:3]
    if str(exc_value).find('cannot restore segment prot after reloc')>-1:
	fixperms = os.path.join(os.path.normpath(os.environ["CCP4MG"]),"bin","fix-selinux-perms")
    	QtGui.QMessageBox.critical(None, "Failed to import some ccp4mg libraries", "SELINUX stoppped ccp4mg working.\nPlease run the script\n"+fixperms+"\nto fix this problem.", QtGui.QMessageBox.Ok )
    else:
        exc_type, exc_value,exc_tb = sys.exc_info()[:3]
        QtGui.QMessageBox.critical(None, "Failed to import some ccp4mg libraries", "There was a problem with some of the program libraries. Please report this as a bug to ccp4mg@ysbl.york.ac.uk.", QtGui.QMessageBox.Ok )
        sys.stderr.write(str(exc_type)+'\n')
        sys.stderr.write(str(exc_value)+'\n')
        import traceback
        traceback.print_tb(exc_tb)
    sys.exit(1)

def getMaxSampleBuffersFormat(start=16):
	numSampleBuffers=start
	haveSampleBuffers = False
	fmt = QtOpenGL.QGLFormat()
	fmt.setRgba (1);
	fmt.setDepth (1);
	fmt.setAlpha (1);
	fmt.setStencil(True)
        if sys.platform != "linux2":
	  fmt.setSwapInterval(1)
	fmt.setSampleBuffers (True);
	return fmt

def applyMiscPrefs():
	try:
		params =  PM("miscell_prefs").getparams()
		app = QtGui.QApplication.instance()
		if params.has_key('flip_text'):
    			app.setProperty("flip_labels",params['flip_text'])
			for dispobj in get_dispobj(): dispobj.set_redraw_text()
			import rebuild
			rebuild.UpdateDisplay()
		
	except:
		print "Error getting micellaneous options"
  
def applyAOPrefs():
	import MGApplication
	try:
		params =  PM("ambient_occlusion_prefs").getparams()
		mainwin = MGApplication.GetMainWindow()
		mainwin.glWidget.setAmbientOcclusionPrefs(params)
	except:
		print "Error getting SSAO options"
  

def createAOParamsManager():
  import services
  pm = services.ParamsManager ( 
          name="ambient_occlusion_prefs",
          title="Ambient occlusion options",
          help="_has_no_help_",
          gui=['ambocc_znear','ambocc_zfar','ambocc_radius','ambocc_scale','ambocc_bias'],
          apply_action = applyAOPrefs,
      default = {
         'ambocc_znear' : 100.0,
         'ambocc_zfar'  : 150.0,
         'ambocc_radius':  15.0,
         'ambocc_bias'  :   0.3,
         'ambocc_scale' :   1.0
      }, 
      definition = {
         "ambocc_znear"  : dict(type=float, min=0,max=600, label='Ambient occlusion Near eye', style='spinbox' ),
         "ambocc_zfar"   : dict(type=float, min=0,max=600, label='Ambient occlusion Far eye', style='spinbox' ),
         "ambocc_radius" : dict(type=float, min=0,max=150,  label='Ambient occlusion radius', style='spinbox' ),
         "ambocc_bias"   : dict(type=float, min=0.0,max=1.0,step=0.1,  label='Ambient occlusion bias', style='spinbox' ),
         "ambocc_scale"  : dict(type=float, min=0.0,max=1.0,step=0.1,  label='Ambient occlusion scale', style='spinbox' )
      }
  )
  return pm


def createMiscParamsManager():
  import services
  pm = services.ParamsManager ( \
          name="miscell_prefs",
          title='Miscellaneous graphics options', \
          help="_has_no_help_",
          c_access= 1,
          apply_action = applyMiscPrefs,
          gui=['text_label_background','text_label_background_colour','fog_text','depth_text','flip_text'], \
      default = { 'depth_text':0, 'fog_text':0, 'text_label_background' : 0, 'flip_text' : 0, 'text_label_background_colour':'white' },
      definition = {
             'text_label_background_colour' : dict(type=str, label='Text label background colour',style='colourcombo'),
             'text_label_background' : dict(type=int,label='Text labels have background', style='checkbox'),
             'fog_text' : dict(type=int,label='Apply depth-cue fog to text labels', style='checkbox'),
             'depth_text' : dict(type=int,label='Text labels can disappear behind objects', style='checkbox'),
             'flip_text' : dict(type=int,label='Invert text display', style='checkbox'),
             })

  return pm

#---------------------------------------------------------------------------------
def createStereoParamsManager():
#---------------------------------------------------------------------------------
  import services
  import MGApplication
 
  def onChange(pmg):
    stereoModeWidget =  pmg.findChild(QtGui.QWidget,'stereo_mode')
    shearSepWidget =  pmg.findChild(QtGui.QWidget,'shear_sep')
    rotSepWidget =  pmg.findChild(QtGui.QWidget,'rot_sep')
    if not stereoModeWidget or not shearSepWidget or not rotSepWidget:
      return
    if not hasattr(stereoModeWidget,"currentText") or not hasattr(shearSepWidget,"setEnabled") or not hasattr(rotSepWidget,"setEnabled"):
      return
    if stereoModeWidget.currentText() == stereoModeWidget.tr("Rotation"):
       shearSepWidget.setEnabled(False)
       rotSepWidget.setEnabled(True)
    else:
       shearSepWidget.setEnabled(True)
       rotSepWidget.setEnabled(False)

  pm = services.ParamsManager ( \
          name="stereo_prefs",
          picture_definition = 1,
          title='Stereo preferences', \
          help="_has_no_help_",
          onCreate=onChange, \
          c_access= 1,
          apply_action = MGApplication.GetMainWindow().applyStereoPrefs,
          gui=['stereo_mode',
               'shear_sep',
               'rot_sep'], \
      default = { 'stereo_mode' : 1,
                  'shear_sep' : 0.1,
                  'rot_sep': 6.0 },
      definition = {
             'stereo_mode' : dict(type=int,label='Stereo mode',
                     style='combobox',menu=['Shear','Rotation'],alias=[0,1],onchange=onChange),
             'shear_sep' : dict(type='float',label='Shear separation',max=5.0,min=-5.0,step=0.05,style='spinbox'),
             'rot_sep' : dict(type='float',label='Rotation angle',max=10.0,min=-10.0,step=0.05,style='spinbox')
             })

  return pm

class MGGLWidget(QtOpenGL.QGLWidget,MGGLWidgetGL):

    def updateGL(self):
	QtOpenGL.QGLWidget.updateGL(self)

    def makeCurrent(self):
	QtOpenGL.QGLWidget.makeCurrent(self)

    def event(self,e):
	if QtCore.QT_VERSION >= 0x40600 and QtCore.PYQT_VERSION >= 0x040700 and sip.SIP_VERSION >= 0x040a00 and e.type() == QtCore.QEvent.Gesture:
          if self.shaders_on and self.shader and self.doShadow:
            shadowQuality = self.shader.getUniformLocation("shadowQuality")
            self.shader.Uniform1i(shadowQuality,0)
          if self.shaders_on and self.circleShader and self.doShadow:
            shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
            self.circleShader.Uniform1i(shadowQuality,0)
          return self.gestureEvent(e)
	return QtOpenGL.QGLWidget.event(self,e)

    def gestureEvent(self,e):
	if  QtCore.QT_VERSION < 0x40600 or QtCore.PYQT_VERSION < 0x040700 or sip.SIP_VERSION < 0x040a00: return
	pinch = e.gesture(QtCore.Qt.PinchGesture)
	swipe = e.gesture(QtCore.Qt.SwipeGesture)
	pan = e.gesture(QtCore.Qt.PanGesture)
	if swipe:
		#print "Swipe"
		pass
	if pan:
		#print "Pan"
		pass
	if pinch:
		self.handleZoom(e,0,50*(pinch.scaleFactor()-pinch.lastScaleFactor()))
        	self.setRotation(0,0,-(pinch.rotationAngle()-pinch.lastRotationAngle()))
	return True
	
    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.qglClearColor(self.bgcolour)
	self.updateGL()
	cprim.RGBReps().SetBackgroundColour([r/255.,g/255.,b/255.,a/255.])

    def centreOn(self,origin,glide=1):
        import functools
        #print "%_%_%_%_%_%_%_%_%_%_%_%_%_%_%_centreOn",origin
        #if glide<0: glide = PM('user_interface').get('camera_glide')
        rpos_old = self.rpos
        rpos_new = (-origin[0],-origin[1],-origin[2])

        if glide:

          self.glide_initial_time = time.time()
          if self.shaders_on and self.shader and self.doShadow:
            shadowQuality = self.shader.getUniformLocation("shadowQuality")
            self.shader.Uniform1i(shadowQuality,0)
          if self.shaders_on and self.circleShader and self.doShadow:
            shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
            self.circleShader.Uniform1i(shadowQuality,0)
          def glide_handler(rpos_old,rpos_new):
            elapsed = time.time() - self.glide_initial_time
            fi = min(1.0,elapsed)
            fip = 1.0 - fi
            rpos_cur = [fip*rpos_old[0]+fi*rpos_new[0],fip*rpos_old[1]+fi*rpos_new[1],fip*rpos_old[2]+fi*rpos_new[2]]
            self.rpos = rpos_cur
            self.emit(QtCore.SIGNAL("PositionChanged"),(self))
            self.SetupSymmetry()
            self.updateGL()
            if elapsed >= 1.0:
              if self.shaders_on and self.shader and self.doShadow:
                shadowQuality = self.shader.getUniformLocation("shadowQuality")
                self.shader.Uniform1i(shadowQuality,2)
              if self.shaders_on and self.circleShader and self.doShadow:
                shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
                self.circleShader.Uniform1i(shadowQuality,2)
              self.glide_timer.stop()

          if hasattr(self,"glide_timer"):
            self.glide_timer.stop()
          self.glide_timer = QtCore.QTimer(self)
          self.connect(self.glide_timer,QtCore.SIGNAL('timeout()'),functools.partial(glide_handler,rpos_old,rpos_new))
          self.glide_timer.start()
	  self.emit(QtCore.SIGNAL("ViewChanged"),(self))
        else:
          self.rpos = rpos_new
          self.emit(QtCore.SIGNAL("PositionChanged"),(self))
          self.SetupSymmetry()
          self.updateGL()
	  self.emit(QtCore.SIGNAL("ViewChanged"),(self))

    def DrawAxes(self):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        if not self.show_axes: return
	MGGLWidgetGL.DrawAxes(self)

    def DrawScale(self):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        if not self.show_scale: return
	MGGLWidgetGL.DrawScale(self)


    def getBackgroundAlpha(self):
      return self.bgcolour.alpha()

    def screenshot_pbuffer_new(self,size=QtCore.QSize(600,600),scalebartext=True,scaleLines=False):
        import time
        t1 = time.time()
        fbo_height = 1024
        fbo_width = 1024
        self.fbo_offset = 512
        old_w,old_h = self.width(), self.height()
        if not hasattr(self,"pbuffer"):
          fmt = QtOpenGL.QGLFramebufferObjectFormat()
          if self.format().samples() > 1:
            fmt.setSamples(self.format().samples())
          fmt.setAttachment(QtOpenGL.QGLFramebufferObject.Depth)
          self.pbuffer = QtOpenGL.QGLFramebufferObject(QtCore.QSize(fbo_height+2*self.fbo_offset,fbo_width+2*self.fbo_offset),fmt)
          self.BindOffScreenBuffer = self.BindOffScreenBufferFBO

        radius = self.RADIUS

        if fbo_height < size.height() or fbo_width < size.width():
          ntiles_x = (size.width()+fbo_width-1)/fbo_width
          ntiles_y = (size.height()+fbo_height-1)/fbo_height
          req_size = QtCore.QSize(ntiles_x*fbo_width,ntiles_y*fbo_height)
          self.RADIUS = float(req_size.height())/size.height()*self.RADIUS
          #self.RADIUS = float(self.pbuffer.height())/req_size.height()*self.RADIUS
          #self.resize(self.pbuffer.width(),self.pbuffer.height())
          self.RADIUS = float(2048)/req_size.height()*self.RADIUS
          print self.RADIUS
          self.resize(2048,2048)
        else:
          req_size = size
          self.resize(req_size.width(),req_size.height())


        self.req_pbuffer_size = req_size
        self.use_pbuffer = True
        if self.shaders_on and self.shader and self.doShadow:
          shadowQuality = self.shader.getUniformLocation("shadowQuality")
          self.shader.Uniform1i(shadowQuality,2)
        if self.shaders_on and self.circleShader and self.doShadow:
          shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
          self.circleShader.Uniform1i(shadowQuality,2)
        self.BindOffScreenBuffer()
        self.drawText = False

        import global_definitions
        misco = global_definitions.PM('miscell_prefs')
        depth_text = misco.get('depth_text')
        doText=True

        if depth_text:
          print "Not doing separate text, because of text depth. But should be scaled",self.fontScaling
          self.drawText = True
          doText=False

        self.drawImages = False
        self.use_pbuffer = True
        self.rebuildAllDisplayObjects(redraw=0)

        self.use_pbuffer = True
        self.BindOffScreenBuffer()

        rpos = self.rpos
        show_axes = self.show_axes
        show_scale = self.show_scale

        # Loop here for tiling
        self.updateGL()

        theScaling = 1.0
        print fbo_height, size.height(), fbo_width, size.width()
        if fbo_height >= size.height() and fbo_width >= size.width():
          self.axes_mag = 1.0
          if scaleLines:
            self.line_scaling = size.width()/float(old_w)
            #print "LINE SCALING",self.line_scaling
          else:
            self.line_scaling = 1.0
          self.show_axes = False
          self.show_scale = False
          self.axes_position = (0.75,0.75)
          self.updateGL()
          image = self.pbuffer.toImage().copy(0,fbo_height-size.height()+2*self.fbo_offset,size.width(),size.height())
          self.updateGL()
          self.show_axes = show_axes
          self.show_scale = show_scale
          #self.line_scaling = fbo_width/float(old_w)
        else:
          # This works for 2048x2048, 4096x4096, 2048x4096, 4096x2048, 8192x8192, 8192x4096, 8192x1024
          # and n x screen size and dpi it seems. Not worked out max feasible size yet....
          self.show_axes = False
          self.show_scale = False
          theScaling = 1.0*size.height()/self.height()

          pix = QtGui.QPixmap(ntiles_x*fbo_width, ntiles_y*fbo_height)
          pix.fill(QtGui.QColor(0,0,0,0))
          self.axes_position = (-(ntiles_x-2.0)/ntiles_x-.25/ntiles_x,-(ntiles_y-2.0)/ntiles_y-.25/ntiles_y)
          self.axes_mag = max(float(size.height())/fbo_height , float(size.height())/fbo_height)
          if scaleLines:
            self.line_scaling = size.width()/float(old_w)
            print "LINE SCALING",self.line_scaling
          else:
            self.line_scaling = 1.0
          customClipPlanes = self.customClipPlanes
          painter = QtGui.QPainter(pix)
 
          for i in range(ntiles_x):
            for j in range(ntiles_y):
              if False and ntiles_y == 1:
                diffCart = pygl_coord.Cartesian((-i+(float(self.fbo_offset)/fbo_width)+0.25+0.5*(ntiles_x-2))*self.viewsize*self.RADIUS/60.*2048./self.height(),0.25,0)
              elif False and ntiles_x == 1:
                diffCart = pygl_coord.Cartesian(0.25,(-j+(float(self.fbo_offset)/fbo_height)+0.25+0.5*(ntiles_y-2))*self.viewsize*self.RADIUS/60.*2048./self.height(),0)
              else:
                diffCart = pygl_coord.Cartesian((-i+(float(self.fbo_offset)/fbo_width)+0.5*(ntiles_x-2))*self.viewsize*self.RADIUS/60.*2048./self.height(),(-j+(float(self.fbo_offset)/fbo_height)+0.5*(ntiles_y-2))*self.viewsize*self.RADIUS/60.*2048./self.height(),0)
              planesNew = []
              for pl in customClipPlanes:
                if hasattr(pl,"has_key") and pl.has_key("visible") and pl.has_key("plane") and len(pl["plane"])==4:
                  thePlane = pl["plane"]
                  pl_b = pygl_coord.Cartesian(-thePlane[0],-thePlane[1],thePlane[2])
                  a1 = 0.0
                  if pl_b.length()>0.0:
                    pl_b.normalize()
                    a1 = pygl_coord.Cartesian.DotProduct(diffCart,pl_b)
                  newPlane = {}
                  newPlane["visible"] = pl["visible"]
                  newPlane["plane"] = (thePlane[0],thePlane[1],thePlane[2],thePlane[3]+a1)
                  planesNew.append(newPlane)
              self.setCustomClipPlanes(planesNew)

              diffCart = self.quat.getInvMatrix()*diffCart
              self.rpos = (rpos[0]+diffCart.get_x(),rpos[1]+diffCart.get_y(),rpos[2]+diffCart.get_z())
              self.updateGL()
              #self.pbuffer.toImage().save("fbo-"+str(i)+"-"+str(j)+".png")
              image = self.pbuffer.toImage().copy(self.fbo_offset,self.fbo_offset,fbo_width,fbo_height)
              painter.drawImage(i*fbo_width,(ntiles_y-j-1)*fbo_height,image)
              print "time for image",i,j,time.time()-t1; sys.stdout.flush()
          painter.end()

          #image = pix.toImage().copy(0,ntiles_y*fbo_height-size.height(),size.width(),size.height())
          image = pix.toImage().copy((req_size.width()-size.width())/2,ntiles_y*fbo_height-size.height()-(req_size.height()-size.height())/2,size.width(),size.height())
          print "time for accumulated image",time.time()-t1; sys.stdout.flush()

          self.show_axes = show_axes
          self.show_scale = show_scale
          self.axes_position = (0.75,0.75)
          self.customClipPlanes = customClipPlanes
          
        self.RADIUS = radius

        # end loop here and accumulate images.
        self.rpos = rpos

        self.applyTextPBuffer(image,doText=doText,theScaling=theScaling,scalebartext=scalebartext)
        print "time for text and overlays",time.time()-t1; sys.stdout.flush()
        self.axes_mag = None
        self.line_scaling = 1.0
        self.drawText = True
        self.drawImages = True
        self.pbuffer.release()
        self.use_pbuffer = False
        print "time for release",time.time()-t1; sys.stdout.flush()
        #self.resize(size.width(),size.height())
        return image

    def screenshot_pbuffer(self,size=QtCore.QSize(600,600),scalebartext=True,scaleLines=False):
        return self.screenshot_pbuffer_new(size,scalebartext,scaleLines)

    def screenshot_pbuffer_old(self,size=QtCore.QSize(600,600)):
          debug = False
          if os.environ.has_key("CCP4MG_DEBUG_PBUFFER"):
             debug = True
          if debug: t1 = time.time()
          r,g,b = self.getBackground()
          a = self.getBackgroundAlpha()
          if not hasattr(self,"pbuffer_glWidget"):
            self.pbuffer_glWidget = MGGLWidget(MAINWINDOW(),self,format=self.format(),use_pbuffer=True,pbuffer_size=QtCore.QSize(2048,2048))
            if debug: t2 = time.time()
            if debug: print "Time for pbuffer construct widget",t2-t1; sys.stdout.flush()

          self.pbuffer_glWidget.req_pbuffer_size = size
          self.pbuffer_glWidget.drawTextSeparately = True
          if hasattr(self,"pbuffer_glWidget"):
            rp,gp,bp = self.pbuffer_glWidget.getBackground()
            ap = self.pbuffer_glWidget.getBackgroundAlpha()
            if a != ap or r != rp or g != gp or b != bp:
              self.pbuffer_glWidget.setBackground(r,g,b,a)
              if debug: t2 = time.time()
              if debug: print "Time for pbuffer set bg",t2-t1; sys.stdout.flush()
          for item in ['RADIUS','quat','fog_enabled','fog_strength','fog_near','fog_far','slab_enabled','slab_width','slab_offset']:
            setattr(self.pbuffer_glWidget,item,getattr(self,item))
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer setattr",t2-t1; sys.stdout.flush()
          if debug: print size, self.pbuffer_glWidget.size()
          if size.width()!=self.pbuffer_glWidget.width() or size.height()!=self.pbuffer_glWidget.height():
             self.pbuffer_glWidget.resizeGL(size.width(),size.height())
             if debug: t2 = time.time()
             if debug: print "Time for pbuffer resize",t2-t1; sys.stdout.flush()
          self.pbuffer_glWidget.setExtraMatrix(None)
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer set extra matrix",t2-t1; sys.stdout.flush()
          self.pbuffer_glWidget.setLights(MAINWINDOW().lights)
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer set lights",t2-t1; sys.stdout.flush()
          shaders = self.getShader()
          self.pbuffer_glWidget.setShader(shaders[0],shaders[1])
          self.pbuffer_glWidget.setShaderState(self.getShaderState())
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer set shaders",t2-t1; sys.stdout.flush()
          self.pbuffer_glWidget.updateGL()
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer draw 1",t2-t1; sys.stdout.flush()
          self.pbuffer_glWidget.drawText = False
          self.pbuffer_glWidget.drawImages = False
          if self.go: 
            self.pbuffer_glWidget.SetGO(self.go,1)
            if debug: t2 = time.time()
            if debug: print "Time for pbuffer set objects",t2-t1; sys.stdout.flush()
            cprim.RenderQuality.SetRenderQuality(1)
            if debug: t2 = time.time()
            if debug: print "Time for pbuffer SetRenderQuality",t2-t1; sys.stdout.flush()
            self.pbuffer_glWidget.rebuildAllDisplayObjects(redraw=0)
            if debug: t2 = time.time()
            if debug: print "Time for pbuffer rebuildAllDisplayObjects",t2-t1; sys.stdout.flush()
            self.pbuffer_glWidget.SetOrigin(self.rpos,0)
            if debug: t2 = time.time()
            if debug: print "Time for pbuffer SetOrigin",t2-t1; sys.stdout.flush()
          self.pbuffer_glWidget.drawText = False
          self.pbuffer_glWidget.drawImages = False
          self.pbuffer_glWidget.updateGL()
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer draw 2",t2-t1; sys.stdout.flush()
          image = self.pbuffer_glWidget.pbuffer.toImage().copy((2048-size.width())/2,(2048-size.height())/2,size.width(),size.height())
          self.resizeGL(size.width(),size.height())
          self.updateGL()
          self.applyTextPBuffer(image)
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer convert to image",t2-t1; sys.stdout.flush()
          #self.pbuffer_glWidget.close()
          if debug: t2 = time.time()
          if debug: print "Time for pbuffer all",t2-t1; sys.stdout.flush()
          cprim.RenderQuality.SetRenderQuality(0)
          return image

    def applyTextPBuffer(self,image,doText=True,theScaling=1.0,scalebartext=True):
          debug = False
          if os.environ.has_key("CCP4MG_DEBUG_MEMORY"):
             debug = True
	  width = image.width()
	  height = image.height()
          theImage = image
	  i = 0
          if self.bgcolour.alpha() == 0 and self.bgcolour.red() == 0 and self.bgcolour.green() == 0 and self.bgcolour.blue() == 0 and self.fogcolour.alpha() != 0 and self.fogcolour.red() != 0 and self.fogcolour.green() != 0 and self.fogcolour.blue() != 0:
	    bright_y = self.fogcolour.redF()*0.299 + self.fogcolour.greenF()*0.587 + self.fogcolour.blueF()*0.114;
          else:
	    bright_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)

	  viewport = pygl_coord.inta(4)
          opengl.glGetIntegerv(opengl.GL_VIEWPORT,viewport);
          tl = opengl.getxyzc(viewport[0],viewport[1])[0];
          bl = opengl.getxyzc(viewport[0],viewport[3])[0];
	  yscale = (tl-bl).length()*theScaling

	  scale = yscale
          print scale

	  import FontedPositionedStrings
	  painter = QtGui.QPainter()
	  painter.begin(image)
  
          images = []
          for go in self.go:
             if go.obj.visible>0:
                 prims = go.obj.GetImagePrimitives()
                 for prim in prims:
						if debug: print prim
						verts = prim.GetVertices()
						imageWidth = prim.GetImageWidth()
						imageHeight = prim.GetImageHeight()
						scale_w = prim.GetScaleW()*self.fontScaling
						scale_h = prim.GetScaleH()*self.fontScaling
						filename = prim.GetFilename()
						isSvg = False
						if filename[-3:] == "svg" and len(verts) > 0 :
							try:
								v0 = verts[0]
								svg = QtSvg.QSvgRenderer(unicode(filename,'utf-8'))
								if svg.isValid():
									x1 = v0.get_x()*painter.device().width()
									y1 = painter.device().height()*(1.0-v0.get_y())-svg.defaultSize().height()*scale_h
									bounds = QtCore.QRectF(x1,y1,svg.defaultSize().width()*scale_w,svg.defaultSize().height()*scale_h)
									#svg.render(painter,bounds)
									image = {"filename":filename, "bounds":bounds}
									images.append(image)
									isSvg = True
							except:
								print "did not load",filename,"as svg"
								sys.stdout.flush()
						piccy = QtGui.QImage(unicode(filename,'utf-8'))
						piccy = piccy.scaled(int(piccy.width()*scale_w),int(piccy.height()*scale_h),QtCore.Qt.IgnoreAspectRatio,QtCore.Qt.SmoothTransformation)
						if not isSvg and len(verts) > 0 and not piccy.isNull() and scale_w > 0 and scale_h >0:
							v0 = verts[0]
							x = int(v0.get_x()*painter.device().width())
							y = int(painter.device().height()*(1.0-v0.get_y()))-piccy.height()
							#painter.drawPixmap(x,y,piccy)
							image = {"filename":filename,"x":x,"y":y,"width":int(piccy.width()),"height":int(piccy.height())}
							images.append(image)

                 if debug: print images
                 for image in images:
					if hasattr(image,"has_key"):
						if image.has_key("bounds") and image.has_key("filename"):
							#print "SVG",image["filename"],image["bounds"]
							svg = QtSvg.QSvgRenderer(unicode(image["filename"],'utf-8'))
							svg.render(painter,image["bounds"])
						if image.has_key("x") and image.has_key("y") and image.has_key("filename") and image.has_key("width") and image.has_key("height"):
							#print "bitmap",image["filename"],image["x"],image["y"],image["width"],image["height"]
							piccy = QtGui.QImage(unicode(image["filename"],'utf-8'))
							piccy = piccy.scaled(image["width"],image["height"],QtCore.Qt.IgnoreAspectRatio,QtCore.Qt.SmoothTransformation)
							painter.drawImage(image["x"],image["y"],piccy)

          import global_definitions
          misco = global_definitions.PM('miscell_prefs')
          tlb = misco.get('text_label_background')
          bgcol = None
          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('_',' '))

	  thePrims = []
          for go in self.go:
             if doText and go.obj.visible>0:
                 prims = go.obj.GetTextPrimitives()
		 for prim in prims:
		     text,isBill,cart = prim.GetText(),prim.IsBillBoard(),prim.GetVertices()[0]
                     cartOrig = cart
		     if not isBill:
			 cart = quat.getMatrix()*(cart+pygl_coord.Cartesian(self.rpos))
			 x,y,z = cart.get_x(),cart.get_y(),-cart.get_z()
			 thePrims.append({'prim':prim,'z':z,'go':go,'x':x,'y':y})
                     symm_mat = []
		     if not isBill:
		                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:
			           cartSym = quat.getMatrix()*(mat*cartOrig+pygl_coord.Cartesian(self.rpos))
			           xSym,ySym,zSym = cartSym.get_x(),cartSym.get_y(),cartSym.get_z()
			 	   thePrims.append({'prim':prim,'z':-zSym,'go':go,'x':xSym,'y':ySym})

	  thePrims = sorted(thePrims,key=operator.itemgetter('z'),reverse=True)
          for go in self.go:
             if doText and go.obj.visible>0:
                 prims = go.obj.GetTextPrimitives()
		 for prim in prims:
		     text,isBill,cart = prim.GetText(),prim.IsBillBoard(),prim.GetVertices()[0]
		     if isBill:
			thePrims.append({'prim':prim,'z':0,'go':go})

	  """
          for go in self.go:
             if doText and go.obj.visible>0:
                 prims = go.obj.GetTextPrimitives()
		 for prim in prims:
	  """
          for _prim in thePrims:
		     prim = _prim['prim']
		     go = _prim['go']
		     text,isBill,cart = prim.GetText(),prim.IsBillBoard(),prim.GetVertices()[0]
                     cartOrig = cart
 		     font = QtGui.QFont(prim.GetFontFamily(),prim.GetFontSize())
		     if prim.GetFontSlant() == "o" or prim.GetFontSlant() == "i":
			font.setItalic(True)
		     else:
			font.setItalic(False)
		     if prim.GetFontWeight() == "bold":
			font.setWeight(QtGui.QFont.Bold)
		     if prim.GetFontUnderline():
			font.setUnderline(True)
		     else:
			font.setUnderline(False)
		     s = FontedPositionedStrings.FontedPositionedStringsFromText(text,fontScaling=self.fontScaling,defaultFont=font)
		     descent = 0
		     fog_factor = 1.0
		     if isBill:
    			 xfrac,yfrac = cart.get_x(),cart.get_y()
			 x,y = xfrac*width, height-int(yfrac*height)-1
			 # Cannot help think we need the same for non-billboards.
		         descent = s.getDescent()
		     else:
			 cart = quat.getMatrix()*(cart+pygl_coord.Cartesian(self.rpos))
			 #x,y,z = cart.get_x(),cart.get_y(),-cart.get_z()
			 x,y,z = _prim['x'],_prim['y'],_prim['z']

			 fog_text = misco.get('fog_text')
			 if fog_text and self.fog_far > self.fog_near:
			   fog_factor = 1.0 - (z - self.fog_near)/(self.fog_far - self.fog_near)
			   fog_factor = min(fog_factor,1.0)
			   fog_factor = max(fog_factor,0.0)

    			 xfrac,yfrac = x/scale+0.5, y/scale+0.5
			 x,y = int((xfrac*height)+(width-height)/2.0),height-int((yfrac*height))-1
			 #pixmaps = renderStringToPixmap(text)
		     #print self.fontScaling
                     brect = s.getBoundingRect()
		     fog_alpha = int(255*fog_factor)
                     if bgcol:
                        painter.setPen(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2],fog_factor))
                        painter.setBrush(QtGui.QBrush(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2],fog_factor)))
		        if isBill:
                          painter.drawRect(x,y+descent-brect.height()*.1,brect.width(),-brect.height())
		        else:
                          painter.drawRect(x,y+descent+brect.height()*.2,brect.width(),-brect.height())
		     if bright_y <0.5:
			 	painter.setPen(QtGui.QColor(255,255,255,fog_alpha))
		     else:
			 	painter.setPen(QtGui.QColor(0,0,0,fog_alpha))
                     FontedPositionedStrings.drawFontedPositionedStrings(s.getStrings(),painter,x,y-descent,defaultFont=font)

          if hasattr(self,"axes_mag") and self.axes_mag and self.show_scale:
            ratio = float(width) / float(height);
            print "Now draw scale on image"
            if bright_y <0.5:
              pen = QtGui.QPen(QtGui.QColor(255,255,255))
            else:
              pen = QtGui.QPen(QtGui.QColor(0,0,0))
            pen.setWidth(3.0*self.line_scaling)
            font = QtGui.QFont("Times",24*self.axes_mag)
            painter.setPen(pen)
            painter.setFont(font)
            print "Scale position",QtCore.QPointF(.7*width,.95*height)
            painter.drawLine(QtCore.QPointF(.7*width,.95*height),QtCore.QPointF(.95*width,.95*height))
            painter.drawLine(QtCore.QPointF(.7*width,.935*height),QtCore.QPointF(.7*width,.965*height))
            painter.drawLine(QtCore.QPointF(.95*width,.935*height),QtCore.QPointF(.95*width,.965*height))
            if scalebartext:
              dist = u"%.1f \u212B" % (ratio*self.viewsize/2.*self.RADIUS/60.)
              dist_q = QtCore.QString(dist)
              fm = QtGui.QFontMetrics(font)
              x_shift = fm.width(dist_q)*.5
              painter.drawText(QtCore.QPointF(0.825*width-x_shift,0.925*height),dist_q)

          if hasattr(self,"axes_mag") and self.axes_mag and self.show_axes:
            axes_pos = QtCore.QPointF(theImage.width()*(self.axes_position[0]/2.+0.5),theImage.height()*(1.0-(self.axes_position[1]/2.+0.5)))
            if bright_y <0.5:
              pen = QtGui.QPen(QtGui.QColor(255,255,255))
            else:
              pen = QtGui.QPen(QtGui.QColor(0,0,0))
            xaxis = self.quat.getMatrix()*pygl_coord.Cartesian(1,0,0);
            yaxis = self.quat.getMatrix()*pygl_coord.Cartesian(0,1,0)
            zaxis = self.quat.getMatrix()*pygl_coord.Cartesian(0,0,1)
            zreal = pygl_coord.Cartesian(0,0,1)
            xproj = xaxis; xproj.set_z(0);
            yproj = yaxis; yproj.set_z(0);
            zproj = zaxis; zproj.set_z(0);
            xprime = pygl_coord.Cartesian.CrossProduct(xproj,zreal); xprime.normalize()
            yprime = pygl_coord.Cartesian.CrossProduct(yproj,zreal); yprime.normalize()
            zprime = pygl_coord.Cartesian.CrossProduct(zproj,zreal); zprime.normalize()
            xprime = xprime*0.004*theImage.width()
            yprime = yprime*0.004*theImage.width()
            zprime = zprime*0.004*theImage.width()
            xaxis = xaxis*0.04*theImage.width()
            yaxis = yaxis*0.04*theImage.width()
            zaxis = zaxis*0.04*theImage.width()
            xppos = QtCore.QPointF(xprime.get_x(),-xprime.get_y())
            yppos = QtCore.QPointF(yprime.get_x(),-yprime.get_y())
            zppos = QtCore.QPointF(zprime.get_x(),-zprime.get_y())
            xpos = QtCore.QPointF(xaxis.get_x(),-xaxis.get_y())+axes_pos
            ypos = QtCore.QPointF(yaxis.get_x(),-yaxis.get_y())+axes_pos
            zpos = QtCore.QPointF(zaxis.get_x(),-zaxis.get_y())+axes_pos
            xposarrow = QtCore.QPointF(0.8*xaxis.get_x(),-0.8*xaxis.get_y())+axes_pos
            yposarrow = QtCore.QPointF(0.8*yaxis.get_x(),-0.8*yaxis.get_y())+axes_pos
            zposarrow = QtCore.QPointF(0.8*zaxis.get_x(),-0.8*zaxis.get_y())+axes_pos
            xpostext = QtCore.QPointF(1.2*xaxis.get_x(),-1.2*xaxis.get_y())+axes_pos
            ypostext = QtCore.QPointF(1.2*yaxis.get_x(),-1.2*yaxis.get_y())+axes_pos
            zpostext = QtCore.QPointF(1.2*zaxis.get_x(),-1.2*zaxis.get_y())+axes_pos
            pen.setWidth(2*self.axes_mag)
            font = QtGui.QFont("Times",24*self.axes_mag)
            painter.setPen(pen)
            painter.setFont(font)
            painter.drawLine(axes_pos,xpos)
            painter.drawLine(axes_pos,ypos)
            painter.drawLine(axes_pos,zpos)
            xpp = xposarrow + xppos
            xpm = xposarrow - xppos
            painter.drawLine(xpos,xpp)
            painter.drawLine(xpos,xpm)
            ypp = yposarrow + yppos
            ypm = yposarrow - yppos
            painter.drawLine(ypos,ypp)
            painter.drawLine(ypos,ypm)
            zpp = zposarrow + zppos
            zpm = zposarrow - zppos
            painter.drawLine(zpos,zpp)
            painter.drawLine(zpos,zpm)
            painter.drawText(xpostext,'x')
            painter.drawText(ypostext,'y')
            painter.drawText(zpostext,'z')

	  painter.end()

    def screenshot(self):
	#print "MGGLWidget.screenshot"; sys.stdout.flush()
	if sys.platform != "win32" and self.drawTextSeparately:
		self.drawText = False

        import global_definitions
        misco = global_definitions.PM('miscell_prefs')
        fog_text = misco.get('fog_text')
        doText=True
        """
        if fog_text:
          print "Not doing separate text, because of fogginess. But should be scaled",self.fontScaling
          self.drawText = True
          doText=False
        """

	self.updateGL()
	self.updateGL()
        iinfo = opengl.get_pixdata()
        iinfo.invert()

	if doText and sys.platform != "win32" and self.drawTextSeparately:
	  import tempfile
          f = tempfile.mkstemp(".png")
          iinfo.writepng(f[0])

	  width = iinfo.get_width()
	  height = iinfo.get_height()
	  i = 0
	  bright_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)
	  viewport = pygl_coord.inta(4)
          opengl.glGetIntegerv(opengl.GL_VIEWPORT,viewport);
          tl = opengl.getxyzc(viewport[0],viewport[1])[0];
          bl = opengl.getxyzc(viewport[0],viewport[3])[0];
	  yscale = (tl-bl).length()

	  scale = yscale

	  import FontedPositionedStrings
	  pixmap = QtGui.QPixmap(f[1])
	  painter = QtGui.QPainter()
	  painter.begin(pixmap)
  
          import global_definitions
          misco = global_definitions.PM('miscell_prefs')
          tlb = misco.get('text_label_background')
          bgcol = None
          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('_',' '))

          for go in self.go:
             if go.obj.visible>0:
                 prims = go.obj.GetTextPrimitives()
		 for prim in prims:
		     text,isBill,cart = prim.GetText(),prim.IsBillBoard(),prim.GetVertices()[0]
                     cartOrig = cart
 		     font = QtGui.QFont(prim.GetFontFamily(),prim.GetFontSize())
		     if prim.GetFontSlant() == "o" or prim.GetFontSlant() == "i":
			font.setItalic(True)
		     else:
			font.setItalic(False)
		     if prim.GetFontWeight() == "bold":
			font.setWeight(QtGui.QFont.Bold)
		     if prim.GetFontUnderline():
			font.setUnderline(True)
		     else:
			font.setUnderline(False)
		     s = FontedPositionedStrings.FontedPositionedStringsFromText(text,fontScaling=self.fontScaling,defaultFont=font)
		     descent = 0
		     if isBill:
    			 xfrac,yfrac = cart.get_x(),cart.get_y()
			 x,y = xfrac*width, height-int(yfrac*height)-1
			 # Cannot help think we need the same for non-billboards.
		         descent = s.getDescent()
		     else:
			 cart = quat.getMatrix()*(cart+pygl_coord.Cartesian(self.rpos))
			 x,y = cart.get_x(),cart.get_y()
    			 xfrac,yfrac = x/scale+0.5, y/scale+0.5
			 x,y = int((xfrac*height)+(width-height)/2.0),height-int((yfrac*height))-1
			 #pixmaps = renderStringToPixmap(text)
		     #print self.fontScaling
                     brect = s.getBoundingRect()
                     if bgcol:
                        painter.setPen(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2]))
                        painter.setBrush(QtGui.QBrush(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2])))
                        painter.drawRect(x,y+descent,brect.width(),-brect.height())
		     if bright_y <0.5:
			 	painter.setPen(QtGui.QColor(255,255,255))
		     else:
			 	painter.setPen(QtGui.QColor(0,0,0))
		     FontedPositionedStrings.drawFontedPositionedStrings(s.getStrings(),painter,x,y-descent,defaultFont=font)
                     symm_mat = []
		     if not isBill:
		                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:
			           cartSym = quat.getMatrix()*(mat*cartOrig+pygl_coord.Cartesian(self.rpos))
			           xSym,ySym = cartSym.get_x(),cartSym.get_y()
    			           xfracSym,yfracSym = xSym/scale+0.5, ySym/scale+0.5
			           xSym,ySym = int((xfracSym*height)+(width-height)/2.0),height-int((yfracSym*height))-1
                                   if bgcol:
                                      painter.setPen(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2]))
                                      painter.setBrush(QtGui.QBrush(QtGui.QColor.fromRgbF(bgcol[0],bgcol[1],bgcol[2])))
                                      painter.drawRect(xSym,ySym+descent,brect.width(),-brect.height())
		                   if bright_y <0.5:
			 	              painter.setPen(QtGui.QColor(255,255,255))
		                   else:
			 	              painter.setPen(QtGui.QColor(0,0,0))
			 	   FontedPositionedStrings.drawFontedPositionedStrings(s.getStrings(),painter,xSym,ySym-descent,defaultFont=font)

	  painter.end()
          f = tempfile.mkstemp(".png")
	  pixmap.toImage().save(f[1])
          iinfo = image_info.image_info(f[1])
	  self.drawText = True
	  os.close(f[0])

	self.updateGL()
        return iinfo

    def SetupKeyboard(self):
        self.keys_down[QtCore.Qt.Key_Escape]=0
        self.keys_down[QtCore.Qt.Key_Tab]=0
        self.keys_down[QtCore.Qt.Key_Backtab]=0
        self.keys_down[QtCore.Qt.Key_Backspace]=0
        self.keys_down[QtCore.Qt.Key_Return]=0
        self.keys_down[QtCore.Qt.Key_Enter]=0
        self.keys_down[QtCore.Qt.Key_Insert]=0
        self.keys_down[QtCore.Qt.Key_Delete]=0
        self.keys_down[QtCore.Qt.Key_Pause]=0
        self.keys_down[QtCore.Qt.Key_Print]=0
        self.keys_down[QtCore.Qt.Key_SysReq]=0
        self.keys_down[QtCore.Qt.Key_Clear]=0
        self.keys_down[QtCore.Qt.Key_Home]=0
        self.keys_down[QtCore.Qt.Key_End]=0
        self.keys_down[QtCore.Qt.Key_Left]=0
        self.keys_down[QtCore.Qt.Key_Up]=0
        self.keys_down[QtCore.Qt.Key_Right]=0
        self.keys_down[QtCore.Qt.Key_Down]=0
        self.keys_down[QtCore.Qt.Key_PageUp]=0
        self.keys_down[QtCore.Qt.Key_PageDown]=0
        self.keys_down[QtCore.Qt.Key_Shift]=0
        self.keys_down[QtCore.Qt.Key_Control]=0
        self.keys_down[QtCore.Qt.Key_Meta]=0
        self.keys_down[QtCore.Qt.Key_Alt]=0
        self.keys_down[QtCore.Qt.Key_AltGr]=0
        self.keys_down[QtCore.Qt.Key_CapsLock]=0
        self.keys_down[QtCore.Qt.Key_NumLock]=0
        self.keys_down[QtCore.Qt.Key_ScrollLock]=0
        self.keys_down[QtCore.Qt.Key_F1]=0
        self.keys_down[QtCore.Qt.Key_F2]=0
        self.keys_down[QtCore.Qt.Key_F3]=0
        self.keys_down[QtCore.Qt.Key_F4]=0
        self.keys_down[QtCore.Qt.Key_F5]=0
        self.keys_down[QtCore.Qt.Key_F6]=0
        self.keys_down[QtCore.Qt.Key_F7]=0
        self.keys_down[QtCore.Qt.Key_F8]=0
        self.keys_down[QtCore.Qt.Key_F9]=0
        self.keys_down[QtCore.Qt.Key_F10]=0
        self.keys_down[QtCore.Qt.Key_F11]=0
        self.keys_down[QtCore.Qt.Key_F12]=0
        self.keys_down[QtCore.Qt.Key_F13]=0
        self.keys_down[QtCore.Qt.Key_F14]=0
        self.keys_down[QtCore.Qt.Key_F15]=0
        self.keys_down[QtCore.Qt.Key_F16]=0
        self.keys_down[QtCore.Qt.Key_F17]=0
        self.keys_down[QtCore.Qt.Key_F18]=0
        self.keys_down[QtCore.Qt.Key_F19]=0
        self.keys_down[QtCore.Qt.Key_F20]=0
        self.keys_down[QtCore.Qt.Key_F21]=0
        self.keys_down[QtCore.Qt.Key_F22]=0
        self.keys_down[QtCore.Qt.Key_F23]=0
        self.keys_down[QtCore.Qt.Key_F24]=0
        self.keys_down[QtCore.Qt.Key_F25]=0
        self.keys_down[QtCore.Qt.Key_F26]=0
        self.keys_down[QtCore.Qt.Key_F27]=0
        self.keys_down[QtCore.Qt.Key_F28]=0
        self.keys_down[QtCore.Qt.Key_F29]=0
        self.keys_down[QtCore.Qt.Key_F30]=0
        self.keys_down[QtCore.Qt.Key_F31]=0
        self.keys_down[QtCore.Qt.Key_F32]=0
        self.keys_down[QtCore.Qt.Key_F33]=0
        self.keys_down[QtCore.Qt.Key_F34]=0
        self.keys_down[QtCore.Qt.Key_F35]=0
        self.keys_down[QtCore.Qt.Key_Super_L]=0
        self.keys_down[QtCore.Qt.Key_Super_R]=0
        self.keys_down[QtCore.Qt.Key_Menu]=0
        self.keys_down[QtCore.Qt.Key_Hyper_L]=0
        self.keys_down[QtCore.Qt.Key_Hyper_R]=0
        self.keys_down[QtCore.Qt.Key_Help]=0
        self.keys_down[QtCore.Qt.Key_Direction_L]=0
        self.keys_down[QtCore.Qt.Key_Direction_R]=0
        self.keys_down[QtCore.Qt.Key_Space]=0
        self.keys_down[QtCore.Qt.Key_Any]=0
        self.keys_down[QtCore.Qt.Key_Exclam]=0
        self.keys_down[QtCore.Qt.Key_QuoteDbl]=0
        self.keys_down[QtCore.Qt.Key_NumberSign]=0
        self.keys_down[QtCore.Qt.Key_Dollar]=0
        self.keys_down[QtCore.Qt.Key_Percent]=0
        self.keys_down[QtCore.Qt.Key_Ampersand]=0
        self.keys_down[QtCore.Qt.Key_Apostrophe]=0
        self.keys_down[QtCore.Qt.Key_ParenLeft]=0
        self.keys_down[QtCore.Qt.Key_ParenRight]=0
        self.keys_down[QtCore.Qt.Key_Asterisk]=0
        self.keys_down[QtCore.Qt.Key_Plus]=0
        self.keys_down[QtCore.Qt.Key_Comma]=0
        self.keys_down[QtCore.Qt.Key_Minus]=0
        self.keys_down[QtCore.Qt.Key_Period]=0
        self.keys_down[QtCore.Qt.Key_Slash]=0
        self.keys_down[QtCore.Qt.Key_0]=0
        self.keys_down[QtCore.Qt.Key_1]=0
        self.keys_down[QtCore.Qt.Key_2]=0
        self.keys_down[QtCore.Qt.Key_3]=0
        self.keys_down[QtCore.Qt.Key_4]=0
        self.keys_down[QtCore.Qt.Key_5]=0
        self.keys_down[QtCore.Qt.Key_6]=0
        self.keys_down[QtCore.Qt.Key_7]=0
        self.keys_down[QtCore.Qt.Key_8]=0
        self.keys_down[QtCore.Qt.Key_9]=0
        self.keys_down[QtCore.Qt.Key_Colon]=0
        self.keys_down[QtCore.Qt.Key_Semicolon]=0
        self.keys_down[QtCore.Qt.Key_Less]=0
        self.keys_down[QtCore.Qt.Key_Equal]=0
        self.keys_down[QtCore.Qt.Key_Greater]=0
        self.keys_down[QtCore.Qt.Key_Question]=0
        self.keys_down[QtCore.Qt.Key_At]=0
        self.keys_down[QtCore.Qt.Key_A]=0
        self.keys_down[QtCore.Qt.Key_B]=0
        self.keys_down[QtCore.Qt.Key_C]=0
        self.keys_down[QtCore.Qt.Key_D]=0
        self.keys_down[QtCore.Qt.Key_E]=0
        self.keys_down[QtCore.Qt.Key_F]=0
        self.keys_down[QtCore.Qt.Key_G]=0
        self.keys_down[QtCore.Qt.Key_H]=0
        self.keys_down[QtCore.Qt.Key_I]=0
        self.keys_down[QtCore.Qt.Key_J]=0
        self.keys_down[QtCore.Qt.Key_K]=0
        self.keys_down[QtCore.Qt.Key_L]=0
        self.keys_down[QtCore.Qt.Key_M]=0
        self.keys_down[QtCore.Qt.Key_N]=0
        self.keys_down[QtCore.Qt.Key_O]=0
        self.keys_down[QtCore.Qt.Key_P]=0
        self.keys_down[QtCore.Qt.Key_Q]=0
        self.keys_down[QtCore.Qt.Key_R]=0
        self.keys_down[QtCore.Qt.Key_S]=0
        self.keys_down[QtCore.Qt.Key_T]=0
        self.keys_down[QtCore.Qt.Key_U]=0
        self.keys_down[QtCore.Qt.Key_V]=0
        self.keys_down[QtCore.Qt.Key_W]=0
        self.keys_down[QtCore.Qt.Key_X]=0
        self.keys_down[QtCore.Qt.Key_Y]=0
        self.keys_down[QtCore.Qt.Key_Z]=0
        self.keys_down[QtCore.Qt.Key_BracketLeft]=0
        self.keys_down[QtCore.Qt.Key_Backslash]=0
        self.keys_down[QtCore.Qt.Key_BracketRight]=0
        self.keys_down[QtCore.Qt.Key_AsciiCircum]=0
        self.keys_down[QtCore.Qt.Key_Underscore]=0
        self.keys_down[QtCore.Qt.Key_QuoteLeft]=0
        self.keys_down[QtCore.Qt.Key_BraceLeft]=0
        self.keys_down[QtCore.Qt.Key_Bar]=0
        self.keys_down[QtCore.Qt.Key_BraceRight]=0
        self.keys_down[QtCore.Qt.Key_AsciiTilde]=0
        self.keys_down[QtCore.Qt.Key_nobreakspace]=0
        self.keys_down[QtCore.Qt.Key_exclamdown]=0
        self.keys_down[QtCore.Qt.Key_cent]=0
        self.keys_down[QtCore.Qt.Key_sterling]=0
        self.keys_down[QtCore.Qt.Key_currency]=0
        self.keys_down[QtCore.Qt.Key_yen]=0
        self.keys_down[QtCore.Qt.Key_brokenbar]=0
        self.keys_down[QtCore.Qt.Key_section]=0
        self.keys_down[QtCore.Qt.Key_diaeresis]=0
        self.keys_down[QtCore.Qt.Key_copyright]=0
        self.keys_down[QtCore.Qt.Key_ordfeminine]=0
        self.keys_down[QtCore.Qt.Key_guillemotleft]=0
        self.keys_down[QtCore.Qt.Key_notsign]=0
        self.keys_down[QtCore.Qt.Key_hyphen]=0
        self.keys_down[QtCore.Qt.Key_registered]=0
        self.keys_down[QtCore.Qt.Key_macron]=0
        self.keys_down[QtCore.Qt.Key_degree]=0
        self.keys_down[QtCore.Qt.Key_plusminus]=0
        self.keys_down[QtCore.Qt.Key_twosuperior]=0
        self.keys_down[QtCore.Qt.Key_threesuperior]=0
        self.keys_down[QtCore.Qt.Key_acute]=0
        self.keys_down[QtCore.Qt.Key_mu]=0
        self.keys_down[QtCore.Qt.Key_paragraph]=0
        self.keys_down[QtCore.Qt.Key_periodcentered]=0
        self.keys_down[QtCore.Qt.Key_cedilla]=0
        self.keys_down[QtCore.Qt.Key_onesuperior]=0
        self.keys_down[QtCore.Qt.Key_masculine]=0
        self.keys_down[QtCore.Qt.Key_guillemotright]=0
        self.keys_down[QtCore.Qt.Key_onequarter]=0
        self.keys_down[QtCore.Qt.Key_onehalf]=0
        self.keys_down[QtCore.Qt.Key_threequarters]=0
        self.keys_down[QtCore.Qt.Key_questiondown]=0
        self.keys_down[QtCore.Qt.Key_Agrave]=0
        self.keys_down[QtCore.Qt.Key_Aacute]=0
        self.keys_down[QtCore.Qt.Key_Acircumflex]=0
        self.keys_down[QtCore.Qt.Key_Atilde]=0
        self.keys_down[QtCore.Qt.Key_Adiaeresis]=0
        self.keys_down[QtCore.Qt.Key_Aring]=0
        self.keys_down[QtCore.Qt.Key_AE]=0
        self.keys_down[QtCore.Qt.Key_Ccedilla]=0
        self.keys_down[QtCore.Qt.Key_Egrave]=0
        self.keys_down[QtCore.Qt.Key_Eacute]=0
        self.keys_down[QtCore.Qt.Key_Ecircumflex]=0
        self.keys_down[QtCore.Qt.Key_Ediaeresis]=0
        self.keys_down[QtCore.Qt.Key_Igrave]=0
        self.keys_down[QtCore.Qt.Key_Iacute]=0
        self.keys_down[QtCore.Qt.Key_Icircumflex]=0
        self.keys_down[QtCore.Qt.Key_Idiaeresis]=0
        self.keys_down[QtCore.Qt.Key_ETH]=0
        self.keys_down[QtCore.Qt.Key_Ntilde]=0
        self.keys_down[QtCore.Qt.Key_Ograve]=0
        self.keys_down[QtCore.Qt.Key_Oacute]=0
        self.keys_down[QtCore.Qt.Key_Ocircumflex]=0
        self.keys_down[QtCore.Qt.Key_Otilde]=0
        self.keys_down[QtCore.Qt.Key_Odiaeresis]=0
        self.keys_down[QtCore.Qt.Key_multiply]=0
        self.keys_down[QtCore.Qt.Key_Ooblique]=0
        self.keys_down[QtCore.Qt.Key_Ugrave]=0
        self.keys_down[QtCore.Qt.Key_Uacute]=0
        self.keys_down[QtCore.Qt.Key_Ucircumflex]=0
        self.keys_down[QtCore.Qt.Key_Udiaeresis]=0
        self.keys_down[QtCore.Qt.Key_Yacute]=0
        self.keys_down[QtCore.Qt.Key_THORN]=0
        self.keys_down[QtCore.Qt.Key_ssharp]=0
        self.keys_down[QtCore.Qt.Key_division]=0
        self.keys_down[QtCore.Qt.Key_ydiaeresis]=0
        self.keys_down[QtCore.Qt.Key_Multi_key]=0
        self.keys_down[QtCore.Qt.Key_Codeinput]=0
        self.keys_down[QtCore.Qt.Key_SingleCandidate]=0
        self.keys_down[QtCore.Qt.Key_MultipleCandidate]=0
        self.keys_down[QtCore.Qt.Key_PreviousCandidate]=0
        self.keys_down[QtCore.Qt.Key_Mode_switch]=0
        self.keys_down[QtCore.Qt.Key_Kanji]=0
        self.keys_down[QtCore.Qt.Key_Muhenkan]=0
        self.keys_down[QtCore.Qt.Key_Henkan]=0
        self.keys_down[QtCore.Qt.Key_Romaji]=0
        self.keys_down[QtCore.Qt.Key_Hiragana]=0
        self.keys_down[QtCore.Qt.Key_Katakana]=0
        self.keys_down[QtCore.Qt.Key_Hiragana_Katakana]=0
        self.keys_down[QtCore.Qt.Key_Zenkaku]=0
        self.keys_down[QtCore.Qt.Key_Hankaku]=0
        self.keys_down[QtCore.Qt.Key_Zenkaku_Hankaku]=0
        self.keys_down[QtCore.Qt.Key_Touroku]=0
        self.keys_down[QtCore.Qt.Key_Massyo]=0
        self.keys_down[QtCore.Qt.Key_Kana_Lock]=0
        self.keys_down[QtCore.Qt.Key_Kana_Shift]=0
        self.keys_down[QtCore.Qt.Key_Eisu_Shift]=0
        self.keys_down[QtCore.Qt.Key_Eisu_toggle]=0
        self.keys_down[QtCore.Qt.Key_Hangul]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Start]=0
        self.keys_down[QtCore.Qt.Key_Hangul_End]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Hanja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Jamo]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Romaja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Jeonja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Banja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_PreHanja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_PostHanja]=0
        self.keys_down[QtCore.Qt.Key_Hangul_Special]=0
        self.keys_down[QtCore.Qt.Key_Dead_Grave]=0
        self.keys_down[QtCore.Qt.Key_Dead_Acute]=0
        self.keys_down[QtCore.Qt.Key_Dead_Circumflex]=0
        self.keys_down[QtCore.Qt.Key_Dead_Tilde]=0
        self.keys_down[QtCore.Qt.Key_Dead_Macron]=0
        self.keys_down[QtCore.Qt.Key_Dead_Breve]=0
        self.keys_down[QtCore.Qt.Key_Dead_Abovedot]=0
        self.keys_down[QtCore.Qt.Key_Dead_Diaeresis]=0
        self.keys_down[QtCore.Qt.Key_Dead_Abovering]=0
        self.keys_down[QtCore.Qt.Key_Dead_Doubleacute]=0
        self.keys_down[QtCore.Qt.Key_Dead_Caron]=0
        self.keys_down[QtCore.Qt.Key_Dead_Cedilla]=0
        self.keys_down[QtCore.Qt.Key_Dead_Ogonek]=0
        self.keys_down[QtCore.Qt.Key_Dead_Iota]=0
        self.keys_down[QtCore.Qt.Key_Dead_Voiced_Sound]=0
        self.keys_down[QtCore.Qt.Key_Dead_Semivoiced_Sound]=0
        self.keys_down[QtCore.Qt.Key_Dead_Belowdot]=0
        self.keys_down[QtCore.Qt.Key_Dead_Hook]=0
        self.keys_down[QtCore.Qt.Key_Dead_Horn]=0
        self.keys_down[QtCore.Qt.Key_Back]=0
        self.keys_down[QtCore.Qt.Key_Forward]=0
        self.keys_down[QtCore.Qt.Key_Stop]=0
        self.keys_down[QtCore.Qt.Key_Refresh]=0
        self.keys_down[QtCore.Qt.Key_VolumeDown]=0
        self.keys_down[QtCore.Qt.Key_VolumeMute]=0
        self.keys_down[QtCore.Qt.Key_VolumeUp]=0
        self.keys_down[QtCore.Qt.Key_BassBoost]=0
        self.keys_down[QtCore.Qt.Key_BassUp]=0
        self.keys_down[QtCore.Qt.Key_BassDown]=0
        self.keys_down[QtCore.Qt.Key_TrebleUp]=0
        self.keys_down[QtCore.Qt.Key_TrebleDown]=0
        self.keys_down[QtCore.Qt.Key_MediaPlay]=0
        self.keys_down[QtCore.Qt.Key_MediaStop]=0
        self.keys_down[QtCore.Qt.Key_MediaPrevious]=0
        self.keys_down[QtCore.Qt.Key_MediaNext]=0
        self.keys_down[QtCore.Qt.Key_MediaRecord]=0
        self.keys_down[QtCore.Qt.Key_HomePage]=0
        self.keys_down[QtCore.Qt.Key_Favorites]=0
        self.keys_down[QtCore.Qt.Key_Search]=0
        self.keys_down[QtCore.Qt.Key_Standby]=0
        self.keys_down[QtCore.Qt.Key_OpenUrl]=0
        self.keys_down[QtCore.Qt.Key_LaunchMail]=0
        self.keys_down[QtCore.Qt.Key_LaunchMedia]=0
        self.keys_down[QtCore.Qt.Key_Launch0]=0
        self.keys_down[QtCore.Qt.Key_Launch1]=0
        self.keys_down[QtCore.Qt.Key_Launch2]=0
        self.keys_down[QtCore.Qt.Key_Launch3]=0
        self.keys_down[QtCore.Qt.Key_Launch4]=0
        self.keys_down[QtCore.Qt.Key_Launch5]=0
        self.keys_down[QtCore.Qt.Key_Launch6]=0
        self.keys_down[QtCore.Qt.Key_Launch7]=0
        self.keys_down[QtCore.Qt.Key_Launch8]=0
        self.keys_down[QtCore.Qt.Key_Launch9]=0
        self.keys_down[QtCore.Qt.Key_LaunchA]=0
        self.keys_down[QtCore.Qt.Key_LaunchB]=0
        self.keys_down[QtCore.Qt.Key_LaunchC]=0
        self.keys_down[QtCore.Qt.Key_LaunchD]=0
        self.keys_down[QtCore.Qt.Key_LaunchE]=0
        self.keys_down[QtCore.Qt.Key_LaunchF]=0
        self.keys_down[QtCore.Qt.Key_MediaLast]=0
        self.keys_down[QtCore.Qt.Key_unknown]=0
        self.keys_down[QtCore.Qt.Key_Call]=0
        self.keys_down[QtCore.Qt.Key_Context1]=0
        self.keys_down[QtCore.Qt.Key_Context2]=0
        self.keys_down[QtCore.Qt.Key_Context3]=0
        self.keys_down[QtCore.Qt.Key_Context4]=0
        self.keys_down[QtCore.Qt.Key_Flip]=0
        self.keys_down[QtCore.Qt.Key_Hangup]=0
        self.keys_down[QtCore.Qt.Key_No]=0
        self.keys_down[QtCore.Qt.Key_Select]=0
        self.keys_down[QtCore.Qt.Key_Yes]=0
        self.keys_down[QtCore.Qt.Key_Execute]=0
        self.keys_down[QtCore.Qt.Key_Printer]=0
        self.keys_down[QtCore.Qt.Key_Play]=0
        self.keys_down[QtCore.Qt.Key_Sleep]=0
        self.keys_down[QtCore.Qt.Key_Zoom]=0
        self.keys_down[QtCore.Qt.Key_Cancel]=0

    def SetGOParams(self, params=None):
        pass
         
    def reInitializeTextPrims(self):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        for go in self.go:
           go.obj.reInitializeTextPrims()


    def rebuildDisplayObject(self, go=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.rebuildDisplayObject(self, go,redraw)

    def removeDisplayObject(self, go_in=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.removeDisplayObject(self, go_in,redraw)

    def addDisplayObject(self, go=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.addDisplayObject(self, go,redraw)

    def __init__(self,parent=None,share=None,format=None,use_pbuffer=False,pbuffer_size=QtCore.QSize(600,600)):
        if format:
          QtOpenGL.QGLWidget.__init__(self,format,parent,share)
          #print "Samples",format.samples(),format.sampleBuffers()
        else:
          QtOpenGL.QGLWidget.__init__(self,parent,share)
          #print "No format specified"
        #print "my Samples",self.format().samples(),self.format().sampleBuffers()

        """
        # Testing
        import mmdb, SimpleObject
        mmdb.InitMatType()
        molHnd = mmdb.CMMDBManager()
        molHnd.SetFlag(mmdb.MMDBF_AllowDuplChainID)
        molHnd.ReadCoorFile("/richelieu/stuart/ccp4-jhbuild-distutils/1sva_1.mmol")
        self.sillyobj = SimpleObject.SimpleObject(molHnd)
        """

        MGGLWidgetGL.__init__(self,parent,share,format)
        self.setAcceptDrops(1)
        self.use_pbuffer=use_pbuffer
	if self.use_pbuffer:
           self.pbuffer = QtOpenGL.QGLPixelBuffer(pbuffer_size,self.format(),self)
           self.BindOffScreenBuffer()

	# A silly number, out of normal range, to force matrix creation first time round.
        self.stereo_shear_separation = 1000 

	self.setFocusPolicy(QtCore.Qt.StrongFocus)
	self.SetupKeyboard()

        self.qkey_timer = QtCore.QTimer(self)
        self.connect(self.qkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.akey_timer = QtCore.QTimer(self)
        self.connect(self.akey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.okey_timer = QtCore.QTimer(self)
        self.connect(self.okey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.pkey_timer = QtCore.QTimer(self)
        self.connect(self.pkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.nkey_timer = QtCore.QTimer(self)
        self.connect(self.nkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.mkey_timer = QtCore.QTimer(self)
        self.connect(self.mkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.leftkey_timer = QtCore.QTimer(self)
        self.connect(self.leftkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.rightkey_timer = QtCore.QTimer(self)
        self.connect(self.rightkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.upkey_timer = QtCore.QTimer(self)
        self.connect(self.upkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        self.downkey_timer = QtCore.QTimer(self)
        self.connect(self.downkey_timer,QtCore.SIGNAL('timeout()'),self.lrudqaopnmkey_handler)
        #self.roll_timer = QtCore.QTimer(self)
        #self.connect(self.roll_timer,QtCore.SIGNAL('timeout()'),self.roll_handler)
        #self.record_timer = QtCore.QTimer(self)
        #self.connect(self.record_timer,QtCore.SIGNAL('timeout()'),self.record_handler)
        self.pluskey_timer = QtCore.QTimer(self)
        self.connect(self.pluskey_timer,QtCore.SIGNAL('timeout()'),self.pluskey_handler)
        self.minuskey_timer = QtCore.QTimer(self)
        self.connect(self.minuskey_timer,QtCore.SIGNAL('timeout()'),self.minuskey_handler)

        self.context_menu = QtGui.QMenu(self.tr('Context'))
        self.connect(self.context_menu,QtCore.SIGNAL('aboutToShow()'),self.aboutToShowHandler)
        self.connect(self.context_menu,QtCore.SIGNAL('aboutToHide()'),self.aboutToHideHandler)
        # This is an annoying hack since aboutToShow seems to always be triggered twice.
        self.showing_context_menu = False

        self.contextMenuHandler = self.defaultContextMenuHandler
        self.doubleClickHandler = self.defaultDoubleClickHandler
        self.leftClickHandler = self.defaultLeftClickHandler
        self.contextMenuPickEvent = None

        import UtilityThread
        self.mt = UtilityThread.UtilityThread()
        self.connect(self.mt,QtCore.SIGNAL('finished()'),self.UtilityThreadFinished)

	self.lastEventType=QtCore.QEvent.None

        self.setDefaultMouseBindings()
        self.setup_colour_pointers()

	if  QtCore.QT_VERSION >= 0x40600 and QtCore.PYQT_VERSION >= 0x040700 and sip.SIP_VERSION >= 0x040a00:
		#print "Maybe have gestures"
        	self.grabGesture(QtCore.Qt.PanGesture);
        	self.grabGesture(QtCore.Qt.PinchGesture);
        	self.grabGesture(QtCore.Qt.SwipeGesture);
		#print "Hopefully grabbed gestures"

        self.show_fps = False
        self.current_fps_text = "0"

    def defaultLeftClickHandler(self,pickevent):
        pass
    
    def defaultDoubleClickHandler(self,pickevent):
        pass

    def defaultContextMenuHandler(self,pickevent):
        pass

    def UtilityThreadFinished(self):
        id = len(self.go)-1
        go = self.go[id]
        self.buildlist(go,self.listids[id])
        self.updateGL()
	statusBar = GetMainWindow().statusBar()
	statusBar.showMessage("")

    def minimumSizeHint(self):
        return QtCore.QSize(150, 150)

    def sizeHint(self):
        return QtCore.QSize(800, 800)

    def setLights(self,lights):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.setLights(self, lights)

    def getOpenGLLightParameters(self,lightID):
	    	self.makeCurrent()
		if self.use_pbuffer:
           		self.BindOffScreenBuffer()
		return MGGLWidgetGL.getOpenGLLightParameters(self, lightID)

    def getLights(self):
	    	self.makeCurrent()
		if self.use_pbuffer:
           		self.BindOffScreenBuffer()
		return MGGLWidgetGL.getLights(self)

    def initializeGL(self):

	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        self.qglClearColor(self.bgcolour)
	MGGLWidgetGL.initializeGL(self)

        if QtOpenGL.QGLFramebufferObject.hasOpenGLFramebufferObjects ():
          reqW = 2048
          reqH = 2048
          self.offScreenBufferDepth = opengl.MGDepthFramebufferObject(1024,1024)
          #print "Got depth map"; sys.stdout.flush()
          if not os.environ.has_key("CCP4MG_DEBUG_SHADOWS"):
            self.offScreenBufferShadow = opengl.MGDepthFramebufferObject(reqW,reqH)
          #print "Got shadow map"; sys.stdout.flush()
          #reqW = 2048
          #reqH = 2048
          fmt = QtOpenGL.QGLFramebufferObjectFormat()
          fmt.setAttachment(QtOpenGL.QGLFramebufferObject.CombinedDepthStencil)
          #fmt.setSamples(self.format().samples())
          #self.offScreenBufferMirror = QtOpenGL.QGLFramebufferObject(QtCore.QSize(reqW,reqH),fmt)
          #self.offScreenBufferTextureMirror = QtOpenGL.QGLFramebufferObject(QtCore.QSize(reqW,reqH))
          #self.offScreenBufferOther = QtOpenGL.QGLFramebufferObject(QtCore.QSize(reqW,reqH))
          self.offScreenBufferSSAO = QtOpenGL.QGLFramebufferObject(QtCore.QSize(1024,1024))
          self.offScreenBufferEdge = QtOpenGL.QGLFramebufferObject(QtCore.QSize(1024,1024))
          self.offScreenBufferBlur = QtOpenGL.QGLFramebufferObject(QtCore.QSize(1024,1024))
          self.offScreenBufferNormal = QtOpenGL.QGLFramebufferObject(QtCore.QSize(1024,1024),fmt)
          if os.environ.has_key("CCP4MG_DEBUG_SHADOWS"):
            self.offScreenBufferShadow = QtOpenGL.QGLFramebufferObject(QtCore.QSize(1024,1024),fmt)

    def setShader(self,vertexShader,fragmentShader):
        if not vertexShader or not fragmentShader:
           return
        if vertexShader == self.vertexShader and fragmentShader == self.fragmentShader:
           return
	try:
		import glShaders
		self.shader = glShaders.MGGLShader(vertexShader,fragmentShader)
                self.vertexShader = vertexShader
                self.fragmentShader = fragmentShader
                self.shader.setShadowState(False)
	except:
		QtGui.QMessageBox.critical(None, "No shader support", "This version of ccp4mg does not have shader support.", QtGui.QMessageBox.Ok )
		

    def setup_clipping(self):
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.setup_clipping(self)

    def setup_fog(self):
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.setup_fog(self)

    def setupModelview(self,furtherQuat=None,furtherMatrix=None):
	self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.setupModelview(self,furtherQuat,furtherMatrix)

    def paintGL(self):
        """
        # Testing
        opengl.glLoadIdentity();
        opengl.glTranslatef(0,0,-600);
        opengl.glScalef(60.0/float(self.RADIUS),60.0/float(self.RADIUS),60.0/float(self.RADIUS))
        glrotmat = self.quat.getInvMatrix().to_dp()
        opengl.glMultMatrixd(glrotmat)
        opengl.delcdp(glrotmat)

        self.qglClearColor(QtGui.QColor(QtCore.Qt.white))
        opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT)
        opengl.glDisable(opengl.GL_LIGHTING);
        opengl.glEnableClientState(opengl.GL_VERTEX_ARRAY)
        opengl.glEnableClientState(opengl.GL_COLOR_ARRAY)

        if hasattr(self,"sillyobj") and hasattr(self.sillyobj,"draw") and callable(self.sillyobj.draw):
          self.sillyobj.draw()
          self.showFPS()
          return
        """

        if self.shaders_on and hasattr(self,"shader") and self.shader:
          ssaoOnLoc = self.shader.getUniformLocation("ssaoOn")
          self.shader.Uniform1f(ssaoOnLoc,False)
          ssaoOnLocCircle = self.circleShader.getUniformLocation("ssaoOn")
          self.circleShader.Uniform1f(ssaoOnLocCircle,False)
          edgeDetectOnLoc = self.shader.getUniformLocation("edgeDetectOn")
          self.shader.Uniform1f(edgeDetectOnLoc,False)
          edgeDetectOnCircleLoc = self.circleShader.getUniformLocation("edgeDetectOn")
          self.circleShader.Uniform1f(edgeDetectOnCircleLoc,False)
          edgeDetectOnCircleLoc = self.circleShadowShader.getUniformLocation("edgeDetectOn")
          self.circleShadowShader.Uniform1f(edgeDetectOnCircleLoc,False)


        if (not self.doMirror and not self.doShadow and not self.doAmbient and not self.doOutline) or not self.shaders_on:
          if self.shaders_on and hasattr(self,"shader") and self.shader:
            self.shader.setShadowState(False)
            self.circleShader.setShadowState(False)
            ShadowMapLoc = self.shader.getUniformLocation("ShadowMap")
            self.shader.Uniform1i(ShadowMapLoc,2)
            ShadowMapLoc = self.circleShader.getUniformLocation("ShadowMap")
            self.circleShader.Uniform1i(ShadowMapLoc,2)
            SSAOMapLoc = self.shader.getUniformLocation("SSAOMap")
            self.shader.Uniform1i(SSAOMapLoc,3)
            EdgeMapLoc = self.shader.getUniformLocation("EdgeMap")
            self.shader.Uniform1i(EdgeMapLoc,4)
            EdgeMapCircleLoc = self.circleShader.getUniformLocation("EdgeMap")
            self.circleShader.Uniform1i(EdgeMapCircleLoc,4)
            EdgeMapCircleLoc = self.circleShadowShader.getUniformLocation("EdgeMap")
            self.circleShadowShader.Uniform1i(EdgeMapCircleLoc,4)
	  if self.multiTextureAvailable:
            opengl.SetMyTextureUnit(opengl.GL_TEXTURE2);
            opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
            opengl.SetMyTextureUnit(opengl.GL_TEXTURE3);
            opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
            opengl.SetMyTextureUnit(opengl.GL_TEXTURE4);
            opengl.glBindTexture( opengl.GL_TEXTURE_2D, 0 );
            opengl.glDisable(opengl.GL_TEXTURE_2D);
            opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
            opengl.glDisable(opengl.GL_TEXTURE_2D);
          self.paintGL2()
          return

        shaders_on = self.shaders_on
        use_pbuffer = self.use_pbuffer
        self.use_pbuffer = False
        if hasattr(self,"pbuffer"):
           self.pbuffer.release()
        self.makeCurrent()

        if self.doOutline and shaders_on and hasattr(self,"normalAsColourShader") and self.normalAsColourShader:

          # I am cheating for testing by using SSAO texture location/flag to get this on screen. Will change.

          self.shaders_on = False
          self.offScreenBufferNormal.bind()
          if hasattr(self,"normalAsColourShader"): self.normalAsColourShader.turnOn()
          reqW = self.offScreenBufferNormal.width()
          reqH = self.offScreenBufferNormal.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          # FIXME - Do something in render loop about lines, etc. (like with shadows).
          self.inAmbient = True
          #print "Call resizeGLMain ambient 1"
          self.resizeGLMain(reqW,reqH,ratio)
          self.paintGL2()
          self.inAmbient = False
          if hasattr(self,"normalAsColourShader"): self.normalAsColourShader.turnOff()
          self.offScreenBufferNormal.release()
          #self.offScreenBufferNormal.toImage().save("normal.png")
          normalTexture = self.offScreenBufferNormal.texture()

          # Render depth to texture
          self.offScreenBufferDepth.bind()
          reqW = self.offScreenBufferDepth.width()
          reqH = self.offScreenBufferDepth.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          # FIXME - Do something in render loop about lines, etc. (like with shadows).
          self.inAmbient = True
          #print "Call resizeGLMain ambient 1"
          self.resizeGLMain(reqW,reqH,ratio)
          #self.shadowShader.turnOn()
          self.paintGL2()
          #self.shadowShader.turnOff()
          self.inAmbient = False
          #opengl.setTextureMatrix()
          self.offScreenBufferDepth.release()
          depthTexture = self.offScreenBufferDepth.texture()

          # Do Edge detect step, draw onto quad.
          self.offScreenBufferEdge.bind()
          reqW = self.offScreenBufferEdge.width()
          reqH = self.offScreenBufferEdge.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          #print "Call resizeGLMain ambient 2"
          self.resizeGLMain(reqW,reqH,ratio)
          depthMapLoc = self.edgeDetectShader.getUniformLocation("depthMap")
          normalMapLoc = self.edgeDetectShader.getUniformLocation("normalMap")
          screenWidthLoc = self.edgeDetectShader.getUniformLocation("screenWidth")
          screenHeightLoc = self.edgeDetectShader.getUniformLocation("screenHeight")
          self.edgeDetectShader.Uniform1f(screenWidthLoc,reqW)
          self.edgeDetectShader.Uniform1f(screenHeightLoc,reqH)
          self.edgeDetectShader.Uniform1i(depthMapLoc,2)
          self.edgeDetectShader.Uniform1i(normalMapLoc,3)

          self.edgeDetectShader.turnOn()
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE2);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,depthTexture)
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE3);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,normalTexture)
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glDisable(opengl.GL_TEXTURE_2D)
          #self.resizeGLMain(w,h,ratio)
       
          opengl.glMatrixMode(opengl.GL_MODELVIEW);
          opengl.glTranslated(-self.rpos[0],-self.rpos[1],-self.rpos[2])
          quat = pygl_coord.Quat(self.quat)
          glrotmat = quat.getMatrix().to_dp()
          opengl.glMultMatrixd(glrotmat)
          opengl.delcdp(glrotmat)
          # FIXME, do not know why, but this helps us zoom in closer and still have AO work.
          opengl.glTranslatef(0,0,240)
          
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.edgeDetectShader.turnOff()
          self.offScreenBufferEdge.release()
          #self.offScreenBufferEdge.toImage().save("edgenormal.png")

          # FIXME Copy of SSAO code - need a general method to do this.
          texture = self.offScreenBufferEdge.texture()
          # Blur with FBO Ping-pong.
          # ping ...
          self.offScreenBufferBlur.bind()
          self.blurXShader.turnOn()
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.blurXShader.turnOff()
          self.offScreenBufferBlur.release()

          # ... pong.
          texture = self.offScreenBufferBlur.texture()

          self.offScreenBufferEdge.bind()
          self.blurYShader.turnOn()
          #self.resizeGLMain(reqW,reqH,1./ratio)
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.blurYShader.turnOff()
          self.offScreenBufferEdge.release()

          self.resizeGLMain(w,h,ratio)
          self.shaders_on = shaders_on

          # FIXME Need a outline location / texture unit.
          if shaders_on and hasattr(self,"shader") and self.shader:
            self.shader.turnOn()
            self.shader.Uniform1f(edgeDetectOnLoc,True)
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          EdgeMapLoc = self.shader.getUniformLocation("EdgeMap")
          screenWidthLoc = self.shader.getUniformLocation("screenWidth")
          screenHeightLoc = self.shader.getUniformLocation("screenHeight")
          self.shader.Uniform1i(EdgeMapLoc,4)
          self.shader.Uniform1f(screenWidthLoc,float(self.width()))
          self.shader.Uniform1f(screenHeightLoc,float(self.height()))
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE4);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,self.offScreenBufferEdge.texture())

          if shaders_on and hasattr(self,"circleShader") and self.circleShader:
            self.circleShader.turnOn()
            edgeDetectOnCircleLoc = self.circleShader.getUniformLocation("edgeDetectOn")
            self.circleShader.Uniform1f(edgeDetectOnCircleLoc,True)
          EdgeMapShadowLoc = self.circleShader.getUniformLocation("EdgeMap")
          screenWidthShadowLoc = self.circleShader.getUniformLocation("screenWidth")
          screenHeightShadowLoc = self.circleShader.getUniformLocation("screenHeight")
          self.circleShader.Uniform1i(EdgeMapShadowLoc,4)
          self.circleShader.Uniform1f(screenWidthShadowLoc,float(self.width()))
          self.circleShader.Uniform1f(screenHeightShadowLoc,float(self.height()))
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE4);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,self.offScreenBufferEdge.texture())
          if shaders_on and hasattr(self,"circleShadowShader") and self.circleShadowShader:
            self.circleShadowShader.turnOn()
            edgeDetectOnCircleLoc = self.circleShadowShader.getUniformLocation("edgeDetectOn")
            self.circleShadowShader.Uniform1f(edgeDetectOnCircleLoc,True)
          EdgeMapShadowLoc = self.circleShadowShader.getUniformLocation("EdgeMap")
          screenWidthShadowLoc = self.circleShadowShader.getUniformLocation("screenWidth")
          screenHeightShadowLoc = self.circleShadowShader.getUniformLocation("screenHeight")
          self.circleShadowShader.Uniform1i(EdgeMapShadowLoc,4)
          self.circleShadowShader.Uniform1f(screenWidthShadowLoc,float(self.width()))
          self.circleShadowShader.Uniform1f(screenHeightShadowLoc,float(self.height()))

          if shaders_on and hasattr(self,"shader") and self.shader:
            self.shader.turnOn()

        if self.doAmbient and shaders_on and hasattr(self,"ssaoShader") and self.ssaoShader:
          # Render depth to texture
          self.shaders_on = False
          self.offScreenBufferDepth.bind()
          reqW = self.offScreenBufferDepth.width()
          reqH = self.offScreenBufferDepth.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          # FIXME - Do something in render loop about lines, etc. (like with shadows).
          self.inAmbient = True
          #print "Call resizeGLMain ambient 1"
          self.resizeGLMain(reqW,reqH,ratio)
          self.paintGL2()
          self.inAmbient = False
          self.offScreenBufferDepth.release()

          # Do SSAO step, draw onto quad.
          self.offScreenBufferSSAO.bind()
          reqW = self.offScreenBufferSSAO.width()
          reqH = self.offScreenBufferSSAO.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          #print "Call resizeGLMain ambient 2"
          self.resizeGLMain(reqW,reqH,ratio)
          depthMapLoc = self.ssaoShader.getUniformLocation("depthMap")
          rotateMapLoc = self.ssaoShader.getUniformLocation("rotateMap")
          screenWidthLoc = self.ssaoShader.getUniformLocation("screenWidth")
          screenHeightLoc = self.ssaoShader.getUniformLocation("screenHeight")
          self.ssaoShader.Uniform1f(screenWidthLoc,reqW)
          self.ssaoShader.Uniform1f(screenHeightLoc,reqH)
          self.ssaoShader.Uniform1i(depthMapLoc,3)
          self.ssaoShader.Uniform1i(rotateMapLoc,2)

          zNearLoc = self.ssaoShader.getUniformLocation("zNear")
          zFarLoc = self.ssaoShader.getUniformLocation("zFar")
          radiusLoc = self.ssaoShader.getUniformLocation("radius")
          attBiasLoc = self.ssaoShader.getUniformLocation("attBias")
          attScaleLoc = self.ssaoShader.getUniformLocation("attScale")
          self.ssaoShader.Uniform1f(zNearLoc,self.ambientOcclusionZNear*self.RADIUS/60.)
          self.ssaoShader.Uniform1f(zFarLoc,self.ambientOcclusionZFar*self.RADIUS/60.)
          self.ssaoShader.Uniform1f(radiusLoc,self.ambientOcclusionRadius)
          self.ssaoShader.Uniform1f(attBiasLoc,self.ambientOcclusionBias)
          self.ssaoShader.Uniform1f(attScaleLoc,self.ambientOcclusionScale)

          self.ssaoShader.turnOn()
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE3);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          texture = self.offScreenBufferDepth.texture()
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE2);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          if not hasattr(self,"rotateMap"):
            self.makeCurrent()
            im = QtGui.QImage(os.path.join(os.environ["CCP4MG"],"shaders","rotate.png"))
            self.rotateMap = self.bindTexture(im)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,self.rotateMap)
          opengl.glTexParameterf( opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_S, opengl.GL_REPEAT );
          opengl.glTexParameterf( opengl.GL_TEXTURE_2D, opengl.GL_TEXTURE_WRAP_T, opengl.GL_REPEAT );
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE0);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glDisable(opengl.GL_TEXTURE_2D)
          #self.resizeGLMain(w,h,ratio)
       
          opengl.glMatrixMode(opengl.GL_MODELVIEW);
          opengl.glTranslated(-self.rpos[0],-self.rpos[1],-self.rpos[2])
          quat = pygl_coord.Quat(self.quat)
          extraQuat = pygl_coord.Quat(self.extra_quat)
          quat.postMult(extraQuat)
          glrotmat = quat.getMatrix().to_dp()
          opengl.glMultMatrixd(glrotmat)
          opengl.delcdp(glrotmat)
          # FIXME, do not know why, but this helps us zoom in closer and still have AO work.
          opengl.glTranslatef(0,0,240)
          texture = self.offScreenBufferDepth.texture()
          
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.ssaoShader.turnOff()
          self.offScreenBufferSSAO.release()

          texture = self.offScreenBufferSSAO.texture()

          # Blur with FBO Ping-pong.
          # ping ...
          self.offScreenBufferBlur.bind()
          self.blurXShader.turnOn()
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.blurXShader.turnOff()
          self.offScreenBufferBlur.release()

          # ... pong.
          texture = self.offScreenBufferBlur.texture()

          self.offScreenBufferSSAO.bind()
          self.blurYShader.turnOn()
          #self.resizeGLMain(reqW,reqH,1./ratio)
          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,0)
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*ratio*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*ratio*glslMult,12*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*ratio*glslMult,12*glslMult,-200)
          opengl.glEnd()
          self.blurYShader.turnOff()
          self.offScreenBufferSSAO.release()

          texture = self.offScreenBufferSSAO.texture()
          # Do normal render with SSAO term set as texture...
          if shaders_on and hasattr(self,"shader") and self.shader:
            self.shader.turnOn()
            self.shader.Uniform1f(ssaoOnLoc,True)
            self.circleShader.Uniform1f(ssaoOnLocCircle,True)
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          SSAOMapLoc = self.shader.getUniformLocation("SSAOMap")
          screenWidthLoc = self.shader.getUniformLocation("screenWidth")
          screenHeightLoc = self.shader.getUniformLocation("screenHeight")
          self.shader.Uniform1i(SSAOMapLoc,3)
          self.shader.Uniform1f(screenWidthLoc,float(self.width()))
          self.shader.Uniform1f(screenHeightLoc,float(self.height()))
          SSAOMapLoc = self.circleShader.getUniformLocation("SSAOMap")
          screenWidthLoc = self.circleShader.getUniformLocation("screenWidth")
          screenHeightLoc = self.circleShader.getUniformLocation("screenHeight")
          self.circleShader.Uniform1i(SSAOMapLoc,3)
          self.circleShader.Uniform1f(screenWidthLoc,float(self.width()))
          self.circleShader.Uniform1f(screenHeightLoc,float(self.height()))
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE3);
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          #print "Call resizeGLMain ambient 3", w,h
          self.resizeGLMain(w,h,ratio)
          """
          self.use_pbuffer = use_pbuffer
          if self.use_pbuffer:
            self.makeCurrent()
          """
          self.shaders_on = shaders_on
          #self.paintGL2()

          #return

        if True and (self.doMirror  or self.doShadow):
          #print self.rpos
          if self.doShadow:
            self.offScreenBufferShadow.bind()
          elif self.doMirror:
            self.offScreenBuffer.bind()
          
          shaders_on = self.shaders_on
          self.shaders_on = False

          if self.doMirror:
            rotX = pygl_coord.Quat(1.0,0.0,0.0,1,-90.0)
            oldQuat = pygl_coord.Quat(self.quat)
            newQuat = pygl_coord.Quat(self.quat)
            newQuat.postMult(rotX)
            self.quat = newQuat

          if shaders_on and self.doShadow:
            self.shaders_on = False
            if  hasattr(self,"shader") and self.shader:
              self.shader.turnOff()

            rotX = pygl_coord.Quat(1.0,0.0,0.0,1,0.0)
            extraQuat = pygl_coord.Quat(self.extra_quat)
            if hasattr(self,"lights"):
              zprime = pygl_coord.Cartesian(self.lights[0].position)
              zprime.normalize()
              zorig = extraQuat.getInvMatrix()*pygl_coord.Cartesian(0,0,1)
              dp = pygl_coord.Cartesian.DotProduct(zprime,zorig)
              #print dp
              angle = math.acos(dp)*180/math.pi
              #print angle
              if (1.0-dp)>1e-6:
                axis = pygl_coord.Cartesian.CrossProduct(zprime,zorig)
                axis.normalize()
                #axis.Print(); print
                rotX = pygl_coord.Quat(axis.get_x(),axis.get_y(),axis.get_z(),1,angle)
            oldQuat = pygl_coord.Quat(self.quat)
            newQuat = pygl_coord.Quat(self.quat)
            newQuat.postMult(extraQuat)
            newQuat.postMult(rotX)
            #opengl.glColorMask(opengl.GL_FALSE, opengl.GL_FALSE, opengl.GL_FALSE, opengl.GL_FALSE)
            #opengl.glEnable(opengl.GL_CULL_FACE)
            opengl.glCullFace(opengl.GL_FRONT)
            self.inShadow = True

          if self.doShadow:
            reqW = self.offScreenBufferShadow.width()
            reqH = self.offScreenBufferShadow.height()
          elif self.doMirror:
            reqW = self.offScreenBuffer.width()
            reqH = self.offScreenBuffer.height()
          w,h = self.width(),self.height()
          if h == 0:
              h = 1
          if w == 0:
              w = 1
          ratio = 1.0*w / h
          #print "Call resizeGLMain shadow 1"
          self.resizeGLMain(reqW,reqH,1)
          if hasattr(self,"shadowShader"):
            self.shadowShader.turnOn()
          if self.doShadow:
            if hasattr(self,"shadowShader"):
              
              """
              self.setupModelview()
              glslMult =  60./float(self.RADIUS)
              cartz0 = pygl_coord.Cartesian(0,0,1)
              #div0 = (self.NEAR+self.FAR)/2.+glslMult*(self.slab_offset+self.slab_width/2.)
              cartz1 = pygl_coord.Cartesian(0,0,1)
              #div1 = -((self.NEAR+self.FAR)/2.+glslMult*(self.slab_offset-self.slab_width/2.))
              cartz0 = oldQuat.getMatrix() * (cartz0)
              #cartz1 = newQuat.getMatrix() * (cartz1)
              glslMult =  60./float(self.RADIUS)
              """
              # FIXME need to use transformed cartz, not test plane. and why shadowExtent? (or is it just randomly 30ish?)
              self.circleShadowShader.setClipPlanes(opengl.newfv4(0,0,-1,-self.shadowExtent*0.5-(self.slab_offset-self.slab_width/2.)-0.5),opengl.newfv4(0,0,-1,60));
              self.shadowShader.setClipPlanes(opengl.newfv4(0,0,-1,-self.shadowExtent*0.5-(self.slab_offset-self.slab_width/2.)-0.5),opengl.newfv4(0,0,-1,60));
              #self.shadowShader.setClipPlanes(opengl.newfv4(cartz0.get_x(),cartz0.get_y(),cartz0.get_z(),div0),opengl.newfv4(cartz1.get_x(),cartz1.get_y(),cartz1.get_z(),div1));
              # FIXME need to be set for shader lang version <=1.2
              #opengl.glClipPlane(opengl.GL_CLIP_PLANE0,opengl.newdv4(cartz0.get_x(),cartz0.get_y(),cartz0.get_z(),-(self.slab_offset-self.slab_width/2.)))
          if self.doShadow:
            self.quat = newQuat
          self.paintGL2()
          if hasattr(self,"shadowShader"):
            self.shadowShader.turnOff()
          if shaders_on and self.doShadow:
            opengl.setTextureMatrix()
          if self.doShadow:
            self.offScreenBufferShadow.release()
          elif self.doMirror:
            self.offScreenBuffer.release()
          if self.doMirror or (shaders_on and self.doShadow):
            self.quat = oldQuat
          self.inShadow = False
          #print "Call resizeGLMain shadow 2"
          self.resizeGLMain(w,h,ratio)
          opengl.glCullFace(opengl.GL_BACK)
          self.shaders_on = shaders_on
          opengl.glColorMask(opengl.GL_TRUE, opengl.GL_TRUE, opengl.GL_TRUE, opengl.GL_TRUE)

        if True and (shaders_on and self.doShadow):
          if os.environ.has_key("CCP4MG_DEBUG_SHADOWS"):
            self.offScreenBufferShadow.toImage().save("vsm.png")

          texture = self.offScreenBufferShadow.texture()
          #self.offScreenBuffer.toImage().save("vsm.png")
          opengl.SetMyTextureUnit(opengl.GL_TEXTURE2);
          # This should not be necessary here, but seems to be. Calling once at init ought to be
          # enough, but that seems not to work. Getting close....
          #if self.shader and hasattr(self.shader,"setSamplerUniforms"): self.shader.setSamplerUniforms()
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          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.shaders_on and self.shader:
            self.shader.setShadowState(True)
            self.circleShader.setShadowState(True)
        else:
          if self.shaders_on and self.shader:
            self.shader.setShadowState(False)
            self.circleShader.setShadowState(False)

        if True and (self.doShadow and self.shaders_on and hasattr(self,"shader") and self.shader):
          self.shader.turnOn()
          xPixelOffsetLoc = self.shader.getUniformLocation("xPixelOffset")
          yPixelOffsetLoc = self.shader.getUniformLocation("yPixelOffset")
          ShadowMapLoc = self.shader.getUniformLocation("ShadowMap")
          self.shader.Uniform1f(xPixelOffsetLoc,1.0/self.offScreenBufferShadow.width())
          self.shader.Uniform1f(yPixelOffsetLoc,1.0/self.offScreenBufferShadow.height())
          self.shader.Uniform1i(ShadowMapLoc,2)
          mw = MAINWINDOW()
          if mw and hasattr(mw,"roll_timer") and mw.roll_timer.isActive() :
            shadowQuality = self.shader.getUniformLocation("shadowQuality")
            self.shader.Uniform1i(shadowQuality,0)

        if True and (self.doShadow and self.shaders_on and hasattr(self,"circleShader") and self.circleShader):
          self.circleShader.turnOn()
          xPixelOffsetLoc = self.circleShader.getUniformLocation("xPixelOffset")
          yPixelOffsetLoc = self.circleShader.getUniformLocation("yPixelOffset")
          ShadowMapLoc = self.circleShader.getUniformLocation("ShadowMap")
          self.circleShader.Uniform1f(xPixelOffsetLoc,1.0/self.offScreenBufferShadow.width())
          self.circleShader.Uniform1f(yPixelOffsetLoc,1.0/self.offScreenBufferShadow.height())
          self.circleShader.Uniform1i(ShadowMapLoc,2)
          mw = MAINWINDOW()
          if mw and hasattr(mw,"roll_timer") and mw.roll_timer.isActive() :
            shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
            self.circleShader.Uniform1i(shadowQuality,0)

        self.use_pbuffer = use_pbuffer
        self.paintGL2()

        if not self.use_pbuffer and self.doMirror:
          opengl.glMatrixMode(opengl.GL_MODELVIEW);
          opengl.glTranslated(-self.rpos[0],-self.rpos[1],-self.rpos[2])
          quat = pygl_coord.Quat(self.quat)
          glrotmat = quat.getMatrix().to_dp()
          opengl.glMultMatrixd(glrotmat)
          opengl.delcdp(glrotmat)
          opengl.glTranslatef(0,0,0)
          if self.offScreenBufferTexture and QtOpenGL.QGLFramebufferObject.hasOpenGLFramebufferBlit():
            rect = QtCore.QRect(0,0,self.offScreenBuffer.width(),self.offScreenBuffer.height())
            QtOpenGL.QGLFramebufferObject.blitFramebuffer(self.offScreenBufferTexture, rect, self.offScreenBuffer, rect);
            texture = self.offScreenBufferTexture.texture()
          else:
            texture = self.offScreenBuffer.texture()
          
          opengl.glEnable(opengl.GL_TEXTURE_2D)
          opengl.glBindTexture(opengl.GL_TEXTURE_2D,texture)
          opengl.glDepthFunc(opengl.GL_LESS);
          opengl.glEnable(opengl.GL_DEPTH_TEST)
          glslMult =  float(self.RADIUS)/60.
          opengl.glNormal3f(1,1,1)
          opengl.glColor4f(1,1,1,1)
          opengl.glBegin(opengl.GL_QUADS)
          opengl.glTexCoord2f(0,1)
          opengl.glVertex3f(-12*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,1)
          opengl.glVertex3f(12*glslMult,-12*glslMult,-200)
          opengl.glTexCoord2f(1,0)
          opengl.glVertex3f(12*glslMult,-2*glslMult,-200)
          opengl.glTexCoord2f(0,0)
          opengl.glVertex3f(-12*glslMult,-2*glslMult,-200)
          opengl.glEnd()

    def setAmbientOcclusionState(self,state=0):
        if type(state) == tuple:
           dum,state = state
        self.doAmbient = state
        w,h = self.width(),self.height()
        self.resizeGL(w,h)
        self.emit(QtCore.SIGNAL("AmbientOcclusionStateChanged"), (self,state))
        
    def setOutlineState(self,state=0):
        self.doOutline = state
        w,h = self.width(),self.height()
        self.resizeGL(w,h)
        
    def setShadowState(self,state=0,quality=2):
        if type(state) == tuple:
           dum,state,quality = state
        self.doShadow = state
        if self.shaders_on and self.shader:
          self.shader.setShadowState(bool(state))
          shadowQuality = self.shader.getUniformLocation("shadowQuality")
          self.shader.Uniform1i(shadowQuality,quality)
        if self.shaders_on and self.circleShader:
          self.circleShader.setShadowState(bool(state))
          shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
          self.circleShader.Uniform1i(shadowQuality,quality)
        w,h = self.width(),self.height()
        self.resizeGL(w,h)
        self.emit(QtCore.SIGNAL("ShadowStateChanged"), (self,state,quality))
        
    def paintGL2(self):
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	"""
        err = opengl.glGetError()
        if err:
          print "Error at start of paint GL", err; sys.stdout.flush()
	"""

	smooth_line = 1
	try:
		smooth_line = PM("render_quality").getparams()["smooth_line"]
	except:
		pass

	if hasattr(self,"shader") and hasattr(self.shader,"turnOff") and callable(self.shader.turnOff): self.shader.turnOff()
        self.setupZalmanStencil(self.width(),self.height())
        opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT)

        if self.doStereo and (self.stereoAvailable or self.doZalmanStereo):
          import MGApplication
	  stereo_mode = MGApplication.GetMainWindow().stereo_mode
          if stereo_mode == 'ROTATION':
            self.left_quat = pygl_coord.Quat(0.0,1.0,0.0,1,0.5*MGApplication.GetMainWindow().stereo_rotation_angle)
            self.right_quat = pygl_coord.Quat(0.0,1.0,0.0,1,-0.5*MGApplication.GetMainWindow().stereo_rotation_angle)
            self.left_furtherMatrix = None
            self.right_furtherMatrix = None
          else:
            self.left_quat = None
            self.right_quat = None
            if self.stereo_shear_separation != MGApplication.GetMainWindow().stereo_shear_separation:
              self.stereo_shear_separation = MGApplication.GetMainWindow().stereo_shear_separation
              shear_plus  = pygl_coord.matrix(4,4,[1,0,0,0,
                                             0,1,0,0,
                                             self.stereo_shear_separation,0,1,0,
                                             0,0,0,1])
              shear_minus = pygl_coord.matrix(4,4,[1,0,0,0,
                                             0,1,0,0,
                                             -self.stereo_shear_separation,0,1,0,
                                             0,0,0,1])
              self.right_furtherMatrix = shear_plus.to_dp()
              self.left_furtherMatrix = shear_minus.to_dp()

          if self.doZalmanStereo:
          	opengl.glEnable(opengl.GL_STENCIL_TEST);
          	opengl.glStencilFunc(opengl.GL_EQUAL, 1, 1);
          	opengl.glStencilOp(opengl.GL_KEEP, opengl.GL_KEEP, opengl.GL_KEEP);

          if not self.doZalmanStereo:
		opengl.glDrawBuffer(opengl.GL_BACK_LEFT)

          opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )
          self.setupModelview(furtherQuat=self.left_quat,furtherMatrix=self.left_furtherMatrix)
          self.paintGLMain(smooth_line)

          if self.doZalmanStereo:
          	opengl.glStencilFunc(opengl.GL_EQUAL, 0, 1);
          	opengl.glStencilOp(opengl.GL_KEEP, opengl.GL_KEEP, opengl.GL_KEEP);

          if not self.doZalmanStereo:
		opengl.glDrawBuffer(opengl.GL_BACK_RIGHT)
		opengl.glClear(opengl.GL_COLOR_BUFFER_BIT | opengl.GL_DEPTH_BUFFER_BIT )

          self.setupModelview(furtherQuat=self.right_quat,furtherMatrix=self.right_furtherMatrix)
          self.paintGLMain(smooth_line)

          opengl.glDisable(opengl.GL_STENCIL_TEST);
        else:
          self.furtherMatrix=None
          self.furtherQuat=None
          self.setupModelview()
          self.paintGLMain(smooth_line)

	"""
        err = opengl.glGetError()
        if err:
          print "Error at end of paint GL", err; sys.stdout.flush()
	"""

    def paintGLMain(self,smooth_line=1):
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.paintGLMain(self,smooth_line)
        self.showFPS()

    def showFPS(self):
        message = ""
	if self.show_fps:
          self.nframes = self.nframes + 1
          t = time.time()
          if t - self.previous_time > 1:
            fps  = (self.nframes-self.previous_frames)/( time.time()-self.previous_time)
            fps_text = ( "%4.0f" ) % fps
            self.previous_frames = self.nframes
            self.previous_time = t
            message = message + "framerate:"+fps_text+" "
            self.current_fps_text = fps_text
          else:
            message = message + "framerate:"+self.current_fps_text+" "

        self.showMessage(message)

    def setupZalmanStencil(self, w, h):

	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        if self.doStereo and self.doZalmanStereo:
		opengl.glPushAttrib(opengl.GL_ENABLE_BIT)
		opengl.glMatrixMode(opengl.GL_PROJECTION);
		opengl.glPushMatrix();
		opengl.glLoadIdentity();
		opengl.glOrtho(0,w,0,h,-10.0,10.0);
		opengl.glMatrixMode(opengl.GL_MODELVIEW);
		opengl.glPushMatrix();
		opengl.glLoadIdentity();
		opengl.glTranslatef(0.33,0.33,0.0); 
		opengl.glDisable(opengl.GL_STENCIL_TEST);

		opengl.glDisable(opengl.GL_ALPHA_TEST);
		opengl.glDisable(opengl.GL_LIGHTING);
		opengl.glDisable(opengl.GL_FOG);
		opengl.glDisable(opengl.GL_NORMALIZE);
		opengl.glDisable(opengl.GL_DEPTH_TEST);
		opengl.glDisable(opengl.GL_COLOR_MATERIAL);
		opengl.glDisable(opengl.GL_LINE_SMOOTH);
		opengl.glDisable(opengl.GL_DITHER);
		opengl.glDisable(opengl.GL_BLEND);
		opengl.glShadeModel(opengl.GL_SMOOTH);
		opengl.glDisable(0x809D); #/* GL_MULTISAMPLE_ARB */

		opengl.glClearStencil(0);
		opengl.glColorMask(False,False,False,False);
		opengl.glDepthMask(False);
		opengl.glClear(opengl.GL_STENCIL_BUFFER_BIT);

		opengl.glEnable(opengl.GL_STENCIL_TEST);
		opengl.glStencilFunc(opengl.GL_ALWAYS, 1, 1);
		opengl.glStencilOp(opengl.GL_KEEP, opengl.GL_KEEP, opengl.GL_REPLACE);

		opengl.glLineWidth(1.0);
		opengl.glBegin(opengl.GL_LINES);
		for y in range(0,h,2):
			opengl.glVertex2i(0,y);
			opengl.glVertex2i(w,y);
		opengl.glEnd()

		opengl.glColorMask(True,True,True,True);
		opengl.glDepthMask(True);

		opengl.glMatrixMode(opengl.GL_MODELVIEW);
		opengl.glPopMatrix();
		opengl.glMatrixMode(opengl.GL_PROJECTION);
		opengl.glPopMatrix();
		opengl.glPopAttrib()

    def resizeGL(self, w, h):
        if not QtOpenGL.QGLFramebufferObject.hasOpenGLFramebufferObjects ():
          self.doMirror = False
          self.doShadow = False
        if QtOpenGL.QGLFramebufferObject.hasOpenGLFramebufferBlit() and self.doMirror:
          self.offScreenBuffer = self.offScreenBufferMirror
          self.offScreenBufferTexture = self.offScreenBufferTextureMirror
        elif self.doAmbient or self.doOutline:
          self.offScreenBuffer = self.offScreenBufferDepth
          self.offScreenBufferTexture = None
          #self.doShadow = False
        elif self.doShadow:
          self.offScreenBuffer = self.offScreenBufferShadow
          self.offScreenBufferTexture = None
        else:
          self.offScreenBuffer = None #self.offScreenBufferOther

	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        if h == 0:
            h = 1
        if w == 0:
            w = 1
        ratio = 1.0*w / h

	if not  self.use_pbuffer:
          self.setupZalmanStencil(w,h)

        if not self.use_pbuffer and (self.doMirror or self.doShadow):
          self.offScreenBuffer.bind()

        self.resizeGLMain(w,h,ratio)

        if not self.use_pbuffer and (self.doMirror or self.doShadow):
          self.offScreenBuffer.release()
          self.resizeGLMain(w,h,ratio)

    def resizeGLMain(self, w, h,ratio):
        opengl.glMatrixMode(opengl.GL_PROJECTION);
        opengl.glLoadIdentity();
	if self.use_pbuffer:
          print "use_pbuffer"; sys.stdout.flush()
          if self.inShadow:
            print "resizeGLMain shadow"
            opengl.glOrtho(-self.shadowExtent/2.,self.shadowExtent/2.,-self.shadowExtent/2.,self.shadowExtent/2.,0.0001,self.shadowExtent);
          elif self.inAmbient:
            print "resizeGLMain ambient"
            opengl.glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,470,530);
          else:
            print "resizeGLMain normal"
            ratio = 1.0*self.pbuffer.width()/self.pbuffer.height()
            opengl.glViewport(0, 0, self.pbuffer.width(), self.pbuffer.height());
            pbuffer_scale = float(self.pbuffer.height()-2*self.fbo_offset)/self.req_pbuffer_size.height()
            opengl.glOrtho(-self.viewsize*ratio*pbuffer_scale,self.viewsize*ratio*pbuffer_scale,-self.viewsize*pbuffer_scale,self.viewsize*pbuffer_scale,self.NEAR,self.FAR);
        else:
          opengl.glViewport(0, 0, w, h);
          if self.inShadow:
            opengl.glOrtho(-self.shadowExtent/2.,self.shadowExtent/2.,-self.shadowExtent/2.,self.shadowExtent/2.,0.0001,self.shadowExtent);
          elif self.inAmbient:
            # FIXME  Numbers seem reasonable until we get in close.
            opengl.glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,0.0001,self.FAR);
            # FIXME  The following is much better for outline depth edge detection
            #opengl.glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,500-.5*self.shadowExtent,500+.5*self.shadowExtent);
          else:
            opengl.glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,self.NEAR,self.FAR);
        opengl.glMatrixMode(opengl.GL_MODELVIEW)
        cprim.BillBoardText().SetMatrices()
        self.emit(QtCore.SIGNAL("SizeChanged"), (self.size()))

    def wheelEvent(self, event):
	if sys.platform == "darwin":
		factor = 1. + (event.delta()/5000.)
	else:
		factor = 1. + (event.delta()/500.)
	self.RADIUS = self.RADIUS * factor 
	if self.RADIUS < 1: self.RADIUS = 1

        self.emit(QtCore.SIGNAL("ZoomChanged"), (self))
        self.updateGL()
	self.emit(QtCore.SIGNAL("ViewChanged"),(self))

    def lrudqaopnmkey_handler(self):
        dx = 0
        dy = 0
        dz = 0
        if self.qkey_timer.isActive():
          dx -= 1
        if self.akey_timer.isActive():
          dx += 1
        if self.okey_timer.isActive():
          dy -= 1
        if self.pkey_timer.isActive():
          dy += 1
        if self.mkey_timer.isActive():
          dz -= 1
        if self.nkey_timer.isActive():
          dz += 1
        if not self.keys_down[QtCore.Qt.Key_Shift]:
          dx *= 0.1
          dy *= 0.1
          dz *= 0.1
        #self.setRotation(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)
        xshift = 0
        yshift = 0
        zshift = 0
        if self.rightkey_timer.isActive():
          xshift += 5
        if self.leftkey_timer.isActive():
          xshift -= 5
        if self.upkey_timer.isActive():
          yshift -= 5
        if self.downkey_timer.isActive():
          yshift += 5

        if not self.keys_down[QtCore.Qt.Key_Shift]:
          xshift *= 0.1
          yshift *= 0.1

        self.rpos = self.movexyz(self.rpos,[xshift,yshift,0])
        self.SetupSymmetry()
        self.updateGL()
        self.emit(QtCore.SIGNAL("QuatChanged"),(self))
        self.emit(QtCore.SIGNAL("PositionChanged"),(self))

    def pluskey_handler(self):
        self.handleZoom(None,0,.4)
        self.updateGL()
    def minuskey_handler(self):
        self.handleZoom(None,0,-.4)
        self.updateGL()

    """
    def toggleRecording(self):
        if self.recording:
          self.record_timer.stop()
          ffmpeg_wrapper.CloseMovie()
          self.recording = 0
          self.parent().record_action.setText(self.tr('Start &recording'))
        else:
	  win_w = self.size().width()
	  win_h = self.size().height()
          ffmpeg_wrapper.OpenMovie(win_w,win_h,"silly.mpg")
          self.record_timer.start(1)
          self.recording = 1
          self.parent().record_action.setText(self.tr('Stop &recording'))

    def record_handler(self):
        iinfo = self.screenshot()
        iinfo.invert()
        yuv = iinfo.getyuv()
        ffmpeg_wrapper.AddYUVMovieFrame(yuv)
        self.updateGL()
        del iinfo
    """

    def roll_handler(self):
        rotQ = pygl_coord.Quat(self.roll_quat[0],self.roll_quat[1],self.roll_quat[2],self.roll_quat[3])
        self.quat.postMult(rotQ)
        self.updateGL()

    def keyPressEvent(self, event):
        if event.isAutoRepeat(): 
          return
        if self.shaders_on and self.shader and self.doShadow:
          shadowQuality = self.shader.getUniformLocation("shadowQuality")
          self.shader.Uniform1i(shadowQuality,0)
          self.updateGL()
        if self.shaders_on and self.circleShader and self.doShadow:
          shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
          self.circleShader.Uniform1i(shadowQuality,0)
          self.updateGL()
	self.keys_down[event.key()]=1
	if event.key() == QtCore.Qt.Key_Escape:
                children = MAINWINDOW().findChildren(QtGui.QAction,"fullscreen")
                for child in children:
                  child.setChecked(False)
                  MAINWINDOW().toggleFullscreen()
                  break
	if event.key() == QtCore.Qt.Key_S:
           self.setShaderState(1-self.getShaderState())
	   self.makeCurrent()
	   self.rebuildAllDisplayObjects()
	   self.updateGL()
	if event.key() == QtCore.Qt.Key_Q:
           self.qkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_A:
           self.akey_timer.start(5)
	if event.key() == QtCore.Qt.Key_O:
           self.okey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Minus:
           self.minuskey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Plus:
           self.pluskey_timer.start(5)
	if event.key() == QtCore.Qt.Key_P:
           self.pkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_N:
           self.nkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_M:
           self.mkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Left:
           self.leftkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Right:
           self.rightkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Up:
           self.upkey_timer.start(5)
	if event.key() == QtCore.Qt.Key_Down:
           self.downkey_timer.start(5)

    def keyReleaseEvent(self, event):
        if event.isAutoRepeat(): 
          return
        keysActive = False
        if (self.qkey_timer.isActive()^ event.key() == QtCore.Qt.Key_Q)\
        or (self.akey_timer.isActive()^ event.key() == QtCore.Qt.Key_A)\
        or (self.okey_timer.isActive()^ event.key() == QtCore.Qt.Key_O)\
        or (self.pkey_timer.isActive()^ event.key() == QtCore.Qt.Key_P)\
        or (self.nkey_timer.isActive()^ event.key() == QtCore.Qt.Key_N)\
        or (self.mkey_timer.isActive()^ event.key() == QtCore.Qt.Key_M)\
        or (self.rightkey_timer.isActive()^ event.key() == QtCore.Qt.Key_Right)\
        or (self.leftkey_timer.isActive()^ event.key() == QtCore.Qt.Key_Left)\
        or (self.upkey_timer.isActive()^ event.key() == QtCore.Qt.Key_Up)\
        or (self.downkey_timer.isActive()^ event.key() == QtCore.Qt.Key_Down):
           keysActive = True
        if not keysActive and self.shaders_on and self.circleShader and self.doShadow:
          shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
          self.circleShader.Uniform1i(shadowQuality,2)
        if not keysActive and self.shaders_on and self.shader and self.doShadow:
          shadowQuality = self.shader.getUniformLocation("shadowQuality")
          self.shader.Uniform1i(shadowQuality,2)
          self.updateGL()
	self.keys_down[event.key()]=0
	if event.key() == QtCore.Qt.Key_Q:
           self.qkey_timer.stop()
	if event.key() == QtCore.Qt.Key_A:
           self.akey_timer.stop()
	if event.key() == QtCore.Qt.Key_O:
           self.okey_timer.stop()
	if event.key() == QtCore.Qt.Key_Plus:
           self.pluskey_timer.stop()
	if event.key() == QtCore.Qt.Key_Minus:
           self.minuskey_timer.stop()
	if event.key() == QtCore.Qt.Key_P:
           self.pkey_timer.stop()
	if event.key() == QtCore.Qt.Key_N:
           self.nkey_timer.stop()
	if event.key() == QtCore.Qt.Key_M:
           self.mkey_timer.stop()
	if event.key() == QtCore.Qt.Key_Left:
           self.leftkey_timer.stop()
	if event.key() == QtCore.Qt.Key_Right:
           self.rightkey_timer.stop()
	if event.key() == QtCore.Qt.Key_Up:
           self.upkey_timer.stop()
	if event.key() == QtCore.Qt.Key_Down:
           self.downkey_timer.stop()
	if event.key() != QtCore.Qt.Key_Shift and event.key()!= QtCore.Qt.Key_Control and event.key()!= QtCore.Qt.Key_Alt and event.key()!= QtCore.Qt.Key_Meta:
	  self.emit(QtCore.SIGNAL("ViewChanged"),(self))

    def DrawInThread(self):
        self.go.draw()

    def mouseDoubleClickEvent(self, event):
	self.lastEventType = event.type()
        self.setupModelview(self.furtherMatrix,self.furtherQuat)
        pickevent = MGPickEvent.MGPickEvent(self,event)
        self.doubleClickHandler(pickevent)
        
    def aboutToHideHandler(self):
        self.showing_context_menu = False

    def aboutToShowHandler(self):
        if self.showing_context_menu == False:
          self.showing_context_menu = True
        else:
	  pass
          #print 'aboutToShowHandler showing_context_menu is true'
          #return
        self.setupModelview(self.furtherMatrix,self.furtherQuat)
        if self.contextMenuPickEvent:
          self.contextMenuHandler(self.contextMenuPickEvent)
          del self.contextMenuPickEvent
          self.contextMenuPickEvent = None
        
    def getLeftClickHandler(self):
        return self.leftClickHandler

    def setLeftClickHandler(self,handler):
        self.leftClickHandler = handler

    def getDoubleClickHandler(self):
        return self.doubleClickHandler

    def setDoubleClickHandler(self,handler):
        self.doubleClickHandler = handler

    def setContextMenuHandler(self,handler):
        self.contextMenuHandler = handler

    def mousePressEvent(self, event):
	self.lastEventType = event.type()
        #self.emit(QtCore.SIGNAL("mousepress"),(event,self))
        self.mousePressEvent_main(event,1)

    def mousePressEvent_main(self, event,real_event=0):
        #print "mousePressEvent_main",event.type()
        # This method was previously handling context menu event
        self.lastPos = QtCore.QPoint(event.pos())
        self.mouseDownPos = QtCore.QPoint(event.pos())

    def contextMenuEvent(self,event):
        self.setupModelview(self.furtherMatrix,self.furtherQuat)
        if  hasattr(self,"context_menu"):
           self.lastPos = QtCore.QPoint(event.pos())
           self.contextMenuPickEvent = MGPickEvent.MGPickEvent(self,event)
           self.context_menu.exec_(self.mapToGlobal(self.lastPos))
           del self.contextMenuPickEvent
           self.contextMenuPickEvent = None
           event.accept()
        else:
           event.ignore()
           
    def mouseReleaseEvent(self, event):
        if self.shaders_on and self.shader and self.doShadow:
          shadowQuality = self.shader.getUniformLocation("shadowQuality")
          self.shader.Uniform1i(shadowQuality,2)
          self.updateGL()
        if self.shaders_on and self.circleShader and self.doShadow:
          shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
          self.circleShader.Uniform1i(shadowQuality,2)
          self.updateGL()

        self.mouseReleaseEvent_main(event,1)

    def mouseReleaseEvent_main(self, event,real_event=0):
	if self.lastEventType==QtCore.QEvent.MouseButtonDblClick: return
        self.setupModelview(self.furtherMatrix,self.furtherQuat)
        moved = ''
        curPos =  QtCore.QPoint(event.pos())
        #print "self.lastPos",self.mouseDownPos.x(),self.mouseDownPos.y(),curPos.x(),curPos.y()
        left = event.buttons() & QtCore.Qt.LeftButton and not event.modifiers()&QtCore.Qt.AltModifier and not event.modifiers()&QtCore.Qt.ControlModifier and not event.modifiers()&QtCore.Qt.MetaModifier
        # Weird -- 'if left and real_event' does not work
        if left!=None and real_event:
            if abs(self.mouseDownPos.x()-curPos.x())>2 or \
               abs(self.mouseDownPos.y()-curPos.y())>2: 
	      self.emit(QtCore.SIGNAL("ViewChanged"),(self))
	    else:
              pickEvent = MGPickEvent.MGPickEvent(self,event)
              self.leftClickHandler(pickEvent)
              del pickEvent

    def setMouseBindings(self,bindings={}):

      # These are the 'local' handlers
      handlers = {
        'rotate-xy' : self.handleRotateXY,
        'rotate-z' : self.handleRotateZ,
        'translate-xy' : self.handleTranslateXY,
        'translate-z' : self.handleTranslateZ ,
        'object-rotate-xy' : self.handleRotateObjectXY,
        'object-rotate-z' :  self.handleRotateObjectZ,
        'object-translate-xy' : self.handleTranslateObjectXY,
        'object-translate-z' : self.handleTranslateObjectZ,
        'zoom' : self.handleZoom,
        'clip-width' : self.handleClipping }
      button_map = {
          'left' :  QtCore.Qt.LeftButton,
          'middle' :  QtCore.Qt.MidButton,
          'right' : QtCore.Qt.RightButton }
      key_map = { ' ': 'no_key','a': QtCore.Qt.Key_A,'b': QtCore.Qt.Key_B,'c': QtCore.Qt.Key_C,'d': QtCore.Qt.Key_D,'e': QtCore.Qt.Key_E,'f': QtCore.Qt.Key_F,'g': QtCore.Qt.Key_G,'h': QtCore.Qt.Key_H,'i': QtCore.Qt.Key_I,'j': QtCore.Qt.Key_J,'k': QtCore.Qt.Key_K,'l': QtCore.Qt.Key_L,'m': QtCore.Qt.Key_M,'n': QtCore.Qt.Key_N,'o': QtCore.Qt.Key_O,'p': QtCore.Qt.Key_P,'q': QtCore.Qt.Key_Q,'r': QtCore.Qt.Key_R,'s': QtCore.Qt.Key_S,'t': QtCore.Qt.Key_T,'u': QtCore.Qt.Key_U,'v': QtCore.Qt.Key_V,'w': QtCore.Qt.Key_W,'x': QtCore.Qt.Key_X,'y': QtCore.Qt.Key_Y,'z': QtCore.Qt.Key_Z }
      
      
      self.mouseMoveHandlers = { QtCore.Qt.LeftButton : {},
                                 QtCore.Qt.MidButton : {},
                                 QtCore.Qt.RightButton : {} }
      
      for handler,defn in bindings.items():
        #print "handler,defn",handler,defn
        h1 = self.mouseMoveHandlers[button_map[defn['mouse_button']]]

        
        if defn.get('shift',0):
           if  defn.get('alt',0):
             if  defn.get('ctrl',0):
               mod = QtCore.Qt.ShiftModifier | QtCore.Qt.AltModifier | QtCore.Qt.ControlModifier
             else:
               mod = QtCore.Qt.ShiftModifier | QtCore.Qt.AltModifier
           else:
             mod = QtCore.Qt.ShiftModifier
        elif defn.get('alt',0):
            if  defn.get('ctrl',0):
              mod = QtCore.Qt.AltModifier | QtCore.Qt.ControlModifier
            else:
              mod = QtCore.Qt.AltModifier
        elif defn.get('ctrl',0):
            mod = QtCore.Qt.ControlModifier
        else:
           mod = QtCore.Qt.NoModifier
        

        if not h1.has_key(mod): h1[mod] = {}
        h2 =  h1[mod]

        key = key_map.get(defn['key'],'')
        if key:
          if handlers.has_key(handler):
             h2[key] = handlers[handler]
          else:
             h2[key] = handler

        #print "setMouseBindings",mod,key,handler
      #print "self.mouseMoveHandlers",self.mouseMoveHandlers

    def removeMouseBindings(self):
      self.mouseMoveHandlers = {}

    def setDefaultMouseBindings(self):
      # initialise mouse bindings
      import MouseBindings
      self.setMouseBindings ( MouseBindings.DEFAULT )

    # ------------------------------------------------------------
    # The following methods will called by object/application
    # that is being transformed following the "TransformObject" signal
    #
    def transformDelta(self):
      return self.transform_delta

    def transformDeltaMode(self):
      return self.transform_delta_mode

    def screenTransform(self):
      return ( float(self.transform_delta[0])/self.size().width(),
               float(self.transform_delta[1])/-self.size().height(),
               float(self.transform_delta[2])/self.size().height() )

    def worldTranslate(self):
      cv1 = self.getxyz(0,0)
      cv2 = self.getxyz(float(self.transform_delta[0]),float(self.transform_delta[1]))
      diffxyz = cv2[0]-cv1[0]
      return (diffxyz.get_x(),diffxyz.get_y(),diffxyz.get_z())

    def worldRotate(self):
      dx = self.transform_delta[0]
      dy = self.transform_delta[1]
      dz = self.transform_delta[2]
      #print 'worldRotate',dx,dy,dz
      #cart = self.extra_quat.getMatrix()*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)
      matx = rotQ.getInvMatrix()
      return matx

    def handleTesting(self,event,dx,dy):
        print "in handleTesting"
        
    def handleClipping(self,event,dx,dy):
        #print 'handleClipping',dx,dy
        self.slab_width = self.slab_width + float(dy)*0.1
        self.emit(QtCore.SIGNAL("SlabChanged"), (self))
        self.updateGL()

    def handleTranslateObjectXY(self,event,dx,dy):
        self.transform_delta_mode = 'translate'
        self.transform_delta = (dx,dy,0)
        self.emit(QtCore.SIGNAL("TransformObject"), (self))
        
    def handleTranslateObjectZ(self,event,dx,dy):
        self.transform_delta_mode = 'translate'
        self.transform_delta = (0,0,dy)
        self.emit(QtCore.SIGNAL("TransformObject"), (self))
    
    def handleRotateObjectXY(self,event,dx,dy):
      self.transform_delta_mode = 'rotate'
      self.transform_delta = (dx,dy,0)
      self.emit(QtCore.SIGNAL("TransformObject"), (self))
  
    def handleRotateObjectZ(self,event,dx,dy):
      self.transform_delta_mode = 'rotate'
      self.transform_delta = (0,0,dy)
      self.emit(QtCore.SIGNAL("TransformObject"), (self))
  
    def handleRotateXY(self,event,dx,dy):
         self.setRotationNoUpdate(dy,dx,0)

        
    def handleRotateZ(self,event,dx,dy):
      win_w = self.size().width()
      win_h = self.size().height()
      x=event.x()
      y=event.y()
      if x<win_w/3:
        self.setRotationNoUpdate(0,0,dy)
      elif x>win_w*2/3:
        self.setRotationNoUpdate(0,0,-dy)
      if y<win_h/3:
        self.setRotationNoUpdate(0,0,-dx)
      elif y>win_h*2/3:
        self.setRotationNoUpdate(0,0,dx)

    def handleZoom(self,event,dx,dy):
      factor = 1. - dy/50.
      self.RADIUS = self.RADIUS * factor
      if self.RADIUS < 1: self.RADIUS = 1
      self.emit(QtCore.SIGNAL("ZoomChanged"), (self))

    def handleTranslateZ(self,event,dx,dy):
      self.rpos = self.movexyz(self.rpos,[0,0,dy])
      self.emit(QtCore.SIGNAL("PositionChanged"),(self))
      self.SetupSymmetry()
              
    def handleTranslateXY(self,event,dx,dy):
      dx = dx * 10.0 * float(self.viewsize)/float(self.size().height()) * float(self.RADIUS)/60.0
      dy = dy * 10.0 * float(self.viewsize)/float(self.size().height()) * float(self.RADIUS)/60.0
      self.rpos = self.movexyz(self.rpos,[dx,dy,0])
      self.emit(QtCore.SIGNAL("PositionChanged"),(self))
      self.SetupSymmetry()

    def mouseMoveEvent(self, event):

      # Make alt-button on trackpad behave like middle button on Mac.
      # Sensible, or do we actually want alt in preferences?
      if sys.platform == 'darwin':
        if event.button()==0:
          if event.modifiers()&QtCore.Qt.AltModifier==QtCore.Qt.AltModifier:
            mods = event.modifiers()
	    mods ^= QtCore.Qt.AltModifier
            newEvent = QtGui.QMouseEvent(QtCore.QEvent.MouseMove,event.pos(),QtCore.Qt.MidButton,QtCore.Qt.MidButton,mods)
	    event = newEvent

      h1 = self.mouseMoveHandlers.get(int(event.buttons()),{})
      #print "h1",int(event.buttons()),h1
      if not h1: return

      h2 = h1.get(int(event.modifiers()),{})
      #print "h2",int(event.modifiers()),h2
      if not h2: return

      handler = ''
      if isinstance(h2,types.DictType):
        for key,h3 in h2.items():
          if key != 'no_key' and self.keys_down[key]:
            handler = h3
            break
        # The following line means that we ignore any
        # key-down that we don't have a binding for and just
        # apply the 'no_key' binding
        if not handler: handler = h2.get('no_key','')
      else:
        handler = h2
      #print "mouseMoveEvent handler",handler
      if not handler: return
      
      diff = QtCore.QPoint(event.pos()) - self.lastPos
      #if diff.manhattanLength()<4: return
      dx = event.x() - self.lastPos.x()
      dy = event.y() - self.lastPos.y()
      if (dx==0 and abs(dy)<2) or (abs(dy)<2 and dx==0): return

      handler(event,dx,dy)

      if self.shaders_on and self.shader and self.doShadow:
        shadowQuality = self.shader.getUniformLocation("shadowQuality")
        self.shader.Uniform1i(shadowQuality,0)
      if self.shaders_on and self.circleShader and self.doShadow:
        shadowQuality = self.circleShader.getUniformLocation("shadowQuality")
        self.circleShader.Uniform1i(shadowQuality,0)

      self.updateGL()
      self.lastPos = QtCore.QPoint(event.pos())
        

    def movexyz(self,r,dr):
      dx,dy,dz = self.getdxdydz(dr[0], dr[1], dr[2])
      dx = dx/5.0;
      dy = dy/5.0;
      dz = dz/5.0;
      return r[0]+dx, r[1]+dy, r[2]+dz

    def getxyz(self,x,y): 
        """
        Work out world x,y,z at near and far clipping planes.
        """
	#if sys.platform == 'win32':
          #return CartesianVectorPtr(getxyzc(x,y))
	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()

	if self.use_pbuffer:
           self.BindOffScreenBuffer()
        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 getdxdydz(self,dx,dy,dz):
        """
        Calculate movement in real coordinates
        corresponding to one in eye coordinates.
        """

        xaxis,yaxis,zaxis = self.xaxis,self.yaxis,self.zaxis
        dr = []
        dr.append(dx*xaxis.get_x())
        dr.append(dx*xaxis.get_y())
        dr.append(dx*xaxis.get_z())

        du = []
        du.append(dy*yaxis.get_x())
        du.append(dy*yaxis.get_y())
        du.append(dy*yaxis.get_z())

        df = []
        df.append(dz*zaxis.get_x())
        df.append(dz*zaxis.get_y())
        df.append(dz*zaxis.get_z())

        dx = dr[0] + du[0] + df[0]
        dy = dr[1] + du[1] + df[1]
        dz = dr[2] + du[2] + df[2]

        return [dx,dy,dz]

    def SetGO(self, go_in=None,redraw=0):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.SetGO(self,go_in,redraw)

    def buildlist(self,go,listid):
        self.makeCurrent()
	if self.use_pbuffer:
           self.BindOffScreenBuffer()
	MGGLWidgetGL.buildlist(self,go,listid)

    def showMessage(self,message):
        if message != "":
            MAINWINDOW().statusBar().showMessage(message)
