#
# simplecube.py
#
# Copyright (c) 2006-2007 Nokia Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

import appuifw, sys, e32
from glcanvas import *
from gles import *
from key_codes import *

class SimpleCube:
  vertices = array(GL_BYTE, 3, (
     [-1,  1,  1.0],
     [ 1,  1,  1],
     [ 1, -1,  1],
     [-1, -1,  1],

     [-1,  1, -1],
     [ 1,  1, -1],
     [ 1, -1, -1],
     [-1, -1, -1]
    )
  )
  
  triangles = array(GL_UNSIGNED_BYTE, 3, (
    # front
    [1,0,3],
    [1,3,2],
    
    # right
    [2,6,5],
    [2,5,1],
    
    # back
    [7,4,5],
    [7,5,6],
    
    # left
    [0,4,7],
    [0,7,3],
    
    # top
    [5,4,0],
    [5,0,1],
    
    # bottom
    [3,7,6],
    [3,6,2]
    )
  )
  
  fanOne = array(GL_UNSIGNED_BYTE, 3, (
    [1,0,3],
    [1,3,2],
    [1,2,6],
    [1,6,5],
    [1,5,4],
    [1,4,0]
    )
  )
  fanTwo = array(GL_UNSIGNED_BYTE, 3, (
    [7,4,5],
    [7,5,6],
    [7,6,2],
    [7,2,3],
    [7,3,0],
    [7,0,4]
    )
  )
  
  colors = array(GL_UNSIGNED_BYTE, 4, (
    [0  ,255,  0,255],
    [0  ,  0,255,255],
    [0  ,255,  0,255],
    [255,  0,  0,255],

    [0  ,  0,255,255],
    [255,  0,  0,255],
    [0  ,  0,255,255],
    [0  ,255,  0,255]
  ))
  
  ETriangles=0
  ETriangleFans=1
  
  def __init__(self):
    """Initializes OpenGL ES, sets the vertex and color arrays and pointers, 
and selects the shading mode."""
    
    # It's best to set these before creating the GL Canvas
    self.iDrawingMode=self.ETriangles
    self.iFrame=0
    self.exitflag = False
    self.render=0
    self.canvas = None
    
    self.old_body=appuifw.app.body
    try:
      self.canvas=GLCanvas(redraw_callback=self.redraw, event_callback=self.event, resize_callback=self.resize)
      appuifw.app.body=self.canvas
    except Exception,e:
      appuifw.note(u"Exception: %s" % (e))
      self.set_exit()
      return
    
    # binds are exactly same as with normal Canvas objects
    self.canvas.bind(EKey1,lambda:self.FullScreen(0))
    self.canvas.bind(EKey2,lambda:self.FullScreen(1))
    self.canvas.bind(EKey3,lambda:self.FullScreen(2))
    
    appuifw.app.menu = [
      (
        u"Shading mode",
        (
          (u"Flat", self.FlatShading),
          (u"Smooth", self.SmoothShading)
        )
      ),
      (
        u"Drawing mode",
        (
          (u"Triangles", self.TriangleMode),
          (u"Triangle fans", self.TriangleFanMode)
        )
      ),
      (
        u"Screen",
        (
          (u"Normal", lambda:self.FullScreen(0)),
          (u"Large", lambda:self.FullScreen(1)),
          (u"Full", lambda:self.FullScreen(2)),
        )
      ),
      (u"Exit", self.set_exit)
    ]
    
    try:
      self.initgl()
    except Exception,e:
      appuifw.note(u"Exception: %s" % (e))
      self.set_exit()
    
  def event(self, ev):
    """Event handler"""
    pass
  
  def resize(self):
    """Resize handler"""
    # This may get called before the canvas is created, so check that the canvas exists
    if self.canvas:
      glViewport(0, 0, self.canvas.size[0], self.canvas.size[1])
      aspect = float(self.canvas.size[1]) / float(self.canvas.size[0])
      glMatrixMode( GL_PROJECTION )
      glLoadIdentity()
      glFrustumf( -1.0, 1.0, -1.0*aspect, 1.0*aspect, 3.0, 1000.0 )
    
  def initgl(self):
    """Initializes OpenGL and sets up the rendering environment"""
    # Set the screen background color. 
    glClearColor( 0.0, 0.0, 0.0, 1.0 )
    
    # Enable back face culling. 
    glEnable( GL_CULL_FACE  )
    
    # Initialize viewport and projection. 
    self.resize()
    
    glMatrixMode( GL_MODELVIEW )
    
    # Enable vertex arrays. 
    glEnableClientState( GL_VERTEX_ARRAY )
    
    # Set array pointers. 
    glVertexPointerb(self.vertices)
    
    # Enable color arrays.
    glEnableClientState( GL_COLOR_ARRAY )
    
    # Set color pointers. 
    glColorPointerub(self.colors )
    
    # Set the initial shading mode 
    glShadeModel( GL_FLAT )
    
    # Do not use perspective correction 
    glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST )
    self.render=1
    
  def FlatShading(self):
    """Sets the GL shading model to flat."""
    glShadeModel( GL_FLAT )
    
  def SmoothShading(self):
    """Sets the GL shading model to smooth."""
    glShadeModel( GL_SMOOTH )
    
  def TriangleMode(self):
    """Sets the rendering mode to triangles."""
    self.iDrawingMode = self.ETriangles
    
  def TriangleFanMode(self):
    """Sets the rendering mode to triangle fans."""
    self.iDrawingMode = self.ETriangleFans
    
  def FullScreen(self,mode):
    if mode == 0:
      appuifw.app.screen = 'normal'
    elif mode == 1:
      appuifw.app.screen = 'large'
    elif mode == 2:
      appuifw.app.screen = 'full'
    
  def drawbox(self, aSizeX, aSizeY, aSizeZ):
    """Draws a box with triangles or triangle fans depending on the current rendering mode.
Scales the box to the given size using glScalef."""
    glScalef( aSizeX, aSizeY, aSizeZ )
    
    if self.iDrawingMode == self.ETriangles:
      glDrawElementsub( GL_TRIANGLES, self.triangles )
    elif self.iDrawingMode == self.ETriangleFans:
      glDrawElementsub( GL_TRIANGLE_FAN, self.fanOne )
      glDrawElementsub( GL_TRIANGLE_FAN, self.fanTwo )
  
  def redraw(self,frame):
    """Draws and animates the objects.
The frame number determines the amount of rotation."""
    self.iFrame = frame
    
    if self.render == 0:
      return
    glMatrixMode( GL_MODELVIEW )
    
    cameraDistance = 100
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT )
    
    # Animate and draw box
    glLoadIdentity()
    glTranslatex( 0 , 0 , -cameraDistance << 16 )
    glRotatex( self.iFrame << 16, 1 << 16,    0   ,    0    )
    glRotatex( self.iFrame << 15,    0   , 1 << 16,    0    )
    glRotatex( self.iFrame << 14,    0   ,    0   , 1 << 16 )
    self.drawbox( 15.0, 15.0, 15.0 )
    
  def close_canvas(self): # break reference cycles
    appuifw.app.body=self.old_body
    self.canvas=None
    self.draw=None
    appuifw.app.exit_key_handler=None
  
  def set_exit(self):
    self.exitflag = True
    
  def run(self):
    appuifw.app.exit_key_handler=self.set_exit
    while not self.exitflag:
      self.canvas.drawNow()
      e32.ao_sleep(0.0001)
    self.close_canvas()
    
appuifw.app.screen='full'
try:
  app=SimpleCube()
except Exception,e:
  appuifw.note(u'Exception: %s' % (e))
else:
  app.run()
  del app
#sys.exit(0)