Added an option for Premultiplied Alpha Blending

As per this conversation with A. Colubri:

http://forum.processing.org/one/topic/drawing-opengl-into-pgraphics-with-alpha-0-5f-produces-extremely-faint-output-more-like-0-1f.html

...And this old bug report:
https://github.com/processing/processing/issues/2083.html

Sorry if this isn't how such simple suggestions are to be done, it's my
first time doing anything with git.

EDIT:

At the bottom is the example sketch from the above thread, altered to now use Premultiply blending, thus giving the expected image outcome, so that switching between direct drawing and through PGraphics objects (spacebar) looks the same.

EDIT 2:

Here's also an exhaustive article on the benefits of premultiplied alpha blending: http://my.opera.com/emoller/blog/2012/08/28/alpha-blending
I'm now no longer sure I'm using it 100% correctly in my example, although I get the expected outcome so it cannot be entirely wrong :)

import java.nio.*;
import javax.media.opengl.GL2;

PGL         pgl;
PGraphics   pg_1, pg_2;
PShader     flatShader;
int         vertLoc, colorLoc;
float[]     vertices, colors;
FloatBuffer vertData, colorData;

int         vertLoc2;
float[]     vertices2;
FloatBuffer vertData2;

boolean     drawPGraphicsImage = true;
boolean     blend = true;
float       alpha = 0.5f;
float angle;
float jitter;

int m_Width   = 400;
int m_Height  = 400;

// Keys: 
// 'a':       toggles between alpha == 0.5f and alpha == 1.0f.
// spacebar:  toggles between rendering directly, and into a PGraphics buffer.
// blend:     toggles between REPLACE and PREMULTIPLY when drawing PGraphics

void setup() {
  size(m_Width, m_Height, OPENGL);

  pg_1 = createGraphics(m_Width, m_Height, OPENGL);
  pg_2 = createGraphics(m_Width, m_Height, OPENGL);
  
  flatShader = loadShader("frag.glsl", "vert.glsl");

  vertices = new float[12];
  vertData = allocateDirectFloatBuffer(12);

  colors = new float[12];
  colorData = allocateDirectFloatBuffer(12);
  
  vertices2 = new float[12];
  vertData2 = allocateDirectFloatBuffer(12);
}

void draw() {
  updateGeometry();
  updateGeometry2();
  
  background(0);
  
  if(drawPGraphicsImage)
    drawImage();
  else
    drawDirectly();
}

void keyPressed() {
  if (key == ' ') {
    drawPGraphicsImage = !drawPGraphicsImage;
  }
  else if (key == 'r') {
    blend = !blend;
  }
  else if (key == 'a') {
    if(alpha == 0.5f)
      alpha = 1.0f;
    else 
      alpha = 0.5f;
  }
}

// This works as expected
void drawDirectly() {
  pgl = beginPGL();
  flatShader.bind();
  vertLoc = pgl.getAttribLocation(flatShader.glProgram, "vertex");
  colorLoc = pgl.getAttribLocation(flatShader.glProgram, "color");
  pgl.enableVertexAttribArray(vertLoc);
  pgl.enableVertexAttribArray(colorLoc);
  pgl.vertexAttribPointer(vertLoc, 4, PGL.FLOAT, false, 0, vertData);
  pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 0, colorData);
  pgl.drawArrays(PGL.TRIANGLES, 0, 3);
  pgl.disableVertexAttribArray(vertLoc);
  pgl.disableVertexAttribArray(colorLoc);
  flatShader.unbind();  
  endPGL();
  
  pgl = beginPGL();
  flatShader.bind();
  vertLoc2 = pgl.getAttribLocation(flatShader.glProgram, "vertex");
  colorLoc = pgl.getAttribLocation(flatShader.glProgram, "color");
  pgl.enableVertexAttribArray(vertLoc2);
  pgl.enableVertexAttribArray(colorLoc);
  pgl.vertexAttribPointer(vertLoc2, 4, PGL.FLOAT, false, 0, vertData2);
  pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 0, colorData);
  pgl.drawArrays(PGL.TRIANGLES, 0, 3);
  pgl.disableVertexAttribArray(vertLoc2);
  pgl.disableVertexAttribArray(colorLoc);
  flatShader.unbind();  
  endPGL();
}

void drawImage() {
  pg_1.beginDraw();
  pg_1.clear();
  pg_1.blendMode(PREMULTIPLY);
  pgl = pg_1.beginPGL();
  flatShader.bind();
  vertLoc = pgl.getAttribLocation(flatShader.glProgram, "vertex");
  colorLoc = pgl.getAttribLocation(flatShader.glProgram, "color");
  pgl.enableVertexAttribArray(vertLoc);
  pgl.enableVertexAttribArray(colorLoc);
  pgl.vertexAttribPointer(vertLoc, 4, PGL.FLOAT, false, 0, vertData);
  pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 0, colorData);
  pgl.drawArrays(PGL.TRIANGLES, 0, 3);
  pgl.disableVertexAttribArray(vertLoc);
  pgl.disableVertexAttribArray(colorLoc);
  flatShader.unbind();  
  pg_1.endPGL();
  pg_1.blendMode(BLEND);
  pg_1.endDraw();
  
  // pg_2:
  pg_2.beginDraw();
  pg_2.clear();
  pg_2.blendMode(PREMULTIPLY);
  pgl = pg_2.beginPGL();
  flatShader.bind();
  vertLoc = pgl.getAttribLocation(flatShader.glProgram, "vertex");
  colorLoc = pgl.getAttribLocation(flatShader.glProgram, "color");  
  pgl.enableVertexAttribArray(vertLoc);
  pgl.enableVertexAttribArray(colorLoc);
  pgl.vertexAttribPointer(vertLoc, 4, PGL.FLOAT, false, 0, vertData2);
  pgl.vertexAttribPointer(colorLoc, 4, PGL.FLOAT, false, 0, colorData);
  pgl.drawArrays(PGL.TRIANGLES, 0, 3);
  pgl.disableVertexAttribArray(vertLoc);
  pgl.disableVertexAttribArray(colorLoc);
  flatShader.unbind();  
  pg_2.endPGL();
  pg_2.blendMode(BLEND);
  pg_2.endDraw();
  
  // output pg_1 to screen 
  image(pg_1, 0, 0, m_Width, m_Height);
  
  if(blend) {
    blendMode(BLEND);
  }
  else { 
    blendMode(REPLACE);
//  pgl = beginPGL(); 
//  GL2 gl2 = pgl.gl.getGL2();
//  gl2.glBlendEquationSeparate(gl2.GL_MAX, gl2.GL_MAX);
//  gl2.glBlendFuncSeparate(gl2.GL_ONE, gl2.GL_ONE, gl2.GL_ONE, gl2.GL_ONE);
//  endPGL();  
}  
     
  // output rotated pg_2 to screen
  image(pg_2, 0, 0, m_Width, m_Height);
  
  blendMode(BLEND);
}

void updateGeometry() {
  // Vertex 1
  vertices[0] = 0;
  vertices[1] = 0;
  vertices[2] = 0;
  vertices[3] = 1;
  colors[0] = 1;
  colors[1] = 0;
  colors[2] = 0;
  colors[3] = alpha;

  // Corner 2
  vertices[4] = width/2;
  vertices[5] = height;
  vertices[6] = 0;
  vertices[7] = 1;
  colors[4] = 0;
  colors[5] = 1;
  colors[6] = 0;
  colors[7] = alpha;
  
  // Corner 3
  vertices[8] = width;
  vertices[9] = 0;
  vertices[10] = 0;
  vertices[11] = 1;
  colors[8] = 0;
  colors[9] = 0;
  colors[10] = 1;
  colors[11] = alpha;
  
  vertData.rewind();
  vertData.put(vertices);
  vertData.position(0);
  
  colorData.rewind();
  colorData.put(colors);
  colorData.position(0);  
}

void updateGeometry2() {
  // Vertex 1
  vertices2[0] = width;
  vertices2[1] = height;
  vertices2[2] = 0;
  vertices2[3] = 1;

  // Corner 2
  vertices2[4] = 0;
  vertices2[5] = height;
  vertices2[6] = 0;
  vertices2[7] = 1;

  // Corner 3
  vertices2[8] = width/2;
  vertices2[9] = 0;
  vertices2[10] = 0;
  vertices2[11] = 1;
  
  vertData2.rewind();
  vertData2.put(vertices2);
  vertData2.position(0);  
}

FloatBuffer allocateDirectFloatBuffer(int n) {
  return ByteBuffer.allocateDirect(n * Float.SIZE/8).order(ByteOrder.nativeOrder()).asFloatBuffer();
}