Exemple #1
0
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21560"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400

        # Start of mousepointer
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1

        # Start of cube
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.target = array([80.0, 0.0, 0.0])

        self.centerOfGrav = array([0.0, -2.0, 0.0])
        self.points = ones((8, 3), float)
        self.savePics = False
        self.drawCounter = 0
        self.fps = 25
        self.dt = 1.0 / float(self.fps)

        self.client = UDPClient(servIP, ownIP, port)
Exemple #2
0
    def __init__(self,
                 servIP="127.0.0.1",
                 ownIP="127.0.0.1",
                 port="21590",
                 buf="16384"):

        # initialize the viewport size
        self.width = 800
        self.height = 600

        # initialize object which the camera follows
        self.centerObj = None
        self.mouseView = True
        self.viewDistance = 30
        self.lastx = -0.5
        self.lasty = 1
        self.lastz = -1

        self.dt = 1
        self.fps = 50
        self.lasttime = time.time()
        self.starttime = time.time()
        self.captureScreen = False
        self.isCapturing = False
        self.isFloorGreen = True

        self.message = None
        self.keyboardCallback = None

        # capture only every frameT. frame
        self.counter = 0
        self.frameT = 1

        self.init_GL()

        # set own callback functions
        glutMotionFunc(self._motionfunc)
        glutPassiveMotionFunc(self._passivemotionfunc)
        glutDisplayFunc(self._drawfunc)
        glutIdleFunc(self._idlefunc)
        glutKeyboardFunc(self._keyfunc)

        self.dt = 1.0 / self.fps
        self.lasttime = time.time()
        self.starttime = self.lasttime

        # initialize udp client
        self.client = UDPClient(servIP, ownIP, port, buf)
Exemple #3
0
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21560"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400
        
        # Start of mousepointer 
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1
   
        # Start of cube 
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.target = array([80.0, 0.0, 0.0])
      
        self.centerOfGrav = array([0.0, -2.0, 0.0])
        self.points = ones((8, 3), float)
        self.savePics = False
        self.drawCounter = 0
        self.fps = 25
        self.dt = 1.0 / float(self.fps)

        self.client = UDPClient(servIP, ownIP, port)
Exemple #4
0
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21590", buf="16384"):

        # initialize the viewport size
        self.width = 800
        self.height = 600

        # initialize object which the camera follows
        self.centerObj = None
        self.mouseView = True
        self.viewDistance = 30
        self.lastx = -0.5
        self.lasty = 1
        self.lastz = -1

        self.dt = 1
        self.fps = 50
        self.lasttime = time.time()
        self.starttime = time.time()
        self.captureScreen = False
        self.isCapturing = False
        self.isFloorGreen = True

        self.message = None
        self.keyboardCallback = None

        # capture only every frameT. frame
        self.counter = 0
        self.frameT = 1

        self.init_GL()

        # set own callback functions
        glutMotionFunc (self._motionfunc)
        glutPassiveMotionFunc(self._passivemotionfunc)
        glutDisplayFunc (self._drawfunc)
        glutIdleFunc (self._idlefunc)
        glutKeyboardFunc (self._keyfunc)


        self.dt = 1.0 / self.fps
        self.lasttime = time.time()
        self.starttime = self.lasttime

        # initialize udp client
        self.client = UDPClient(servIP, ownIP, port, buf)
Exemple #5
0
class FlexCubeRenderer(object):
    #Options: ServerIP(default:localhost), OwnIP(default:localhost), Port(default:21560)
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21560"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400

        # Start of mousepointer
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1

        # Start of cube
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.target = array([80.0, 0.0, 0.0])

        self.centerOfGrav = array([0.0, -2.0, 0.0])
        self.points = ones((8, 3), float)
        self.savePics = False
        self.drawCounter = 0
        self.fps = 25
        self.dt = 1.0 / float(self.fps)

        self.client = UDPClient(servIP, ownIP, port)

    # If self.savePics=True this method saves the produced images
    def saveTo(self, filename, format="JPEG"):
        import Image  # get PIL's functionality... @UnresolvedImport
        width, height = 800, 600
        glPixelStorei(GL_PACK_ALIGNMENT, 1)
        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
        image = Image.fromstring("RGB", (width, height), data)
        image = image.transpose(Image.FLIP_TOP_BOTTOM)
        image.save(filename, format)
        print('Saved image to ', filename)
        return image

    # the render method containing the Glut mainloop
    def _render(self):
        # Call init: Parameter(Window Position -> x, y, height, width)
        self.init_GL(self, 300, 300, 800, 600)
        self.object = objects3d.Objects3D()
        self.quad = gluNewQuadric()
        glutMainLoop()

    # The Glut idle function
    def drawIdleScene(self):
        #recive data from server and update the points of the cube
        try:
            self.points, self.centerOfGrav = eval(
                self.client.listen([self.points, self.centerOfGrav]))
        except:
            pass
        if self.points == "r":
            self.target = array([80.0, 0.0, 0.0])
            self.centerOfGrav = array([0.0, -2.0, 0.0])
            self.points = ones((8, 3), float)
        self.drawScene()
        if self.savePics:
            self.saveTo("./screenshots/image_jump" +
                        repr(10000 + self.picCount) + ".jpg")
            self.picCount += 1
        else:
            sleep(self.dt)

    def drawScene(self):
        ''' This methode describes the complete scene.'''
        # clear the buffer
        if self.zDis < 10: self.zDis += 0.25
        if self.lastz > 200: self.lastz -= self.zDis
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()

        # Point of view
        glRotatef(self.lastx, 0.0, 1.0, 0.0)
        glRotatef(self.lasty, 1.0, 0.0, 0.0)
        #glRotatef(15, 0.0, 0.0, 1.0)
        # direction of view is aimed to the center of gravity of the cube
        glTranslatef(-self.centerOfGrav[0], -self.centerOfGrav[1] - 50.0,
                     -self.centerOfGrav[2] - self.lastz)

        #Objects
        #Target Ball
        glColor3f(1, 0.25, 0.25)
        glPushMatrix()
        glTranslate(self.target[0], 0.0, self.target[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()

        #Massstab
        for lk in range(41):
            if float(lk - 20) / 10.0 == (lk - 20) / 10:
                glColor3f(0.75, 0.75, 0.75)
                glPushMatrix()
                glRotatef(90, 1, 0, 0)
                glTranslate(
                    self.worldRadius / 40.0 * float(lk) -
                    self.worldRadius / 2.0, -40.0, -30)
                quad = gluNewQuadric()
                gluCylinder(quad, 2, 2, 60, 4, 1)
                glPopMatrix()
            else:
                if float(lk - 20) / 5.0 == (lk - 20) / 5:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(
                        self.worldRadius / 40.0 * float(lk) -
                        self.worldRadius / 2.0, -40.0, -15.0)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 1, 1, 30, 4, 1)
                    glPopMatrix()
                else:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(
                        self.worldRadius / 40.0 * float(lk) -
                        self.worldRadius / 2.0, -40.0, -7.5)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 0.5, 0.5, 15, 4, 1)
                    glPopMatrix()

        #Mirror Center Ball
        glColor3f(1, 1, 1)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0], -self.centerOfGrav[1],
                    self.centerOfGrav[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()

        #Mirror Cube
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        glColor4f(0.5, 0.75, 0.5, 0.75)
        glPushMatrix()
        glTranslatef(0, -0.05, 0)
        self.object.drawMirCreat(self.points, self.centerOfGrav)
        glPopMatrix()

        # Floor
        tile = self.worldRadius / 40.0
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        for xF in range(40):
            for yF in range(40):
                if float(xF + yF) / 2.0 == (xF + yF) / 2:
                    glColor3f(0.8, 0.8, 0.7)
                else:
                    glColor4f(0.8, 0.8, 0.8, 0.7)
                glPushMatrix()
                glTranslatef(0.0, -0.03, 0.0)
                glBegin(GL_QUADS)
                glNormal(0.0, 1.0, 0.0)
                for i in range(2):
                    for k in range(2):
                        glVertex3f((i + xF - 20) * tile, 0.0,
                                   ((k ^ i) + yF - 20) * tile)
                glEnd()
                glPopMatrix()

        #Center Ball
        glColor3f(1, 1, 1)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0], self.centerOfGrav[1],
                    self.centerOfGrav[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()

        # Cube
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        glColor4f(0.5, 0.75, 0.5, 0.75)
        glPushMatrix()
        self.object.drawCreature(self.points, self.centerOfGrav)
        glPopMatrix()

        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        # Cubes shadow
        glColor4f(0, 0, 0, 0.5)
        glPushMatrix()
        self.object.drawShadow(self.points, self.centerOfGrav)
        glPopMatrix()

        # swap the buffer
        glutSwapBuffers()

    def resizeScene(self, width, height):
        '''Needed if window size changes.'''
        if height == 0:  # Prevent A Divide By Zero If The Window Is Too Small
            height = 1

        glViewport(
            0, 0, width, height
        )  # Reset The Current Viewport And Perspective Transformation
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45.0, float(width) / float(height), 0.1, 700.0)
        glMatrixMode(GL_MODELVIEW)

    def activeMouse(self, x, y):
        #Returns mouse coordinates while any mouse button is pressed.
        # store the mouse coordinate
        if self.mouseButton == GLUT_LEFT_BUTTON:
            self.lastx = x - self.xOffset
            self.lasty = y - self.yOffset
        if self.mouseButton == GLUT_RIGHT_BUTTON:
            self.lastz = y - self.zOffset
        # redisplay
        glutPostRedisplay()

    def passiveMouse(self, x, y):
        '''Returns mouse coordinates while no mouse button is pressed.'''
        pass

    def completeMouse(self, button, state, x, y):
        #Returns mouse coordinates and which button was pressed resp. released.
        self.mouseButton = button
        if state == GLUT_DOWN:
            self.xOffset = x - self.lastx
            self.yOffset = y - self.lasty
            self.zOffset = y - self.lastz
        # redisplay
        glutPostRedisplay()

        #Initialise an OpenGL windows with the origin at x, y and size of height, width.
    def init_GL(self, pyWorld, x, y, height, width):
        # initialize GLUT
        glutInit([])

        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
        glutInitWindowSize(height, width)
        glutInitWindowPosition(x, y)
        glutCreateWindow("The Curious Cube")
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glShadeModel(GL_SMOOTH)
        glMatrixMode(GL_MODELVIEW)
        # initialize lighting */
        glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1.0])
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1.0, 1.0, 1.0, 1.0])
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        #
        glColorMaterial(GL_FRONT, GL_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)
        # Automatic vector normalise
        glEnable(GL_NORMALIZE)

        ### Instantiate the virtual world ###
        glutDisplayFunc(pyWorld.drawScene)
        glutMotionFunc(pyWorld.activeMouse)
        glutMouseFunc(pyWorld.completeMouse)
        glutReshapeFunc(pyWorld.resizeScene)
        glutIdleFunc(pyWorld.drawIdleScene)
Exemple #6
0
    def __init__(self, servIP='127.0.0.1', ownIP='127.0.0.1', port='21590',
            buf='16384', verbose=False, window_name='ODE Viewer'):
        """Initialize

        Initializes all viewer attributes and starts the OpenGL engine.
        The UDP server is also started.
        """
        self.verbose = verbose
        self.window_name = window_name

        # Determine if the viewport will display in stereoscopic mode
        self.is_stereoscopic = True

        # Figure out the spacing between cameras for stereoscopic projection
        # NOTE: Pupillary distance for 95% of men in the USA is 7cm
        # Source: (Wikipedia: Pupillary Distance)
        self.stereoscopic_offset = 0.07 / 2.0 # [m]

        # initialize viewport starting size
        self.width = 800
        self.height = 600

        # Determine if fullscreen is active or not
        self.is_fullscreen = False

        # Calculate the initial aspect ratio of the window
        self.aspect_ratio = float(self.width) / float(self.height)
        self.aspect_ratio_changed = False

        # initialize object which the camera follows
        self.mouseView = True

        # Toggles to determine if the view should zoom or rotate
        self.motion_rotate_mode = False
        self.motion_zoom_mode = False

        # Stores the location of the mouse the last time it was clicked
        self.motion_last_mouse_down_pos = [0.0, 0.0]

        self.centerObj = None

        # Define the initial spherical camera positions
        self.cam_r_init = 1.0
        self.cam_theta_init = pi / 4.0
        self.cam_phi_init = 0.0

        # Define the camera spherical coodrinate attributes
        self.cam_r = self.cam_r_init
        self.cam_theta = self.cam_theta_init
        self.cam_phi = self.cam_phi_init

        # Define attributes to maintain frame rate
        self.fps = 60
        self.dt = 1.0 / self.fps

        self.last_time = time.time()

        self.capture_screen = False

        # Define attributes to store geometries to display
        self.message = None
        self.prev_message = None

        # Capture screen only every 'frameT'-th frame
        self.counter = 0
        self.frameT = 2

        # Initialize the OpenGL viewer window
        self.init_gl()

        # Set OpenGL callback functions
        glutKeyboardFunc(self._keyboard_callback)
        glutMouseFunc(self._mouse_callback)
        glutMotionFunc(self._motion_callback)
        glutPassiveMotionFunc(self._passive_motion_callback)
        glutDisplayFunc(self._display_callback)
        glutIdleFunc(self._idle_callback)

        # Initialize UDP client connection to the ODE simulation
        self.client = UDPClient(servIP, ownIP, port, buf, verbose=self.verbose)

        return
Exemple #7
0
class ODEViewer(object):
    def __init__(self, servIP='127.0.0.1', ownIP='127.0.0.1', port='21590',
            buf='16384', verbose=False, window_name='ODE Viewer'):
        """Initialize

        Initializes all viewer attributes and starts the OpenGL engine.
        The UDP server is also started.
        """
        self.verbose = verbose
        self.window_name = window_name

        # Determine if the viewport will display in stereoscopic mode
        self.is_stereoscopic = True

        # Figure out the spacing between cameras for stereoscopic projection
        # NOTE: Pupillary distance for 95% of men in the USA is 7cm
        # Source: (Wikipedia: Pupillary Distance)
        self.stereoscopic_offset = 0.07 / 2.0 # [m]

        # initialize viewport starting size
        self.width = 800
        self.height = 600

        # Determine if fullscreen is active or not
        self.is_fullscreen = False

        # Calculate the initial aspect ratio of the window
        self.aspect_ratio = float(self.width) / float(self.height)
        self.aspect_ratio_changed = False

        # initialize object which the camera follows
        self.mouseView = True

        # Toggles to determine if the view should zoom or rotate
        self.motion_rotate_mode = False
        self.motion_zoom_mode = False

        # Stores the location of the mouse the last time it was clicked
        self.motion_last_mouse_down_pos = [0.0, 0.0]

        self.centerObj = None

        # Define the initial spherical camera positions
        self.cam_r_init = 1.0
        self.cam_theta_init = pi / 4.0
        self.cam_phi_init = 0.0

        # Define the camera spherical coodrinate attributes
        self.cam_r = self.cam_r_init
        self.cam_theta = self.cam_theta_init
        self.cam_phi = self.cam_phi_init

        # Define attributes to maintain frame rate
        self.fps = 60
        self.dt = 1.0 / self.fps

        self.last_time = time.time()

        self.capture_screen = False

        # Define attributes to store geometries to display
        self.message = None
        self.prev_message = None

        # Capture screen only every 'frameT'-th frame
        self.counter = 0
        self.frameT = 2

        # Initialize the OpenGL viewer window
        self.init_gl()

        # Set OpenGL callback functions
        glutKeyboardFunc(self._keyboard_callback)
        glutMouseFunc(self._mouse_callback)
        glutMotionFunc(self._motion_callback)
        glutPassiveMotionFunc(self._passive_motion_callback)
        glutDisplayFunc(self._display_callback)
        glutIdleFunc(self._idle_callback)

        # Initialize UDP client connection to the ODE simulation
        self.client = UDPClient(servIP, ownIP, port, buf, verbose=self.verbose)

        return

    def start(self):
        # start the OpenGL main loop
        glutMainLoop()
        return

    def set_dt(self, dt):
        self.dt = dt
        self.fps = 1.0 / self.dt
        return

    def set_fps(self, fps):
        self.fps = fps
        self.dt = 1.0 / self.fps
        return

    def init_gl(self):
        """ initialize OpenGL. This function has to be called only once before drawing. """
        glutInit([])

        # Set up the new window
        glutInitWindowPosition(0, 0)
        glutInitWindowSize(self.width, self.height)
        glutCreateWindow(self.window_name)

        # Determine if stereoscopic is supported if it is desired
        if self.is_stereoscopic and not glGetBooleanv(GL_STEREO):
            print '>>> OpenGL stereoscopic is not supported'
            print '>>> Reverting to monoscopic viewer'
            self.is_stereoscopic = False

        # Initialize the display for either stereo or monoscopic
        if self.is_stereoscopic:
            glutInitDisplayMode(GLUT_STEREO | GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
        else:
            glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
 
        # Initialize Viewport and Shading
        glViewport(0, 0, self.width, self.height)
        glShadeModel(GL_SMOOTH)
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)

        #glClearColor(1.0, 1.0, 1.0, 0.0)
        glClearColor(0.52, 0.80, 0.98, 1.0)

        # Initialize Depth Buffer
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)

        # Initialize Lighting
        glEnable(GL_LIGHTING)
        glLightfv(GL_LIGHT1, GL_AMBIENT, [0.7, 0.7, 0.7, 1.0])
        glLightfv(GL_LIGHT1, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0])
        glLightfv(GL_LIGHT1, GL_POSITION, [0.0, 5.0, 5.0, 1.0])
        glEnable(GL_LIGHT1)

        # enable material coloring
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

        glEnable(GL_NORMALIZE)

        return

    def calc_aspect_ratio(self):
        """Calculate Aspect Ratio

        Recalculates the value of the aspect ratio of the viewport using the
        width and height of the viewport.

        Returns:
            The current aspect ratio as a floating point value.
        """
        # Calculate the current aspect ratio so we have an accurate model
        (_, _, x, y) = glGetIntegerv(GL_VIEWPORT)

        # Protect against divide by zero exceptions
        if y == 0:
            y = 1

        # Aspect Ratio = Width / Height
        ratio = float(x) / float(y)

        return ratio

    def prepare_gl(self):
        """Prepare drawing. This function is called in every step. It clears the screen and sets the new camera position"""
        # Do prep to determine the center of focus and general camera position

        # Center the camera on a given object or (0, 0, 0) if not specified
        center = [0.0, 0.0, 0.0]

        if self.centerObj is not None:
            center[0], center[1], center[2] = self.centerObj.getPosition()

        # Convert spherical to cartesian coordinates
        cam = [0.0, 0.0, 0.0]
        cam[0] = self.cam_r * sin(self.cam_theta) * sin(self.cam_phi)
        cam[1] = self.cam_r * cos(self.cam_theta)
        cam[2] = self.cam_r * sin(self.cam_theta) * cos(self.cam_phi)

        # If the aspect ratio changed due to fullscreen, recalculate the value
        if self.aspect_ratio_changed:
            self.aspect_ratio = self.calc_aspect_ratio()

        # Begin drawing into OpenGL buffers depending on mono or stereoscopic
        if self.is_stereoscopic:
            self.prepare_stereoscopic(cam, center, self.stereoscopic_offset)
        else:
            self.prepare_monoscopic(cam, center)

        return

    def prepare_stereoscopic(self, cam, center, eye_offset):
        """Prepare Stereoscopic View

        Draws the buffers required for stereoscopic support. Note that
        if this function is called without verifying that stereoscopic
        support exists, OpenGL exceptions will be thrown.

        NOTE: The stereoscopic support code was modified from the tutorial for
        Stereo Geometry in OpenGL. The website can be found here:
        http://www.orthostereo.com/geometryopengl.html

        Arguments:
            cam: A 3-element list of [x, y, z] float positions of the camera.
            center: A 3-element list of [x, y, z] float positions of the
                object to center the camera on.
            eye_offset: The distance of each eye to the left and right of the
                given cam position.
        """
        # Calculate the distance of each eye from the center perspective
        # Draw into both back color buffers
        glDrawBuffer(GL_BACK)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # Draw the left eye perspective
        glDrawBuffer(GL_BACK_LEFT)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        # Define the perspective based on current aspect ratio
        gluPerspective(45, self.aspect_ratio, 0.1, 50.0)

        # Draw the world as seen through the left eye
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # TODO: At the moment, the eye_offset is just given to the x offset.
        # this is not correct as the z position should also change with
        # the sperical rotation. y position is not affected.

        # Place the left eye and set the camera's target object
        gluLookAt(cam[0]-eye_offset, cam[1], cam[2],
                center[0]-eye_offset, center[1], center[2], 0, 1, 0)

        # Draw the right eye perspective
        glDrawBuffer(GL_BACK_RIGHT)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        # Define the perspective based on current aspect ratio
        gluPerspective(45, self.aspect_ratio, 0.1, 50.0)

        # Draw the world as seen through the right eye
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # Place the left eye and set the camera's target object
        gluLookAt(cam[0]+eye_offset, cam[1], cam[2],
                center[0]+eye_offset, center[1], center[2], 0, 1, 0)

        return

    def prepare_monoscopic(self, cam, center):
        """Prepare Monoscopic View

        Draws the buffer required for single-camera (monoscopic) viewer.

        Arguments:
            cam: A 3-element list of [x, y, z] float positions of the camera.
            center: A 3-element list of [x, y, z] float positions of the
                object to center the camera on.
        """
        # Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # Load the Projection matrix
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()

        # Define the perspective based on current aspect ratio
        gluPerspective(45, self.aspect_ratio, 0.1, 50.0)

        # Initialize ModelView matrix
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # Place the camera and set the camera's target object
        gluLookAt(cam[0], cam[1], cam[2], center[0], center[1], center[2], 0, 1, 0)

        return

    def draw_item(self, item):
        """Draw Item

        Draws an object from the ODE specifications.

        Arguments:
            item: A dictionary containing keys relating to an ODE geometry.
        """
        glDisable(GL_TEXTURE_2D)

        # Create a matrix for the new geometry calculations
        glPushMatrix()

        # Determine which geometric object we are dealing with. Draw it
        if item['type'] in ['box', 'sphere', 'cylinder', 'ccylinder']:
            # set color of object (currently dark gray)
            if item.has_key('color'):
                glEnable(GL_BLEND)
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                glColor4f(*(item['color']))
            else: glColor3f(0.1, 0.1, 0.1)

            # transform (rotate, translate) body accordingly
            (x, y, z) = item['position']
            R = item['rotation']

            # Create rotation matrix
            rot = [R[0], R[3], R[6], 0.0,
                   R[1], R[4], R[7], 0.0,
                   R[2], R[5], R[8], 0.0,
                      x,    y,    z, 1.0]

            # Apply rotation matrix to any shape created
            glMultMatrixd(rot)

            if item['type'] == 'box':
                # Draw a cube scaled to size
                (sx, sy, sz) = item['scale']
                glScaled(float(sx), float(sy), float(sz))
                glutSolidCube(1.0)
            elif item['type'] == 'sphere':
                # sphere
                glutSolidSphere(item['radius'], 20, 20)
            elif item['type'] == 'ccylinder':
                quad = gluNewQuadric()
                # draw cylinder and two spheres, one at each end
                glTranslate(0.0, 0.0, -item['length']/2.0)

                # Draw the cylinder object
                gluCylinder(quad, item['radius'], item['radius'], item['length'], 32, 32)

                # Draw the first cylinder end sphere
                glutSolidSphere(item['radius'], 20, 20)

                # Draw the second cylinder end sphere
                glTranslate(0.0, 0.0, item['length'])
                glutSolidSphere(item['radius'], 20, 20)
            elif item['type'] == 'cylinder':
                glTranslate(0.0, 0.0, -item['length']/2.0)

                # Draw the first cylinder end disk
                quad = gluNewQuadric()
                # Modify the orientation. This quad normal is inward
                gluQuadricOrientation(quad, GLU_INSIDE)
                gluDisk(quad, 0, item['radius'], 32, 1)

                # Draw the cylinder
                quad = gluNewQuadric()
                gluCylinder(quad, item['radius'], item['radius'], item['length'], 32, 32)

                # Draw the second cylinder end disk
                glTranslate(0.0, 0.0, item['length'])
                quad = gluNewQuadric()
                gluDisk(quad, 0.0, item['radius'], 32, 1)
        elif item['type'] == 'plane':
            # set color of plane (currently green)
            glColor3f(0.0, 0.2, 0.0)

            # for planes, we need a Quadric object
            quad = gluNewQuadric()
            gluQuadricTexture(quad, GL_TRUE)

            p = item['normal']      # the normal vector to the plane
            d = item['distance']    # the distance to the origin
            q = (0.0, 0.0, 1.0)     # the normal vector of default gluDisks (z=0 plane)

            # calculate the cross product to get the rotation axis
            c = crossproduct(p, q)
            # calculate the angle between default normal q and plane normal p
            theta = acos(dotproduct(p, q) / (norm(p) * norm(q))) / pi * 180

            # rotate the plane
            glTranslate(d * p[0], d * p[1], d * p[2])
            glRotate(-theta, c[0], c[1], c[2])

            # Create the disk with "infinite" (very large) radius
            gluDisk(quad, 0, 200, 20, 1)

        glPopMatrix()
        return

    @staticmethod
    def _loadTexture(textureFile):
        image = open(textureFile)
        ix = image.size[0]
        iy = image.size[1]

        image = image.tostring("raw", "RGBX", 0, -1)

        # Create Texture
        textures = glGenTextures(3)
        glBindTexture(GL_TEXTURE_2D, textures[0])       # 2d texture (x and y size)

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_BYTE, image)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)

        # Create Linear Filtered Texture
        glBindTexture(GL_TEXTURE_2D, textures[1])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)

        # Create MipMapped Texture
        glBindTexture(GL_TEXTURE_2D, textures[2])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST)
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, ix, iy, GL_RGBA, GL_UNSIGNED_BYTE, image)
        return textures

    def _display_callback (self):
        """ draw callback function """
        # Draw the scene
        self.prepare_gl()

        if self.message is not None:
            for item_name, item in self.message.iteritems():
                try:
                    # Attempt to draw in item from the message
                    self.draw_item(item)
                except:
                    # If something goes wrong in draw_item, we need to
                    # pop the matrix to prevent stack overflow
                    glPopMatrix()

        glutSwapBuffers()

        if self.capture_screen:
            self._screenshot()

        return

    def _idle_callback(self):
        # Listen for the latest data
        try:
            self.message = self.client.listen()
        except:
            pass

        if self.message is None:
            # If the message wasn't properly received, use the old message
            self.message = self.prev_message
        else:
            # Message received in full. Fill in any unsent items from the
            # previous message. These have not been modified
            if self.prev_message is not None:
                for item_name, item in self.prev_message.iteritems():
                    if item_name not in self.message:
                        self.message[item_name] = item

            #Store it for future use
            self.prev_message = self.message

        # Display the latest data directly after receiving
        glutPostRedisplay()

        # Maintain the frame rate at the desired fps
        t = self.dt - (time.time() - self.last_time)

        if (t > 0.0):
            time.sleep(t)

        self.last_time = time.time()

        return

    def _keyboard_callback(self, key, x, y):
        """ keyboard call-back function. """
        if key == 's':
            self.capture_screen = not self.capture_screen
            print "Screen Capture: " + (self.capture_screen and "on" or "off")
        elif key == 'f':
            self.aspect_ratio_changed = True

            if self.is_fullscreen:
                # Toggle out of fullscreen mode
                glutReshapeWindow(self.width, self.height)
                glutPositionWindow(0, 0)
                glutSetCursor(GLUT_CURSOR_INHERIT)

                self.is_fullscreen = False
            else:
                # Toggle into fullscreen mode
                glutFullScreen()
                glutSetCursor(GLUT_CURSOR_NONE)
                self.is_fullscreen = True
        elif key in ['x', 'q']:
            sys.exit()
        elif key == 'c':
            print 'Reset Camera'
            self.cam_r = self.cam_r_init
            self.cam_theta = self.cam_theta_init
            self.cam_phi = self.cam_phi_init

        return

    def _mouse_callback(self, button, state, x, y):
        if state == GLUT_DOWN:
            self.motion_last_mouse_down_pos = (x, y)

        if button == GLUT_LEFT_BUTTON:
            # If the left button is down, activate rotation mode
            if state == GLUT_DOWN:
                self.motion_rotate_mode = True
            elif state == GLUT_UP:
                self.motion_rotate_mode = False
        elif button == GLUT_RIGHT_BUTTON:
            # If the right button is down, activate zoom mode
            if state == GLUT_DOWN:
                self.motion_zoom_mode = True
            elif state == GLUT_UP:
                self.motion_zoom_mode = False

        return

    def _motion_callback(self, x, y):
        x_down, y_down = self.motion_last_mouse_down_pos

        # Note that if a mouse has two buttons (left/right) pressed at the
        # same time, rotate mode will always override zoom mode
        if self.motion_rotate_mode:
            # Modify the polar and azimuthal angles via y, x mouse direction
            d_phi = 0.2 * (float(x) - float(x_down)) / self.height
            d_theta = 0.2 * (float(y) - float(y_down)) / self.width

            # Set camera angle constraints
            if 0.0 <= self.cam_theta + d_theta <= pi / 2.0:
                self.cam_theta += d_theta

            if -pi / 2.0 <= self.cam_phi + d_phi <= pi / 2.0:
                self.cam_phi += d_phi
        elif self.motion_zoom_mode:
            # Change radius from target based on the relative 'y' position of
            # the mouse from the last click
            dr = 0.2 * (float(y) - float(y_down)) / self.height

            # Limit the zoom range between 0.2 and 10 meters
            if 0.2 < self.cam_r + dr < 10:
                self.cam_r += dr

        return

    def _passive_motion_callback(self, x, z):
        pass

    def _screenshot(self, path_prefix='.', format='PNG'):
        """Saves a screenshot of the current frame buffer.
        The save path is <path_prefix>/.screenshots/shot<num>.png
        The path is automatically created if it does not exist.
        Shots are automatically numerated based on how many files
        are already in the directory."""

        if self.counter == self.frameT:
            self.counter = 1
            dir = os.path.join(path_prefix, 'screenshots')
            if not os.path.exists(dir):
                os.makedirs(dir)

            num_present = len(os.listdir(dir))
            num_digits = len(str(num_present))
            index = '0' * (5 - num_digits) + str(num_present)

            path = os.path.join(dir, 'shot' + index + '.' + format.lower())
            glPixelStorei(GL_PACK_ALIGNMENT, 1)
            data = glReadPixels(0, 0, self.width, self.height, GL_RGB, GL_UNSIGNED_BYTE)
            image = Image.fromstring("RGB", (self.width, self.height), data)
            image = image.transpose(Image.FLIP_TOP_BOTTOM)
            image.save(path, format)
            print 'Image saved to %s' % (os.path.basename(path))
        else:
            self.counter += 1

        return
Exemple #8
0
class FlexCubeRenderer(object): 
    #Options: ServerIP(default:localhost), OwnIP(default:localhost), Port(default:21560)
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21560"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400
        
        # Start of mousepointer 
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1
   
        # Start of cube 
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.target = array([80.0, 0.0, 0.0])
      
        self.centerOfGrav = array([0.0, -2.0, 0.0])
        self.points = ones((8, 3), float)
        self.savePics = False
        self.drawCounter = 0
        self.fps = 25
        self.dt = 1.0 / float(self.fps)

        self.client = UDPClient(servIP, ownIP, port)

    # If self.savePics=True this method saves the produced images      
    def saveTo(self, filename, format="JPEG"):
        import Image # get PIL's functionality... @UnresolvedImport
        width, height = 800, 600
        glPixelStorei(GL_PACK_ALIGNMENT, 1)
        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
        image = Image.fromstring("RGB", (width, height), data)
        image = image.transpose(Image.FLIP_TOP_BOTTOM)
        image.save(filename, format)
        print('Saved image to ', filename)
        return image

    # the render method containing the Glut mainloop
    def _render(self):
        # Call init: Parameter(Window Position -> x, y, height, width)
        self.init_GL(self, 300, 300, 800, 600)    
        self.object = objects3d.Objects3D()
        self.quad = gluNewQuadric()
        glutMainLoop()

    # The Glut idle function
    def drawIdleScene(self):
        #recive data from server and update the points of the cube
        try:
            self.points, self.centerOfGrav = eval(self.client.listen([self.points, self.centerOfGrav]))
        except: pass
        if self.points == "r":
            self.target = array([80.0, 0.0, 0.0])
            self.centerOfGrav = array([0.0, -2.0, 0.0])
            self.points = ones((8, 3), float)
        self.drawScene()
        if self.savePics:
            self.saveTo("./screenshots/image_jump" + repr(10000 + self.picCount) + ".jpg")
            self.picCount += 1
        else: sleep(self.dt)
          
    def drawScene(self):
        ''' This methode describes the complete scene.'''
        # clear the buffer
        if self.zDis < 10: self.zDis += 0.25
        if self.lastz > 200: self.lastz -= self.zDis
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        
        # Point of view
        glRotatef(self.lastx, 0.0, 1.0, 0.0)
        glRotatef(self.lasty, 1.0, 0.0, 0.0)      
        #glRotatef(15, 0.0, 0.0, 1.0)      
        # direction of view is aimed to the center of gravity of the cube
        glTranslatef(-self.centerOfGrav[0], -self.centerOfGrav[1] - 50.0, -self.centerOfGrav[2] - self.lastz)
        
        #Objects
        #Target Ball
        glColor3f(1, 0.25, 0.25)
        glPushMatrix()
        glTranslate(self.target[0], 0.0, self.target[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()
        
        #Massstab
        for lk in range(41):
            if float(lk - 20) / 10.0 == (lk - 20) / 10: 
                glColor3f(0.75, 0.75, 0.75)
                glPushMatrix()
                glRotatef(90, 1, 0, 0)
                glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -30)
                quad = gluNewQuadric()
                gluCylinder(quad, 2, 2, 60, 4, 1);
                glPopMatrix()
            else: 
                if float(lk - 20) / 5.0 == (lk - 20) / 5:       
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -15.0)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 1, 1, 30, 4, 1);
                    glPopMatrix()
                else:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -7.5)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 0.5, 0.5, 15, 4, 1);
                    glPopMatrix()
    
        #Mirror Center Ball
        glColor3f(1, 1, 1)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0], -self.centerOfGrav[1], self.centerOfGrav[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()
        
        #Mirror Cube
        glEnable (GL_BLEND)
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        glColor4f(0.5, 0.75, 0.5, 0.75)
        glPushMatrix()
        glTranslatef(0, -0.05, 0)
        self.object.drawMirCreat(self.points, self.centerOfGrav)
        glPopMatrix()
        
        # Floor
        tile = self.worldRadius / 40.0
        glEnable (GL_BLEND)
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        for xF in range(40):
            for yF in range(40):
                if float(xF + yF) / 2.0 == (xF + yF) / 2: glColor3f(0.8, 0.8, 0.7)
                else: glColor4f(0.8, 0.8, 0.8, 0.7)
                glPushMatrix()
                glTranslatef(0.0, -0.03, 0.0)
                glBegin(GL_QUADS)
                glNormal(0.0, 1.0, 0.0)      
                for i in range(2):
                    for k in range(2):
                        glVertex3f((i + xF - 20) * tile, 0.0, ((k ^ i) + yF - 20) * tile);
                glEnd()
                glPopMatrix()
     
        #Center Ball
        glColor3f(1, 1, 1)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0], self.centerOfGrav[1], self.centerOfGrav[2])
        glutSolidSphere(1.5, 8, 8)
        glPopMatrix()
        
        # Cube    
        glEnable (GL_BLEND)
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        glColor4f(0.5, 0.75, 0.5, 0.75)
        glPushMatrix()
        self.object.drawCreature(self.points, self.centerOfGrav)
        glPopMatrix()
        
        glEnable (GL_BLEND)
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        # Cubes shadow
        glColor4f(0, 0, 0, 0.5)
        glPushMatrix()
        self.object.drawShadow(self.points, self.centerOfGrav)
        glPopMatrix()
        
        # swap the buffer
        glutSwapBuffers()    
    
    def resizeScene(self, width, height):
        '''Needed if window size changes.'''
        if height == 0: # Prevent A Divide By Zero If The Window Is Too Small 
            height = 1
    
        glViewport(0, 0, width, height) # Reset The Current Viewport And Perspective Transformation
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45.0, float(width) / float(height), 0.1, 700.0)
        glMatrixMode(GL_MODELVIEW)

    def activeMouse(self, x, y):
        #Returns mouse coordinates while any mouse button is pressed.
        # store the mouse coordinate
        if self.mouseButton == GLUT_LEFT_BUTTON:
            self.lastx = x - self.xOffset
            self.lasty = y - self.yOffset
        if self.mouseButton == GLUT_RIGHT_BUTTON:
            self.lastz = y - self.zOffset 
        # redisplay
        glutPostRedisplay()
  
    def passiveMouse(self, x, y):
        '''Returns mouse coordinates while no mouse button is pressed.'''
        pass
    
    def completeMouse(self, button, state, x, y):
        #Returns mouse coordinates and which button was pressed resp. released.
        self.mouseButton = button
        if state == GLUT_DOWN:
            self.xOffset = x - self.lastx
            self.yOffset = y - self.lasty
            self.zOffset = y - self.lastz
        # redisplay
        glutPostRedisplay()
    
        #Initialise an OpenGL windows with the origin at x, y and size of height, width.
    def init_GL(self, pyWorld, x, y, height, width):
        # initialize GLUT 
        glutInit([])
          
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
        glutInitWindowSize(height, width)
        glutInitWindowPosition(x, y)
        glutCreateWindow("The Curious Cube")
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glShadeModel(GL_SMOOTH)
        glMatrixMode(GL_MODELVIEW)
        # initialize lighting */
        glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1.0])
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1.0, 1.0, 1.0, 1.0])
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        # 
        glColorMaterial(GL_FRONT, GL_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)
        # Automatic vector normalise
        glEnable(GL_NORMALIZE)
        
        ### Instantiate the virtual world ###
        glutDisplayFunc(pyWorld.drawScene)
        glutMotionFunc(pyWorld.activeMouse)
        glutMouseFunc(pyWorld.completeMouse)
        glutReshapeFunc(pyWorld.resizeScene)
        glutIdleFunc(pyWorld.drawIdleScene)
Exemple #9
0
class ODEViewer(object):
    def __init__(self,
                 servIP="127.0.0.1",
                 ownIP="127.0.0.1",
                 port="21590",
                 buf="16384"):

        # initialize the viewport size
        self.width = 800
        self.height = 600

        # initialize object which the camera follows
        self.centerObj = None
        self.mouseView = True
        self.viewDistance = 30
        self.lastx = -0.5
        self.lasty = 1
        self.lastz = -1

        self.dt = 1
        self.fps = 50
        self.lasttime = time.time()
        self.starttime = time.time()
        self.captureScreen = False
        self.isCapturing = False
        self.isFloorGreen = True

        self.message = None
        self.keyboardCallback = None

        # capture only every frameT. frame
        self.counter = 0
        self.frameT = 1

        self.init_GL()

        # set own callback functions
        glutMotionFunc(self._motionfunc)
        glutPassiveMotionFunc(self._passivemotionfunc)
        glutDisplayFunc(self._drawfunc)
        glutIdleFunc(self._idlefunc)
        glutKeyboardFunc(self._keyfunc)

        self.dt = 1.0 / self.fps
        self.lasttime = time.time()
        self.starttime = self.lasttime

        # initialize udp client
        self.client = UDPClient(servIP, ownIP, port, buf)

    def start(self):
        # start the OpenGL main loop
        while True:
            glutMainLoop()

    def setFrameRate(self, fps):
        self.fps = fps
        self.dt = 1.0 / self.fps

    def setCaptureScreen(self, capture):
        self.captureScreen = capture

    def getCaptureScreen(self):
        return self.captureScreen

    def waitScreenCapturing(self):
        self.isCapturing = True

    def isScreenCapturing(self):
        return self.isCapturing

    def setCenterObj(self, obj):
        self.centerObj = obj

    def updateData(self):
        try:
            self.message = self.client.listen()
        except:
            pass

    def init_GL(self, width=800, height=600):
        """ initialize OpenGL. This function has to be called only once before drawing. """
        glutInit([])

        # Open a window
        glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
        self.width = width
        self.height = height
        glutInitWindowPosition(500, 0)
        glutInitWindowSize(self.width, self.height)
        self._myWindow = glutCreateWindow("ODE Viewer")

        # Initialize Viewport and Shading
        glViewport(0, 0, self.width, self.height)
        glShadeModel(GL_SMOOTH)
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
        glClearColor(1.0, 1.0, 1.0, 0.0)

        # Initialize Depth Buffer
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)

        # Initialize Lighting
        glEnable(GL_LIGHTING)
        glLightfv(GL_LIGHT1, GL_AMBIENT, [0.5, 0.5, 0.5, 1.0])
        glLightfv(GL_LIGHT1, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0])
        glLightfv(GL_LIGHT1, GL_POSITION, [0.0, 5.0, 5.0, 1.0])
        glEnable(GL_LIGHT1)

        # enable material coloring
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

        glEnable(GL_NORMALIZE)

    def prepare_GL(self):
        """Prepare drawing. This function is called in every step. It clears the screen and sets the new camera position"""
        # Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # Projection mode
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45, 1.3333, 0.2, 500)

        # Initialize ModelView matrix
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # View transformation (if "centerOn(...)" is set, keep camera to specific object)
        if self.centerObj is not None:
            (centerX, centerY, centerZ) = self.centerObj.getPosition()
        else:
            centerX = centerY = centerZ = 0
        # use the mouse to shift eye sensor on a hemisphere
        eyeX = self.viewDistance * self.lastx
        eyeY = self.viewDistance * self.lasty + centerY
        eyeZ = self.viewDistance * self.lastz
        gluLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, 0, 1, 0)

    def draw_item(self, item):
        """ draws an object (spere, cube, plane, ...) """
        glDisable(GL_TEXTURE_2D)

        glPushMatrix()

        if item['type'] in [
                'GeomBox', 'GeomSphere', 'GeomCylinder', 'GeomCCylinder'
        ]:
            # set color of object (currently dark gray)
            if item.has_key('color'):
                glEnable(GL_BLEND)
                glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                glColor4f(*(item['color']))
            else:
                glColor3f(0.1, 0.1, 0.1)

            # transform (rotate, translate) body accordingly
            (x, y, z) = item['position']
            R = item['rotation']

            rot = [
                R[0], R[3], R[6], 0.0, R[1], R[4], R[7], 0.0, R[2], R[5], R[8],
                0.0, x, y, z, 1.0
            ]

            glMultMatrixd(rot)

            # switch different geom objects
            if item['type'] == 'GeomBox':
                # cube
                (sx, sy, sz) = item['scale']
                glScaled(sx, sy, sz)
                glutSolidCube(1)
            elif item['type'] == 'GeomSphere':
                # sphere
                glutSolidSphere(item['radius'], 20, 20)

            elif item['type'] == 'GeomCCylinder':
                quad = gluNewQuadric()
                # draw cylinder and two spheres, one at each end
                glTranslate(0.0, 0.0, -item['length'] / 2)
                gluCylinder(quad, item['radius'], item['radius'],
                            item['length'], 32, 32)
                glutSolidSphere(item['radius'], 20, 20)
                glTranslate(0.0, 0.0, item['length'])
                glutSolidSphere(item['radius'], 20, 20)

            elif item['type'] == 'GeomCylinder':
                glTranslate(0.0, 0.0, -item['length'] / 2)
                quad = gluNewQuadric()
                gluDisk(quad, 0, item['radius'], 32, 1)
                quad = gluNewQuadric()
                gluCylinder(quad, item['radius'], item['radius'],
                            item['length'], 32, 32)
                glTranslate(0.0, 0.0, item['length'])
                quad = gluNewQuadric()
                gluDisk(quad, 0, item['radius'], 32, 1)
            else:
                # TODO: add other geoms here
                pass

        elif item['type'] == 'GeomPlane':
            # set color of plane (currently green)
            if self.isFloorGreen:
                glColor3f(0.2, 0.6, 0.3)
            else:
                glColor3f(0.2, 0.3, 0.8)

            # for planes, we need a Quadric object
            quad = gluNewQuadric()
            gluQuadricTexture(quad, GL_TRUE)

            p = item['normal']  # the normal vector to the plane
            d = item['distance']  # the distance to the origin
            q = (0.0, 0.0, 1.0
                 )  # the normal vector of default gluDisks (z=0 plane)

            # calculate the cross product to get the rotation axis
            c = crossproduct(p, q)
            # calculate the angle between default normal q and plane normal p
            theta = acos(dotproduct(p, q) / (norm(p) * norm(q))) / pi * 180

            # rotate the plane
            glPushMatrix()
            glTranslate(d * p[0], d * p[1], d * p[2])
            glRotate(-theta, c[0], c[1], c[2])
            gluDisk(quad, 0, 20, 20, 1)
            glPopMatrix()

        glPopMatrix()

    @staticmethod
    def _loadTexture(textureFile):
        image = open(textureFile)
        ix = image.size[0]
        iy = image.size[1]

        image = image.tostring("raw", "RGBX", 0, -1)

        # Create Texture
        textures = glGenTextures(3)
        glBindTexture(GL_TEXTURE_2D, textures[0])  # 2d texture (x and y size)

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_BYTE, image)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)

        # Create Linear Filtered Texture
        glBindTexture(GL_TEXTURE_2D, textures[1])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE,
                     image)

        # Create MipMapped Texture
        glBindTexture(GL_TEXTURE_2D, textures[2])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
                        GL_LINEAR_MIPMAP_NEAREST)
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, ix, iy, GL_RGBA, GL_UNSIGNED_BYTE,
                          image)
        return textures

    def _drawfunc(self):
        """ draw callback function """
        # Draw the scene
        self.prepare_GL()

        if self.message:
            for item in self.message:
                self.draw_item(item)

        glutSwapBuffers()
        if self.captureScreen:
            self._screenshot()

    def _idlefunc(self):
        self.updateData()
        t = self.dt - (time.time() - self.lasttime)
        if (t > 0):
            time.sleep(t)
        self.lasttime = time.time()
        glutPostRedisplay()

    def _keyfunc(self, c, x, y):
        """ keyboard call-back function. """
        if c == 's':
            self.setCaptureScreen(not self.getCaptureScreen())
            print("Screen Capture: " +
                  (self.getCaptureScreen() and "on" or "off"))
        if c in ['x', 'q']:
            sys.exit()
        if c == 'v':
            self.mouseView = not self.mouseView

    def _motionfunc(self, x, z):
        """Control the zoom factor"""
        if not self.mouseView: return
        zn = 2.75 * float(z) / self.height + 0.25  # [0.25,3]
        self.viewDistance = 3.0 * zn * zn
        self._passivemotionfunc(x, z)

    def _passivemotionfunc(self, x, z):
        """ Store the mouse coordinates (relative to center and normalized)
         the eye does not exactly move on a unit hemisphere; we fudge the projection
         a little by shifting the hemisphere into the ground by 0.1 units,
         such that approaching the perimeter dows not cause a huge change in the
         viewing direction. The limit for l is thus cos(arcsin(0.1))."""
        if not self.mouseView: return
        x1 = 3 * float(x) / self.width - 1.5
        z1 = -3 * float(z) / self.height + 1.5
        lsq = x1 * x1 + z1 * z1
        l = sqrt(lsq)
        if l > 0.994987:
            # for mouse outside window, project onto the unit circle
            x1 = x1 / l
            z1 = z1 / l
            y1 = 0
        else:
            y1 = max(0.0, sqrt(1.0 - x1 * x1 - z1 * z1) - 0.1)
        self.lasty = y1
        self.lastx = x1
        self.lastz = z1

    def _screenshot(self, path_prefix='.', format='PNG'):
        """Saves a screenshot of the current frame buffer.
        The save path is <path_prefix>/.screenshots/shot<num>.png
        The path is automatically created if it does not exist.
        Shots are automatically numerated based on how many files
        are already in the directory."""

        if self.counter == self.frameT:
            self.counter = 1
            dir = os.path.join(path_prefix, 'screenshots')
            if not os.path.exists(dir):
                os.makedirs(dir)

            num_present = len(os.listdir(dir))
            num_digits = len(str(num_present))
            index = '0' * (5 - num_digits) + str(num_present)

            path = os.path.join(dir, 'shot' + index + '.' + format.lower())
            glPixelStorei(GL_PACK_ALIGNMENT, 1)
            data = glReadPixels(0, 0, self.width, self.height, GL_RGB,
                                GL_UNSIGNED_BYTE)
            image = Image.fromstring("RGB", (self.width, self.height), data)
            image = image.transpose(Image.FLIP_TOP_BOTTOM)
            image.save(path, format)
            print('Image saved to %s' % (os.path.basename(path)))
        else:
            self.counter += 1

        self.isCapturing = False
class FlexCubeRenderer(object):
    #Options: ServerIP(default:localhost), OwnIP(default:localhost), Port(default:21560)
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21580"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400

        # Start of mousepointer
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1

        # Start of cube
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.sensors = [0.0, 0.0, 0.0]
        self.centerOfGrav = array([0.0, 5.0, 0.0])

        self.savePics = False
        self.drawCounter = 0
        self.fps = 50
        self.dt = 1.0 / float(self.fps)
        self.step = 0

        self.client = UDPClient(servIP, ownIP, port)

    # If self.savePics=True this method saves the produced images
    def saveTo(self, filename, format="JPEG"):
        import Image  # get PIL's functionality...
        width, height = 800, 600
        glPixelStorei(GL_PACK_ALIGNMENT, 1)
        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
        image = Image.fromstring("RGB", (width, height), data)
        image = image.transpose(Image.FLIP_TOP_BOTTOM)
        image.save(filename, format)
        print('Saved image to ', filename)
        return image

    # the render method containing the Glut mainloop
    def _render(self):
        # Call init: Parameter(Window Position -> x, y, height, width)
        self.init_GL(self, 300, 300, 800, 600)
        self.quad = gluNewQuadric()
        glutMainLoop()

    # The Glut idle function
    def drawIdleScene(self):
        #recive data from server and update the points of the cube
        try:
            self.sensors = self.client.listen(self.sensors)
        except:
            pass
        if self.sensors == ["r", "r", "r"]:
            self.centerOfGrav = array([0.0, 5.0, 0.0])
        else:
            self.step += 1
            a = self.sensors[0] / 360.0 * 3.1428
            dir = array([cos(a), 0.0, -sin(a)])
            self.centerOfGrav += self.sensors[2] * dir * 0.02
            self.drawScene()
        if self.savePics:
            self.saveTo("./screenshots/image_jump" +
                        repr(10000 + self.picCount) + ".jpg")
            self.picCount += 1
        else:
            sleep(self.dt)

    def drawScene(self):
        ''' This methode describes the complete scene.'''
        # clear the buffer
        if self.zDis < 10: self.zDis += 0.25
        if self.lastz > 100: self.lastz -= self.zDis
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()

        # Point of view
        glRotatef(self.lastx, 0.0, 1.0, 0.0)
        glRotatef(self.lasty, 1.0, 0.0, 0.0)
        #glRotatef(15, 0.0, 0.0, 1.0)
        # direction of view is aimed to the center of gravity of the cube
        glTranslatef(-self.centerOfGrav[0], -self.centerOfGrav[1] - 50.0,
                     -self.centerOfGrav[2] - self.lastz)

        #Objects

        #Massstab
        for lk in range(41):
            if float(lk - 20) / 10.0 == (lk - 20) / 10:
                glColor3f(0.75, 0.75, 0.75)
                glPushMatrix()
                glRotatef(90, 1, 0, 0)
                glTranslate(
                    self.worldRadius / 40.0 * float(lk) -
                    self.worldRadius / 2.0, -40.0, -30)
                quad = gluNewQuadric()
                gluCylinder(quad, 2, 2, 60, 4, 1)
                glPopMatrix()
            else:
                if float(lk - 20) / 5.0 == (lk - 20) / 5:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(
                        self.worldRadius / 40.0 * float(lk) -
                        self.worldRadius / 2.0, -40.0, -15.0)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 1, 1, 30, 4, 1)
                    glPopMatrix()
                else:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(
                        self.worldRadius / 40.0 * float(lk) -
                        self.worldRadius / 2.0, -40.0, -7.5)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 0.5, 0.5, 15, 4, 1)
                    glPopMatrix()

        # Floor
        tile = self.worldRadius / 40.0
        glEnable(GL_BLEND)
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)

        glColor3f(0.8, 0.8, 0.5)
        glPushMatrix()
        glTranslatef(0.0, -3.0, 0.0)
        glBegin(GL_QUADS)
        glNormal(0.0, 1.0, 0.0)
        glVertex3f(-self.worldRadius, 0.0, -self.worldRadius)
        glVertex3f(-self.worldRadius, 0.0, self.worldRadius)
        glVertex3f(self.worldRadius, 0.0, self.worldRadius)
        glVertex3f(self.worldRadius, 0.0, -self.worldRadius)
        glEnd()
        glPopMatrix()

        #Water
        for xF in range(40):
            for yF in range(40):
                if float(xF + yF) / 2.0 == (xF + yF) / 2:
                    glColor4f(0.7, 0.7, 1.0, 0.5)
                else:
                    glColor4f(0.9, 0.9, 1.0, 0.5)
                glPushMatrix()
                glTranslatef(0.0, -0.03, 0.0)
                glBegin(GL_QUADS)
                glNormal(0.5 + sin(float(xF) + float(self.step) / 4.0) * 0.5,
                         0.5 + cos(float(xF) + float(self.step) / 4.0) * 0.5,
                         0.0)
                for i in range(2):
                    for k in range(2):
                        glVertex3f(
                            (i + xF - 20) * tile,
                            sin(float(xF + i) + float(self.step) / 4.0) * 3.0,
                            ((k ^ i) + yF - 20) * tile)
                glEnd()
                glPopMatrix()

        self.ship()

        # swap the buffer
        glutSwapBuffers()

    def ship(self):
        glColor3f(0.4, 0.1, 0.2)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0] + 14, self.centerOfGrav[1],
                    self.centerOfGrav[2])
        glRotatef(180 - self.sensors[0], 0.0, 1.0, 0.0)

        self.cuboid(0, 0, 0, 20, 5, 5)
        #bow of ship
        glBegin(GL_TRIANGLES)
        glNormal3fv(
            self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 5, 5]),
                            self.points2Vector([-5, 6, 2.5], [0, 5, 0])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 5, 0), glVertex3f(0, 5, 5)
        glNormal3fv(
            self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 0, 5]),
                            self.points2Vector([-5, 6, 2.5], [0, 5, 5])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 5), glVertex3f(0, 5, 5)
        glNormal3fv(
            self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 0, 0]),
                            self.points2Vector([-5, 6, 2.5], [0, 0, 5])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 5), glVertex3f(0, 0, 0)
        glNormal3fv(
            self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 5, 0]),
                            self.points2Vector([-5, 6, 2.5], [0, 0, 0])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 0), glVertex3f(0, 5, 0)
        glEnd()
        # stern
        glPushMatrix()
        glRotatef(-90, 1.0, 0.0, 0.0)
        glTranslatef(15, -2.5, 0)
        gluCylinder(self.quad, 2.5, 2.5, 5, 10, 1)
        glTranslatef(0, 0, 5)
        gluDisk(self.quad, 0, 2.5, 10, 1)
        glPopMatrix()
        # deck
        if abs(self.sensors[0]) < 5.0: reward = (self.sensors[2] + 10.0) / 50.0
        else: reward = 0.2
        glColor3f(1.0 - reward, reward, 0)
        self.cuboid(5, 5, 1, 10, 8, 4)
        glPushMatrix()
        glRotatef(-90, 1.0, 0.0, 0.0)
        glTranslatef(13, -2.5, 5)
        glColor3f(1, 1, 1)
        gluCylinder(self.quad, 1, 0.8, 5, 20, 1)
        glPopMatrix()
        glPopMatrix()

    def cuboid(self, x0, y0, z0, x1, y1, z1):
        glBegin(GL_QUADS)
        glNormal(0, 0, 1)
        glVertex3f(x0, y0, z1)
        glVertex3f(x0, y1, z1)
        glVertex3f(x1, y1, z1)
        glVertex3f(x1, y0, z1)  #front
        glNormal(-1, 0, 0)
        glVertex3f(x0, y0, z0)
        glVertex3f(x0, y0, z1)
        glVertex3f(x0, y1, z1)
        glVertex3f(x0, y1, z0)  # left
        glNormal(0, -1, 0)
        glVertex3f(x0, y0, z0)
        glVertex3f(x0, y0, z1)
        glVertex3f(x1, y0, z1)
        glVertex3f(x1, y0, z0)  # bottom
        glNormal(0, 0, -1)
        glVertex3f(x0, y0, z0)
        glVertex3f(x1, y0, z0)
        glVertex3f(x1, y1, z0)
        glVertex3f(x0, y1, z0)  # back
        glNormal(0, 1, 0)
        glVertex3f(x0, y1, z0)
        glVertex3f(x1, y1, z0)
        glVertex3f(x1, y1, z1)
        glVertex3f(x0, y1, z1)  # top
        glNormal(1, 0, 0)
        glVertex3f(x1, y0, z0)
        glVertex3f(x1, y0, z1)
        glVertex3f(x1, y1, z1)
        glVertex3f(x1, y1, z0)  # right
        glEnd()

    def calcNormal(self, xVector, yVector):
        result = [0, 0, 0]
        result[0] = xVector[1] * yVector[2] - yVector[1] * xVector[2]
        result[1] = -xVector[0] * yVector[2] + yVector[0] * xVector[2]
        result[2] = xVector[0] * yVector[1] - yVector[0] * xVector[1]
        return [result[0], result[1], result[2]]

    def points2Vector(self, startPoint, endPoint):
        result = [0, 0, 0]
        result[0] = endPoint[0] - startPoint[0]
        result[1] = endPoint[1] - startPoint[1]
        result[2] = endPoint[2] - startPoint[2]
        return [result[0], result[1], result[2]]

    def resizeScene(self, width, height):
        '''Needed if window size changes.'''
        if height == 0:  # Prevent A Divide By Zero If The Window Is Too Small
            height = 1

        glViewport(
            0, 0, width, height
        )  # Reset The Current Viewport And Perspective Transformation
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45.0, float(width) / float(height), 0.1, 700.0)
        glMatrixMode(GL_MODELVIEW)

    def activeMouse(self, x, y):
        #Returns mouse coordinates while any mouse button is pressed.
        # store the mouse coordinate
        if self.mouseButton == GLUT_LEFT_BUTTON:
            self.lastx = x - self.xOffset
            self.lasty = y - self.yOffset
        if self.mouseButton == GLUT_RIGHT_BUTTON:
            self.lastz = y - self.zOffset
        # redisplay
        glutPostRedisplay()

    def passiveMouse(self, x, y):
        '''Returns mouse coordinates while no mouse button is pressed.'''
        pass

    def completeMouse(self, button, state, x, y):
        #Returns mouse coordinates and which button was pressed resp. released.
        self.mouseButton = button
        if state == GLUT_DOWN:
            self.xOffset = x - self.lastx
            self.yOffset = y - self.lasty
            self.zOffset = y - self.lastz
        # redisplay
        glutPostRedisplay()

    #Initialise an OpenGL windows with the origin at x, y and size of height, width.
    def init_GL(self, pyWorld, x, y, height, width):
        # initialize GLUT
        glutInit([])

        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
        glutInitWindowSize(height, width)
        glutInitWindowPosition(x, y)
        glutCreateWindow("The Curious Cube")
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glShadeModel(GL_SMOOTH)
        glMatrixMode(GL_MODELVIEW)
        # initialize lighting */
        glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1.0])
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1.0, 1.0, 1.0, 1.0])
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        #
        glColorMaterial(GL_FRONT, GL_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)
        # Automatic vector normalise
        glEnable(GL_NORMALIZE)

        ### Instantiate the virtual world ###
        glutDisplayFunc(pyWorld.drawScene)
        glutMotionFunc(pyWorld.activeMouse)
        glutMouseFunc(pyWorld.completeMouse)
        glutReshapeFunc(pyWorld.resizeScene)
        glutIdleFunc(pyWorld.drawIdleScene)
Exemple #11
0
class ODEViewer(object):
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21590", buf="16384"):

        # initialize the viewport size
        self.width = 800
        self.height = 600

        # initialize object which the camera follows
        self.centerObj = None
        self.mouseView = True
        self.viewDistance = 30
        self.lastx = -0.5
        self.lasty = 1
        self.lastz = -1

        self.dt = 1
        self.fps = 50
        self.lasttime = time.time()
        self.starttime = time.time()
        self.captureScreen = False
        self.isCapturing = False
        self.isFloorGreen = True

        self.message = None
        self.keyboardCallback = None

        # capture only every frameT. frame
        self.counter = 0
        self.frameT = 1

        self.init_GL()

        # set own callback functions
        glutMotionFunc (self._motionfunc)
        glutPassiveMotionFunc(self._passivemotionfunc)
        glutDisplayFunc (self._drawfunc)
        glutIdleFunc (self._idlefunc)
        glutKeyboardFunc (self._keyfunc)


        self.dt = 1.0 / self.fps
        self.lasttime = time.time()
        self.starttime = self.lasttime

        # initialize udp client
        self.client = UDPClient(servIP, ownIP, port, buf)


    def start(self):
        # start the OpenGL main loop
        while True:
            glutMainLoop()

    def setFrameRate(self, fps):
        self.fps = fps
        self.dt = 1.0 / self.fps

    def setCaptureScreen(self, capture):
        self.captureScreen = capture

    def getCaptureScreen(self):
        return self.captureScreen

    def waitScreenCapturing(self):
        self.isCapturing = True

    def isScreenCapturing(self):
        return self.isCapturing

    def setCenterObj(self, obj):
        self.centerObj = obj


    def updateData(self):
        try:
            self.message = self.client.listen()
        except:
            pass


    def init_GL(self, width=800, height=600):
        """ initialize OpenGL. This function has to be called only once before drawing. """
        glutInit([])

        # Open a window
        glutInitDisplayMode (GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH)
        self.width = width
        self.height = height
        glutInitWindowPosition (500, 0)
        glutInitWindowSize (self.width, self.height)
        self._myWindow = glutCreateWindow ("ODE Viewer")

        # Initialize Viewport and Shading
        glViewport(0, 0, self.width, self.height)
        glShadeModel(GL_SMOOTH)
        glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST)
        glClearColor(1.0, 1.0, 1.0, 0.0)

        # Initialize Depth Buffer
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glDepthFunc(GL_LESS)

        # Initialize Lighting
        glEnable(GL_LIGHTING)
        glLightfv(GL_LIGHT1, GL_AMBIENT, [0.5, 0.5, 0.5, 1.0])
        glLightfv(GL_LIGHT1, GL_DIFFUSE, [1.0, 1.0, 1.0, 1.0])
        glLightfv(GL_LIGHT1, GL_POSITION, [0.0, 5.0, 5.0, 1.0])
        glEnable(GL_LIGHT1)

        # enable material coloring
        glEnable(GL_COLOR_MATERIAL)
        glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE)

        glEnable(GL_NORMALIZE)

    def prepare_GL(self):
        """Prepare drawing. This function is called in every step. It clears the screen and sets the new camera position"""
        # Clear the screen
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)

        # Projection mode
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective (45, 1.3333, 0.2, 500)

        # Initialize ModelView matrix
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        # View transformation (if "centerOn(...)" is set, keep camera to specific object)
        if self.centerObj is not None:
            (centerX, centerY, centerZ) = self.centerObj.getPosition()
        else:
            centerX = centerY = centerZ = 0
        # use the mouse to shift eye sensor on a hemisphere
        eyeX = self.viewDistance * self.lastx
        eyeY = self.viewDistance * self.lasty + centerY
        eyeZ = self.viewDistance * self.lastz
        gluLookAt (eyeX, eyeY, eyeZ, centerX, centerY, centerZ, 0, 1, 0)

    def draw_item(self, item):
        """ draws an object (spere, cube, plane, ...) """
        glDisable(GL_TEXTURE_2D)

        glPushMatrix()

        if item['type'] in ['GeomBox', 'GeomSphere', 'GeomCylinder', 'GeomCCylinder']:
            # set color of object (currently dark gray)
            if item.has_key('color'):
                glEnable (GL_BLEND)
                glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
                glColor4f(*(item['color']))
            else: glColor3f(0.1, 0.1, 0.1)

            # transform (rotate, translate) body accordingly
            (x, y, z) = item['position']
            R = item['rotation']

            rot = [R[0], R[3], R[6], 0.0,
                   R[1], R[4], R[7], 0.0,
                   R[2], R[5], R[8], 0.0,
                      x, y, z, 1.0]

            glMultMatrixd(rot)

            # switch different geom objects
            if item['type'] == 'GeomBox':
                # cube
                (sx, sy, sz) = item['scale']
                glScaled(sx, sy, sz)
                glutSolidCube(1)
            elif item['type'] == 'GeomSphere':
                # sphere
                glutSolidSphere(item['radius'], 20, 20)

            elif item['type'] == 'GeomCCylinder':
                quad = gluNewQuadric()
                # draw cylinder and two spheres, one at each end
                glTranslate(0.0, 0.0, -item['length'] / 2)
                gluCylinder(quad, item['radius'], item['radius'], item['length'], 32, 32)
                glutSolidSphere(item['radius'], 20, 20)
                glTranslate(0.0, 0.0, item['length'])
                glutSolidSphere(item['radius'], 20, 20)

            elif item['type'] == 'GeomCylinder':
                glTranslate(0.0, 0.0, -item['length'] / 2)
                quad = gluNewQuadric()
                gluDisk(quad, 0, item['radius'], 32, 1)
                quad = gluNewQuadric()
                gluCylinder(quad, item['radius'], item['radius'], item['length'], 32, 32)
                glTranslate(0.0, 0.0, item['length'])
                quad = gluNewQuadric()
                gluDisk(quad, 0, item['radius'], 32, 1)
            else:
                # TODO: add other geoms here
                pass

        elif item['type'] == 'GeomPlane':
            # set color of plane (currently green)
            if self.isFloorGreen:
                glColor3f(0.2, 0.6, 0.3)
            else:
                glColor3f(0.2, 0.3, 0.8)

            # for planes, we need a Quadric object
            quad = gluNewQuadric()
            gluQuadricTexture(quad, GL_TRUE)

            p = item['normal']      # the normal vector to the plane
            d = item['distance']    # the distance to the origin
            q = (0.0, 0.0, 1.0)     # the normal vector of default gluDisks (z=0 plane)

            # calculate the cross product to get the rotation axis
            c = crossproduct(p, q)
            # calculate the angle between default normal q and plane normal p
            theta = acos(dotproduct(p, q) / (norm(p) * norm(q))) / pi * 180

            # rotate the plane
            glPushMatrix()
            glTranslate(d * p[0], d * p[1], d * p[2])
            glRotate(-theta, c[0], c[1], c[2])
            gluDisk(quad, 0, 20, 20, 1)
            glPopMatrix()

        glPopMatrix()

    @staticmethod
    def _loadTexture(textureFile):
        image = open(textureFile)
        ix = image.size[0]
        iy = image.size[1]

        image = image.tostring("raw", "RGBX", 0, -1)

        # Create Texture
        textures = glGenTextures(3)
        glBindTexture(GL_TEXTURE_2D, textures[0])       # 2d texture (x and y size)

        glPixelStorei(GL_UNPACK_ALIGNMENT, 1)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_BYTE, image)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST)
        glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST)
        glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_DECAL)

        # Create Linear Filtered Texture
        glBindTexture(GL_TEXTURE_2D, textures[1])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)
        glTexImage2D(GL_TEXTURE_2D, 0, 3, ix, iy, 0, GL_RGBA, GL_UNSIGNED_BYTE, image)

        # Create MipMapped Texture
        glBindTexture(GL_TEXTURE_2D, textures[2])
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST)
        gluBuild2DMipmaps(GL_TEXTURE_2D, 3, ix, iy, GL_RGBA, GL_UNSIGNED_BYTE, image)
        return textures



    def _drawfunc (self):
        """ draw callback function """
        # Draw the scene
        self.prepare_GL()

        if self.message:
            for item in self.message:
                self.draw_item(item)

        glutSwapBuffers()
        if self.captureScreen:
            self._screenshot()

    def _idlefunc(self):
        self.updateData()
        t = self.dt - (time.time() - self.lasttime)
        if (t > 0):
            time.sleep(t)
        self.lasttime = time.time()
        glutPostRedisplay ()

    def _keyfunc (self, c, x, y):
        """ keyboard call-back function. """
        if c == 's':
            self.setCaptureScreen(not self.getCaptureScreen())
            print "Screen Capture: " + (self.getCaptureScreen() and "on" or "off")
        if c in ['x', 'q']:
            sys.exit()
        if c == 'v':
            self.mouseView = not self.mouseView

    def _motionfunc(self, x, z):
        """Control the zoom factor"""
        if not self.mouseView: return
        zn = 2.75 * float(z) / self.height + 0.25   # [0.25,3]
        self.viewDistance = 3.0 * zn * zn
        self._passivemotionfunc(x, z)

    def _passivemotionfunc(self, x, z):
        """ Store the mouse coordinates (relative to center and normalized)
         the eye does not exactly move on a unit hemisphere; we fudge the projection
         a little by shifting the hemisphere into the ground by 0.1 units,
         such that approaching the perimeter dows not cause a huge change in the
         viewing direction. The limit for l is thus cos(arcsin(0.1))."""
        if not self.mouseView: return
        x1 = 3 * float(x) / self.width - 1.5
        z1 = -3 * float(z) / self.height + 1.5
        lsq = x1 * x1 + z1 * z1
        l = sqrt(lsq)
        if l > 0.994987:
            # for mouse outside window, project onto the unit circle
            x1 = x1 / l
            z1 = z1 / l
            y1 = 0
        else:
            y1 = max(0.0, sqrt(1.0 - x1 * x1 - z1 * z1) - 0.1)
        self.lasty = y1
        self.lastx = x1
        self.lastz = z1

    def _screenshot(self, path_prefix='.', format='PNG'):
        """Saves a screenshot of the current frame buffer.
        The save path is <path_prefix>/.screenshots/shot<num>.png
        The path is automatically created if it does not exist.
        Shots are automatically numerated based on how many files
        are already in the directory."""

        if self.counter == self.frameT:
            self.counter = 1
            dir = os.path.join(path_prefix, 'screenshots')
            if not os.path.exists(dir):
                os.makedirs(dir)

            num_present = len(os.listdir(dir))
            num_digits = len(str(num_present))
            index = '0' * (5 - num_digits) + str(num_present)

            path = os.path.join(dir, 'shot' + index + '.' + format.lower())
            glPixelStorei(GL_PACK_ALIGNMENT, 1)
            data = glReadPixels(0, 0, self.width, self.height, GL_RGB, GL_UNSIGNED_BYTE)
            image = Image.fromstring("RGB", (self.width, self.height), data)
            image = image.transpose(Image.FLIP_TOP_BOTTOM)
            image.save(path, format)
            print 'Image saved to %s' % (os.path.basename(path))
        else:
            self.counter += 1

        self.isCapturing = False
class FlexCubeRenderer(object): 
    #Options: ServerIP(default:localhost), OwnIP(default:localhost), Port(default:21560)
    def __init__(self, servIP="127.0.0.1", ownIP="127.0.0.1", port="21580"):
        self.oldScreenValues = None
        self.view = 0
        self.worldRadius = 400
                  
        # Start of mousepointer 
        self.lastx = 0
        self.lasty = 15
        self.lastz = 300
        self.zDis = 1
        
        # Start of cube 
        self.cube = [0.0, 0.0, 0.0]
        self.bmpCount = 0
        self.actCount = 0
        self.calcPhysics = 0
        self.newPic = 1
        self.picCount = 0
        self.sensors = [0.0, 0.0, 0.0]
        self.centerOfGrav = array([0.0, 5.0, 0.0])
        
        self.savePics = False
        self.drawCounter = 0
        self.fps = 50
        self.dt = 1.0 / float(self.fps)
        self.step = 0
        
        self.client = UDPClient(servIP, ownIP, port)
  
    # If self.savePics=True this method saves the produced images      
    def saveTo(self, filename, format="JPEG"):
        import Image # get PIL's functionality...
        width, height = 800, 600
        glPixelStorei(GL_PACK_ALIGNMENT, 1)
        data = glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE)
        image = Image.fromstring("RGB", (width, height), data)
        image = image.transpose(Image.FLIP_TOP_BOTTOM)
        image.save(filename, format)
        print 'Saved image to ', filename
        return image
    
    # the render method containing the Glut mainloop
    def _render(self):
        # Call init: Parameter(Window Position -> x, y, height, width)
        self.init_GL(self, 300, 300, 800, 600)    
        self.quad = gluNewQuadric()
        glutMainLoop()

    # The Glut idle function
    def drawIdleScene(self):
        #recive data from server and update the points of the cube
        try: self.sensors = self.client.listen(self.sensors)
        except: pass
        if self.sensors == ["r", "r", "r"]: self.centerOfGrav = array([0.0, 5.0, 0.0])
        else:
            self.step += 1
            a = self.sensors[0] / 360.0 * 3.1428
            dir = array([cos(a), 0.0, -sin(a)])
            self.centerOfGrav += self.sensors[2] * dir * 0.02
            self.drawScene()
        if self.savePics:
            self.saveTo("./screenshots/image_jump" + repr(10000 + self.picCount) + ".jpg")
            self.picCount += 1
        else: sleep(self.dt)
          
    def drawScene(self):
        ''' This methode describes the complete scene.'''
        # clear the buffer
        if self.zDis < 10: self.zDis += 0.25
        if self.lastz > 100: self.lastz -= self.zDis
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        glLoadIdentity()
        
        # Point of view
        glRotatef(self.lastx, 0.0, 1.0, 0.0)
        glRotatef(self.lasty, 1.0, 0.0, 0.0)      
        #glRotatef(15, 0.0, 0.0, 1.0)      
        # direction of view is aimed to the center of gravity of the cube
        glTranslatef(-self.centerOfGrav[0], -self.centerOfGrav[1] - 50.0, -self.centerOfGrav[2] - self.lastz)
        
        #Objects
       
        #Massstab
        for lk in range(41):
            if float(lk - 20) / 10.0 == (lk - 20) / 10: 
                glColor3f(0.75, 0.75, 0.75)
                glPushMatrix()
                glRotatef(90, 1, 0, 0)
                glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -30)
                quad = gluNewQuadric()
                gluCylinder(quad, 2, 2, 60, 4, 1)
                glPopMatrix()
            else: 
                if float(lk - 20) / 5.0 == (lk - 20) / 5:       
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -15.0)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 1, 1, 30, 4, 1)
                    glPopMatrix()
                else:
                    glColor3f(0.75, 0.75, 0.75)
                    glPushMatrix()
                    glRotatef(90, 1, 0, 0)
                    glTranslate(self.worldRadius / 40.0 * float(lk) - self.worldRadius / 2.0, -40.0, -7.5)
                    quad = gluNewQuadric()
                    gluCylinder(quad, 0.5, 0.5, 15, 4, 1)
                    glPopMatrix()
        
        # Floor
        tile = self.worldRadius / 40.0
        glEnable (GL_BLEND)
        glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)
        
        glColor3f(0.8, 0.8, 0.5)
        glPushMatrix()
        glTranslatef(0.0, -3.0, 0.0)
        glBegin(GL_QUADS)
        glNormal(0.0, 1.0, 0.0)      
        glVertex3f(-self.worldRadius, 0.0, -self.worldRadius)
        glVertex3f(-self.worldRadius, 0.0, self.worldRadius)
        glVertex3f(self.worldRadius, 0.0, self.worldRadius)
        glVertex3f(self.worldRadius, 0.0, -self.worldRadius)
        glEnd()
        glPopMatrix()
    
        #Water            
        for xF in range(40):
            for yF in range(40):
                if float(xF + yF) / 2.0 == (xF + yF) / 2: glColor4f(0.7, 0.7, 1.0, 0.5)
                else: glColor4f(0.9, 0.9, 1.0, 0.5)
                glPushMatrix()
                glTranslatef(0.0, -0.03, 0.0)
                glBegin(GL_QUADS)
                glNormal(0.5 + sin(float(xF) + float(self.step) / 4.0) * 0.5, 0.5 + cos(float(xF) + float(self.step) / 4.0) * 0.5, 0.0)      
                for i in range(2):
                    for k in range(2):
                        glVertex3f((i + xF - 20) * tile, sin(float(xF + i) + float(self.step) / 4.0) * 3.0, ((k ^ i) + yF - 20) * tile)
                glEnd()
                glPopMatrix()
    
        self.ship()
                  	    
        # swap the buffer
        glutSwapBuffers()    

    def ship(self):
        glColor3f(0.4, 0.1, 0.2)
        glPushMatrix()
        glTranslate(self.centerOfGrav[0] + 14, self.centerOfGrav[1], self.centerOfGrav[2])
        glRotatef(180 - self.sensors[0], 0.0, 1.0, 0.0)
        
        self.cuboid(0, 0, 0, 20, 5, 5)
        #bow of ship
        glBegin(GL_TRIANGLES)
        glNormal3fv(self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 5, 5]), self.points2Vector([-5, 6, 2.5], [0, 5, 0])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 5, 0), glVertex3f(0, 5, 5)
        glNormal3fv(self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 0, 5]), self.points2Vector([-5, 6, 2.5], [0, 5, 5])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 5), glVertex3f(0, 5, 5)
        glNormal3fv(self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 0, 0]), self.points2Vector([-5, 6, 2.5], [0, 0, 5])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 5), glVertex3f(0, 0, 0)
        glNormal3fv(self.calcNormal(self.points2Vector([-5, 6, 2.5], [0, 5, 0]), self.points2Vector([-5, 6, 2.5], [0, 0, 0])))
        glVertex3f(-5, 6, 2.5), glVertex3f(0, 0, 0), glVertex3f(0, 5, 0)
        glEnd()
        # stern
        glPushMatrix()
        glRotatef(-90, 1.0, 0.0, 0.0)
        glTranslatef(15, -2.5, 0)
        gluCylinder(self.quad, 2.5, 2.5, 5, 10, 1)
        glTranslatef(0, 0, 5)
        gluDisk(self.quad, 0, 2.5, 10, 1)
        glPopMatrix()
        # deck
        if abs(self.sensors[0]) < 5.0: reward = (self.sensors[2] + 10.0) / 50.0
        else: reward = 0.2
        glColor3f(1.0 - reward, reward, 0)
        self.cuboid(5, 5, 1, 10, 8, 4)
        glPushMatrix()
        glRotatef(-90, 1.0, 0.0, 0.0)
        glTranslatef(13, -2.5, 5)
        glColor3f(1, 1, 1)
        gluCylinder(self.quad, 1, 0.8, 5, 20, 1)
        glPopMatrix()
        glPopMatrix()
    
    def cuboid(self, x0, y0, z0, x1, y1, z1):
        glBegin(GL_QUADS)
        glNormal(0, 0, 1)
        glVertex3f(x0, y0, z1); glVertex3f(x0, y1, z1); glVertex3f(x1, y1, z1); glVertex3f(x1, y0, z1)  #front
        glNormal(-1, 0, 0)
        glVertex3f(x0, y0, z0); glVertex3f(x0, y0, z1); glVertex3f(x0, y1, z1); glVertex3f(x0, y1, z0) # left
        glNormal(0, -1, 0)
        glVertex3f(x0, y0, z0); glVertex3f(x0, y0, z1); glVertex3f(x1, y0, z1); glVertex3f(x1, y0, z0) # bottom
        glNormal(0, 0, -1)
        glVertex3f(x0, y0, z0); glVertex3f(x1, y0, z0); glVertex3f(x1, y1, z0); glVertex3f(x0, y1, z0) # back
        glNormal(0, 1, 0)
        glVertex3f(x0, y1, z0); glVertex3f(x1, y1, z0); glVertex3f(x1, y1, z1); glVertex3f(x0, y1, z1) # top
        glNormal(1, 0, 0)
        glVertex3f(x1, y0, z0); glVertex3f(x1, y0, z1); glVertex3f(x1, y1, z1); glVertex3f(x1, y1, z0) # right
        glEnd()
    
    def calcNormal(self, xVector, yVector):
        result = [0, 0, 0]
        result[0] = xVector[1] * yVector[2] - yVector[1] * xVector[2]
        result[1] = -xVector[0] * yVector[2] + yVector[0] * xVector[2]
        result[2] = xVector[0] * yVector[1] - yVector[0] * xVector[1]
        return [result[0], result[1], result[2]]
        
    def points2Vector(self, startPoint, endPoint):
        result = [0, 0, 0]
        result[0] = endPoint[0] - startPoint[0]
        result[1] = endPoint[1] - startPoint[1]
        result[2] = endPoint[2] - startPoint[2]
        return [result[0], result[1], result[2]]
        
    def resizeScene(self, width, height):
        '''Needed if window size changes.'''
        if height == 0: # Prevent A Divide By Zero If The Window Is Too Small 
            height = 1
    
        glViewport(0, 0, width, height) # Reset The Current Viewport And Perspective Transformation
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        gluPerspective(45.0, float(width) / float(height), 0.1, 700.0)
        glMatrixMode(GL_MODELVIEW)
    
    def activeMouse(self, x, y):
        #Returns mouse coordinates while any mouse button is pressed.
        # store the mouse coordinate
        if self.mouseButton == GLUT_LEFT_BUTTON:
            self.lastx = x - self.xOffset
            self.lasty = y - self.yOffset
        if self.mouseButton == GLUT_RIGHT_BUTTON:
            self.lastz = y - self.zOffset 
        # redisplay
        glutPostRedisplay()
      
    def passiveMouse(self, x, y):
        '''Returns mouse coordinates while no mouse button is pressed.'''
        pass
        
    def completeMouse(self, button, state, x, y):
        #Returns mouse coordinates and which button was pressed resp. released.
        self.mouseButton = button
        if state == GLUT_DOWN:
            self.xOffset = x - self.lastx
            self.yOffset = y - self.lasty
            self.zOffset = y - self.lastz
        # redisplay
        glutPostRedisplay()
        
    #Initialise an OpenGL windows with the origin at x, y and size of height, width.
    def init_GL(self, pyWorld, x, y, height, width):
        # initialize GLUT 
        glutInit([])
          
        glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH)
        glutInitWindowSize(height, width)
        glutInitWindowPosition(x, y)
        glutCreateWindow("The Curious Cube")
        glClearDepth(1.0)
        glEnable(GL_DEPTH_TEST)
        glClearColor(0.0, 0.0, 0.0, 0.0)
        glShadeModel(GL_SMOOTH)
        glMatrixMode(GL_MODELVIEW)
        # initialize lighting */
        glLightfv(GL_LIGHT0, GL_DIFFUSE, [1, 1, 1, 1.0])
        glLightModelfv(GL_LIGHT_MODEL_AMBIENT, [1.0, 1.0, 1.0, 1.0])
        glEnable(GL_LIGHTING)
        glEnable(GL_LIGHT0)
        # 
        glColorMaterial(GL_FRONT, GL_DIFFUSE)
        glEnable(GL_COLOR_MATERIAL)
        # Automatic vector normalise
        glEnable(GL_NORMALIZE)
        
        ### Instantiate the virtual world ###
        glutDisplayFunc(pyWorld.drawScene)
        glutMotionFunc(pyWorld.activeMouse)
        glutMouseFunc(pyWorld.completeMouse)
        glutReshapeFunc(pyWorld.resizeScene)
        glutIdleFunc(pyWorld.drawIdleScene)