/*
 *  Copyright 2015 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */

package org.webrtc;

import android.opengl.GLES20;

/**
 * Helper class for handling OpenGL framebuffer with only color attachment and no depth or stencil
 * buffer. Intended for simple tasks such as texture copy, texture downscaling, and texture color
 * conversion.
 */
// TODO(magjed): Add unittests for this class.
public class GlTextureFrameBuffer {
  private final int frameBufferId;
  private final int textureId;
  private final int pixelFormat;
  private int width;
  private int height;

  /**
   * Generate texture and framebuffer resources. An EGLContext must be bound on the current thread
   * when calling this function. The framebuffer is not complete until setSize() is called.
   */
  public GlTextureFrameBuffer(int pixelFormat) {
    switch (pixelFormat) {
      case GLES20.GL_LUMINANCE:
      case GLES20.GL_RGB:
      case GLES20.GL_RGBA:
        this.pixelFormat = pixelFormat;
        break;
      default:
        throw new IllegalArgumentException("Invalid pixel format: " + pixelFormat);
    }

    textureId = GlUtil.generateTexture(GLES20.GL_TEXTURE_2D);
    this.width = 0;
    this.height = 0;

    // Create framebuffer object and bind it.
    final int frameBuffers[] = new int[1];
    GLES20.glGenFramebuffers(1, frameBuffers, 0);
    frameBufferId = frameBuffers[0];
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);
    GlUtil.checkNoGLES2Error("Generate framebuffer");

    // Attach the texture to the framebuffer as color attachment.
    GLES20.glFramebufferTexture2D(
        GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textureId, 0);
    GlUtil.checkNoGLES2Error("Attach texture to framebuffer");

    // Restore normal framebuffer.
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
  }

  /**
   * (Re)allocate texture. Will do nothing if the requested size equals the current size. An
   * EGLContext must be bound on the current thread when calling this function. Must be called at
   * least once before using the framebuffer. May be called multiple times to change size.
   */
  public void setSize(int width, int height) {
    if (width == 0 || height == 0) {
      throw new IllegalArgumentException("Invalid size: " + width + "x" + height);
    }
    if (width == this.width && height == this.height) {
      return;
    }
    this.width = width;
    this.height = height;

    // Bind our framebuffer.
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);
    GlUtil.checkNoGLES2Error("glBindFramebuffer");

    // Allocate texture.
    GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
    GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, pixelFormat, width, height, 0, pixelFormat,
        GLES20.GL_UNSIGNED_BYTE, null);

    // Check that the framebuffer is in a good state.
    final int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);
    if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) {
      throw new IllegalStateException("Framebuffer not complete, status: " + status);
    }

    // Restore normal framebuffer.
    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
  }

  public int getWidth() {
    return width;
  }

  public int getHeight() {
    return height;
  }

  public int getFrameBufferId() {
    return frameBufferId;
  }

  public int getTextureId() {
    return textureId;
  }

  /**
   * Release texture and framebuffer. An EGLContext must be bound on the current thread when calling
   * this function. This object should not be used after this call.
   */
  public void release() {
    GLES20.glDeleteTextures(1, new int[] {textureId}, 0);
    GLES20.glDeleteFramebuffers(1, new int[] {frameBufferId}, 0);
    width = 0;
    height = 0;
  }
}

@@ -2785,157 +2785,8 @@
 t;%0A%0A
-    // Bind our framebuffer.%0A    GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, frameBufferId);%0A    GlUtil.checkNoGLES2Error(%22glBindFramebuffer%22);%0A%0A
     
@@ -2806,16 +2806,16 @@
 exture.%0A
+
     GLES
@@ -3050,426 +3050,118 @@
 l);%0A
-%0A
     
-// Check that the framebuffer is in a good state.%0A    final int status = GLES20.glCheckFramebufferStatus(GLES20.GL_FRAMEBUFFER);%0A    if (status != GLES20.GL_FRAMEBUFFER_COMPLETE) %7B%0A      throw new IllegalStateException(%22Framebuffer not complete, status: %22 + status);%0A    %7D%0A%0A    // Restore normal framebuffer.%0A    GLES20.glBind
+GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);%0A    GlUtil.checkNoGLES2Error(%22GlTexture
 Frame
-b
+B
 uffer
-(GLES20.GL_FRAMEBUFFER, 0);%0A    GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0
+ setSize%22
 );%0A 

Remove binding framebuffer from GlTextureFrameBuffer.setSize.