@Override
  public void onDrawFrame(GL10 gl) {
    try {
      gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
      gl.glMatrixMode(GL10.GL_MODELVIEW);
      gl.glLoadIdentity();

      if (positionBuffer != null) {
        gl.glLightfv(GL10.GL_LIGHT0, GL10.GL_POSITION, positionBuffer);
      }

      synchronized (camera) {
        PointF c = getCameraLocation();
        if (c == camera) {
          GLU.gluLookAt(gl, c.x, c.y, zoom, camera.x, camera.y, 0.0f, 0.0f, 1.0f, 0.0f);
        } else {
          GLU.gluLookAt(
              gl,
              c.x,
              c.y,
              zoom / followHeightFactor,
              camera.x,
              camera.y,
              -FOLLOW_LOOK_AT_HEIGHT,
              0.0f,
              0.0f,
              -1.0f);
        }
      }

      synchronized (areas) {
        for (SimArea area : areas.values()) {
          if (!onlySeenAreas || seenAreas.contains(area.getID())) {
            area.draw(gl);
          }
        }
      }

      if (drawWalls) {
        synchronized (walls) {
          for (SimWall wall : walls) {
            wall.draw(gl);
          }
        }

        synchronized (wallTops) {
          for (SimWallTop wallTop : wallTops) {
            wallTop.draw(gl);
          }
        }
      }

      synchronized (objects) {
        for (SimObject obj : objects.values()) {
          obj.draw(gl);
        }
      }

      synchronized (robots) {
        for (SimRobot robot : robots.values()) {
          robot.draw(gl, drawRedLidar, drawBlueLidar, drawYellowWaypoint);
        }
      }

      synchronized (lastFloorTouch) {
        GLUtil.drawRect(
            gl,
            lastFloorTouch.x - 0.05f,
            lastFloorTouch.y - 0.25f,
            -0.01f,
            0.1f,
            0.5f,
            GLUtil.GRAY);
        GLUtil.drawRect(
            gl,
            lastFloorTouch.x - 0.25f,
            lastFloorTouch.y - 0.05f,
            -0.01f,
            0.5f,
            0.1f,
            GLUtil.GRAY);
      }

    } catch (ConcurrentModificationException e) {
      e.printStackTrace();
    }
  }