text: # A translation of the gears demo that comes with mesa.
  # Conversion from gtk.gl module to PyGtkGLExt by Naofumi Yasufuku
  # Conversion to PyGUI by Greg Ewing
  
  import math
  from GUI import Window, Task, application
  from GUI.GL import GLView
  from OpenGL import GL
  
  frame_interval = 0.01
  rotation_step = 5.0
  
  rotations = {
  	'up_arrow':    (-rotation_step, 0.0, 0.0),
  	'down_arrow':  ( rotation_step, 0.0, 0.0),
  	'left_arrow':  (0.0, -rotation_step, 0.0),
  	'right_arrow': (0.0,  rotation_step, 0.0),
  }
  
  #----------------------------------------------------------------------------
  
  # Draw a gear wheel.	You'll probably want to call this function when
  # building a display list since we do a lot of trig here.
  #
  #  Input:
  #    inner_radius - radius of hole at center
  #    outer_radius - radius at center of teeth
  #    width - width of gear
  #    teeth - number of teeth
  #    tooth_depth - depth of tooth
  def gear(inner_radius, outer_radius, width, teeth, tooth_depth):
  		cos = math.cos
  		sin = math.sin
  		
  		r0 = inner_radius
  		r1 = outer_radius - tooth_depth/2.0
  		r2 = outer_radius + tooth_depth/2.0
  		
  		da = 2.0*math.pi / teeth / 4.0
  		
  		GL.glShadeModel(GL.GL_FLAT)
  		
  		GL.glNormal3f(0.0, 0.0, 1.0)
  		
  		# draw front face 
  		GL.glBegin(GL.GL_QUAD_STRIP)
  		for i in range(teeth + 1):
  			angle = i * 2.0*math.pi / teeth
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5)
  			GL.glVertex3f(r1*cos(angle), r1*sin(angle), width*0.5)
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5)
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5)
  		GL.glEnd()
  		
  		# draw front sides of teeth
  		GL.glBegin(GL.GL_QUADS)
  		da = 2.0*math.pi / teeth / 4.0
  		for i in range(teeth):
  			angle = i * 2.0*math.pi / teeth
  			GL.glVertex3f(r1*cos(angle),			r1*sin(angle),			width*0.5)
  			GL.glVertex3f(r2*cos(angle+da),		r2*sin(angle+da),		width*0.5)
  			GL.glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5)
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5)
  		GL.glEnd()
  		
  		GL.glNormal3f(0.0, 0.0, -1.0)
  		
  		# draw back face
  		GL.glBegin(GL.GL_QUAD_STRIP)
  		for i in range(teeth + 1):
  			angle = i * 2.0 * math.pi / teeth
  			GL.glVertex3f(r1*cos(angle), r1*sin(angle), -width*0.5)
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5)
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da),-width*0.5)
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5)
  		GL.glEnd()
  		
  		# draw back sides of teeth
  		GL.glBegin(GL.GL_QUADS)
  		da = 2.0*math.pi / teeth / 4.0
  		for i in range(teeth):
  			angle = i * 2.0*math.pi / teeth
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da),-width*0.5)
  			GL.glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da),-width*0.5)
  			GL.glVertex3f(r2*cos(angle+da),		r2*sin(angle+da),	 -width*0.5)
  			GL.glVertex3f(r1*cos(angle),			r1*sin(angle),		 -width*0.5)
  		GL.glEnd()
  		
  		# draw outward faces of teeth
  		GL.glBegin(GL.GL_QUAD_STRIP)
  		for i in range(teeth):
  			angle = i * 2.0*math.pi / teeth
  			GL.glVertex3f(r1*cos(angle), r1*sin(angle),	 width*0.5)
  			GL.glVertex3f(r1*cos(angle), r1*sin(angle), -width*0.5)
  			u = r2*cos(angle+da) - r1*cos(angle)
  			v = r2*sin(angle+da) - r1*sin(angle)
  			len = math.sqrt(u*u + v*v)
  			u = u / len
  			v = v / len
  			GL.glNormal3f(v, -u, 0.0)
  			GL.glVertex3f(r2*cos(angle+da),		r2*sin(angle+da),		width*0.5)
  			GL.glVertex3f(r2*cos(angle+da),		r2*sin(angle+da),	 -width*0.5)
  			GL.glNormal3f(cos(angle), sin(angle), 0.0)
  			GL.glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da), width*0.5)
  			GL.glVertex3f(r2*cos(angle+2*da), r2*sin(angle+2*da),-width*0.5)
  			u = r1*cos(angle+3*da) - r2*cos(angle+2*da)
  			v = r1*sin(angle+3*da) - r2*sin(angle+2*da)
  			GL.glNormal3f(v, -u, 0.0)
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da), width*0.5)
  			GL.glVertex3f(r1*cos(angle+3*da), r1*sin(angle+3*da),-width*0.5)
  			GL.glNormal3f(cos(angle), sin(angle), 0.0)
  		
  		GL.glVertex3f(r1*cos(0), r1*sin(0), width*0.5)
  		GL.glVertex3f(r1*cos(0), r1*sin(0), -width*0.5)
  		
  		GL.glEnd()
  		
  		GL.glShadeModel(GL.GL_SMOOTH)
  		
  		# draw inside radius cylinder
  		GL.glBegin(GL.GL_QUAD_STRIP)
  		for i in range(teeth + 1):
  			angle = i * 2.0*math.pi / teeth;
  			GL.glNormal3f(-cos(angle), -sin(angle), 0.0)
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), -width*0.5)
  			GL.glVertex3f(r0*cos(angle), r0*sin(angle), width*0.5)
  		GL.glEnd()
  
  #----------------------------------------------------------------------------
  
  class GearsView(GLView):
  
  	view_rotx=20.0
  	view_roty=30.0
  	view_rotz=0.0
  	angle = 0.0
  
  	def init_context(self):
  		#print "Init Context" ###
  		pos = (5.0, 5.0, 10.0, 0.0)
  		red = (0.8, 0.1, 0.0, 1.0)
  		green = (0.0, 0.8, 0.2, 1.0)
  		blue = (0.2, 0.2, 1.0, 1.0)
  		#
  		GL.glLightfv(GL.GL_LIGHT0, GL.GL_POSITION, pos)
  		GL.glEnable(GL.GL_CULL_FACE)
  		GL.glEnable(GL.GL_LIGHTING)
  		GL.glEnable(GL.GL_LIGHT0)
  		GL.glEnable(GL.GL_DEPTH_TEST)
  		#
  		self.gear1 = GL.glGenLists(1)
  		GL.glNewList(self.gear1, GL.GL_COMPILE)
  		GL.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, red)
  		gear(1.0, 4.0, 1.0, 20, 0.7)
  		GL.glEndList()
  		#
  		self.gear2 = GL.glGenLists(1)
  		GL.glNewList(self.gear2, GL.GL_COMPILE)
  		GL.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, green)
  		gear(0.5, 2.0, 2.0, 10, 0.7)
  		GL.glEndList()
  		#
  		self.gear3 = GL.glGenLists(1)
  		GL.glNewList(self.gear3, GL.GL_COMPILE)
  		GL.glMaterialfv(GL.GL_FRONT, GL.GL_AMBIENT_AND_DIFFUSE, blue)
  		gear(1.3, 2.0, 0.5, 10, 0.7)
  		GL.glEndList()
  		#
  		GL.glEnable(GL.GL_NORMALIZE)
  		#
  		self.frame_task = Task(self.next_frame, frame_interval, repeat = 1)
  
  	def init_projection(self):
  		#print "init_projection" ###
  		width, height = self.size		 
  		if width > height:
  			w = float(width) / float(height)
  			GL.glFrustum(-w, w, -1.0, 1.0, 5.0, 60.0)
  		else:
  			h = float(height) / float(width)
  			GL.glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0)
  
  	def render(self):
  		#print "Render" ###
  		#GL.glMatrixMode(GL.GL_MODELVIEW)
  		#GL.glLoadIdentity()
  		GL.glTranslatef(0.0, 0.0, -40.0)
  		GL.glClear(GL.GL_COLOR_BUFFER_BIT | GL.GL_DEPTH_BUFFER_BIT)
  		#
  		GL.glPushMatrix()
  		#
  		GL.glRotatef(self.view_rotx, 1.0, 0.0, 0.0)
  		GL.glRotatef(self.view_roty, 0.0, 1.0, 0.0)
  		GL.glRotatef(self.view_rotz, 0.0, 0.0, 1.0)
  		#
  		GL.glPushMatrix()
  		GL.glTranslatef(-3.0, -2.0, 0.0)
  		GL.glRotatef(self.angle, 0.0, 0.0, 1.0)
  		GL.glCallList(self.gear1)
  		GL.glPopMatrix()
  		#
  		GL.glPushMatrix()
  		GL.glTranslatef(3.1, -2.0, 0.0)
  		GL.glRotatef(-2.0 * self.angle - 9.0, 0.0, 0.0, 1.0)
  		GL.glCallList(self.gear2)
  		GL.glPopMatrix()
  		#
  		GL.glPushMatrix()
  		GL.glTranslatef(-3.1, 4.2, 0.0)
  		GL.glRotatef(-2.0 * self.angle - 25.0, 0.0, 0.0, 1.0)
  		GL.glCallList(self.gear3)
  		GL.glPopMatrix()
  		#
  		GL.glPopMatrix()
  
  	def next_frame(self):
  		#print "Next Frame" ###
  		self.angle += 2.0
  		self.invalidate()
  		self.update()
  	
  	def key_down(self, event):
  		#print "Key:", event ###
  		try:
  			xa, ya, za = rotations[event.key]
  			self.view_rotx += xa
  			self.view_roty += ya
  			self.view_rotz += za
  		except KeyError:
  			pass
  
  #----------------------------------------------------------------------------
  
  def test():
  	view = GearsView(size = (300, 300))
  	win = Window(title = "Gears")
  	win.place(view, sticky = "nsew")
  	view.become_target()
  	win.shrink_wrap()
  	win.show()
  	application().run()
  
  instructions = """
  Gears should be spinning. The arrow keys should rotate the view.
  """
  
  print instructions
  test()
  