Package bloom

Source Code of bloom.Bloom

package bloom;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL10;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.Mesh;
import com.badlogic.gdx.graphics.Pixmap.Format;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.VertexAttribute;
import com.badlogic.gdx.graphics.VertexAttributes.Usage;
import com.badlogic.gdx.graphics.glutils.FrameBuffer;
import com.badlogic.gdx.graphics.glutils.ShaderProgram;

/** Bloomlib allow easy but efficient way to add bloom effect as post process effect
* @author kalle_h
*
*/
public class Bloom {

  /**
   * To use implement bloom more like a glow. Texture alpha channel can be
   * used as mask which part are glowing and whic are not. see more info at:
   * http://www.gamasutra.com/view/feature/2107/realtime_glow.php
   *
   * NOTE: need to be set before bloom instance is created. After that this
   * does nothing.
   */
  public static boolean useAlphaChannelAsMask = false;

  /** how many blur pass */
  public int blurPasses = 1;

  private ShaderProgram tresholdShader;
  private ShaderProgram bloomShader;

  private Mesh fullScreenQuad;

  private Texture pingPongTex1;
  private Texture pingPongTex2;
  private Texture original;

  private FrameBuffer frameBuffer;
  private FrameBuffer pingPongBuffer1;
  private FrameBuffer pingPongBuffer2;

  private ShaderProgram blurShader;

  private float bloomIntensity;
  private float originalIntensity;
  private float treshold;
  private int w;
  private int h;
  private boolean blending = false;
  private boolean capturing = false;
  private float r = 0f;
  private float g = 0f;
  private float b = 0f;
  private float a = 0f;
  private boolean disposeFBO = true;

  /**
   * IMPORTANT NOTE CALL THIS WHEN RESUMING
   */
  public void resume() {
    setSize(w, h);
    setTreshold(treshold);
    setBloomIntesity(bloomIntensity);
    setOriginalIntesity(originalIntensity);

    original = frameBuffer.getColorBufferTexture();
    pingPongTex1 = pingPongBuffer1.getColorBufferTexture();
    pingPongTex2 = pingPongBuffer2.getColorBufferTexture();
  }

  /**
   * Initialize bloom class that capsulate original scene capturate,
   * tresholding, gaussian blurring and blending. Default values: depth = true
   * blending = false 32bits = true
   */
  public Bloom() {
    initialize(Gdx.graphics.getWidth() / 4, Gdx.graphics.getHeight() / 4,
        null, true, false, true);
  }

  /**
   * Initialize bloom class that capsulate original scene capturate,
   * tresholding, gaussian blurring and blending.
   *
   * @param FBO_W
   * @param FBO_H
   *            how big fbo is used for bloom texture, smaller = more blur and
   *            lot faster but aliasing can be problem
   * @param hasDepth
   *            do rendering need depth buffer
   * @param useBlending
   *            does fbo need alpha channel and is blending enabled when final
   *            image is rendered. This allow to combine background graphics
   *            and only do blooming on certain objects param use32bitFBO does
   *            fbo use higher precision than 16bits.
   */
  public Bloom(int FBO_W, int FBO_H, boolean hasDepth, boolean useBlending,
      boolean use32bitFBO) {
    initialize(FBO_W, FBO_H, null, hasDepth, useBlending, use32bitFBO);

  }

  /**
   * EXPERT FUNCTIONALITY. no error checking. Use this only if you know what
   * you are doing. Remember that bloom.capture() clear the screen so use
   * continue instead if that is a problem.
   *
   * Initialize bloom class that capsulate original scene capturate,
   * tresholding, gaussian blurring and blending.
   *
   * * @param sceneIsCapturedHere diposing is user responsibility.
   *
   * @param FBO_W
   * @param FBO_H
   *            how big fbo is used for bloom texture, smaller = more blur and
   *            lot faster but aliasing can be problem
   * @param hasDepth
   *            do rendering need depth buffer
   * @param useBlending
   *            does fbo need alpha channel and is blending enabled when final
   *            image is rendered. This allow to combine background graphics
   *            and only do blooming on certain objects param use32bitFBO does
   *            fbo use higher precision than 16bits.
   */
  public Bloom(int FBO_W, int FBO_H, FrameBuffer sceneIsCapturedHere,
      boolean useBlending, boolean use32bitFBO) {

    initialize(FBO_W, FBO_H, sceneIsCapturedHere, false, useBlending,
        use32bitFBO);
    disposeFBO = false;
  }

  private void initialize(int FBO_W, int FBO_H, FrameBuffer fbo,
      boolean hasDepth, boolean useBlending, boolean use32bitFBO) {
    blending = useBlending;
    Format format = null;

    if (use32bitFBO) {
      if (useBlending) {
        format = Format.RGBA8888;
      } else {
        format = Format.RGB888;
      }

    } else {
      if (useBlending) {
        format = Format.RGBA4444;
      } else {
        format = Format.RGB565;
      }
    }
    if (fbo == null) {
      frameBuffer = new FrameBuffer(format, Gdx.graphics.getWidth(),
          Gdx.graphics.getHeight(), hasDepth);
    } else {
      frameBuffer = fbo;
    }

    pingPongBuffer1 = new FrameBuffer(format, FBO_W, FBO_H, false);

    pingPongBuffer2 = new FrameBuffer(format, FBO_W, FBO_H, false);

    original = frameBuffer.getColorBufferTexture();
    pingPongTex1 = pingPongBuffer1.getColorBufferTexture();
    pingPongTex2 = pingPongBuffer2.getColorBufferTexture();

    fullScreenQuad = createFullScreenQuad();

    bloomShader = ShaderLoader.createShader("bloom/screenspace",
        "bloom/bloom");

    if (useAlphaChannelAsMask) {
      tresholdShader = ShaderLoader.createShader("bloom/screenspace",
          "bloom/maskedtreshold");
    } else {
      tresholdShader = ShaderLoader.createShader("bloom/screenspace",
          "bloom/treshold");
    }

    blurShader = ShaderLoader.createShader("bloom/blurspace",
        "bloom/gaussian");

    setSize(FBO_W, FBO_H);
    setBloomIntesity(2.5f);
    setOriginalIntesity(0.8f);
    setTreshold(0.5f);
  }

  /**
   * Set clearing color for capturing buffer
   *
   * @param r
   * @param g
   * @param b
   * @param a
   */
  public void setClearColor(float r, float g, float b, float a) {
    this.r = r;
    this.g = g;
    this.b = b;
    this.a = a;
  }

  /**
   * Call this before rendering scene.
   */
  public void capture() {
    if (!capturing) {
      capturing = true;
      frameBuffer.begin();
      Gdx.gl.glClearColor(r, g, b, a);
      Gdx.gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);

    }
  }

  /**
   * Pause capturing to fbo.
   */
  public void capturePause() {
    if (capturing) {
      capturing = false;
      frameBuffer.end();
    }
  }

  /** Start capturing again after pause, no clearing is done to framebuffer */
  public void captureContinue() {
    if (!capturing) {
      capturing = true;
      frameBuffer.begin();
    }
  }

  /**
   * Call this after scene. Renders the bloomed scene.
   */
  public void render() {
    if (capturing) {
      capturing = false;
      frameBuffer.end();
    }

    Gdx.gl.glDisable(GL10.GL_BLEND);
    Gdx.gl.glDisable(GL10.GL_DEPTH_TEST);
    Gdx.gl.glDepthMask(false);

    gaussianBlur();

    if (blending) {
      Gdx.gl.glEnable(GL10.GL_BLEND);
      Gdx.gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE_MINUS_SRC_ALPHA);
    }

    pingPongTex1.bind(1);
    original.bind(0);
    bloomShader.begin();
    {
      bloomShader.setUniformi("u_texture0", 0);
      bloomShader.setUniformi("u_texture1", 1);
      fullScreenQuad.render(bloomShader, GL20.GL_TRIANGLE_FAN);
    }
    bloomShader.end();

  }

  private void gaussianBlur() {

    // cut bright areas of the picture and blit to smaller fbo

    original.bind(0);
    pingPongBuffer1.begin();
    {
      tresholdShader.begin();
      {
        // tresholdShader.setUniformi("u_texture0", 0);
        fullScreenQuad.render(tresholdShader, GL20.GL_TRIANGLE_FAN, 0,
            4);
      }
      tresholdShader.end();
    }
    pingPongBuffer1.end();

    for (int i = 0; i < blurPasses; i++) {

      pingPongTex1.bind(0);

      // horizontal
      pingPongBuffer2.begin();
      {
        blurShader.begin();
        {
          // blurShader.setUniformi("u_texture", 0);
          blurShader.setUniformf("dir", 1f, 0f);
          fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
              4);
        }
        blurShader.end();
      }
      pingPongBuffer2.end();

      pingPongTex2.bind(0);
      // vertical
      pingPongBuffer1.begin();
      {
        blurShader.begin();
        {
          // blurShader.setUniformi("u_texture", 0);
          blurShader.setUniformf("dir", 0f, 1f);

          fullScreenQuad.render(blurShader, GL20.GL_TRIANGLE_FAN, 0,
              4);
        }
        blurShader.end();
      }
      pingPongBuffer1.end();
    }
  }

  /**
   * set intensity for bloom. higher mean more brightening for spots that are
   * over treshold
   *
   * @param intensity
   *            multiplier for blurred texture in combining phase. must be
   *            positive.
   */
  public void setBloomIntesity(float intensity) {
    bloomIntensity = intensity;
    bloomShader.begin();
    {
      bloomShader.setUniformf("BloomIntensity", intensity);
    }
    bloomShader.end();
  }

  /**
   * set intensity for original scene. under 1 mean darkening and over 1 means
   * lightening
   *
   * @param intensity
   *            multiplier for captured texture in combining phase. must be
   *            positive.
   */
  public void setOriginalIntesity(float intensity) {
    originalIntensity = intensity;
    bloomShader.begin();
    {
      bloomShader.setUniformf("OriginalIntensity", intensity);
    }
    bloomShader.end();
  }

  /**
   * Treshold for bright parts. everything under treshold is clamped to 0
   *
   * @param treshold
   *            must be in range 0..1
   */
  public void setTreshold(float treshold) {
    this.treshold = treshold;
    tresholdShader.begin();
    {
      tresholdShader.setUniformf("treshold", treshold);
      tresholdShader.setUniformf("tresholdD", (1f / (1 - treshold)));
    }
    tresholdShader.end();
  }

  private void setSize(int FBO_W, int FBO_H) {
    w = FBO_W;
    h = FBO_H;
    blurShader.begin();
    blurShader.setUniformf("size", FBO_W, FBO_H);
    blurShader.end();
  }

  /**
   * Call this when application is exiting.
   *
   */
  public void dispose() {
    if (disposeFBO)
      frameBuffer.dispose();

    fullScreenQuad.dispose();

    pingPongBuffer1.dispose();
    pingPongBuffer2.dispose();

    blurShader.dispose();
    bloomShader.dispose();
    tresholdShader.dispose();

  }

  private Mesh createFullScreenQuad() {
    float[] verts = new float[16];// VERT_SIZE
    int i = 0;
    verts[i++] = -1; // x1
    verts[i++] = -1; // y1

    verts[i++] = 0f; // u1
    verts[i++] = 0f; // v1

    verts[i++] = 1f; // x2
    verts[i++] = -1; // y2

    verts[i++] = 1f; // u2
    verts[i++] = 0f; // v2

    verts[i++] = 1f; // x3
    verts[i++] = 1f; // y2

    verts[i++] = 1f; // u3
    verts[i++] = 1f; // v3

    verts[i++] = -1; // x4
    verts[i++] = 1f; // y4

    verts[i++] = 0f; // u4
    verts[i++] = 1f; // v4

    Mesh tmpMesh = new Mesh(true, 4, 0, new VertexAttribute(
        Usage.Position, 2, "a_position"), new VertexAttribute(
        Usage.TextureCoordinates, 2, "a_texCoord0"));

    tmpMesh.setVertices(verts);
    return tmpMesh;

  }

}
TOP

Related Classes of bloom.Bloom

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.