@Override
  public void onUpdate() {
    cur = now;
    now = getTimeSinceStartMillis();
    TIME_DELTA = (now - cur) / 100.0f;
    if (current_world != null && !isPaused()) {
      if (!dontUpdate) {
        Iterator<UpdatableDrawable> updates = current_world.getUpdatables();
        while (updates.hasNext()) {
          UpdatableDrawable s = updates.next();
          if (s == null) continue;
          try {
            s.update();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
      }
      glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
      glClearColor(0f, 0f, 0f, 1f);
      // ROBO //todo get this crap changed into proper ogl
      glMatrixMode(GL_MODELVIEW);
      glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
      glLoadIdentity();
      glScalef(ZOOM_SCALE, ZOOM_SCALE, 1f);

      // ROBO //todo change this crap into proper postprocess and per material shaders
      ShaderFactory.executePreRender();

      if (isFading) {
        long time = getTime() - startTime;
        curAlpha = Camera.ease(startAlpha, newAlpha, speed, time);
        if (curAlpha == newAlpha) {
          isFading = false;
        }
      }
      if (isFadingBox) {
        long time = getTime() - startTime;
        float alpha = Camera.ease(0f, 1f, speed, time);
        if (alpha == 1f) {
          isFadingBox = false;
        }
        glColor4f(1f, 1f, 1f, alpha);
        renderBox();
      }

      glTranslatef(-Camera.getX(), -Camera.getY(), 0f);

      glColor4f(1f, 1f, 1f, curAlpha);
      // ROBO //todo get all these into proper batches

      if (curAlpha > 0f) {
        Iterator<Drawable> usprites = current_world.getUnsortedDrawables();
        while (usprites.hasNext()) {
          Drawable s = usprites.next();
          if (s == null) continue;
          try {
            if (!s.neverClip()
                && (!(s instanceof TileObject) || !((TileObject) s).isParallaxLayer())
                && Camera.isOffScreen(s.getX(), s.getY(), s.getWidth() / 2, s.getHeight() / 2))
              continue;
            s.render();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }

        Iterator<Drawable> sprites = current_world.getSortedDrawables();
        while (sprites.hasNext()) {
          Drawable s = sprites.next();
          if (s == null) continue;
          try {
            if (!s.neverClip()
                && (!(s instanceof TileObject) || !((TileObject) s).isParallaxLayer())
                && Camera.isOffScreen(s.getX(), s.getY(), s.getWidth() / 2, s.getHeight() / 2))
              continue;
            s.render();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
      }

      ShaderFactory.executePostRender();

      glLoadIdentity();
      glScalef(ZOOM_SCALE, ZOOM_SCALE, 1f);

      if (show_ui) {
        for (UI e : current_world.getElements()) {
          if (e == null) return;
          try {
            e.render();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }
      }

      if (next_world != null) {
        long time = getTime() - fadeStartTime;
        float percent;
        if (time > fadeDuration) {
          percent = 1;
        } else {
          percent = time / fadeDuration;
        }
        float emu = curAlpha;
        curAlpha =
            percent; // Some drawables require the curAlpha to be set, so we save what it use to be
        // and set it
        glColor4f(1f, 1f, 1f, curAlpha);

        Iterator<Drawable> next_sprites = next_world.getSortedDrawables();
        while (next_sprites.hasNext()) {
          Drawable s = next_sprites.next();
          if (s == null) continue;
          try {
            if (!s.neverClip()
                && (!(s instanceof TileObject) || !((TileObject) s).isParallaxLayer())
                && Camera.isOffScreen(s.getX(), s.getY(), s.getWidth() / 2, s.getHeight() / 2))
              continue;
            s.render();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }

        glLoadIdentity();
        glScalef(ZOOM_SCALE, ZOOM_SCALE, 1f);

        for (UI e : next_world.getElements()) {
          if (e == null) return;
          try {
            e.render();
          } catch (Throwable t) {
            t.printStackTrace();
          }
        }

        curAlpha = emu;

        if (percent == 1) {
          current_world.onUnload();
          current_world = next_world;
          current_world.onDisplay();
          next_world = null;
        }
      }

      try {
        AnimationFactory.executeTick(); // Execute any animation
      } catch (IllegalAccessException e) {
        e.printStackTrace();
      }

      Camera.executeAnimation(); // Execute any interlop
      // exitOnGLError("RenderService.renderSprites");

      Display.update();

      fpsTime += TIME_DELTA;
      fpsCount++;
      if (fpsCount == 100) {
        fpsCount = 0;
        FPS = (1000f / fpsTime);
        Display.setTitle("FPS: " + FPS);
        fpsTime = 0;
      }
      if (Display.isCloseRequested()) {
        kill();
      }

      if (GameSettings.Graphics.FPSLimit != -1) {
        Display.sync(GameSettings.Graphics.FPSLimit);
      }
    } else {
      try {
        Thread.sleep(15); // Keep the thread busy
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
    }
  }
  @Override
  protected void onStart() {
    INSTANCE = this;

    RENDER_THREAD_ID = Thread.currentThread().getId();

    try {
      loadIcons();
      Display.setIcon(icons);
      Display.setVSyncEnabled(GameSettings.Graphics.vsync);
    } catch (IOException e) {
      e.printStackTrace();
    }

    try {
      setDisplayMode(
          GameSettings.Display.window_width,
          GameSettings.Display.window_height,
          GameSettings.Display.fullscreen);
      Display.create();
      // ROBO //todo get all this changed to proper OGL
      glClearColor(0f, 0f, 0f, 1f);
      glClearDepth(1f);
      glViewport(0, 0, GameSettings.Display.window_width, GameSettings.Display.window_height);
      glMatrixMode(GL_PROJECTION);
      glLoadIdentity();

      glOrtho(
          0.0f,
          GameSettings.Display.resolution.getWidth(),
          GameSettings.Display.resolution.getHeight(),
          0.0f,
          0.1f,
          -1f);
      glMatrixMode(GL_MODELVIEW);
      glEnable(GL_TEXTURE_2D);
      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
      glLoadIdentity();
      curAlpha = 1f;
      capabilities = GLContext.getCapabilities();

      System.out.println("OpenGL version: " + glGetString(GL_VERSION));

      System.out.println("Building shaders..");
      long ms = getTime();
      ShaderFactory.buildAllShaders();
      System.out.println("Done! Took " + (getTime() - ms) + "ms.");

    } catch (LWJGLException e) {
      e.printStackTrace();
      System.exit(0);
    } catch (Exception e) {
      e.printStackTrace();
      System.exit(0);
    } finally {
      if (looping) {
        looping = false;
        Display.destroy();
      }
    }

    started = getTime();
    next_tick = getTime();
    getDelta();
  }