protected void runLoop() {
    if (!created.get()) {
      throw new IllegalStateException();
    }

    if (pbuffer.isBufferLost()) {
      pbuffer.destroy();

      try {
        pbuffer = new Pbuffer(width, height, pixelFormat, null);
        pbuffer.makeCurrent();

        // Context MUST be reset here to avoid invalid objects!
        renderer.invalidateState();
      } catch (LWJGLException ex) {
        listener.handleError("Failed to restore pbuffer content", ex);
      }
    }

    listener.update();
    checkGLError();

    renderer.postFrame();

    // Need to flush GL commands
    // to see any result on the pbuffer's front buffer.
    GL11.glFlush();

    int frameRate = settings.getFrameRate();
    if (frameRate >= 1) {
      Display.sync(frameRate);
    }
  }
  private void render(
      final List<? extends Spatial> toDrawA,
      final Spatial toDrawB,
      final Scene toDrawC,
      final List<Texture> texs,
      final int clear) {
    try {
      if (_pbuffer == null || _pbuffer.isBufferLost()) {
        if (_pbuffer != null && _pbuffer.isBufferLost()) {
          logger.warning("PBuffer contents lost - will recreate the buffer");
          deactivate();
          _pbuffer.destroy();
        }
        initPbuffer();
      }

      if (texs.size() == 1
          && _useDirectRender
          && !texs.get(0).getTextureStoreFormat().isDepthFormat()) {
        // setup and render directly to a 2d texture.
        LwjglTextureStateUtil.doTextureBind(texs.get(0), 0, true);
        activate();
        switchCameraIn(clear);
        _pbuffer.releaseTexImage(Pbuffer.FRONT_LEFT_BUFFER);

        if (toDrawA != null) {
          doDraw(toDrawA);
        } else {
          doDraw(toDrawB);
        }

        switchCameraOut();

        deactivate();
        _pbuffer.bindTexImage(Pbuffer.FRONT_LEFT_BUFFER);
      } else {
        // render and copy to a texture
        activate();
        switchCameraIn(clear);

        if (toDrawA != null) {
          doDraw(toDrawA);
        } else {
          doDraw(toDrawB);
        }

        switchCameraOut();

        for (int i = 0; i < texs.size(); i++) {
          copyToTexture(texs.get(i), 0, 0, _width, _height, 0, 0);
        }

        deactivate();
      }

    } catch (final Exception e) {
      logger.logp(
          Level.SEVERE, this.getClass().toString(), "render(Spatial, Texture)", "Exception", e);
    }
  }
  protected void deinitInThread() {
    renderable.set(false);

    listener.destroy();
    renderer.cleanup();
    pbuffer.destroy();
    logger.fine("Offscreen buffer destroyed.");

    super.internalDestroy();
  }
  protected int determineMaxSamples(int requestedSamples) {
    boolean displayWasCurrent = false;
    try {
      // If we already have a valid context, determine samples using current
      // context.
      if (Display.isCreated() && Display.isCurrent()) {
        if (GLContext.getCapabilities().GL_ARB_framebuffer_object) {
          return GL11.glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES);
        } else if (GLContext.getCapabilities().GL_EXT_framebuffer_multisample) {
          return GL11.glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT);
        }
        // Doesn't support any of the needed extensions .. continue down.
        displayWasCurrent = true;
      }
    } catch (LWJGLException ex) {
      listener.handleError("Failed to check if display is current", ex);
    }

    if ((Pbuffer.getCapabilities() & Pbuffer.PBUFFER_SUPPORTED) == 0) {
      // No pbuffer, assume everything is supported.
      return Integer.MAX_VALUE;
    } else {
      Pbuffer pb = null;

      if (!displayWasCurrent) {
        // OpenGL2 method: Create pbuffer and query samples
        // from GL_ARB_framebuffer_object or GL_EXT_framebuffer_multisample.
        try {
          pb = new Pbuffer(1, 1, new PixelFormat(0, 0, 0), null);
          pb.makeCurrent();

          if (GLContext.getCapabilities().GL_ARB_framebuffer_object) {
            return GL11.glGetInteger(ARBFramebufferObject.GL_MAX_SAMPLES);
          } else if (GLContext.getCapabilities().GL_EXT_framebuffer_multisample) {
            return GL11.glGetInteger(EXTFramebufferMultisample.GL_MAX_SAMPLES_EXT);
          }

          // OpenGL2 method failed.
        } catch (LWJGLException ex) {
          // Something else failed.
          return Integer.MAX_VALUE;
        } finally {
          if (pb != null) {
            pb.destroy();
            pb = null;
          }
        }
      }

      // OpenGL1 method (DOESNT WORK RIGHT NOW ..)
      requestedSamples = FastMath.nearestPowerOfTwo(requestedSamples);
      try {
        requestedSamples = Integer.MAX_VALUE;
        /*
        while (requestedSamples > 1) {
            try {
                pb = new Pbuffer(1, 1, new PixelFormat(16, 0, 8, 0, requestedSamples), null);
            } catch (LWJGLException ex) {
                if (ex.getMessage().startsWith("Failed to find ARB pixel format")) {
                    // Unsupported format, so continue.
                    requestedSamples = FastMath.nearestPowerOfTwo(requestedSamples / 2);
                } else {
                    // Something else went wrong ..
                    return Integer.MAX_VALUE;
                }
            } finally {
                if (pb != null){
                    pb.destroy();
                    pb = null;
                }
            }
        }*/
      } finally {
        if (displayWasCurrent) {
          try {
            Display.makeCurrent();
          } catch (LWJGLException ex) {
            listener.handleError("Failed to make display current after checking samples", ex);
          }
        }
      }

      return requestedSamples;
    }
  }
 public void cleanup() {
   ContextManager.removeContext(_pbuffer);
   _pbuffer.destroy();
 }