"""
     pygl/MG.py: CCP4MG Molecular Graphics Program
     Copyright (C) 2001-2008 University of York, CCLRC

     This library is free software: you can redistribute it and/or
     modify it under the terms of the GNU Lesser General Public License
     version 3, modified in accordance with the provisions of the 
     license to address the requirements of UK law.
 
     You should have received a copy of the modified GNU Lesser General 
     Public License along with this library.  If not, copies may be 
     downloaded from http://www.ccp4.ac.uk/ccp4license.php
 
     This program is distributed in the hope that it will be useful,
     but WITHOUT ANY WARRANTY; without even the implied warranty of
     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     GNU Lesser General Public License for more details.
"""


import sys
from joyevent import *
from pygl_coord import *
from opengl import *
from point_funcs import *
import eventdefs
import time, threading
import Queue
import displayobject
import util
import jitter
import Light
import clip
from image_info import *
import string
import math
import cprim, pygl_coord
import glevent
import os
#import font_cache
import xmapview

class cube: 
  p0 = Cartesian(); p1 = Cartesian(); p2 = Cartesian(); p3 = Cartesian(); 
  p4 = Cartesian(); p5 = Cartesian(); p6 = Cartesian(); p7 = Cartesian(); 
  def __init__(self):
     pass

def nullfunc():
    pass

class GLUTThread(threading.Thread): 
    """
    An OpenGL/Glut thread class.
    This class is a high level self-standing data instance
    which uses the GLUT API to open and control a window 
    containing an OpenGL (or similar) context. 
    Instances of
    the class are intended to run in their own threads:
    GRAPHICS_thread = MG.GLUTThread()
    GRAPHICS_thread.setDaemon(1)
    GRAPHICS_thread.start()
    """

    NOGRAPHICS = 0
    
    x = 0
    y = 0

    pid = os.getpid()
    title = "CCP4 Molecular Graphics Program" + str(pid)

    RADIUS = 60.0
    drot = (0.0,0.0,0.0)
    quat = pygl_coord.Quat(0.0,0.0,0.0,0)
    win_w = 0;  win_h = 0
    screen_x, screen_y = 0,0
    
    rocking = 0

    resize = 0
    glready = threading.Event()    
    glpause = threading.Event()    
    jq = Queue.Queue(0)
    rotscalex = 1.0;  rotscaley = 1.0
    movescalex = 1.0;  movescaley = 1.0
    joyscalex = 0.0001;
    joyscaley = 0.0001;
    joybuttons = {}
    PERSPECTIVE = 0
    ORTHO = 1
    viewsize = 20
    xyratio = 1.0
    rpos = [0.0, 0.0, 0.0]
    dx = 0;  dy = 0;  dz = 0
    keyleft = GLUT_KEY_LEFT
    keyright = GLUT_KEY_RIGHT
    keyup = GLUT_KEY_UP
    keydown = GLUT_KEY_DOWN
    MOUSE = 1
    KEYBOARD = 2
    LEFT_MOTION = 3
    RIGHT_MOTION = 4
    MIDDLE_MOTION = 5
    WHEEL_UP = 6
    WHEEL_DOWN = 7
    SPECIAL = 8
    MENU = 9
    JOYSTICK_AXIS = 10
    KEYBOARD_UP = 11
    
    BUTTON_PRESSED = LEFT_MOTION

    CENTRE_ON_PRIMITIVE = 0
    LABEL_PRIMITIVE = 1

    NOSTEREO = 0
    REDBLUE = 1
    REDGREEN = 2
    REDCYAN = 3
    BLUERED = 4
    GREENRED = 5
    CYANRED = 6
    QUADBUFFER = 7
    SIDEBYSIDE = 8
    LEFTSTEREOONLY = 10
    RIGHTSTEREOONLY = 9
    SHIFT = 0
    CTRL = 1
    ALT = 2
    ROTATION_STEREO=0
    SHEAR_STEREO=1
    stereo_view_style = ROTATION_STEREO
    stereo_view_style = SHEAR_STEREO
    screenshot_filename="screendump.ppm"
    ps_filename="screendump.ps"
    ps_paper = "A4"
    pov_filename="screendump.pov"
    dumpbitmap = 0
    dumpps = 0
    dumppov = 0
    modifiers = [0,0,0]
    section = 0

    start_width = 100; start_height = 100 
    rubber_band_start = (-5,-5)
    rubber_band_end = (start_width+5,start_height+5)
    rubber_band_box = cube()

    near_min = 1
    far_max = 1000
    fog_far_max = 2000
    min_slab_delta=2.0
    NEAR = near_min
    FAR = far_max
    FOG_START=25
    FOG_END=90
    fog_strength = 0
    projectmode = ORTHO
    stereo_on = 0
    stereo_mode = SIDEBYSIDE
    if stereo_view_style == ROTATION_STEREO:
      stereoseparation = 10; 
    else:
      stereoseparation = 1.5; 
    hardware_stereo_available = 0
    stereo_angle = -6
    shear = .02
    antialias = 0
    old_antialias = 0
    antialias_screenshot = 0
    ACSIZE=15
    fog_on = 1
    fog_density = 0.015
    fog_mode = GL_EXP2
    #fog_mode = GL_LINEAR
    lighting = 1

    IMMEDIATE = 0
    DISPLAYLISTS = 1
    VERTEXARRAY = 2
    #rendermode = IMMEDIATE
    rendermode = DISPLAYLISTS

    draw_symmetry = 0
    symm_diff_colour = 0

    multiview = 0

    joy_x = 0
    joy_y = 0

    nframes = 0
    previous_frames = nframes
    initial_time = time.time()
    previous_time = initial_time
    show_fps = 0
    show_axes = 0
    moving = 0

    smooth_line = 1
    smooth_polygons = 0

    mouse_event = []

    screen_box = ""

    do_exit = 0

    reparented = 0
 
    diagnostic = {
      'opengl':0 }
    
    set_camera_glide = 1
    set_camera_reset_radius = 1
    set_camera_zoom_radius = 10.0
    set_camera_time = 2.0

    background_alpha = 1.0

    redraw = 1

    keyboard_is_active = 0
    special_is_active = 0

    offscreen_buffer = 0
    onscreen_buffer = 0
    mirror_buffers = 0
    default_output_buffer = 0
    offscreen_buffer_override = 0

    use_transparency = 0

    gl_renderer = ''

    update_matrices = 0
    click_timer = threading.Timer(0.0,nullfunc)
    click_timer.start()

    axes_x = ''
    axes_y = ''
    axes_z = ''

    render_quality = 0
    request_render_quality = 1
    fsaa_on = 0

    frame_count = '-1'
    idle_pause = 0.2

    cue_text = 1

    screenshot_width = -1
    screenshot_height = -1

    slab_width = 6
    slab_on = 0

    alpha_available = 0
    weighted_zoom = 1
    zoom_warp = 0.5

    def IdleFunction(self):
      self.glpause.wait(3000)
      if self.section > 0 or self.moving or self.redraw == 1 or self.keyboard_is_active or self.special_is_active:
        glutPostRedisplay()
      else:
        time.sleep(self.idle_pause)

    def CheckErrors(self,info=""):
      err = glGetError()
      if err:
         if info: print info,
         print err; sys.stdout.flush()

    def setup_colour_pointers(self):
        import COLOUR
        white = COLOUR.COLOUR.insts.RGB("white")
        self.whitep = doublea(4)
        self.whitep[0] = white[0]; self.whitep[1] = white[1]; self.whitep[2] = white[2]; self.whitep[3] = white[3]; 
        self.symcolp = []
        excludes = ['green','red','blue','white','black','yellow']

        exclude = []
        next = COLOUR.COLOUR.insts.next('default')
        while exclude.count(next) == 0:
                  exclude.append(next)
                  next = COLOUR.COLOUR.insts.next(next)

        final = []
        for col in exclude:
          if not excludes.count(col):
             rgb =  COLOUR.COLOUR.insts.RGB(col)
             symcolp = doublea(4)
             symcolp[0] = rgb[0]; symcolp[1] = rgb[1]; symcolp[2] = rgb[2]; symcolp[3] = rgb[3]; 
             self.symcolp.append(symcolp)

    def IsPointOnScreen(self,o):
      if sys.platform == "win32":
        self.screen_box = self.GetScreenBox()
      if self.screen_box == "":
        return 1
      if len(self.screen_box)<8:
        return 1
      screen_box = self.screen_box
      p1 = Plane(screen_box[0], screen_box[1], screen_box[2])
      p2 = Plane(screen_box[1], screen_box[7], screen_box[5])
      p3 = Plane(screen_box[7], screen_box[6], screen_box[5])
      p4 = Plane(screen_box[6], screen_box[0], screen_box[2])
      p5 = Plane(screen_box[3], screen_box[5], screen_box[2])
      p6 = Plane(screen_box[1], screen_box[0], screen_box[6])
      v = Volume()
      v.AddPlane(p1); v.AddPlane(p3); # We ignore p2 and p4, they are front and back,
      v.AddPlane(p5); v.AddPlane(p6); # since zooming will never point between them.
      return v.PointInVolume(Cartesian(-o[0],-o[1],-o[2]))

    def set_viewsize(self,viewsize=''):
      if viewsize: self.viewsize = viewsize

    def set_camera_origin(self,o_in='',radius='',zoom=0,plane=None,plane_up=None,set_camera_glide='',quat=None):
      #print "into set_camera_origin viewsize",self.viewsize
      set_quat = 0
      if plane:
        quat_new = pygl_coord.Quat(plane.get_normal(),plane_up);
        quat_old =  pygl_coord.Quat(self.quat)
        set_quat = 1
      elif quat:
        quat_new = pygl_coord.Quat(quat)
        quat_old =  pygl_coord.Quat(self.quat)
        set_quat = 1
      if plane or quat:
        l1,l2= pygl_coord.Quat.Distance(quat_old,quat_new), pygl_coord.Quat.Distance(quat_old,-quat_new)
        if l2<l1: quat_new = -quat_new
      # Define old and new position and radius
      rad_old = self.RADIUS
      rpos_old = self.rpos
      if zoom and self.set_camera_reset_radius:
        if radius:
          rad_new = float(radius)
        else:
          rad_new = self.set_camera_zoom_radius
      else:
        rad_new = self.RADIUS
      if o_in:
        rpos_new = o_in
      else:
        rpos_new = rpos_old

        
      #print "set_quat,glide",set_quat,set_camera_glide


      if set_camera_glide==0 or (set_camera_glide=='' and not self.set_camera_glide):
        # Update immediately
        #self.glready.wait(3000)
        self.Pause()
        self.RADIUS = rad_new
        self.rpos = rpos_new
        if set_quat: self.quat =  quat_new
        self.UnPause()
        self.redraw = 1
        return


      # The required final centre is not currently on screen then
      # pan out until it is (or give up after a second)
      if not self.IsPointOnScreen(rpos_new):
        count = 0
        while not self.IsPointOnScreen(o_in) and count < 50:
          time.sleep(0.02)
          self.glready.wait(3000)
          count = count + 1
          self.RADIUS = self.RADIUS + 2.0
          self.redraw = 1
        time.sleep(0.04)
        rad_old = self.RADIUS
        

      t1 = time.time()
      elapsed = 0.0
      delay = 0.005
      while elapsed <  self.set_camera_time + delay:
        if elapsed < self.set_camera_time:
          f1 = float(elapsed)/float(self.set_camera_time)
        else:
          f1 = 1.0
        f0 = 1.0 - f1
        rpos_cur = [f0*rpos_old[0]+f1*rpos_new[0],f0*rpos_old[1]+f1*rpos_new[1],f0*rpos_old[2]+f1*rpos_new[2]]
        rad_cur = f0*rad_old +f1*rad_new
        time.sleep(delay)
        elapsed = time.time() - t1
        self.glready.wait(3000)
        self.rpos = rpos_cur
        self.RADIUS = rad_cur
        if set_quat: self.quat = quat_new*f1+quat_old*f0 
        self.redraw = 1

            
    def TransformBetweenTwoViews(self,o1,o2,q1,q2):
      # Not usable until we use pygl_coord.Quat throughout instead of Quat.Quat.
      quick = 1
      l1,l2= pygl_coord.Quat.Distance(q1,q2), pygl_coord.Quat.Distance(q1,-q2)
      if l2<l1: q2 = -q2
      if not quick:
        t1 = time.time()
        elapsed = 0.0
        rpos_old = o1
        rpos_new = o2
        rad_old = self.RADIUS
        rad_new = 10
        while elapsed <= 1.02:
          if elapsed < 1.0:
            i = elapsed
          else:
            i = 1.0
          fi = i
          fip = 1.0 - fi
          self.quat = q1*fip+q2*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]]

          time.sleep(0.02)
          elapsed = time.time() - t1
          self.glready.wait(3000)
          self.rpos = rpos_cur
          self.redraw = 1
          glutPostRedisplay()
          if zoom:
            rad_cur = fip * rad_old + fi * rad_new
            self.RADIUS = rad_cur
            self.redraw = 1
            glutPostRedisplay()

      self.glready.wait(3000)
      self.rpos = o2
      self.quat = q2
      self.redraw = 1
      glutPostRedisplay()

    def glutinit(self):
        argc = intp()
        argc.assign(2)
        argv = ["CCP4MG",""]
        glutInit(argc,argv)
        self.displayobj = []
        self.visibility_list = []
        self.alpha_list = []
        glutInitWindowPosition(10,10);
        glutInitWindowSize(self.start_width,self.start_height);
        a = dir(os)
        try:
           a.index('uname')
           renderer_string = "\"OpenGL renderer string:\""
           command = "glxinfo| grep "+renderer_string+"|grep -q \""+"Mesa DRI Intel(R) 945GM 20050225 x86/MMX/SSE2"+"\""
           rc1 = os.system(command)
           if rc1:
               self.alpha_available = CheckIfAlphaStereoAvailable()
               stereo_available = CheckIfStereoAvailable()
           else:
               self.alpha_available = 0
               stereo_available = 0
        except:
           self.alpha_available = CheckIfAlphaAvailable()
           stereo_available = CheckIfStereoAvailable()

        if stereo_available:
           glut_flags = GLUT_ACCUM|GLUT_DOUBLE|GLUT_DEPTH|GLUT_RGB|GLUT_STEREO
        else:
           glut_flags = GLUT_ACCUM|GLUT_DOUBLE|GLUT_DEPTH|GLUT_RGB

        if self.alpha_available == 1:
           glut_flags |= GLUT_ALPHA

        glutInitDisplayMode(glut_flags)

        self.winid = glutCreateWindow(self.title)

        glutDisplayFunc(self.orient);
        glutReshapeFunc (self.changeSize); 
        glutIdleFunc(self.IdleFunction);
        glutMouseFunc(self.mouse);
        glutSpecialFunc(self.special);
        glutSpecialUpFunc(self.special_up)
        glutMotionFunc(self.motion)
        #glutPassiveMotionFunc(self.passive)
        glutKeyboardFunc(self.keyboard);
        glutKeyboardUpFunc(self.keyboard_up);
        #glutEntryFunc(self.entry);
        glutIgnoreKeyRepeat(1)
        self.onscreen_buffer = OnScreenBuffer()

    def TestIfGLIsBroken(self):
      from GLBrokenDriver_db import BrokenDrivers
      self.glbroken = 0
      
      a = dir(os)
      try:
        a.index('uname')
        renderer_string = "\"OpenGL renderer string:\""
        version_string = "\"OpenGL version string:\""
        direct_rendering_string = "\"direct rendering:\""
        for driver in BrokenDrivers:
           if os.uname()[0] == driver[0]:
              command = "glxinfo| grep "+renderer_string+"|grep -q \""+driver[1]+"\""
              rc1 = os.system(command)
              command = "glxinfo| grep "+version_string+"|grep -q \""+driver[2]+"\""
              rc2 = os.system(command)
              command = "glxinfo| grep "+direct_rendering_string+"|grep -q \""+driver[3]+"\""
              rc3 = os.system(command)
              if not rc1 and not rc2 and not rc3:
                self.glbroken = 1
      except:
        pass

    def __init__(self):
        """
        Constructor, setting initial variables.
        """
        GLUTThread.insts = self
        self._stopevent = threading.Event()
        self._sleepperiod = 1.0

        self.glevent = glevent.GLEvent(self)
        self.TestIfGLIsBroken()
        if self.glbroken:
          self.glutinit()

        threading.Thread.__init__(self, name="Glut Thread")
        self.fps_text = ''
        self.fps_prim = cprim.BillBoardText(pygl_coord.Cartesian(0.02,0.02,0),self.fps_text,pygl_coord.Cartesian(0,0,0))
        self.fps_prim.SetFontSize(24)
        """
        Sets up GLUT callbacks, opens window, etc.
        """

        #self.key_presses = IntVector(128)
	self.key_presses = []
	for i in range(128):
          self.key_presses.append(0)
        #self.old_key_presses = IntVector(128)
	self.old_key_presses = []
	for i in range(128):
          self.old_key_presses.append(0)
        #self.special_presses = IntVector(128)
	self.special_presses = []
	for i in range(128):
          self.special_presses.append(0)
        #self.old_special_presses = IntVector(128)
	self.old_special_presses = []
	for i in range(128):
          self.old_special_presses.append(0)

        self.setup_colour_pointers()

        if self.diagnostic['opengl']: print "%s starts" % (self.getName(),)
        self.win_w = self.start_width
        self.win_h = self.start_height

        import COLOUR

        self.bgcolor = COLOUR.COLOUR.insts.RGB("black")

        rgbreps = cprim.RGBReps()
        col = COLOUR.COLOUR.insts.RGB('default')
        rgbreps.AddColour('default',col[1],col[2],col[3])
        exclude = []
        next = COLOUR.COLOUR.insts.next('default')
        while exclude.count(next) == 0:
          col = COLOUR.COLOUR.insts.RGB(next)
          rgbreps.AddColour(next,col[0],col[1],col[2],col[3])
          exclude.append(next)
          next = COLOUR.COLOUR.insts.next(next)

        self.dl_lines = []
        self.dl_solids = []
	self.rebuild_lists = 0

   
    def Exit(self):
        self.glready.wait(3000)
        self.do_exit = 1

    def clear(self):
        self.glready.wait(3000)
	self.glready.clear()
        self.displayobj = []
        self.dl_lines = []
        self.dl_solids = []
	self.glready.set()
        self.glpause.set()
        
    def addobj(self,displayobj):
        """
        Recieve info about display-objects and 
        ask idle function to build lists.
        """
        self.glready.wait(3000)
        self.displayobj.append(displayobj)
        displayobj.rebuild()
        self.redraw = 1

    def deleteobj(self,id):
        """
        Delete a display object instance
        and the GL display list which corresponds to it.
        """
        self.glready.wait(3000)
        self.redraw = 1
        if (self.displayobj): self.displayobj.pop(id)
        if len(self.dl_lines)>id:  self.dl_lines.pop(id)
        if len(self.dl_solids)>id: self.dl_solids.pop(id)
        
    def registerqueue(self,jq='',interrupt=''):
        """
        A function which tells the thread
        which Python Queue it is meant to 
        push events to.
        """
        if jq: self.jq = jq
        if interrupt: self.interruptq=interrupt 
        self.glevent.registerqueue(jq=jq,interrupt=interrupt)

    def setup_clipping(self):
        if self.slab_on == 1:
          self.clip_planes[0].turn_on()
          self.clip_planes[1].turn_on()
        else:
          self.clip_planes[0].turn_off()
          self.clip_planes[1].turn_off()
        for plane in self.clip_planes:
          plane.apply()
        

    def initialize_clipping(self):
        self.clip_planes = []
        self.clip_planes.append(clip.clipping(GL_CLIP_PLANE0))
        self.clip_planes.append(clip.clipping(GL_CLIP_PLANE1))
        self.clip_planes[0].eqn=(0,0,1,self.slab_width/2)
        self.clip_planes[1].eqn=(0,0,-1,self.slab_width/2)
        #self.clip_planes[0].turn_on()
        #self.clip_planes[1].turn_on()


    def get_lighting_params(self):
      params = []
      for light in self.lights:
        params.append([light.on,light.position,light.ambient, \
                      light.specular,light.diffuse])
      return params

    def set_lighting_params(self,params=[]):
      
      if params:
        i=0
        done = min(len(self.lights),len(params))
        for i in range(0, done):
          self.lights[i].position = params[i][1]
          self.lights[i].ambient = params[i][2]
          self.lights[i].specular = params[i][3]
          self.lights[i].diffuse = params[i][4]
          if params[i][0]:
              self.lights[i].turn_on()
          else:
              self.lights[i].turn_off()
      else:
        # default shiny
        self.lights[0].position = (0.0, 0.0, 60.0)
        self.lights[0].ambient = (0.0, 0.0, 0.0)
        self.lights[0].specular = (1.0, 1.0, 1.0)
        self.lights[0].diffuse = (1.0, 1.0, 1.0)
        self.lights[0].turn_on()
        #default soft
        self.lights[1].position = (0.0, 0.0, 60.0)
        self.lights[1].ambient = (0.2, 0.2, 0.2)
        self.lights[1].specular = (0.0, 0.0, 0.0)
        self.lights[1].diffuse = (0.7, 0.7, 0.7)
        self.lights[1].turn_off()
        #default shadowed
        self.lights[2].position = (-60.0,60.0,60.0)
        self.lights[2].ambient = (0.1, 0.1, 0.1)
        self.lights[2].specular = (0.7, 0.7, 0.7)
        self.lights[2].diffuse = (0.4, 0.4, 0.4)
        self.lights[2].turn_off()
        self.lights[3].position = (0.0,60.0,60.0)
        self.lights[3].ambient = (0.1, 0.1, 0.1)
        self.lights[3].specular = (0.7, 0.7, 0.7)
        self.lights[3].diffuse = (0.4, 0.4, 0.4)
        self.lights[3].turn_off()
        done = 4
      
      ambient=(0.1, 0.1, 0.1)
      specular=(0.7, 0.7, 0.7)
      diffuse=(0.7, 0.7, 0.7)
      position=(60.0, 60.0, 60.0)

      for i in range(done,8):
        self.lights[i].position = position
        self.lights[i].ambient = ambient
        self.lights[i].specular = specular
        self.lights[i].diffuse = diffuse
        self.lights[i].turn_off()
        
    def initialize_lighting(self,params=[]):
        light_names = [GL_LIGHT0,GL_LIGHT1,GL_LIGHT2,GL_LIGHT3, \
                       GL_LIGHT4,GL_LIGHT5,GL_LIGHT6,GL_LIGHT7]
        self.lights = []
        
        glEnable(GL_LIGHTING)
        
        ambient=(0.1, 0.1, 0.1)
        specular=(0.7, 0.7, 0.7)
        diffuse=(0.7, 0.7, 0.7)
        position=(60.0, 60.0, 60.0)
        for name in light_names:
          self.lights.append(Light.Light(name,position,ambient,specular,diffuse))

        self.set_lighting_params(params=params)

    def setup_lighting(self):
        """
        Setup OpenGL lighting model.
        """

        if self.lighting > 0:
          glEnable(GL_LIGHTING);
        else:
          glDisable(GL_LIGHTING);
          return

        glLightModeli(GL_LIGHT_MODEL_LOCAL_VIEWER,GL_TRUE)

        for light in self.lights:
          light.apply()
        
    def print_glinfo(self):
        """
        Get OpenGL info.
        """
        print "GL Vendor:", glbyte2str(glGetString(GL_VENDOR))
        print "GL Renderer:", glbyte2str(glGetString(GL_RENDERER))
        print "GL Version:", glbyte2str(glGetString(GL_VERSION))
        print "GL Extensions:", glbyte2str(glGetString(GL_EXTENSIONS))
        print "GLU Version:", glbyte2str(gluGetString(GLU_VERSION))
        print "GLU Extensions:", glbyte2str(gluGetString(GLU_EXTENSIONS))
        params = intp()
        glGetIntegerv(GL_MAX_CLIP_PLANES, params);
        print "Max clipping planes:",params.value()
        glGetIntegerv(GL_MAX_MODELVIEW_STACK_DEPTH, params);
        print "Max modelview stack depth:",params.value()
        glGetIntegerv(GL_AUX_BUFFERS, params);
        print "Auxiliary buffers",params.value()
        glGetIntegerv(GL_DOUBLEBUFFER, params);
        print "Double buffered:",params.value()
        glGetIntegerv(GL_ACCUM_RED_BITS, params);
        print "Accum red bits:",params.value()
        glGetIntegerv(GL_ACCUM_GREEN_BITS, params);
        print "Accum green bits:",params.value()
        glGetIntegerv(GL_ACCUM_BLUE_BITS, params);
        print "Accum blue bits:",params.value()
        glGetIntegerv(GL_ACCUM_ALPHA_BITS, params);
        print "Accum alpha bits:",params.value()
        
    def simple_orient(self):
        pass

    def run(self):
        if not self.glbroken:
          self.glutinit()
        self.stop = 0
        self.glready.clear()
        self.window_id = GetGLUTWindowID(self.pid);
        if self.diagnostic['opengl']: print "GLUT Window ID is", self.window_id

        params = intp()
        glGetIntegerv(GL_STEREO, params);
        if params.value():
           self.stereo_mode = self.QUADBUFFER
           self.hardware_stereo_available = 1
        self.glready.set()
        self.glpause.set()

        if string.count(sys.version,"Red Hat Linux") and string.count(sys.version,"GCC 3.3.1") and string.count(sys.version,"2.2.3"):
          pass
        else:
          pass
          #glutHideWindow()
        glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)

        glEnable(GL_DEPTH_TEST);
        glPolygonMode(GL_FRONT,GL_FILL)
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);

        glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);

        #glEnable(GL_CULL_FACE);
        #glCullFace(GL_BACK);

        self.initialize_clipping()
        self.initialize_lighting()
        self.setup_lighting()

        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        self.BuildPrimitiveDisplayList()
        if self.diagnostic['opengl']:  self.print_glinfo()

        self.joys = OpenJoysticks();

        self.gl_renderer = glbyte2str(glGetString(GL_RENDERER))
        glutMainLoop();

    def join(self,timeout=None):
        """
        Stop the thread. Shouldn't ever get here.
        """
        self.stop = 1;
        self._stopevent.set()
	self.glready.wait(3000)
        threading.Thread.join(self, timeout)

    def toggle_rocking(self):
        if self.rocking == 1:
           self.rocking = 0
        else:
           self.rocking = 1

    def CheckKeysAndMouseStatus(self):
        """
        The idle function. Notices certain
        changes of state which have been
        triggered outside the thread and takes
        action within this thread.
        """

        #print "CheckKeysAndMouseStatus",self.moving,self.mouse_event

        if not self.reparented:
          if sys.platform[:6] == 'irix64':
             self.window_id = GetGLUTWindowID(self.pid);
          if self.diagnostic['opengl']: print "GLUT Window ID is", self.window_id
          glut = self.window_id
          parent = GetParentWindow(glut)
          root = GetRootWindowID()
          if root != parent:
            self.redraw = 1
            self.reparented = 1
            self.changeSize(self.win_w,self.win_h)
          return

        if sys.platform != "win32":
          self.screen_box = self.GetScreenBox()

        if self.resize > 0:
           self.resize = 0
           self.changeSize(self.win_w,self.win_h)
           self.redraw = 1

        if self.joys and len(self.joys)>0:

          joyevent =  GetJoystickEvent(self.joys[0])
          self.joy_x = joyevent.axes[0]
          self.joy_y = joyevent.axes[1]
          self.joybuttons = joyevent.buttons
          if self.joy_x != 0 or self.joy_y != 0:
            if  os.uname()[0] == 'Darwin':
              self.joy_x = self.joy_x * 32768/1200 # Better way?
              self.joy_y = self.joy_y * 32768/1200
            binfo = {}
            binfo["x"] = self.joy_x
            binfo["y"] = self.joy_y
            binfo["window"] = glutGetWindow()
            binfo["joybuttons"] = self.joybuttons
            binfo["key_presses"] = self.key_presses
            job = [  self.JOYSTICK_AXIS, binfo ]
            self.glevent.glevent(job)
            self.redraw = 1
            #glutPostRedisplay (); 
         
	#if sys.platform == 'win32':
	  #CheckKeys(self.key_presses)

        binfo={}
        binfo['screenx']=self.screen_x
        binfo['screeny']=self.screen_y
	key = 0



	if self.keyboard_is_active == 1:
	 for ii in range(self.key_presses.count(1)):
          key = self.key_presses[key:].index(1)+key
          job = [ self.KEYBOARD, key, self.mouse_x, self.mouse_y, self.modifiers,binfo ]
	  key = key+1
          self.glevent.glevent(job)

	key = 0
	if self.keyboard_is_active == 1:
	 for ii in range(self.key_presses.count(-1)):
          key = self.key_presses[key:].index(-1)+key
          job = [self.KEYBOARD_UP, key, self.mouse_x, self.mouse_y, self.modifiers,binfo ]
          self.key_presses[key]=0
	  key = key+1
          self.glevent.glevent(job)

	key = 0
	if self.special_is_active == 1:
	 for ii in range(self.special_presses.count(1)):
          key = self.special_presses[key:].index(1)+key
          job = [ self.SPECIAL, key, self.mouse_x, self.mouse_y, self.modifiers,binfo ]
          self.glevent.glevent(job)
	  key = key+1

	key = 0
	if self.special_is_active == 1:
	 for ii in range(self.special_presses.count(-1)):
          key = self.special_presses[key:].index(-1)+key
          job = [self.SPECIAL_UP, key, self.mouse_x, self.mouse_y, self.modifiers,binfo ]
          self.special_presses[key]=0
          self.glevent.glevent(job)
	  key = key+1

	if self.key_presses.count(1) == 0 and self.key_presses.count(-1) == 0:
	  self.keyboard_is_active = 0
	if self.special_presses.count(1) == 0 and self.special_presses.count(-1) == 0:
	  self.special_is_active = 0

        if self.do_exit:
          sys.exit()
        if self.moving:         
           dx = self.mouse_x - self.start_x
           dy = self.mouse_y - self.start_y
           if dx or dy:
             self.SendMotionEvent(dx,dy,self.start_x,self.start_y)
             #glutPostRedisplay (); 
           self.start_x = self.mouse_x
           self.start_y = self.mouse_y


        if self.redraw == 0:
          return
        self.redraw = 0

    def buildlist(self,listid):
        """
        This function does the business of turning
        display-object data containing primitives, and other stuff
        into display lists and auxiliary info.
        """

        displayobj = self.displayobj[listid]

        if displayobj.BuildDisplayList() != 1:
          return

        glNewList(self.dl_lines[listid],GL_COMPILE)
        if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
            if displayobj.get_transparent() == 0: 
              displayobj.draw_lines(self.whitep,0)
        else:
            if displayobj.get_transparent() == 0: 
              displayobj.draw_lines("NULL",0)
        glEndList()

        glNewList(self.dl_solids[listid],GL_COMPILE)
        if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
            if displayobj.get_transparent() == 0: 
              displayobj.draw_solids(self.whitep,0)
        else:
            if displayobj.get_transparent() == 0: 
              displayobj.draw_solids("NULL",0)
        glEndList()

    def switch_projection(self):
        """
        Switch between orthographic and
        perspective representations.
        """
        if self.projectmode == self.PERSPECTIVE:
           self.projectmode = self.ORTHO
        else:
           self.projectmode = self.PERSPECTIVE
        self.changeSize(self.win_w,self.win_h)

    def toggle_antialiasing(self):
        if self.antialias > 0:
           self.antialias = 0
        else:
           self.antialias = 2

    def DrawRubberBand(self):

      glPushAttrib(GL_ENABLE_BIT|GL_CURRENT_BIT); # Draw Rubber Band
      glDisable(GL_LIGHTING)
      glColor3f(1-self.bgcolor[0],1-self.bgcolor[1],1-self.bgcolor[2])
      glLineWidth(1.0);
      glBegin(GL_LINE_STRIP)
      glVertex3f(self.rubber_band_box.p0.get_x(),self.rubber_band_box.p0.get_y(),self.rubber_band_box.p0.get_z())
      glVertex3f(self.rubber_band_box.p1.get_x(),self.rubber_band_box.p1.get_y(),self.rubber_band_box.p1.get_z())
      glVertex3f(self.rubber_band_box.p2.get_x(),self.rubber_band_box.p2.get_y(),self.rubber_band_box.p2.get_z())
      glVertex3f(self.rubber_band_box.p3.get_x(),self.rubber_band_box.p3.get_y(),self.rubber_band_box.p3.get_z())
      glVertex3f(self.rubber_band_box.p0.get_x(),self.rubber_band_box.p0.get_y(),self.rubber_band_box.p0.get_z())
      glEnd()
      glPopAttrib()

    def SetStereoMode(self,stereo_mode):
      if not self.hardware_stereo_available and stereo_mode == self.QUADBUFFER:
        return
      self.stereo_mode = stereo_mode
      if self.stereo_mode == self.LEFTSTEREOONLY or self.stereo_mode == self.RIGHTSTEREOONLY or self.stereo_mode == self.SIDEBYSIDE:
        if self.stereo_view_style == self.ROTATION_STEREO:
          self.stereoseparation = 5
        else:
          self.stereoseparation = 1.5
      else:
        if self.stereo_view_style == self.ROTATION_STEREO:
          self.stereoseparation = 10
        else:
          self.stereoseparation = 1.5
      for obj in self.displayobj:
	 obj.rebuild()

    def SetAxes(self,axes_on):
      self.show_axes = axes_on
      self.redraw = 1

    def SetFog(self,fog_on):
      self.fog_on = fog_on
      self.redraw = 1

    def SetStereo(self,stereo_on):
      self.stereo_on = stereo_on
      for obj in self.displayobj:
	 obj.rebuild()
      self.redraw = 1

    def BuildPrimitiveDisplayList(self):
      col = doublea(4); col[0] = col[1] = col[2] = col[3] = 0.0
      cprim.sphere(0,1.0,1)
      cprim.sphere(1,1.0,1)
      cprim.sphere(2,1.0,1)
      cprim.sphere(3,1.0,1)
      cprim.sphere(4,1.0,1)
      carts = CartesianVector()
      carts.append(Cartesian(0,0,0))
      carts.append(Cartesian(0,0,1))
      cprim.draw_cylinder(carts,1.0,4,0,1)
      cprim.draw_cylinder(carts,1.0,8,0,1)
      cprim.draw_cylinder(carts,1.0,16,0,1)
      cprim.draw_cylinder(carts,1.0,32,0,1)

    def SetDefaultOutputBuffer(self):
        self.offscreen_buffer = self.default_output_buffer
        self.offscreen_buffer_override = 0

    def SetOffScreenBuffer(self,buffer):
	self.offscreen_buffer = buffer
        self.offscreen_buffer_override = 1

    def BuildLists(self,force=0):
      rebuilt = 0
   
      if self.rendermode == self.DISPLAYLISTS:
        i = 0
        for obj in self.displayobj:
          if obj.get_rebuild() == 1 or force == 1:
            if i >= len(self.dl_lines):
              self.dl_lines.append(glGenLists(1))
              self.dl_solids.append(glGenLists(1))
              t1 = time.time()
              self.buildlist(len(self.dl_lines)-1)
              t2 = time.time()
            else:
              self.buildlist(i)
            obj.rebuild(0)
            rebuilt = 1
          i = i + 1
      self.rebuild_lists = 0
      return rebuilt

    def CalculateJitter(self):

        xoff   = 0
        yoff   = 0
        acsize = 1 
        jarray = [(0.0,0.0)]
        
        acsize=self.ACSIZE
        jarray = jitter.get_jarray(acsize)

        if len(jarray) > 0:

            viewport = inta(4)
            glGetIntegerv(GL_VIEWPORT, viewport);
            xoff = 0.125*self.RADIUS/60.0
            yoff = 0.125*self.RADIUS/60.0
        else:
            acsize = 1
     
        return acsize,xoff,yoff,jarray

    def Jitter(self,acsize,xoff,yoff,jarray,jit,axes):
          if acsize > 1:
             glTranslatef(jarray[jit][0]*xoff*axes[0].get_x(),jarray[jit][0]*xoff*axes[0].get_y(),jarray[jit][0]*xoff*axes[0].get_z())
             glTranslatef(jarray[jit][1]*yoff*axes[1].get_x(),jarray[jit][1]*yoff*axes[1].get_y(),jarray[jit][1]*yoff*axes[1].get_z())

    def SetTransparency(self,transparency=-1):
        self.rebuild_lists = 1
        if transparency>=0: self.use_transparency = transparency


    def drawlists(self):
        """
        Call the display lists and draw them at the
        correct position and orientation.
        """

        glEnable(GL_NORMALIZE);

        rebuilt = self.BuildLists(self.rebuild_lists)
        #self.define_rubber_band_cube()

        if self.smooth_line:
          glEnable(GL_LINE_SMOOTH);
          glEnable(GL_POINT_SMOOTH);
        else:
          glDisable(GL_LINE_SMOOTH);
          glDisable(GL_POINT_SMOOTH);

        self.use_transparency = 0
        for displayobj in self.displayobj:
          if displayobj.get_transparent() == 1: 
            self.use_transparency = 1
            break
          displayobj.move_origin()

        if self.fog_on:
          glEnable(GL_FOG)

        glPixelTransferi(GL_MAP_COLOR,GL_FALSE);
        glDisable(GL_TEXTURE_2D)

        glDisable(GL_BLEND)
        glEnable(GL_LIGHTING)
        glDepthMask(GL_TRUE);
        glDepthFunc(GL_LESS);
        glEnable(GL_DEPTH_TEST);

        glPolygonMode(GL_FRONT,GL_FILL);

        acsize, xoff, yoff, jarray = self.CalculateJitter()

        if self.antialias == 1 and self.use_transparency == 0:
          axes = self.getaxes()
          invacsize=1.0/acsize
          params = intp()
          for i in range(acsize):
            print "antialias step", i, "of", acsize; sys.stdout.flush()
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
            self.Jitter(acsize,xoff,yoff,jarray,i,axes)
            self.draw_solids(0)
            glAccum(GL_ACCUM,1./float(acsize))
          glAccum(GL_RETURN,1.0)
        else:
          self.draw_solids(0)

        if self.antialias == 0 or self.use_transparency == 0:
          if self.smooth_line:
            glEnable(GL_BLEND)
          self.draw_lines(0) 

        if self.use_transparency:
          if len(self.visibility_list)!=len(self.displayobj):
             self.visibility_list = []
             rebuilt = 1
             for ob in self.displayobj:
               self.visibility_list.append(ob.visible)
          else:
            iob=0
            for ob in self.displayobj:
               if self.visibility_list[iob] != ob.visible:
                  rebuilt = 1
                  break
               iob = iob + 1
            if rebuilt:
               self.visibility_list = []
               for ob in self.displayobj:
                 self.visibility_list.append(ob.visible)
          if len(self.alpha_list)!=len(self.displayobj):
             self.alpha_list = []
             rebuilt = 1
             for ob in self.displayobj:
               self.alpha_list.append(ob.GetAlpha())
          else:
            iob=0
            for ob in self.displayobj:
               if ob.visible:
                 if self.alpha_list[iob] != ob.GetAlpha():
                    rebuilt = 1
                    break
               iob = iob + 1
            if rebuilt:
               self.alpha_list = []
               for ob in self.displayobj:
                 self.alpha_list.append(ob.GetAlpha())
            if self.antialias != self.old_antialias: rebuilt = 1
          
          axes = self.getaxes()
          # Hack needed because swig isn't up to converting [] to std::vector with derived objects it seems.
          cobjs = xmapview.DisplayobjectVector()
          for ob in self.displayobj:
            cobjs.append(ob)
          v = cprim.DoubleDoubleVector()
          for j in jarray:
            v.append(j)
          cprim.DrawSortedTransparentPrimitives(cobjs, acsize, xoff, yoff, v, axes, self.antialias, rebuilt)
        self.old_antialias = self.antialias

        self.draw(0) # Draws images only now.

        glDepthMask(GL_TRUE);
        glDisable(GL_BLEND);

        if not self.cue_text: glDisable(GL_FOG);
        glDisable(GL_LIGHTING);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glDepthMask(GL_FALSE);
        glPixelTransferi(GL_MAP_COLOR,GL_TRUE);

        glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
        glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        # This puts the text at the front
        glDepthFunc(GL_ALWAYS);
        self.draw(0,text=1)

        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 + ' fps'
          self.fps_prim.SetText(fps_text)
          self.previous_frames = self.nframes
          self.previous_time = t

        if self.show_fps > 0:
          if font_cache.FontCache().NumberOfFonts() > 0:
            self.fps_prim.draw()

        glDepthMask(GL_TRUE);
        glDisable(GL_BLEND);

        #self.DrawRubberBand()

        glFlush();

    def DrawPostscript(self,psfilename="",paper=""):
      q = pygl_coord.Quat(self.quat)

      if psfilename != "":
        fname = psfilename
      else:
        fname = self.ps_filename

      if paper == "":
        paper = self.ps_paper

      import streams
      import psutil
      stream = streams.ofstream(fname)

      if paper == "BBox":
        ratio = self.xyratio* self.win_w / self.win_h
        xoff = 297
        yoff = 421
        leftbb  = int(xoff - ratio * yoff)
        rightbb = int(xoff + ratio * yoff)
        bounding_box = "BoundingBox: " + str(leftbb) + " 0 " + str(rightbb) + " 843";
        psutil.PSHeader(stream,fname,bounding_box)
      else:
        psutil.PSHeader(stream,fname,paper)

      """
      if self.fog_on == 1:
        # We have to convert this into final transformed coords which zsortps uses.
        dist = .5*(self.FOG_START+self.FOG_END)
        fog_near = max(dist - self.viewsize,self.FOG_START)
        fog_far = min(dist + 2*self.viewsize,2*self.FOG_END)
        stream.Print("% FOG_START: "+str(fog_near)+"\n")
        stream.Print("% FOG_END: "+str(fog_far)+"\n")
        stream.Print("% FOG_DENSITY: "+str(float(self.fog_density))+"\n")
        print "NEAR",self.NEAR
        print "FAR",self.FAR
      """

      for i in range(len(self.displayobj)):
        if self.displayobj[i].visible > 0:
          self.displayobj[i].DrawPostscript(stream,q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])

      if self.show_axes:
        x_axis = Cartesian(1,0,0)
        y_axis = Cartesian(0,1,0)
        z_axis = Cartesian(0,0,1)
        m = self.quat.getInvMatrix()
        x_axis = m * x_axis
        y_axis = m * y_axis
        z_axis = m * z_axis
        x_x = 530 + x_axis.get_x() * 40
        x_y = 780 + x_axis.get_y() * 40
        y_x = 530 + y_axis.get_x() * 40
        y_y = 780 + y_axis.get_y() * 40
        z_x = 530 + z_axis.get_x() * 40
        z_y = 780 + z_axis.get_y() * 40
        x_x_t = 530 + x_axis.get_x() * 50
        x_y_t = 780 + x_axis.get_y() * 50
        y_x_t = 530 + y_axis.get_x() * 50
        y_y_t = 780 + y_axis.get_y() * 50
        z_x_t = 530 + z_axis.get_x() * 50
        z_y_t = 780 + z_axis.get_y() * 50
        arrowrot = pygl_coord.Quat(0,0,1,1,5)
        x_arrow_p = arrowrot.getInvMatrix() * x_axis
        x_arrow_m = arrowrot.getMatrix() * x_axis
        y_arrow_p = arrowrot.getInvMatrix() * y_axis
        y_arrow_m = arrowrot.getMatrix() * y_axis
        z_arrow_p = arrowrot.getInvMatrix() * z_axis
        z_arrow_m = arrowrot.getMatrix() * z_axis
        x_arrow_p_x = 530 + x_arrow_p.get_x() * 35
        x_arrow_p_y = 780 + x_arrow_p.get_y() * 35
        x_arrow_m_x = 530 + x_arrow_m.get_x() * 35
        x_arrow_m_y = 780 + x_arrow_m.get_y() * 35
        y_arrow_p_x = 530 + y_arrow_p.get_x() * 35
        y_arrow_p_y = 780 + y_arrow_p.get_y() * 35
        y_arrow_m_x = 530 + y_arrow_m.get_x() * 35
        y_arrow_m_y = 780 + y_arrow_m.get_y() * 35
        z_arrow_p_x = 530 + z_arrow_p.get_x() * 35
        z_arrow_p_y = 780 + z_arrow_p.get_y() * 35
        z_arrow_m_x = 530 + z_arrow_m.get_x() * 35
        z_arrow_m_y = 780 + z_arrow_m.get_y() * 35
        stream.Print("1.0 slw n 530.000 780.000 m "+str(x_x)+" "+str(x_y)+" l  cp 0 0 0 srgb s\n")
        stream.Print("1.0 slw n 530.000 780.000 m "+str(y_x)+" "+str(y_y)+" l  cp 0 0 0 srgb s\n")
        stream.Print("1.0 slw n 530.000 780.000 m "+str(z_x)+" "+str(z_y)+" l  cp 0 0 0 srgb s\n")
        stream.Print("/CenturySchoolbookL ff 16 scf sf "+str(x_x_t)+" "+str(x_y_t)+" m gs 1 1 sc (x) 0 0 0 srgb sh gr %TEXT\n")
        stream.Print("/CenturySchoolbookL ff 16 scf sf "+str(y_x_t)+" "+str(y_y_t)+" m gs 1 1 sc (y) 0 0 0 srgb sh gr %TEXT\n")
        stream.Print("/CenturySchoolbookL ff 16 scf sf "+str(z_x_t)+" "+str(z_y_t)+" m gs 1 1 sc (z) 0 0 0 srgb sh gr %TEXT\n")
        stream.Print("1.0 slw n "+str(x_arrow_p_x)+" "+str(x_arrow_p_y)+" m "+str(x_x)+" "+str(x_y)+" l "+str(x_arrow_m_x)+" "+str(x_arrow_m_y)+" l cp fill gs 0 0 0 srgb s gr\n")
        stream.Print("1.0 slw n "+str(y_arrow_p_x)+" "+str(y_arrow_p_y)+" m "+str(y_x)+" "+str(y_y)+" l "+str(y_arrow_m_x)+" "+str(y_arrow_m_y)+" l cp fill gs 0 0 0 srgb s gr\n")
        stream.Print("1.0 slw n "+str(z_arrow_p_x)+" "+str(z_arrow_p_y)+" m "+str(z_x)+" "+str(z_y)+" l "+str(z_arrow_m_x)+" "+str(z_arrow_m_y)+" l cp fill gs 0 0 0 srgb s gr\n")

      psutil.PSTail(stream)
      stream.Close()
      psutil.zsortps(fname,self.fog_on)

    def DrawPovRay(self,filename=""):
      q = pygl_coord.Quat(self.quat)

      if filename != "":
        fname = filename
      else:
        fname = self.pov_filename

      if os.path.exists(fname):
         os.remove(fname)
      fname_tmp = fname+'-tmp'
      if os.path.exists(fname_tmp):
         os.remove(fname_tmp)

      import streams
      stream = streams.ofstream(fname_tmp)

      stream.Print('#include "colors.inc"\n')
      stream.Print('camera {\n')
      stream.Print('orthographic location <0,0,-60>\n')
      #stream.Print('orthographic location <0,0,0>\n') ??
      stream.Print('look_at <0,0,0>')
      stream.Print('up <0,'+str(self.viewsize*2*self.RADIUS/60)+',0>')
      stream.Print('right <'+str(self.viewsize*2*self.RADIUS/60*self.xyratio* self.win_w / self.win_h)+',0,0>')
      stream.Print('}\n')
      stream.Print('background { color rgb <' + str(self.bgcolor[0]) + ','+  str(self.bgcolor[1]) + ','+ str(self.bgcolor[2]) + '> }\n')
      for light in self.lights:
        if light.on > 0:
          stream.Print('light_source { <' +  str(light.position[0]*10) + ',' +  str(light.position[1]*10) + ',' +  str(-light.position[2]*10) + '>color  White}\n')
      if self.fog_on: 
        if self.background_alpha > 0.1:
          stream.Print('fog { distance 100 colour rgb<'+ str(self.bgcolor[0]) + ','+  str(self.bgcolor[1]) + ','+ str(self.bgcolor[2]) + '> }\n')
      for i in range(len(self.displayobj)):
        if self.displayobj[i].visible > 0:
          self.displayobj[i].DrawPovRay(stream,q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
      if self.show_axes:
        xpos = (self.viewsize*2*self.RADIUS/60*self.xyratio* self.win_w / self.win_h / 2.0) * 0.8
        ypos = (self.viewsize*2*self.RADIUS/60 / 2.0) * 0.8
        axo = pygl_coord.Cartesian(xpos,ypos,55)
        xax = pygl_coord.Cartesian((self.viewsize*2*self.RADIUS/60* self.win_w / self.win_h / 2.0) * 0.1,0,0)
        yax = pygl_coord.Cartesian(0,(self.viewsize*2*self.RADIUS/60* self.win_w / self.win_h / 2.0) * 0.1,0)
        zax = pygl_coord.Cartesian(0,0,(self.viewsize*2*self.RADIUS/60* self.win_w / self.win_h / 2.0) * 0.1)
        ax_width = 0.01 * (self.viewsize*2*self.RADIUS/60* self.win_w / self.win_h / 2.0)
        xaxp = q.getInvMatrix() * xax
        yaxp = q.getInvMatrix() * yax
        zaxp = q.getInvMatrix() * zax
        xaxend = axo + xaxp
        yaxend = axo + yaxp
        zaxend = axo + zaxp
        xaxend2 = axo + xaxp*1.5
        yaxend2 = axo + yaxp*1.5
        zaxend2 = axo + zaxp*1.5
	colour_y = 0.299*float(self.bgcolor[0]) + 0.587*float(self.bgcolor[1]) + 0.114*float(self.bgcolor[2])
	if colour_y>0.5:
          axes_col_label = '    pigment { color rgb <0, 0, 0> }\n'
        else:
          axes_col_label = '    pigment { color rgb <1, 1, 1> }\n'
        stream.Print('sphere {\n')
        stream.Print(' < '+str(xpos)+','+str(ypos)+',-55>\n')
        stream.Print(' '+str(ax_width)+'\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cone {\n')
        stream.Print(' < '+str(xaxend.get_x())+','+str(xaxend.get_y())+',-55>,\n')
        stream.Print(' '+str(ax_width*2)+',\n')
        stream.Print(' < '+str(xaxend2.get_x())+','+str(xaxend2.get_y())+',-55>,\n')
        stream.Print(' 0\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cone {\n')
        stream.Print(' < '+str(yaxend.get_x())+','+str(yaxend.get_y())+',-55>,\n')
        stream.Print(' '+str(ax_width*2)+',\n')
        stream.Print(' < '+str(yaxend2.get_x())+','+str(yaxend2.get_y())+',-55>,\n')
        stream.Print(' 0\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cone {\n')
        stream.Print(' < '+str(zaxend.get_x())+','+str(zaxend.get_y())+',-55>,\n')
        stream.Print(' '+str(ax_width*2)+',\n')
        stream.Print(' < '+str(zaxend2.get_x())+','+str(zaxend2.get_y())+',-55>,\n')
        stream.Print(' 0\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cylinder {\n')
        stream.Print(' < '+str(xpos)+','+str(ypos)+',-55>,\n')
        stream.Print(' < '+str(xaxend.get_x())+','+str(xaxend.get_y())+',-55>\n')
        stream.Print(' '+str(ax_width)+'\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cylinder {\n')
        stream.Print(' < '+str(xpos)+','+str(ypos)+',-55>,\n')
        stream.Print(' < '+str(yaxend.get_x())+','+str(yaxend.get_y())+',-55>\n')
        stream.Print(' '+str(ax_width)+'\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')
        stream.Print('cylinder {\n')
        stream.Print(' < '+str(xpos)+','+str(ypos)+',-55>,\n')
        stream.Print(' < '+str(zaxend.get_x())+','+str(zaxend.get_y())+',-55>\n')
        stream.Print(' '+str(ax_width)+'\n')
        stream.Print(' texture {\n')
        stream.Print(axes_col_label)
        stream.Print('    finish {diffuse 1.0 specular 1.0}\n')
        stream.Print(' }\n')
        stream.Print('}\n')

      stream.Close()
      os.rename(fname_tmp,fname)

      fname_old = fname
      if len(fname)>4 and fname[len(fname)-4:]==".pov":
         fname = fname[:len(fname)-4] + "-pov.py"
      else:
         fname = fname + "-pov.py"
      if os.path.exists(fname):
         os.remove(fname)
      fname_tmp = fname+'-tmp'
      if os.path.exists(fname_tmp):
         os.remove(fname_tmp)
      stream = streams.ofstream(fname_tmp)
      stream.Print('import image_info\n')
      stream.Print('import sys\n')
      stream.Print('import math\n')
      stream.Print('if len(sys.argv)<2:\n')
      stream.Print('  print "Usage: "+sys.argv[0]+" rendered_file"\n')
      stream.Print('  print "eg "+sys.argv[0]+" myfile.png"\n')
      stream.Print('  sys.exit()\n')
      stream.Print('import font_cache\n')
      stream.Print('text_labels = []\n')
      stream.Print('image_labels = []\n')
      stream.Print("ok_font = ''\n")
      stream.Print('bad_fonts = []\n')
      for i in range(len(self.displayobj)):
        if self.displayobj[i].visible > 0:
          self.displayobj[i].OutputTextLabels(stream,q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])

      if self.show_axes:
        xax = pygl_coord.Cartesian(0.08,0,0)
        yax = pygl_coord.Cartesian(0,0.08,0)
        zax = pygl_coord.Cartesian(0,0,0.08)
        xaxp = q.getInvMatrix() * xax
        yaxp = q.getInvMatrix() * yax
        zaxp = q.getInvMatrix() * zax
        axo = pygl_coord.Cartesian(0.9,0.9,0.0)
        xaxend = axo + xaxp
        yaxend = axo + yaxp
        zaxend = axo + zaxp
	colour_y = 0.299*float(self.bgcolor[0]) + 0.587*float(self.bgcolor[1]) + 0.114*float(self.bgcolor[2])
	if colour_y>0.5:
          axes_col_label = 'label["colour"]=[0,0,0]\n'
        else:
          axes_col_label = 'label["colour"]=[1,1,1]\n'
        stream.Print('label={}\n')
        stream.Print('label["position"]=['+str(xaxend.get_x())+','+str(xaxend.get_y())+']\n')
        stream.Print('font ={}\n')
        stream.Print('font["family"]="Century Schoolbook L"\n')
        stream.Print('font["weight"]="medium"\n')
        stream.Print('font["slant"]="r"\n')
        stream.Print('font["size"]="24"\n')
        stream.Print('label["font"]=font\n')
        stream.Print('label["text"]="x"\n')
        stream.Print(axes_col_label)
        stream.Print('text_labels.append(label)\n')
        stream.Print('label={}\n')
        stream.Print('label["position"]=['+str(yaxend.get_x())+','+str(yaxend.get_y())+']\n')
        stream.Print('font ={}\n')
        stream.Print('font["family"]="Century Schoolbook L"\n')
        stream.Print('font["weight"]="medium"\n')
        stream.Print('font["slant"]="r"\n')
        stream.Print('font["size"]="24"\n')
        stream.Print('label["font"]=font\n')
        stream.Print('label["text"]="y"\n')
        stream.Print(axes_col_label)
        stream.Print('text_labels.append(label)\n')
        stream.Print('label={}\n')
        stream.Print('label["position"]=['+str(zaxend.get_x())+','+str(zaxend.get_y())+']\n')
        stream.Print('font ={}\n')
        stream.Print('font["family"]="Century Schoolbook L"\n')
        stream.Print('font["weight"]="medium"\n')
        stream.Print('font["slant"]="r"\n')
        stream.Print('font["size"]="24"\n')
        stream.Print('label["font"]=font\n')
        stream.Print('label["text"]="z"\n')
        stream.Print(axes_col_label)
        stream.Print('text_labels.append(label)\n')

      stream.Print('iinfo = image_info.image_info(sys.argv[1])\n')
      stream.Print('new_name = "labelled"+sys.argv[1]\n')
      stream.Print('iinfo.write(new_name)\n')
      stream.Print('for image in image_labels:\n')
      stream.Print('  iinfo = image_info.image_info(new_name)\n')
      stream.Print('  overlay_iinfo = image_info.image_info(image["filename"])\n')
      stream.Print('  overlay_width = float(overlay_iinfo.get_width())\n')
      stream.Print('  overlay_height = float(overlay_iinfo.get_height())\n')
      stream.Print('  overlay_width = int(overlay_width * image["scale_w"])\n')
      stream.Print('  overlay_height = int(overlay_height * image["scale_h"])\n')
      stream.Print('  width = float(iinfo.get_width())\n')
      stream.Print('  height = float(iinfo.get_height())\n')
      stream.Print('  overlay_iinfo.invert()\n')
      stream.Print('  overlay_iinfo.ScaleImage(overlay_width,overlay_height)\n')
      stream.Print('  x = int(math.floor(width*image["position"][0]))\n')
      stream.Print('  y = int(math.floor(height*image["position"][1]))\n')
      stream.Print('  iinfo.invert()\n')
      stream.Print('  iinfo.Overlay(overlay_iinfo,x,y)\n')
      stream.Print('  iinfo.invert()\n')
      stream.Print('  iinfo.write(new_name)\n')
      stream.Print('font_cache.FontCache().LoadAllFonts()\n')
      stream.Print('for label in text_labels:\n')
      stream.Print('  iinfo = image_info.image_info(new_name)\n')
      stream.Print('  text = label["text"]\n')
      stream.Print('  colour = label["colour"]\n')
      stream.Print('  red = hex(int(colour[0]*255))[2:]\n')
      stream.Print('  green = hex(int(colour[1]*255))[2:]\n')
      stream.Print('  blue = hex(int(colour[2]*255))[2:]\n')
      stream.Print('  if len(red)==1: red = "0"+red\n')
      stream.Print('  if len(green)==1: green = "0"+green\n')
      stream.Print('  if len(blue)==1: blue = "0"+blue\n')
      stream.Print('  hex_colour = "#"+red+green+blue\n')
      stream.Print('  family = label["font"]["family"]\n')
      stream.Print('  weight = label["font"]["weight"]\n')
      stream.Print('  slant = label["font"]["slant"]\n')
      stream.Print('  size = int(label["font"]["size"])\n')
      stream.Print('  x = int(label["position"][0]*iinfo.get_width())\n')
      stream.Print('  y = iinfo.get_height()-int(label["position"][1]*iinfo.get_height())-size\n')
      stream.Print('  idx = -1\n')
      stream.Print('  try:\n')
      stream.Print('    idx=bad_fonts.index(label["font"])\n')
      stream.Print('  except:\n')
      stream.Print('    pass\n')
      stream.Print('  if idx >-1 and ok_font:\n')
      stream.Print('    finfo = ok_font\n')
      stream.Print('  else:\n')
      stream.Print('    finfo = font_cache.FontCache().GetFont("",family,weight,slant,"",size)\n')
      stream.Print('  if not finfo.isValid():\n')
      stream.Print('    bad_fonts.append(label["font"])\n')
      stream.Print('    finfo = font_cache.FontCache().GetFont(0)\n')
      stream.Print('  if finfo.isValid():\n')
      stream.Print('    if int(finfo.Size())==0:\n')
      stream.Print('      finfo2 = font_cache.FontCache().GetFont("",finfo.Family(),finfo.Weight(),finfo.Slant(),"",size)\n')
      stream.Print('      if int(finfo2.Size())==0:\n')
      stream.Print('        newsize = font_cache.FontCache().FindNextFontSize(finfo.Family(),finfo.Weight(),finfo.Slant(),12,1);\n')
      stream.Print('        finfo2 = font_cache.FontCache().GetFont("",finfo.Family(),finfo.Weight(),finfo.Slant(),"",newsize)\n')
      stream.Print('        if int(finfo2.Size())==0:\n')
      stream.Print('          print "Failed to load any font to overlay text labels"\n')
      stream.Print('          print "Maybe you need to set DISPLAY (if on Unix/Linux/Mac OS X)"\n')
      stream.Print('          sys.exit()\n')
      stream.Print('      finfo = finfo2\n')
      stream.Print('    ok_font = finfo\n')
      stream.Print('    iinfo2 = image_info.image_infoPtr(font_cache.OverlayTextOnImage(iinfo,finfo,x,y,text,hex_colour))\n')
      stream.Print('    iinfo2.write(new_name)\n')
      stream.Print('  else:\n')
      stream.Print('    print "Failed to load any font to overlay text labels"\n')
      stream.Print('    print "Maybe you need to set DISPLAY (if on Unix/Linux/Mac OS X)"\n')
      stream.Print('    sys.exit()\n')
      stream.Close()
      os.rename(fname_tmp,fname)

    def draw(self,transparent,text=0):

          q = pygl_coord.Quat(self.quat)

          for i in range(len(self.displayobj)):
            if self.displayobj[i].visible > 0:

              displayobj = self.displayobj[i]

              displayobj.camera_quat = q

              glPushMatrix()

              displayobj.ApplyTranslation()
              displayobj.ApplyRotation()

              if text > 0:
                displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
              else:
                displayobj.draw_images()

              nsym = displayobj.GetNumSymmetryMatrices()
              symm_nos = displayobj.symm_nos
              symm_mat = MatrixVector(displayobj.symm_mat)

              if nsym>0 and len(symm_nos) == nsym  and len(symm_mat) == nsym and self.draw_symmetry>0 and displayobj.GetDrawSymmetry():
                  for isym in range(nsym):
                    
                    glPushMatrix()
                    glMultMatrixd(symm_mat[isym].Transpose().to_dp())
  
                    if text > 0:
                      displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
                    else:
                      displayobj.draw_images()
  
                    glPopMatrix()
              glPopMatrix()

    def draw_lines(self,transparent,text=0):

          q = pygl_coord.Quat(self.quat)

          for i in range(len(self.displayobj)):
            if self.displayobj[i].visible > 0:

              displayobj = self.displayobj[i]

              displayobj.camera_quat = q

              glPushMatrix()

              displayobj.ApplyTranslation()
              displayobj.ApplyRotation()

              if text > 0:
                displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
              else:
                if self.rendermode == self.DISPLAYLISTS and displayobj.BuildDisplayList() == 1:
                  glCallList(self.dl_lines[i])
                if self.rendermode == self.IMMEDIATE or displayobj.BuildDisplayList() == 0:
                  if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
                    displayobj.draw_lines(self.whitep,transparent)
                  else:
                    displayobj.draw_lines("NULL",transparent)

              nsym = displayobj.GetNumSymmetryMatrices()
              symm_nos = displayobj.symm_nos
              symm_mat = MatrixVector(displayobj.symm_mat)

              if displayobj.GetDrawUnitCell():
                 displayobj.DrawUnitCell()
              if nsym>0 and len(symm_nos) == nsym  and len(symm_mat) == nsym and self.draw_symmetry>0 and displayobj.GetDrawSymmetry():
                  for isym in range(nsym):
                    
                    glPushMatrix()
                    glMultMatrixd(symm_mat[isym].Transpose().to_dp())
  
                    if text > 0:
                      displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
                    else:
                      if self.rendermode == self.DISPLAYLISTS and displayobj.BuildDisplayList() == 1:
                        if self.symm_diff_colour and displayobj.GetDrawSymmetryColoured(): 
                            if symm_nos[isym] < len(self.symcolp):
                              displayobj.draw_lines(self.symcolp[symm_nos[isym]],transparent,1)
                            else:
                              displayobj.draw_lines(self.whitep,transparent,1)
                        else:
                          glCallList(self.dl_lines[i])
  
                      if self.rendermode == self.IMMEDIATE or displayobj.BuildDisplayList() == 0:
                        if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
                          displayobj.draw_lines(self.whitep,transparent)
                        else:
                          displayobj.draw_lines("NULL",transparent)
  
                    glPopMatrix()
              glPopMatrix()

    def draw_solids(self,transparent,text=0):

          q = pygl_coord.Quat(self.quat)

          for i in range(len(self.displayobj)):
            if self.displayobj[i].visible > 0:

              displayobj = self.displayobj[i]

              displayobj.camera_quat = q

              glPushMatrix()

              displayobj.ApplyTranslation()
              displayobj.ApplyRotation()

              if text > 0:
                displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
              else:
                if self.rendermode == self.DISPLAYLISTS and displayobj.BuildDisplayList() == 1:
                  glCallList(self.dl_solids[i])
                if self.rendermode == self.IMMEDIATE or displayobj.BuildDisplayList() == 0:
                  cprim.RenderQuality.SetRenderQuality(self.render_quality)
                  if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
                    displayobj.draw_solids(self.whitep,transparent)
                  else:
                    displayobj.draw_solids("NULL",transparent)
                  cprim.RenderQuality.SetRenderQuality(0)

              nsym = displayobj.GetNumSymmetryMatrices()
              symm_nos = displayobj.symm_nos
              symm_mat = MatrixVector(displayobj.symm_mat)

              """
              if displayobj.GetDrawUnitCell():
                 displayobj.DrawUnitCell()
              """
              if nsym>0 and len(symm_nos) == nsym  and len(symm_mat) == nsym and self.draw_symmetry>0 and displayobj.GetDrawSymmetry():
  
                  for isym in range(nsym):
                    
                    glPushMatrix()
                    glMultMatrixd(symm_mat[isym].Transpose().to_dp())
  
                    if text > 0:
                      displayobj.draw_text(q,self.RADIUS,self.rpos[0],self.rpos[1],self.rpos[2])
                    else:
                      if self.rendermode == self.DISPLAYLISTS and displayobj.BuildDisplayList() == 1:
                        if self.symm_diff_colour and displayobj.GetDrawSymmetryColoured(): 
                            if symm_nos[isym] < len(self.symcolp):
                              displayobj.draw_solids(self.symcolp[symm_nos[isym]],transparent,1)
                            else:
                              displayobj.draw_solids(self.whitep,transparent,1)
                        else:
                          glCallList(self.dl_solids[i])
  
                      if self.rendermode == self.IMMEDIATE or displayobj.BuildDisplayList() == 0:
                        cprim.RenderQuality.SetRenderQuality(self.render_quality)
                        if self.stereo_on and self.stereo_mode != self.QUADBUFFER and self.stereo_mode != self.SIDEBYSIDE and self.stereo_mode != self.LEFTSTEREOONLY and self.stereo_mode != self.RIGHTSTEREOONLY:
                          displayobj.draw_solids(self.whitep,transparent)
                        else:
                          displayobj.draw_solids("NULL",transparent)
                        cprim.RenderQuality.SetRenderQuality(0)
  
                    glPopMatrix()
              glPopMatrix()


    def setmaxviewsize(self,size):
        """
        Get info about how big the viewport should
        be and request resizing.
        """
        if size != self.viewsize:
           self.viewsize = size
           self.resize = 1

    def UnDefineSlab(self):
        self.slab_on = 0
        self.clip_planes[0].turn_off()
        self.clip_planes[1].turn_off()
        self.redraw = 1

        """
    def DefineFog(self,near='',far='',**keywords):        
        print "Define Fog",near,far
        if far:
          far = float(far)
          if near:
            self.FOG_END = max(min(far,self.fog_far_max),float(near)+self.near_min)
          else:
            self.FOG_END = max(min(far,self.fog_far_max),self.FOG_START+self.min_slab_delta)
        if near:
            self.FOG_START = min(max(float(near),1.0),self.FOG_END-self.min_slab_delta)
        self.resize = 1
        """

    def DefineSlab(self,width='',turn_on='',**keywords):        
        if turn_on and int(turn_on) == 1: self.slab_on = 1
        if width: self.slab_width = float(width)
        self.clip_planes[0].eqn=(0,0,1,self.slab_width/2)
        self.clip_planes[1].eqn=(0,0,-1,self.slab_width/2)
        self.redraw = 1

    def MoveSlab(self,dist):
        # We need another thing, slab depth, but somewhat redundant.
        pass

    def ExpandSlab(self,delta):
        delta = float(delta)
        self.slab_width = self.slab_width + delta
        self.DefineSlab(self.slab_width)

    def GetWindowSize(self):
      return [self.win_w,self.win_h]

    def set_default_clip_planes(self,near,far):
        self.NEAR = near
        self.FAR = far
        self.resize = 1

    def SetScreenSection(self,section,w,h):
        
        ratio = self.xyratio*w/h
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();

        glViewport(0, 0, w,  h);

        if self.projectmode == self.PERSPECTIVE:
          gluPerspective(45,ratio,self.NEAR,self.FAR); # This is obvious nonsense.

        if self.projectmode == self.ORTHO:
          if section == -1:
            glOrtho(-self.viewsize*ratio,self.viewsize*ratio, -self.viewsize,self.viewsize,self.NEAR,self.FAR);
            #glOrtho(-self.viewsize*ratio,self.viewsize*ratio, -self.viewsize,self.viewsize,self.NEAR,self.FAR);

          else:
            nsec = int(math.sqrt(self.dumpbitmap))
            j = section / nsec
            i = section -  section / nsec * nsec
            maxdim_x = self.viewsize*ratio*2 / nsec * nsec
            maxdim_y = self.viewsize*2 / nsec * nsec
            xstart = i     * maxdim_x / nsec - maxdim_x / 2
            xend   = (i+1) * maxdim_x / nsec - maxdim_x / 2
            ystart = j     * maxdim_y / nsec - maxdim_y / 2
            yend   = (j+1) * maxdim_y / nsec - maxdim_y / 2
            glOrtho(xstart,xend, ystart,yend,self.NEAR,self.FAR);
            #glOrtho(xstart,xend, ystart,yend,self.NEAR,self.FAR);

    def changeSize(self,w,h):
        """
        OpenGL resize callback function.
        """
        # FOG_START, NEAR problem with slabbing !!!!
        if h == 0:
            h = 1
        if w == 0:
            w = 1
        ratio = self.xyratio* w / h
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
        glViewport(0, 0, w, h);
        if self.projectmode == self.PERSPECTIVE:
          gluPerspective(45,ratio,self.NEAR,self.FAR);
        if self.projectmode == self.ORTHO:
            glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,self.NEAR,self.FAR);
            #glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,self.NEAR,self.FAR);
            cprim.BillBoardText().SetMatrices()
        self.movescalex = 2.0 * float(self.viewsize)/float(h) * float(self.RADIUS)/60.0
        self.movescaley = 2.0 * float(self.viewsize)/float(h) * float(self.RADIUS)/60.0

        self.rotscalex = 0.5 * 1280/w
        self.rotscaley = 0.5 * 1024/h
        self.set_rubber_band_start(-5,-5)
        self.set_rubber_band_end(w+5,h+5)
        self.win_w = w
        self.win_h = h
        if self.gl_renderer.find("Mesa DRI") > -1:
           a = dir(os)
           try:
             a.index('uname')
             renderer_string = "\"OpenGL renderer string:\""
             command = "glxinfo| grep "+renderer_string+"|grep -q \""+"Mesa DRI Intel(R) 945GM 20050225 x86/MMX/SSE2"+"\""
             rc1 = os.system(command)
             if not rc1: return
           except:
             return
           if self.default_output_buffer:
             del self.default_output_buffer
             self.default_output_buffer = 0
           self.default_output_buffer = OffScreenBuffer(self.win_w, self.win_h)
           if self.offscreen_buffer_override == 0:
             self.offscreen_buffer = self.default_output_buffer 
        glutPostRedisplay()
   
    def applystereoshear(self,obj):
        """
        Apply the quaternion rotation +- a small variation
        to get two rotation matrices which will be used to
        rotate the stereo pair. Also apply the mean rotation
        to the actual display list.
        """

        quat = obj.quat; 
        drot = obj.drot

        rotQ = pygl_coord.Quat(drot[0],drot[1],drot[2],0)
        quat.postMult(rotQ)

        glrotmat = quat.getMatrix()
	glrotmat1, glrotmat2 = pygl_coord.matrix(glrotmat), pygl_coord.matrix(glrotmat)
	shear_plus  = pygl_coord.matrix(4,4,[1,0,0,0,
                                             0,1,0,0,
                                             -0.1,0,1,0,
                                             0,0,0,1])
	shear_minus = pygl_coord.matrix(4,4,[1,0,0,0,
                                             0,1,0,0,
                                             0.1,0,1,0,
                                             0,0,0,1])
	glrotmat1 = glrotmat*shear_plus 
	glrotmat2 = glrotmat*shear_minus 

        return glrotmat1, glrotmat2

    def applystereorotation(self,obj):
        """
        Apply the quaternion rotation +- a small variation
        to get two rotation matrices which will be used to
        rotate the stereo pair. Also apply the mean rotation
        to the actual display list.
        """

        quat = obj.quat; 
        drot = obj.drot

        rotQ = pygl_coord.Quat(0,self.stereo_angle,0,0)
        quat.postMult(rotQ)
        glrotmat1 = quat.getMatrix()

        rotQ = pygl_coord.Quat(0,-2*self.stereo_angle,0,0)
        quat.postMult(rotQ)
        glrotmat2 = quat.getMatrix()

        rotQ = pygl_coord.Quat(drot[0],drot[1]+self.stereo_angle,drot[2],0)
        quat.postMult(rotQ)

        return glrotmat1, glrotmat2

    def copyrotation(self,obj1,obj2):
        """
        Copy one objects quaternion representation
        to another. Probably should be in displayobject
        class ....
        """
        obj2.quat.dval = []
        obj2.quat.dval.append(obj1.quat.dval[0])
        obj2.quat.dval.append(obj1.quat.dval[1])
        obj2.quat.dval.append(obj1.quat.dval[2])
        obj2.quat.dval.append(obj1.quat.dval[3])

    def resetrotation(self,obj):
        """
        Reset an objects quaternion representation
        to the unit representation.
        """
        obj.quat.dval = [1.0, 0.0, 0.0, 0.0 ]

    def applyorthorotations(self,obj):
        """
        Apply the rotation to the world's quaternion 
        and return the corresponding rotation matrix for the
        OpenGL transformations.
        """

        quatx =  pygl_coord.Quat( 1,0,0,1,90)
        quaty =  pygl_coord.Quat( 0,1,0,1,90)
  
        quat = obj.quat; 
        drot = obj.drot

        rotQ = pygl_coord.Quat(drot[0],drot[1],drot[2],0)
        quat.postMult(rotQ)

        quat2x = pygl_coord.Quat(quat)
        quat2x.postMult(quatx)

        quat2y = pygl_coord.Quat(quat)
        quat2y.postMult(quaty)

        glrotmat = quat.getMatrix()

        glrotmatx = quat2x.getMatrix()

        glrotmaty = quat2y.getMatrix()

        return glrotmat, glrotmatx, glrotmaty

    def applyrotation(self,obj):
        """
        Apply the rotation to the world's quaternion 
        and return the corresponding rotation matrix for the
        OpenGL transformations.
        """
  
        quat = obj.quat; 
        drot = obj.drot

        rotQ = pygl_coord.Quat(drot[0],drot[1],drot[2],0)
        quat.postMult(rotQ)

        glrotmat = quat.getMatrix()

        return glrotmat

    def getaxes(self):
        """
        Return the eyes' x,y and z axes.
        """
        dum = self.getxyz(float(self.win_w/2),float(self.win_h/2))
        xyzo = dum[1]
        xyzf = dum[0]
        dum2 = self.getxyz(float(self.win_w),float(self.win_h/2))
        xyzr = dum2[1]
        dum3 = self.getxyz(float(self.win_w/2),float(self.win_h))
        xyzu = dum3[1]
        xaxis = xyzr - xyzo
        yaxis = xyzu - xyzo
        zaxis = xyzf - xyzo

        xaxis.normalize()
        yaxis.normalize()
        zaxis.normalize()

        return xaxis,yaxis,zaxis

    def setup_fog(self):
        self.FOG_START = self.NEAR # Temporary
        self.FOG_END = self.FAR
        #print "setup_fog",self.FOG_START,self.FOG_END, self.viewsize
        """
        Apply fog.
        """
        if self.fog_on == 0:
           glDisable(GL_FOG)
           return

        dist = .5*(self.FOG_START+self.FOG_END)
        #fog_near = max(dist - self.viewsize,self.FOG_START)
        #fog_far = min(dist + 2*self.viewsize,2*self.FOG_END)
        fog_near = max(dist - ((20.*self.slab_width)/self.RADIUS), self.FOG_START)
        fog_strength = min(self.fog_strength,0.99)
        fog_far = min(dist + ((40.*self.slab_width)/self.RADIUS), self.FOG_END) - fog_strength * self.slab_width
        #print self.viewsize, dist, fog_near, fog_far, self.RADIUS
        glEnable(GL_FOG)
        fogcolour = newfv4(self.bgcolor[0],self.bgcolor[1],self.bgcolor[2],self.bgcolor[3])
        #glFogi(GL_FOG_MODE,self.fog_mode)
        glFogi(GL_FOG_MODE,GL_LINEAR)
        glFogfv(GL_FOG_COLOR, fogcolour)
        #glFogf(GL_FOG_DENSITY,float(self.fog_density))
        glFogf(GL_FOG_START,fog_near)
        glFogf(GL_FOG_END,fog_far)
        #glFogf(GL_FOG_START, self.NEAR)
        #glFogf(GL_FOG_END, self.FAR)
        #glFogf(GL_FOG_START,self.FOG_START)
        #glFogf(GL_FOG_END,self.FOG_END)
        delcGLfp(fogcolour)
        
    def set_colourmask(self,eye):
        """
        Determine and set the colour mask for each eye
        when doing colour filter stereo.
        """
        glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);
        if eye == "left":
          if self.stereo_mode == self.REDBLUE or self.stereo_mode == self.REDGREEN or self.stereo_mode == self.REDCYAN:
            glColorMask(GL_TRUE,GL_FALSE,GL_FALSE,GL_TRUE);
          if self.stereo_mode == self.BLUERED: 
            glColorMask(GL_FALSE,GL_FALSE,GL_TRUE,GL_TRUE);
          if self.stereo_mode == self.GREENRED: 
            glColorMask(GL_FALSE,GL_TRUE,GL_FALSE,GL_TRUE);
          if self.stereo_mode == self.CYANRED: 
            glColorMask(GL_FALSE,GL_TRUE,GL_TRUE,GL_TRUE);
        else:
          if self.stereo_mode == self.REDBLUE:
            glColorMask(GL_FALSE,GL_FALSE,GL_TRUE,GL_TRUE);
          if self.stereo_mode == self.REDGREEN:
            glColorMask(GL_FALSE,GL_TRUE,GL_FALSE,GL_TRUE);
          if self.stereo_mode == self.REDCYAN:
            glColorMask(GL_FALSE,GL_TRUE,GL_TRUE,GL_TRUE);
          if self.stereo_mode == self.BLUERED or self.stereo_mode == self.GREENRED or self.stereo_mode == self.CYANRED:
            glColorMask(GL_TRUE,GL_FALSE,GL_FALSE,GL_TRUE);

    def DrawAxes(self,glrotmat,w,h):
        glDisable(GL_CLIP_PLANE0)
        glDisable(GL_CLIP_PLANE1)
        glPushMatrix()
        glLoadIdentity()
        glDepthFunc(GL_ALWAYS);
        glDisable(GL_BLEND);
        glDisable(GL_LIGHTING)
        if self.smooth_line:
          glEnable(GL_BLEND);
          glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
          glEnable(GL_LINE_SMOOTH);
        else:
          glDisable(GL_LINE_SMOOTH);
        glColor3f(1-self.bgcolor[0],1-self.bgcolor[1],1-self.bgcolor[2])
        ratio = self.xyratio* w / h
        scale_x = self.viewsize*ratio
        scale_y = self.viewsize
        glTranslatef(0,0,-40)

        glScalef(self.viewsize,self.viewsize,self.viewsize);
        glTranslatef(0.8*ratio,0.8,0)
        matp1 = glrotmat.to_dp()
        glMultMatrixd(matp1)
        deldp(matp1)
        glLineWidth(1.0);
        glBegin(GL_LINES)
        glVertex3f(0,0,0)
        glVertex3f(0.1,0,0)
        glVertex3f(0,0,0)
        glVertex3f(0,0.1,0)
        glVertex3f(0,0,0)
        glVertex3f(0,0,0.1)
        glVertex3f(0.1,0,0)
        glVertex3f(0.08,0.01,0)
        glVertex3f(0.1,0,0)
        glVertex3f(0.08,-0.01,0)
        glVertex3f(0,0.1,0)
        glVertex3f(0.01,0.08,0)
        glVertex3f(0,0.1,0)
        glVertex3f(-0.01,0.08,0)
        glVertex3f(0,0,0.1)
        glVertex3f(0.01,0,0.08)
        glVertex3f(0,0,0.1)
        glVertex3f(-0.01,0,0.08)
        glEnd()
        glDisable(GL_FOG);
        glDisable(GL_LIGHTING);

        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        glPixelTransferi(GL_MAP_COLOR,GL_TRUE);

        glPixelStorei(GL_UNPACK_SWAP_BYTES, GL_FALSE);
        glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE);
        glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
        glPixelStorei(GL_UNPACK_SKIP_ROWS, 0);
        glPixelStorei(GL_UNPACK_SKIP_PIXELS, 0);
        glPixelStorei(GL_UNPACK_ALIGNMENT, 1);

        if font_cache.FontCache().NumberOfFonts() > 0 and (not self.axes_x or not self.axes_y or not self.axes_z):
          cart = pygl_coord.Cartesian(0.13,0,0)
          self.axes_x = cprim.Text(pygl_coord.Cartesian(0.13,0,0),'x',cart)
          self.axes_x.SetFontSize(18)
          cart = pygl_coord.Cartesian(0,0.13,0)
          self.axes_y = cprim.Text(pygl_coord.Cartesian(0,0.13,0),'y',cart)
          self.axes_y.SetFontSize(18)
          cart = pygl_coord.Cartesian(0,0,0.13)
          self.axes_z = cprim.Text(pygl_coord.Cartesian(0,0,0.13),'z',cart)
          self.axes_z.SetFontSize(18)
        if self.axes_x and self.axes_y and self.axes_z:
          self.axes_x.SetColour(1-self.bgcolor[0],1-self.bgcolor[1],1-self.bgcolor[2],1)
          self.axes_x.draw()
          self.axes_y.draw()
          self.axes_z.draw()
        glPopMatrix()
        glDepthFunc(GL_LESS);

    def draw_scene(self,w,h):

      glMatrixMode(GL_MODELVIEW);
      glLoadIdentity();

      if self.NEAR> 60 or self.FAR < 60 or (self.FAR-self.NEAR)<60 or 1:
        dist = .5*(self.NEAR+self.FAR)
      else:
        dist = 60
      glTranslatef(0,0,-dist)
      if self.projectmode == self.ORTHO:
        glScalef(60.0/float(self.RADIUS),60.0/float(self.RADIUS),60.0/float(self.RADIUS))
      #glTranslatef(0,0,-.5*(self.NEAR+self.FAR))
      #print self.NEAR,self.FAR,.5*(self.NEAR+self.FAR),self.slab_width, self.RADIUS, self.rpos[2]

      self.setup_lighting()
      self.setup_clipping()
      self.setup_fog()

      glClearColor(self.bgcolor[0],self.bgcolor[1],self.bgcolor[2],self.background_alpha)
      if self.antialias:
        if self.hardware_stereo_available == 1:
          if self.stereo_on > 0:
            glDrawBuffer (GL_BACK_LEFT);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)
            glDrawBuffer (GL_BACK_RIGHT);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)
          else:
            glDrawBuffer (GL_BACK);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)
        else:
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ACCUM_BUFFER_BIT)
      else:
        if self.hardware_stereo_available == 1:
          if self.stereo_on > 0:
            glDrawBuffer (GL_BACK_LEFT);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
            glDrawBuffer (GL_BACK_RIGHT);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
          else:
            glDrawBuffer (GL_BACK);
            glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
        else:
          glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
      
      glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

      if self.stereo_on > 0:
	if self.stereo_view_style == self.SHEAR_STEREO:
          glrotmat1, glrotmat2  = self.applystereoshear(self)
	else:
          glrotmat1, glrotmat2  = self.applystereorotation(self)
        matp1 = glrotmat1.to_dp()
        glMultMatrixd(matp1)
        deldp(matp1)
        self.xaxis,self.yaxis,self.zaxis = self.getaxes()
        self.rpos = self.movexyz(self.rpos,(self.dx,self.dy,self.dz))
        self.calculate_extents()
        glTranslatef(self.rpos[0],self.rpos[1],self.rpos[2])

        stereoseparation = self.stereoseparation
        if self.stereo_mode == self.QUADBUFFER:
          stereoseparation = 0
        stereox,stereoy,stereoz = self.movexyz((0,0,0),(self.RADIUS/60.0*float(stereoseparation),0.0,0.0))
        glTranslatef(stereox,stereoy,stereoz)

        if self.stereo_mode == self.REDBLUE or self.stereo_mode == self.REDGREEN or self.stereo_mode == self.REDCYAN:
          self.set_colourmask("left")

        if self.stereo_mode != self.LEFTSTEREOONLY:
          self.drawlists()
        

        if self.stereo_mode == self.REDBLUE or self.stereo_mode == self.REDGREEN or self.stereo_mode == self.REDCYAN:
          glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

        glMatrixMode(GL_MODELVIEW);
        glLoadIdentity();
        if self.NEAR> 60 or self.FAR < 60 or (self.FAR-self.NEAR)<60 or 1:
          dist = .5*(self.NEAR+self.FAR)
        else:
          dist = 60
        glTranslatef(0,0,-dist)
        if self.projectmode == self.ORTHO:
          glScalef(60.0/float(self.RADIUS),60.0/float(self.RADIUS),60.0/float(self.RADIUS))

        matp2 = glrotmat2.to_dp()
        glMultMatrixd(matp2)
        deldp(matp2)
        self.xaxis,self.yaxis,self.zaxis = self.getaxes()
        glTranslatef(self.rpos[0],self.rpos[1],self.rpos[2])

        stereox,stereoy,stereoz = self.movexyz((0,0,0),(self.RADIUS/60.0*float(-stereoseparation),0.0,0.0))
        glTranslatef(stereox,stereoy,stereoz)

        if self.stereo_mode != self.QUADBUFFER:
          glClear(GL_DEPTH_BUFFER_BIT);
        if self.stereo_mode == self.REDBLUE or self.stereo_mode == self.REDGREEN or self.stereo_mode == self.REDCYAN:
          self.set_colourmask("right")
        if self.stereo_mode == self.QUADBUFFER:
          glDrawBuffer (GL_BACK_LEFT);
          glClear(GL_DEPTH_BUFFER_BIT|GL_COLOR_BUFFER_BIT)

        if self.stereo_mode != self.RIGHTSTEREOONLY:
          self.drawlists()

        if self.stereo_mode == self.REDBLUE or self.stereo_mode == self.REDGREEN or self.stereo_mode == self.REDCYAN:
          glColorMask(GL_TRUE,GL_TRUE,GL_TRUE,GL_TRUE);

        if self.show_axes and self.stereo_mode != self.QUADBUFFER:
           self.DrawAxes((glrotmat1+glrotmat2)*0.5,w,h)
        if self.show_axes and self.stereo_mode == self.QUADBUFFER:
          self.DrawAxes(glrotmat1,w,h)
          self.DrawAxes(glrotmat2,w,h)

      else:
        #print "orient applying drot",self.drot
        glrotmat = self.applyrotation(self)
     
        matp = glrotmat.to_dp()
        glMultMatrixd(matp)
        deldp(matp)
        self.xaxis,self.yaxis,self.zaxis = self.getaxes()

        self.rpos = self.movexyz(self.rpos,(self.dx,self.dy,self.dz))
        self.calculate_extents()
        glTranslatef(self.rpos[0],self.rpos[1],self.rpos[2])
        self.drawlists()
        if self.show_axes:
          self.DrawAxes(glrotmat,w,h)

      self.setup_clipping() # So that the setting can be picked up by screen grabs, etc.


    def orient(self):
      self.CheckKeysAndMouseStatus()

      if self.dumpbitmap and self.request_render_quality:
        self.rebuild_lists = 1
        self.render_quality = 1
        self.rendermode = self.IMMEDIATE
      else:
        self.rendermode = self.DISPLAYLISTS

      if self.dumpbitmap and self.offscreen_buffer:
        if sys.platform != "win32":
          screen_width=glutGet(GLUT_SCREEN_WIDTH)
          screen_height=glutGet(GLUT_SCREEN_HEIGHT)
          if self.offscreen_buffer.GetWidth() > screen_width or self.offscreen_buffer.GetHeight() > screen_height:
             ntiles_w = (self.offscreen_buffer.GetWidth()+screen_width-1)/screen_width
             ntiles_h = (self.offscreen_buffer.GetHeight()+screen_height-1)/screen_height
             ntiles = max(ntiles_w,ntiles_h)
             new_width = self.offscreen_buffer.GetWidth()/ntiles
             new_height = self.offscreen_buffer.GetHeight()/ntiles
             self.dumpbitmap = ntiles*ntiles
             self.offscreen_buffer = OffScreenBuffer(new_width,new_height)
        self.setup_lighting()
        self.setup_clipping()
        self.setup_fog()
        ratio = self.xyratio* self.offscreen_buffer.GetWidth() / self.offscreen_buffer.GetHeight()
        self.offscreen_buffer.MakeCurrent()
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT,GL_AMBIENT_AND_DIFFUSE)
        glEnable(GL_NORMALIZE);
        glHint(GL_LINE_SMOOTH_HINT,GL_NICEST);
        cprim.ForceLoadTextures()
        glEnable(GL_DEPTH_TEST);
        glPolygonMode(GL_FRONT,GL_FILL);
        glMatrixMode(GL_PROJECTION);
        glLoadIdentity();
	self.BuildPrimitiveDisplayList()
        glViewport(0, 0, self.offscreen_buffer.GetWidth(), self.offscreen_buffer.GetHeight()
);
        glOrtho(-self.viewsize*ratio,self.viewsize*ratio,-self.viewsize,self.viewsize,max(self.FOG_START,self.NEAR),min(self.FOG_END+self.viewsize,self.FAR));
        w = self.offscreen_buffer.GetWidth(); h = self.offscreen_buffer.GetHeight()
        cprim.BillBoardText().SetMatrices()
	# Always do this incase we have a new context
	self.rebuild_lists = 1
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_LIGHTING);
        glPolygonMode(GL_FRONT,GL_FILL)
        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_NORMAL_ARRAY);


      else:
        w = self.win_w; h = self.win_h
        if self.update_matrices:
          cprim.BillBoardText().SetMatrices()
          self.update_matrices = 0

      if self.stop == 1:
	return

      self.CheckErrors("CheckErrors at start of orient")

      """
      OpenGL display callback function. This does world/camera
      positioning and orientation and all basic initializations
      before drawing everything. Also sets up the stereo pair
      views as required.
      """
      self.glready.clear()

      orig_anti = self.antialias

      if self.dumpbitmap > 0:
         if self.antialias_screenshot:
            self.antialias = 1

      if self.dumpbitmap > 1:
        if self.section == self.dumpbitmap:
          self.dumpbitmap = 0
          self.section = 0
          self.SetScreenSection(-1,w,h)
          self.idle_pause = self.old_idle_pause
        elif self.dumpbitmap != 0:
          self.SetScreenSection(self.section,w,h)

      self.draw_scene(w,h)
      if self.dumpbitmap and self.offscreen_buffer and self.mirror_buffers:
        self.onscreen_buffer.MakeCurrent()
        self.draw_scene(w,h)
        # and we'll have to swap buffers if this is a double buffer ...

      self.dx = 0
      self.dy = 0
      self.dz = 0
      self.drot = (0.0,0.0,0.0)

      if self.dumpbitmap > 1:
        if self.offscreen_buffer == 0 and sys.platform == "darwin": glReadBuffer(GL_BACK)
        #self.redraw = 1 # Hmm, might I need this?
        self.screenshot()
        self.section = self.section + 1
	if self.offscreen_buffer == 0 and sys.platform == "darwin": glReadBuffer(GL_FRONT)
        self.render_quality = 0
        self.rendermode = self.DISPLAYLISTS

      if self.dumpbitmap == 1:
        if self.offscreen_buffer == 0 and sys.platform == "darwin": glReadBuffer(GL_BACK)
	glFlush()
        self.screenshot()
        self.dumpbitmap = 0
	if self.offscreen_buffer == 0 and sys.platform == "darwin": glReadBuffer(GL_FRONT)
        if self.offscreen_buffer:
          cprim.UnForceLoadTextures()
          self.update_matrices = 1
        self.render_quality = 0
        self.rendermode = self.DISPLAYLISTS

      if not self.offscreen_buffer:
        glutSwapBuffers();

      if self.dumpbitmap and self.offscreen_buffer:
        self.onscreen_buffer.MakeCurrent()

      if self.dumpps == 1:
        self.DrawPostscript()
        self.dumpps = 0

      if self.dumppov == 1:
        self.DrawPovRay()
        self.dumppov = 0

      if self.antialias_screenshot:
         self.antialias = orig_anti

      self.glready.set()
      if self.dumpbitmap == 0 and self.offscreen_buffer:
        del self.offscreen_buffer
        self.offscreen_buffer = 0

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

    def calculate_extents(self):
        xaxis,yaxis,zaxis = self.xaxis,self.yaxis,self.zaxis
        ratio = self.xyratio* self.win_w / self.win_h

        tr = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        tl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() + self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() + self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 + self.viewsize*yaxis.get_z()]
        bl = [self.rpos[0] + self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] + self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] + self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        br = [self.rpos[0] - self.viewsize*ratio*xaxis.get_x() - self.viewsize*yaxis.get_x(), self.rpos[1] - self.viewsize*ratio*xaxis.get_y() - self.viewsize*yaxis.get_y(), self.rpos[2] - self.viewsize*ratio*xaxis.get_z()/2.0 - self.viewsize*yaxis.get_z()]
        self.extents = [tl,tr,br,bl]

    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 bgcolour(self,colour):
        """
        Set the background colour.
        """
        import COLOUR
        self.bgcolor = COLOUR.COLOUR.insts.RGB(colour)
        self.redraw = 1

    def zoom_camera(self,zoom):
        """
        Zoom in and out
        """
        if self.weighted_zoom:
          self.RADIUS = self.RADIUS + self.zoom_warp* (zoom * self.RADIUS/30.0)
        else:
          self.RADIUS = self.RADIUS +  self.zoom_warp*zoom
        if self.RADIUS < .5:
          self.RADIUS =.5 
        #print "zoom_camera",zoom,self.viewsize,self.win_w,self.RADIUS
        self.movescalex = 2.0 * float(self.viewsize)/float(self.win_w) * float(self.RADIUS)/60.0
        self.movescaley = 2.0 * float(self.viewsize)/float(self.win_w) * float(self.RADIUS)/60.0
        #self.redraw = 1

    def SetRotation(self,q=''):
        """
        Define a standard orientation
        """
        if q: self.quat = q
        self.redraw = 1
        
    def move_camera(self,dx,dy,dz):
        """
        Move camera around.
        """
        self.dx = self.dx + dx
        self.dy = self.dy + dy
        self.dz = self.dz + dz

    def move_camera_scale(self,dx,dy,dz):
      #print "move_camera_str",self.movescaley
      self.move_camera(float(dx)*self.movescalex,float(dy)*self.movescaley,float(dz)*self.movescaley)
      
    def rotate_camera(self,drot):
        """
        Pick up info about world rotation which
        will be used in quaternion calculations.
        """
        self.drot = (drot[0]+self.drot[0],drot[1]+self.drot[1],drot[2]+self.drot[2])

    def getmodifiers(self):
        """
        Find out which modifiers are pressed.
        """
        glmods = glutGetModifiers()
        shift = 0
        ctrl = 0
        alt = 0
        if glmods|GLUT_ACTIVE_SHIFT == glmods :
           shift = 1
        if glmods|GLUT_ACTIVE_CTRL == glmods :
           ctrl = 1
        if glmods|GLUT_ACTIVE_ALT == glmods :
           alt = 1
        mods = [0,0,0]
        mods[self.SHIFT] = shift
        mods[self.CTRL] = ctrl
        mods[self.ALT] = alt

        return mods
        #return [ shift, ctrl, alt ]

    def GetWorldXY(self):
        world_x = intp()
        world_y = intp()
        GetWorldMousePosition(world_x, world_y)
        x = world_x.value()
        y = world_y.value()
        return (x,y) 
 
    def GetScreenBox(self):
        xyzs = [ self.getxyz(0,self.win_h),self.getxyz(0,0), self.getxyz(self.win_w,0), self.getxyz(self.win_w,self.win_h) ]

        #print "GetScreenBox self.screen_box",self.screen_box
        if not self.screen_box: 
          xyzbox = CartesianVector()
        else:
          xyzbox = self.screen_box
          while len(xyzbox)>0:
            xyzbox.pop()
        xyzbox.append(xyzs[0][0]); xyzbox.append(xyzs[0][1]); xyzbox.append(xyzs[1][0]); xyzbox.append(xyzs[1][1]);
        xyzbox.append(xyzs[2][0]); xyzbox.append(xyzs[2][1]); xyzbox.append(xyzs[3][0]); xyzbox.append(xyzs[3][1]);
        #print "GetScreenBox xyzbox",xyzbox
        return xyzbox

    def GetXYZBox(self, x, y):
        xyzs = [ self.getxyz(x-10,y+10),self.getxyz(x-10,y-10), self.getxyz(x+10,y-10), self.getxyz(x+10,y+10) ]
        xyzbox = CartesianVector()
        xyzbox.append(xyzs[0][0]); xyzbox.append(xyzs[0][1]); xyzbox.append(xyzs[1][0]); xyzbox.append(xyzs[1][1]);
        xyzbox.append(xyzs[2][0]); xyzbox.append(xyzs[2][1]); xyzbox.append(xyzs[3][0]); xyzbox.append(xyzs[3][1]);
        return xyzbox

    def mouse(self, button, state, x, y):
        """
        Mouse callback function. Dispatch events
        to job queue.
        """
        screenx, screeny = self.GetWorldXY()

        xyzbox = self.GetXYZBox(x,y)

        self.modifiers = self.getmodifiers()
        if sys.platform == 'darwin':
           if button == 0 and self.modifiers[1] == 1:
             button = 2
             self.modifiers[1] = 0

        if state==GLUT_DOWN:
           if button==GLUT_LEFT_BUTTON:
             self.BUTTON_PRESSED = self.LEFT_MOTION
           elif button==GLUT_RIGHT_BUTTON:
             self.BUTTON_PRESSED = self.RIGHT_MOTION
           elif button==GLUT_MIDDLE_BUTTON:
             self.BUTTON_PRESSED = self.MIDDLE_MOTION

        binfo = {}
        binfo["button"] = button
        binfo["state"] = state
        binfo["x"] = x
        binfo["y"] = y
        binfo["xyzbox"] = xyzbox
        binfo["screenx"] = screenx
        binfo["screeny"] = screeny
        binfo["window"] = glutGetWindow()
        binfo["key_presses"] = self.key_presses
        binfo["time"] = time.time()

        if button==3:
          job = [  self.WHEEL_UP,   binfo ]
        elif button==4:
          job = [  self.WHEEL_DOWN, binfo ]
        elif button==2:
          job = [  self.MOUSE,      binfo ]
        else:
          job = [  self.MOUSE,      binfo ]

        if state == GLUT_DOWN:
           self.start_x = x
           self.start_y = y
        else:
           if self.moving:
             self.mouse_event = []
             self.moving = 0
             glutPostRedisplay()
             return
           self.moving = 0


        #self.glevent.glevent(job)
        if button == 2 or button == 3 or button == 4:
          self.glevent.glevent(job)
        else:
          self.mouse_event.append(job)
          endjob = self.mouse_event[len(self.mouse_event)-1]
          job1 = self.mouse_event[0]
          if len(self.mouse_event) == 2 or len(self.mouse_event) == 4:
            job2 = self.mouse_event[1]
            if len(self.mouse_event) == 4:
              binfo["state"] = 2
              self.click_timer.cancel()
              self.click_timer = threading.Timer(0.0,nullfunc)
              self.click_timer.start()
              job = [  self.MOUSE,      binfo ]
              self.glevent.glevent(job)
              self.mouse_event = []
            else:
              self.click_timer = threading.Timer(0.5,self.ClearMouseEvents)
              self.click_timer.start()
              self.glevent.glevent(job1)
              self.glevent.glevent(job2)
          if len(self.mouse_event) > 4:
            self.mouse_event = []

        glutPostRedisplay()
    
    def ClearMouseEvents(self):
        self.mouse_event = []
        self.click_timer = threading.Timer(0.0,nullfunc)
        self.click_timer.start()
 
    def entry(self, state):
        if state == GLUT_LEFT:
          for key in range(128):
            self.old_key_presses[key] = self.key_presses[key]
            self.key_presses[key] = 0
            self.old_special_presses[key] = self.key_presses[key]
            self.special_presses[key] = 0
        else:
          for key in range(128):
            self.key_presses[key] = self.old_key_presses[key]
            self.special_presses[key] = self.old_special_presses[key]

    def keyboard_up(self, key, x, y):
        if key>128: return
        if self.key_presses[key]: self.key_presses[key] = -1
        self.modifiers = self.getmodifiers()
        shift_key = ShiftKey(key)
        if shift_key<=128 and self.key_presses[shift_key]:
          self.key_presses[shift_key] = -1
        no_shift_key=NoShiftKey(key)
        if no_shift_key<=128 and self.key_presses[no_shift_key]:
          self.key_presses[no_shift_key] = -1
        self.screen_x, self.screen_y = self.GetWorldXY()
	if self.key_presses.count(1) > 0 or self.key_presses.count(-1) > 0:
	  self.keyboard_is_active = 1
        else:
	  self.keyboard_is_active = 0
        glutPostRedisplay()
        
    def keyboard(self, key, x, y):
        """
        Keyboard callback function. Dispatch events
        to job queue.
        """
        if key>128: return
        self.modifiers = self.getmodifiers()
        self.key_presses[key] = 1
        self.screen_x, self.screen_y = self.GetWorldXY()
	if self.key_presses.count(1) > 0 or self.key_presses.count(-1) > 0:
	  self.keyboard_is_active = 1
        else:
	  self.keyboard_is_active = 0
        glutPostRedisplay()
    
    def special(self, key, x, y):
        """
        Special Key callback function. Dispatch events
        to job queue.
        """
        if key>128: return
        self.special_presses[key] = 1
        self.modifiers = self.getmodifiers()
        self.screen_x, self.screen_y = self.GetWorldXY()
	if self.special_presses.count(1) > 0 or self.special_presses.count(-1) > 0:
	  self.special_is_active = 1
        else:
	  self.special_is_active = 0
        glutPostRedisplay()

    def special_up(self, key, x, y):
        if key>128: return
        self.special_presses[key] = 0
        self.modifiers = self.getmodifiers()
        self.screen_x, self.screen_y = self.GetWorldXY()
	if self.special_presses.count(1) > 0 or self.special_presses.count(-1) > 0:
	  self.special_is_active = 1
        else:
	  self.special_is_active = 0
        glutPostRedisplay()
    
    def passive(self, x, y):

        self.mouse_x = x
        self.mouse_y = y

    def SendMotionEvent(self,dx,dy,x,y):
        mods = CheckModifiers();

        if mods > -1:
          shift = 0
          ctrl = 0
          alt = 0
          if mods|GLUT_ACTIVE_SHIFT == mods :
            shift = 1
          if mods|GLUT_ACTIVE_CTRL == mods :
            ctrl = 1
          if mods|GLUT_ACTIVE_ALT == mods :
            alt = 1
          mods = [0,0,0]
          mods[self.SHIFT] = shift
          mods[self.CTRL] = ctrl
          mods[self.ALT] = alt
          self.modifiers = mods

        xyzbox = self.GetXYZBox(x,y)

        binfo = {}
        binfo["x"] = x
        binfo["y"] = y
        binfo["dx"] = dx
        binfo["dy"] = dy
        binfo["xyzbox"] = xyzbox
        binfo["window"] = glutGetWindow()
        binfo["key_presses"] = self.key_presses

        job = [  self.BUTTON_PRESSED, binfo ]
        self.glevent.glevent(job)

    def motion(self, x, y):

        self.moving = 1
        self.mouse_x = x
        self.mouse_y = y
        glutPostRedisplay()

    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 = inta(4)
	mvmatrix = doublea(16)
	projmatrix = doublea(16)
	wx = doublep()
	wy = doublep()
	wz = doublep()

        glGetIntegerv(GL_VIEWPORT,viewport);
        glGetDoublev(GL_PROJECTION_MATRIX,projmatrix);
        glGetDoublev(GL_MODELVIEW_MATRIX,mvmatrix);
        realy = viewport[3] - y - 1;
        gluUnProject(x,realy,0.0,mvmatrix,projmatrix,viewport,wx,wy,wz);
	cart1 = Cartesian(wx.value(), wy.value(), wz.value())
        gluUnProject(x,realy,1.0,mvmatrix,projmatrix,viewport,wx,wy,wz);
	cart2 = Cartesian(wx.value(), wy.value(), wz.value())
	cv = CartesianVector()
	cv.append(cart1)
	cv.append(cart2)
        del viewport
        del mvmatrix
        del projmatrix
        del wx
        del wy
        del wz
	return cv;

    def get_pixdata(self):
        return image_infoPtr(get_pixdata(int(math.ceil(self.background_alpha))))

    def screenshot(self,name=""):

        import tempfile
        import os
        import shutil
        temp_filename = tempfile.mktemp()
        if name != "":
          temp_filename = name #temp_filename + name[name.rfind('.'):]
          if self.offscreen_buffer:
            self.offscreen_buffer.Write(temp_filename,self.screenshot_width,self.screenshot_height,int(math.ceil(self.background_alpha)))
          else:
            write_pixdata(temp_filename,self.screenshot_width,self.screenshot_height,int(math.ceil(self.background_alpha)))
        else:
          name = self.screenshot_filename
          temp_filename = name #temp_filename + name[name.rfind('.'):]
          if self.dumpbitmap > 1:
            if self.section == 0:
              self.screen_sections = ImageInfoVector()
            if self.offscreen_buffer:
              iinfo = image_infoPtr(self.offscreen_buffer.get_pixdata(int(math.ceil(self.background_alpha))))
            else:
              iinfo = self.get_pixdata()
            iinfo.invert()
            self.screen_sections.append(iinfo)
            if self.section == self.dumpbitmap - 1:
              nsec = int(math.sqrt(self.dumpbitmap))
              b = []
              for i in range(nsec):
                a = []
                for j in range(nsec):
                  a.append(i*nsec+j)
                b.append(a)
              b.reverse()
              ii = IntIntVector()
              for a in b:
                ii.append(a)
              iinfo = image_info(self.screen_sections,ii)
              iinfo.write(temp_filename)
          else:
            if self.offscreen_buffer:
              self.offscreen_buffer.Write(temp_filename,self.screenshot_width,self.screenshot_height,int(math.ceil(self.background_alpha)))
            else:
              write_pixdata(temp_filename,self.screenshot_width,self.screenshot_height,int(math.ceil(self.background_alpha)))

          """
          try:
            shutil.copy(temp_filename,name)
          except:
            print "Failed to write file", name, "."
          """

    def request_screenshot(self,filename="screendump.ppm",antialias=0,sections=0,blocking=1,width=-1,height=-1,render_quality=1):
        """
        Save a Bitmap.
        """
        self.request_render_quality = render_quality
	if blocking:
          self.glready.wait(3000)
          self.glready.set()
        if antialias:
          self.antialias_screenshot = 1
        else:
          self.antialias_screenshot = 0

        self.screenshot_filename = filename
        self.screenshot_width = width
        self.screenshot_height = height
        if sections > 0:
          self.dumpbitmap = sections
          self.old_idle_pause = self.idle_pause
          self.idle_pause = 0.0
        else:
          self.dumpbitmap = 1

	if blocking:
          self.glready.clear()
        
    def request_screenshot_ps(self,filename="screendump.ps"):
        """
        Save a PostScript File.
        """
        self.ps_filename = filename
        self.dumpps = 1

    def request_screenshot_pov(self,filename="screendump.pov"):
        """
        Save a PovRay input File.
        """
        self.pov_filename = filename
        self.dumppov = 1

    def UnPause(self):
        self.redraw = 1
        self.glpause.set()

    def Pause(self,hard=0):
        if hard:
	  self.glready.wait(3000)
        self.glpause.clear()

    def Wait(self):
        """
        This blocks until end of self.orient, ie rendering is finished.
        """
        self.glready.wait(3000)
        self.glready.clear()

    def Flush(self):
        """
        This blocks until end of self.orient, ie rendering is finished.
        """
        self.glready.wait(3000)
        self.glready.clear()
        self.glready.wait(3000)

    def set_rubber_band_start(self,x,y):
        self.rubber_band_start = (x,y)
        self.rubber_band_end = (x,y)
        self.define_rubber_band_cube()

    def set_rubber_band_end(self,x,y):
        self.rubber_band_end = (x,y)
        self.define_rubber_band_cube()

    def define_rubber_band_cube(self):

        xyz1 = self.getxyz(self.rubber_band_start[0],self.rubber_band_start[1])
        xyz2 = self.getxyz(self.rubber_band_start[0],self.rubber_band_end[1])
        xyz3 = self.getxyz(self.rubber_band_end[0],self.rubber_band_end[1])
        xyz4 = self.getxyz(self.rubber_band_end[0],self.rubber_band_start[1])
        self.rubber_band_box.p0 = xyz1[0]
        self.rubber_band_box.p1 = xyz2[0]
        self.rubber_band_box.p2 = xyz3[0]
        self.rubber_band_box.p3 = xyz4[0]
        self.rubber_band_box.p4 = xyz1[1]
        self.rubber_band_box.p5 = xyz2[1]
        self.rubber_band_box.p6 = xyz3[1]
        self.rubber_band_box.p7 = xyz4[1]

    def get_clipping_planes(self):

        M = self.quat.getInvMatrix()

        triangles = []
        for plane in self.clip_planes:
          triangle_rotated = []
          triangle = util.find_points_on_plane(plane.eqn)
          rotatedp = util.matrixXvector(M,triangle[1])
          transrotp = util.vsubv(rotatedp,self.rpos)
          transrotp = util.vsubv(transrotp,self.rpos)
          triangle_rotated.append(transrotp)
          rotatedp = util.matrixXvector(M,triangle[0])
          transrotp = util.vsubv(rotatedp,self.rpos)
          transrotp = util.vsubv(transrotp,self.rpos)
          triangle_rotated.append(transrotp)
          rotatedp = util.matrixXvector(M,triangle[2])
          transrotp = util.vsubv(rotatedp,self.rpos)
          transrotp = util.vsubv(transrotp,self.rpos)
          triangle_rotated.append(transrotp)
          triangles.append(triangle_rotated)
          
        return triangles

    def get_rubber_band_planes(self):
        """
        This returns sets of planes defined by what is rubber banded
        on screen. It should have a better name and also
        return general clipping planes.
        """
        box = self.rubber_band_box
        return [Plane(box.p0,box.p1,box.p2),\
                Plane(box.p4,box.p7,box.p6),\
                Plane(box.p0,box.p4,box.p5),\
                Plane(box.p2,box.p6,box.p7),\
                Plane(box.p0,box.p3,box.p7),\
                Plane(box.p1,box.p5,box.p6)]
