mirror of
https://github.com/processing/processing4.git
synced 2026-06-16 04:26:26 +02:00
FBO-based onscreen rendering for incremental drawing on Android is working again, added some more PGL utilities.
This commit is contained in:
@@ -58,10 +58,8 @@ public class PFramebuffer implements PConstants {
|
||||
protected PTexture[] colorBufferTex;
|
||||
|
||||
protected boolean screenFb;
|
||||
protected boolean noDepth;
|
||||
protected boolean fboMode;
|
||||
protected boolean noDepth;
|
||||
|
||||
protected PTexture backupTexture;
|
||||
protected IntBuffer pixelBuffer;
|
||||
|
||||
PFramebuffer(PApplet parent, int w, int h) {
|
||||
@@ -84,8 +82,6 @@ public class PFramebuffer implements PConstants {
|
||||
glStencilBufferID = 0;
|
||||
glDepthStencilBufferID = 0;
|
||||
glColorBufferMultisampleID = 0;
|
||||
|
||||
fboMode = PGraphicsAndroid3D.fboSupported;
|
||||
|
||||
if (screen) {
|
||||
// If this framebuffer is used to represent a on-screen buffer,
|
||||
@@ -135,14 +131,6 @@ public class PFramebuffer implements PConstants {
|
||||
noDepth = false;
|
||||
|
||||
pixelBuffer = null;
|
||||
|
||||
if (!screenFb && !fboMode) {
|
||||
// When FBOs are not available, rendering to texture is implemented by saving a portion of
|
||||
// the screen, doing the "offscreen" rendering on this portion, copying the screen color
|
||||
// buffer to the texture bound as color buffer to this PFramebuffer object and then drawing
|
||||
// the backup texture back on the screen.
|
||||
backupTexture = new PTexture(parent, width, height, new PTexture.Parameters(ARGB, POINT));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -185,27 +173,10 @@ public class PFramebuffer implements PConstants {
|
||||
}
|
||||
|
||||
public void bind() {
|
||||
// if context is outdated ??
|
||||
|
||||
|
||||
if (screenFb) {
|
||||
if (PGraphicsAndroid3D.fboSupported) {
|
||||
pgl.glBindFramebuffer(PGL.GL_FRAMEBUFFER, 0);
|
||||
}
|
||||
} else if (fboMode) {
|
||||
pgl.glBindFramebuffer(PGL.GL_FRAMEBUFFER, glFboID);
|
||||
} else {
|
||||
backupScreen();
|
||||
|
||||
if (0 < numColorBuffers) {
|
||||
// Drawing the current contents of the first color buffer to emulate
|
||||
// front-back buffer swap.
|
||||
pg.drawTexture(colorBufferTex[0].glTarget, colorBufferTex[0].glID, width, height, 0, 0, width, height, 0, 0, width, height);
|
||||
}
|
||||
|
||||
if (noDepth) {
|
||||
pgl.glDisable(PGL.GL_DEPTH_TEST);
|
||||
}
|
||||
pgl.glBindFramebuffer(PGL.GL_FRAMEBUFFER, glFboID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -222,46 +193,7 @@ public class PFramebuffer implements PConstants {
|
||||
pgl.glEnable(PGL.GL_DEPTH_TEST);
|
||||
}
|
||||
}
|
||||
|
||||
if (!screenFb && !fboMode) {
|
||||
copyToColorBuffers();
|
||||
restoreBackup();
|
||||
if (!noDepth) {
|
||||
// Reading the contents of the depth buffer is not possible in OpenGL ES:
|
||||
// http://www.idevgames.com/forum/archive/index.php?t-15828.html
|
||||
// so if this framebuffer uses depth and is offscreen with no FBOs, then
|
||||
// the depth buffer is cleared to avoid artifacts when rendering more stuff
|
||||
// after this offscreen render.
|
||||
// A consequence of this behavior is that all the offscreen rendering when
|
||||
// no FBOs are available should be done before any onscreen drawing.
|
||||
pgl.glClearColor(0, 0, 0, 0);
|
||||
pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Saves content of the screen into the backup texture.
|
||||
public void backupScreen() {
|
||||
if (pixelBuffer == null) createPixelBuffer();
|
||||
pixelBuffer.rewind();
|
||||
pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
copyToTexture(pixelBuffer, backupTexture.glID, backupTexture.glTarget);
|
||||
}
|
||||
|
||||
// Draws the contents of the backup texture to the screen.
|
||||
public void restoreBackup() {
|
||||
pg.drawTexture(backupTexture, 0, 0, width, height, 0, 0, width, height);
|
||||
}
|
||||
|
||||
// Copies current content of screen to color buffers.
|
||||
public void copyToColorBuffers() {
|
||||
if (pixelBuffer == null) createPixelBuffer();
|
||||
pixelBuffer.rewind();
|
||||
pgl.glReadPixels(0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, pixelBuffer);
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
copyToTexture(pixelBuffer, colorBufferTex[i].glID, colorBufferTex[i].glTarget);
|
||||
}
|
||||
}
|
||||
|
||||
public void readPixels() {
|
||||
if (pixelBuffer == null) createPixelBuffer();
|
||||
@@ -314,23 +246,21 @@ public class PFramebuffer implements PConstants {
|
||||
colorBufferTex[i] = textures[i];
|
||||
}
|
||||
|
||||
if (fboMode) {
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
// Making sure nothing is attached.
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, PGL.GL_TEXTURE_2D, 0, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, colorBufferTex[i].glTarget, colorBufferTex[i].glID, 0);
|
||||
}
|
||||
|
||||
validateFbo();
|
||||
|
||||
pg.popFramebuffer();
|
||||
// Making sure nothing is attached.
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, PGL.GL_TEXTURE_2D, 0, 0);
|
||||
}
|
||||
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, colorBufferTex[i].glTarget, colorBufferTex[i].glID, 0);
|
||||
}
|
||||
|
||||
pgl.validateFramebuffer();
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
|
||||
|
||||
@@ -346,10 +276,8 @@ public class PFramebuffer implements PConstants {
|
||||
|
||||
if (screenFb) {
|
||||
glFboID = 0;
|
||||
} else if (fboMode) {
|
||||
} else {
|
||||
glFboID = pg.createFrameBufferObject();
|
||||
} else {
|
||||
glFboID = 0;
|
||||
}
|
||||
|
||||
// create the rest of the stuff...
|
||||
@@ -406,8 +334,6 @@ public class PFramebuffer implements PConstants {
|
||||
for (int i = 0; i < numColorBuffers; i++) {
|
||||
colorBufferTex[i] = null;
|
||||
}
|
||||
|
||||
backupTexture = null;
|
||||
}
|
||||
return outdated;
|
||||
}
|
||||
@@ -416,17 +342,15 @@ public class PFramebuffer implements PConstants {
|
||||
protected void createColorBufferMultisample() {
|
||||
if (screenFb) return;
|
||||
|
||||
if (fboMode) {
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
glColorBufferMultisampleID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glColorBufferMultisampleID);
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_RGBA8, width, height);
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0, PGL.GL_RENDERBUFFER, glColorBufferMultisampleID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
glColorBufferMultisampleID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glColorBufferMultisampleID);
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_RGBA8, width, height);
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0, PGL.GL_RENDERBUFFER, glColorBufferMultisampleID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
|
||||
|
||||
@@ -437,24 +361,22 @@ public class PFramebuffer implements PConstants {
|
||||
throw new RuntimeException("PFramebuffer: size undefined.");
|
||||
}
|
||||
|
||||
if (fboMode) {
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
glDepthStencilBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_DEPTH24_STENCIL8, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, PGL.GL_DEPTH24_STENCIL8, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
glDepthStencilBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, PGL.GL_DEPTH24_STENCIL8, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, PGL.GL_DEPTH24_STENCIL8, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthStencilBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
|
||||
|
||||
@@ -465,32 +387,30 @@ public class PFramebuffer implements PConstants {
|
||||
throw new RuntimeException("PFramebuffer: size undefined.");
|
||||
}
|
||||
|
||||
if (fboMode) {
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
glDepthBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepthBufferID);
|
||||
glDepthBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glDepthBufferID);
|
||||
|
||||
int glConst = PGL.GL_DEPTH_COMPONENT16;
|
||||
if (depthBits == 16) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT16;
|
||||
} else if (depthBits == 24) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT24;
|
||||
} else if (depthBits == 32) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT32;
|
||||
}
|
||||
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
int glConst = PGL.GL_DEPTH_COMPONENT16;
|
||||
if (depthBits == 16) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT16;
|
||||
} else if (depthBits == 24) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT24;
|
||||
} else if (depthBits == 32) {
|
||||
glConst = PGL.GL_DEPTH_COMPONENT32;
|
||||
}
|
||||
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_DEPTH_ATTACHMENT, PGL.GL_RENDERBUFFER, glDepthBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
|
||||
|
||||
@@ -501,31 +421,29 @@ public class PFramebuffer implements PConstants {
|
||||
throw new RuntimeException("PFramebuffer: size undefined.");
|
||||
}
|
||||
|
||||
if (fboMode) {
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(this);
|
||||
|
||||
glStencilBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glStencilBufferID);
|
||||
glStencilBufferID = pg.createRenderBufferObject();
|
||||
pgl.glBindRenderbuffer(PGL.GL_RENDERBUFFER, glStencilBufferID);
|
||||
|
||||
int glConst = PGL.GL_STENCIL_INDEX1;
|
||||
if (stencilBits == 1) {
|
||||
glConst = PGL.GL_STENCIL_INDEX1;
|
||||
} else if (stencilBits == 4) {
|
||||
glConst = PGL.GL_STENCIL_INDEX4;
|
||||
} else if (stencilBits == 8) {
|
||||
glConst = PGL.GL_STENCIL_INDEX8;
|
||||
}
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glStencilBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
int glConst = PGL.GL_STENCIL_INDEX1;
|
||||
if (stencilBits == 1) {
|
||||
glConst = PGL.GL_STENCIL_INDEX1;
|
||||
} else if (stencilBits == 4) {
|
||||
glConst = PGL.GL_STENCIL_INDEX4;
|
||||
} else if (stencilBits == 8) {
|
||||
glConst = PGL.GL_STENCIL_INDEX8;
|
||||
}
|
||||
if (multisample) {
|
||||
pgl.glRenderbufferStorageMultisample(PGL.GL_RENDERBUFFER, nsamples, glConst, width, height);
|
||||
} else {
|
||||
pgl.glRenderbufferStorage(PGL.GL_RENDERBUFFER, glConst, width, height);
|
||||
}
|
||||
|
||||
pgl.glFramebufferRenderbuffer(PGL.GL_FRAMEBUFFER, PGL.GL_STENCIL_ATTACHMENT, PGL.GL_RENDERBUFFER, glStencilBufferID);
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
|
||||
|
||||
@@ -533,36 +451,4 @@ public class PFramebuffer implements PConstants {
|
||||
pixelBuffer = IntBuffer.allocate(width * height);
|
||||
pixelBuffer.rewind();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
// Utilities.
|
||||
|
||||
// Internal copy to texture method.
|
||||
protected void copyToTexture(IntBuffer buffer, int glid, int gltarget) {
|
||||
pgl.enableTexturing(gltarget);
|
||||
pgl.glBindTexture(gltarget, glid);
|
||||
pgl.glTexSubImage2D(gltarget, 0, 0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, buffer);
|
||||
pgl.glBindTexture(gltarget, 0);
|
||||
pgl.disableTexturing(gltarget);
|
||||
}
|
||||
|
||||
public boolean validateFbo() {
|
||||
int status = pgl.glCheckFramebufferStatus(PGL.GL_FRAMEBUFFER);
|
||||
if (status == PGL.GL_FRAMEBUFFER_COMPLETE) {
|
||||
return true;
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_UNSUPPORTED) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_UNSUPPORTED" + Integer.toHexString(status));
|
||||
} else {
|
||||
throw new RuntimeException("PFramebuffer: unknown framebuffer error (" + Integer.toHexString(status) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,8 @@ package processing.core;
|
||||
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
|
||||
@@ -88,11 +90,17 @@ public class PGL {
|
||||
|
||||
/** Maximum dimension of a texture used to hold font data. **/
|
||||
public static final int MAX_FONT_TEX_SIZE = 256;
|
||||
|
||||
public static int DEFAULT_DEPTH_BITS = 16;
|
||||
public static int DEFAULT_STENCIL_BITS = 8;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// OpenGL constants
|
||||
|
||||
public static final int GL_FALSE = GLES20.GL_FALSE;
|
||||
public static final int GL_TRUE = GLES20.GL_TRUE;
|
||||
|
||||
public static final int GL_LESS = GLES20.GL_LESS;
|
||||
public static final int GL_LEQUAL = GLES20.GL_LEQUAL;
|
||||
public static final int GL_CCW = GLES20.GL_CCW;
|
||||
@@ -102,8 +110,9 @@ public class PGL {
|
||||
|
||||
public static final int GL_VIEWPORT = GLES20.GL_VIEWPORT;
|
||||
|
||||
public static final int GL_SCISSOR_TEST = GLES20.GL_SCISSOR_TEST;
|
||||
public static final int GL_DEPTH_TEST = GLES20.GL_DEPTH_TEST;
|
||||
public static final int GL_SCISSOR_TEST = GLES20.GL_SCISSOR_TEST;
|
||||
public static final int GL_DEPTH_TEST = GLES20.GL_DEPTH_TEST;
|
||||
public static final int GL_DEPTH_WRITEMASK = GLES20.GL_DEPTH_WRITEMASK;
|
||||
|
||||
public static final int GL_COLOR_BUFFER_BIT = GLES20.GL_COLOR_BUFFER_BIT;
|
||||
public static final int GL_DEPTH_BUFFER_BIT = GLES20.GL_DEPTH_BUFFER_BIT;
|
||||
@@ -211,8 +220,13 @@ public class PGL {
|
||||
public static final int GL_READ_FRAMEBUFFER = -1;
|
||||
public static final int GL_DRAW_FRAMEBUFFER = -1;
|
||||
|
||||
public static final int GL_VERTEX_SHADER = GLES20.GL_VERTEX_SHADER;
|
||||
public static final int GL_FRAGMENT_SHADER = GLES20.GL_FRAGMENT_SHADER;
|
||||
public static final int GL_VERTEX_SHADER = GLES20.GL_VERTEX_SHADER;
|
||||
public static final int GL_FRAGMENT_SHADER = GLES20.GL_FRAGMENT_SHADER;
|
||||
public static final int GL_INFO_LOG_LENGTH = GLES20.GL_INFO_LOG_LENGTH;
|
||||
public static final int GL_SHADER_SOURCE_LENGTH = GLES20.GL_SHADER_SOURCE_LENGTH;
|
||||
public static final int GL_COMPILE_STATUS = GLES20.GL_COMPILE_STATUS;
|
||||
public static final int GL_LINK_STATUS = GLES20.GL_LINK_STATUS;
|
||||
public static final int GL_VALIDATE_STATUS = GLES20.GL_VALIDATE_STATUS;
|
||||
|
||||
public static final int GL_MULTISAMPLE = -1;
|
||||
public static final int GL_POINT_SMOOTH = -1;
|
||||
@@ -238,12 +252,60 @@ public class PGL {
|
||||
/** The renderer object driving the rendering loop,
|
||||
* analogous to the GLEventListener in JOGL */
|
||||
protected AndroidRenderer renderer;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// FBO for incremental drawing
|
||||
|
||||
protected boolean firstOnscreenFrame = true;
|
||||
protected int[] textures = { 0, 0 };
|
||||
protected int[] fbo = { 0 };
|
||||
protected int[] depth = { 0 };
|
||||
protected int[] stencil = { 0 };
|
||||
protected int texWidth, texHeight;
|
||||
protected int backTex, frontTex;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Texture rendering
|
||||
|
||||
protected boolean loadedTexShader = false;
|
||||
protected int texShaderProgram;
|
||||
protected int texVertShader;
|
||||
protected int texFragShader;
|
||||
|
||||
protected int texVertLoc;
|
||||
protected int texTCoordLoc;
|
||||
|
||||
protected float[] texCoords = {
|
||||
// X, Y, U, V
|
||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||
+1.0f, -1.0f, 1.0f, 0.0f,
|
||||
-1.0f, +1.0f, 0.0f, 1.0f,
|
||||
+1.0f, +1.0f, 1.0f, 1.0f
|
||||
};
|
||||
protected FloatBuffer texData;
|
||||
|
||||
protected String texVertShaderSource = "attribute vec2 inVertex;" +
|
||||
"attribute vec2 inTexcoord;" +
|
||||
"varying vec2 vertTexcoord;" +
|
||||
"void main() {" +
|
||||
" gl_Position = vec4(inVertex, 0, 1);" +
|
||||
" vertTexcoord = inTexcoord;" +
|
||||
"}";
|
||||
|
||||
protected String texFragShaderSource = "precision mediump float;" +
|
||||
"uniform sampler2D textureSampler;" +
|
||||
"varying vec2 vertTexcoord;" +
|
||||
"void main() {" +
|
||||
" gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" +
|
||||
"}";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Intialization, finalization
|
||||
|
||||
// TODO: implement double buffering support in onscreen rendering, offscreen rendering.
|
||||
// TODO: implement double buffering support in offscreen rendering.
|
||||
|
||||
|
||||
public PGL(PGraphicsAndroid3D pg) {
|
||||
@@ -259,6 +321,52 @@ public class PGL {
|
||||
|
||||
|
||||
public void updatePrimary() {
|
||||
if (!initialized) {
|
||||
String ext = GLES20.glGetString(GLES20.GL_EXTENSIONS);
|
||||
if (-1 < ext.indexOf("texture_non_power_of_two")) {
|
||||
texWidth = pg.width;
|
||||
texHeight = pg.height;
|
||||
} else {
|
||||
texWidth = PGL.nextPowerOfTwo(pg.width);
|
||||
texHeight = PGL.nextPowerOfTwo(pg.height);
|
||||
}
|
||||
|
||||
// We create the GL resources we need to draw incrementally, ie: not clearing
|
||||
// the screen in each frame. Because the way Android handles double buffering
|
||||
// we need to handle our own custom buffering using FBOs.
|
||||
GLES20.glGenTextures(2, textures, 0);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_NEAREST);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
|
||||
GLES20.glTexImage2D(GLES20.GL_TEXTURE_2D, 0, GLES20.GL_RGBA, texWidth, texHeight, 0, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, null);
|
||||
initTexture(GLES20.GL_TEXTURE_2D, texWidth, texHeight, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE);
|
||||
}
|
||||
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
|
||||
|
||||
GLES20.glGenFramebuffers(1, fbo, 0);
|
||||
GLES20.glGenRenderbuffers(1, depth, 0);
|
||||
GLES20.glGenRenderbuffers(1, stencil, 0);
|
||||
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
|
||||
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, depth[0]);
|
||||
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_DEPTH_COMPONENT16, texWidth, texHeight);
|
||||
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_DEPTH_ATTACHMENT, GLES20.GL_RENDERBUFFER, depth[0]);
|
||||
|
||||
GLES20.glBindRenderbuffer(GLES20.GL_RENDERBUFFER, stencil[0]);
|
||||
GLES20.glRenderbufferStorage(GLES20.GL_RENDERBUFFER, GLES20.GL_STENCIL_INDEX8, texWidth, texHeight);
|
||||
GLES20.glFramebufferRenderbuffer(GLES20.GL_FRAMEBUFFER, GLES20.GL_STENCIL_ATTACHMENT, GLES20.GL_RENDERBUFFER, stencil[0]);
|
||||
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
|
||||
backTex = 1;
|
||||
frontTex = 0;
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,50 +374,9 @@ public class PGL {
|
||||
gl = primary.gl;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void initPrimarySurface(int antialias) {
|
||||
/*
|
||||
|
||||
offscreenTexCrop = new int[4];
|
||||
offscreenTexCrop[0] = 0;
|
||||
offscreenTexCrop[1] = 0;
|
||||
offscreenTexCrop[2] = width;
|
||||
offscreenTexCrop[3] = height;
|
||||
|
||||
offscreenImages = new PImage[2];
|
||||
offscreenParams = new PTexture.Parameters[2];
|
||||
|
||||
// Nearest filtering is used for the primary surface, otherwise some
|
||||
// artifacts appear (diagonal line when blending, for instance). This
|
||||
// might deserve further examination.
|
||||
offscreenParams[0] = new PTexture.Parameters(ARGB, POINT);
|
||||
offscreenParams[1] = new PTexture.Parameters(ARGB, POINT);
|
||||
offscreenImages[0] = parent.createImage(width, height, ARGB, offscreenParams[0]);
|
||||
offscreenImages[1] = parent.createImage(width, height, ARGB, offscreenParams[1]);
|
||||
|
||||
offscreenTextures = new PTexture[2];
|
||||
offscreenTextures[0] = addTexture(offscreenImages[0]);
|
||||
offscreenTextures[1] = addTexture(offscreenImages[1]);
|
||||
|
||||
// Drawing textures are marked as flipped along Y to ensure they are properly
|
||||
// rendered by Processing, which has inverted Y axis with respect to
|
||||
// OpenGL.
|
||||
offscreenTextures[0].setFlippedY(true);
|
||||
offscreenTextures[1].setFlippedY(true);
|
||||
|
||||
offscreenIndex = 0;
|
||||
|
||||
offscreenFramebuffer = new PFramebuffer(parent, offscreenTextures[0].glWidth, offscreenTextures[0].glHeight,
|
||||
1, 1, offscreenDepthBits, offscreenStencilBits, false);
|
||||
|
||||
// The image texture points to the current offscreen texture.
|
||||
texture = offscreenTextures[offscreenIndex];
|
||||
this.setCache(a3d, offscreenTextures[offscreenIndex]);
|
||||
this.setParams(a3d, offscreenParams[offscreenIndex]);
|
||||
|
||||
*/
|
||||
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -332,6 +399,7 @@ public class PGL {
|
||||
offscreenImages[0] = parent.createImage(width, height, ARGB, offscreenParams[0]);
|
||||
offscreenImages[1] = parent.createImage(width, height, ARGB, offscreenParams[1]);
|
||||
|
||||
|
||||
offscreenTextures = new PTexture[2];
|
||||
offscreenTextures[0] = addTexture(offscreenImages[0]);
|
||||
offscreenTextures[1] = addTexture(offscreenImages[1]);
|
||||
@@ -344,6 +412,10 @@ public class PGL {
|
||||
|
||||
offscreenIndex = 0;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
offscreenFramebuffer = new PFramebuffer(parent, offscreenTextures[0].glWidth, offscreenTextures[0].glHeight,
|
||||
1, 1, offscreenDepthBits, offscreenStencilBits, false);
|
||||
|
||||
@@ -363,86 +435,70 @@ public class PGL {
|
||||
// Frame rendering
|
||||
|
||||
|
||||
public void beginOnscreenDraw(boolean clear, int frame) {
|
||||
GLES20.glClearColor(0, 0, 0, 0);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
|
||||
/*
|
||||
public void beginOnscreenDraw(boolean clear) {
|
||||
if (clear) {
|
||||
// Simplest scenario: clear mode means we clear both the color and depth buffers.
|
||||
// No need for saving front color buffer, etc.
|
||||
gl.glClearColor(0, 0, 0, 0);
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
|
||||
GLES20.glClearColor(0, 0, 0, 0);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
} else {
|
||||
// We need to save the color buffer after finishing with the rendering of this frame,
|
||||
// to use is as the background for the next frame (I call this "incremental rendering").
|
||||
|
||||
if (fboSupported) {
|
||||
if (offscreenFramebuffer != null) {
|
||||
// Setting the framebuffer corresponding to this surface.
|
||||
pushFramebuffer();
|
||||
setFramebuffer(offscreenFramebuffer);
|
||||
// Setting the current front color buffer.
|
||||
offscreenFramebuffer.setColorBuffer(offscreenTextures[offscreenIndex]);
|
||||
|
||||
// Drawing contents of back color buffer as background.
|
||||
gl.glClearColor(0, 0, 0, 0);
|
||||
if (frame == 0) {
|
||||
// No need to draw back color buffer because we are in the first frame ever.
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
|
||||
} else {
|
||||
gl.glClear(GL10.GL_DEPTH_BUFFER_BIT);
|
||||
// Render previous draw texture as background.
|
||||
drawOffscreenTexture((offscreenIndex + 1) % 2);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (texture != null) {
|
||||
gl.glClearColor(0, 0, 0, 0);
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
|
||||
if (0 < frame) {
|
||||
drawTexture();
|
||||
}
|
||||
}
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, fbo[0]);
|
||||
GLES20.glFramebufferTexture2D(GLES20.GL_FRAMEBUFFER, GLES20.GL_COLOR_ATTACHMENT0, GLES20.GL_TEXTURE_2D, textures[frontTex], 0);
|
||||
|
||||
int status = glCheckFramebufferStatus(PGL.GL_FRAMEBUFFER);
|
||||
if (status != PGL.GL_FRAMEBUFFER_COMPLETE) {
|
||||
if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_UNSUPPORTED) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_UNSUPPORTED" + Integer.toHexString(status));
|
||||
} else {
|
||||
throw new RuntimeException("PFramebuffer: unknown framebuffer error (" + Integer.toHexString(status) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
// We need to save the color buffer after finishing with the rendering of this frame,
|
||||
// to use is as the background for the next frame ("incremental drawing").
|
||||
GLES20.glClearColor(0, 0, 0, 0);
|
||||
GLES20.glClear(GLES20.GL_DEPTH_BUFFER_BIT | GLES20.GL_STENCIL_BUFFER_BIT);
|
||||
if (firstOnscreenFrame) {
|
||||
// No need to draw back color buffer because we are in the first frame.
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
|
||||
firstOnscreenFrame = false;
|
||||
} else {
|
||||
// Render previous draw texture as background.
|
||||
drawTexture(GLES20.GL_TEXTURE_2D, textures[backTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void endOnscreenDraw(boolean clear0) {
|
||||
/*
|
||||
if (!clear0) {
|
||||
// We are in the primary surface, and no clear mode, this means that the current
|
||||
// contents of the front buffer needs to be used in the next frame as the background
|
||||
// for incremental rendering. Depending on whether or not FBOs are supported,
|
||||
// one of the two following paths is selected.
|
||||
if (fboSupported) {
|
||||
if (offscreenFramebuffer != null) {
|
||||
// Restoring screen buffer.
|
||||
popFramebuffer();
|
||||
if (!clear0) {
|
||||
// We are in the primary surface, and no clear mode, this means that the current
|
||||
// contents of the front buffer needs to be used in the next frame as the background.
|
||||
GLES20.glBindFramebuffer(GLES20.GL_FRAMEBUFFER, 0);
|
||||
|
||||
// Only the primary surface in clear mode will write the contents of the
|
||||
// offscreen framebuffer to the screen.
|
||||
gl.glClearColor(0, 0, 0, 0);
|
||||
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
|
||||
GLES20.glClearColor(0, 0, 0, 0);
|
||||
GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT | GLES20.GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
// Render current draw texture to screen.
|
||||
drawOffscreenTexture(offscreenIndex);
|
||||
|
||||
swapOffscreenIndex();
|
||||
}
|
||||
} else {
|
||||
if (texture != null) {
|
||||
copyFrameToTexture();
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
// Render current front texture to screen.
|
||||
drawTexture(GLES20.GL_TEXTURE_2D, textures[frontTex], texWidth, texHeight, 0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height);
|
||||
|
||||
// Swapping front and back textures.
|
||||
int temp = frontTex;
|
||||
frontTex = backTex;
|
||||
backTex = temp;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void beginOffscreenDraw(boolean clear, int frame) {
|
||||
public void beginOffscreenDraw(boolean clear) {
|
||||
/*
|
||||
// Drawing contents of back color buffer as background.
|
||||
gl.glClearColor(0, 0, 0, 0);
|
||||
@@ -494,6 +550,15 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glGetBooleanv(int name, boolean[] values, int offset) {
|
||||
if (-1 < name) {
|
||||
GLES20.glGetBooleanv(name, values, offset);
|
||||
} else {
|
||||
Arrays.fill(values, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Enable/disable caps
|
||||
@@ -643,6 +708,11 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glDrawArrays(int mode, int first, int count) {
|
||||
GLES20.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
|
||||
public void glDrawElements(int mode, int count, int type, int offset) {
|
||||
GLES20.glDrawElements(mode, count, type, offset);
|
||||
}
|
||||
@@ -659,7 +729,12 @@ public class PGL {
|
||||
|
||||
|
||||
public void glVertexAttribPointer(int loc, int size, int type, boolean normalized, int stride, int offset) {
|
||||
GLES20.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
|
||||
GLES20.glVertexAttribPointer(loc, size, type, normalized, stride, offset);
|
||||
}
|
||||
|
||||
|
||||
public void glVertexAttribPointer(int loc, int size, int type, boolean normalized, int stride, Buffer data) {
|
||||
GLES20.glVertexAttribPointer(loc, size, type, normalized, stride, data);
|
||||
}
|
||||
|
||||
|
||||
@@ -890,6 +965,26 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glGetShaderiv(int shader, int pname, int[] params, int offset) {
|
||||
GLES20.glGetShaderiv(shader, pname, params, offset);
|
||||
}
|
||||
|
||||
|
||||
public String glGetShaderInfoLog(int shader) {
|
||||
return GLES20.glGetShaderInfoLog(shader);
|
||||
}
|
||||
|
||||
|
||||
public void glGetProgramiv(int prog, int pname, int[] params, int offset) {
|
||||
GLES20.glGetProgramiv(prog, pname, params, offset);
|
||||
}
|
||||
|
||||
|
||||
public String glGetProgramInfoLog(int prog) {
|
||||
return GLES20.glGetProgramInfoLog(prog);
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Viewport
|
||||
@@ -1107,17 +1202,160 @@ public class PGL {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void drawTexture(int target, int id, int width, int height,
|
||||
int texX0, int texY0, int texX1, int texY1,
|
||||
int scrX0, int scrY0, int scrX1, int scrY1) {
|
||||
|
||||
|
||||
public String getShaderLog(int id) {
|
||||
int[] compiled = new int[1];
|
||||
GLES20.glGetShaderiv(id, GLES20.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == 0) {
|
||||
return GLES20.glGetShaderInfoLog(id);
|
||||
} else {
|
||||
return "";
|
||||
if (!loadedTexShader) {
|
||||
texVertShader = createShader(GL_VERTEX_SHADER, texVertShaderSource);
|
||||
texFragShader = createShader(GL_FRAGMENT_SHADER, texFragShaderSource);
|
||||
if (0 < texVertShader && 0 < texFragShader) {
|
||||
texShaderProgram = createProgram(texVertShader, texFragShader);
|
||||
}
|
||||
if (0 < texShaderProgram) {
|
||||
texVertLoc = glGetAttribLocation(texShaderProgram, "inVertex");
|
||||
texTCoordLoc = glGetAttribLocation(texShaderProgram, "inTexcoord");
|
||||
}
|
||||
texData = ByteBuffer.allocateDirect(texCoords.length * SIZEOF_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
loadedTexShader = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 < texShaderProgram) {
|
||||
// When drawing the texture we don't write to the
|
||||
// depth mask, so the texture remains in the background
|
||||
// and can be occluded by anything drawn later, even if
|
||||
// if it is behind it.
|
||||
boolean[] val = new boolean[1];
|
||||
glGetBooleanv(GL_DEPTH_WRITEMASK, val, 0);
|
||||
boolean writeMask = val[0];
|
||||
glDepthMask(false);
|
||||
|
||||
glUseProgram(texShaderProgram);
|
||||
|
||||
glEnableVertexAttribArray(texVertLoc);
|
||||
glEnableVertexAttribArray(texTCoordLoc);
|
||||
|
||||
// Vertex coordinates of the textured quad are specified
|
||||
// in normalized screen space (-1, 1):
|
||||
|
||||
// Corner 1
|
||||
texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1;
|
||||
texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1;
|
||||
texCoords[ 2] = (float)texX0 / width;
|
||||
texCoords[ 3] = (float)texY0 / height;
|
||||
|
||||
// Corner 2
|
||||
texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1;
|
||||
texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1;
|
||||
texCoords[ 6] = (float)texX1 / width;
|
||||
texCoords[ 7] = (float)texY0 / height;
|
||||
|
||||
// Corner 3
|
||||
texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1;
|
||||
texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1;
|
||||
texCoords[10] = (float)texX0 / width;
|
||||
texCoords[11] = (float)texY1 / height;
|
||||
|
||||
// Corner 4
|
||||
texCoords[12] = 2 * (float)scrX1 / pg.width - 1;
|
||||
texCoords[13] = 2 * (float)scrY1 / pg.height - 1;
|
||||
texCoords[14] = (float)texX1 / width;
|
||||
texCoords[15] = (float)texY1 / height;
|
||||
|
||||
texData.rewind();
|
||||
texData.put(texCoords);
|
||||
|
||||
enableTexturing(target);
|
||||
glActiveTexture(target);
|
||||
glBindTexture(target, id);
|
||||
|
||||
texData.position(0);
|
||||
glVertexAttribPointer(texVertLoc, 2, GL_FLOAT, false, 4 * SIZEOF_FLOAT, texData);
|
||||
texData.position(2);
|
||||
glVertexAttribPointer(texTCoordLoc, 2, GL_FLOAT, false, 4 * SIZEOF_FLOAT, texData);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBindTexture(target, 0);
|
||||
disableTexturing(target);
|
||||
|
||||
glDisableVertexAttribArray(texVertLoc);
|
||||
glDisableVertexAttribArray(texTCoordLoc);
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
glDepthMask(writeMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// bit shifting this might be more efficient
|
||||
static public int nextPowerOfTwo(int val) {
|
||||
int ret = 1;
|
||||
while (ret < val) {
|
||||
ret <<= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
public int createShader(int shaderType, String source) {
|
||||
int shader = glCreateShader(shaderType);
|
||||
if (shader != 0) {
|
||||
glShaderSource(shader, source);
|
||||
glCompileShader(shader);
|
||||
int[] compiled = new int[1];
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == GL_FALSE) {
|
||||
System.err.println("Could not compile shader " + shaderType + ":");
|
||||
System.err.println(glGetShaderInfoLog(shader));
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
||||
public int createProgram(int vertexShader, int fragmentShader) {
|
||||
int program = glCreateProgram();
|
||||
if (program != 0) {
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
int[] linked = new int[1];
|
||||
glGetProgramiv(program, GL_LINK_STATUS, linked, 0);
|
||||
if (linked[0] == GL_FALSE) {
|
||||
System.err.println("Could not link program: ");
|
||||
System.err.println(glGetProgramInfoLog(program));
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
|
||||
public boolean validateFramebuffer() {
|
||||
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE) {
|
||||
return true;
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_FORMATS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_UNSUPPORTED" + Integer.toHexString(status));
|
||||
} else {
|
||||
throw new RuntimeException("PFramebuffer: unknown framebuffer error (" + Integer.toHexString(status) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////////
|
||||
@@ -1280,9 +1518,9 @@ public class PGL {
|
||||
alphaBits = a;
|
||||
depthBits = d;
|
||||
stencilBits = s;
|
||||
|
||||
pg.offscreenDepthBits = d;
|
||||
pg.offscreenStencilBits = s;
|
||||
|
||||
DEFAULT_DEPTH_BITS = d;
|
||||
DEFAULT_STENCIL_BITS = s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -42,7 +42,7 @@ import java.util.Stack;
|
||||
*/
|
||||
public class PGraphicsAndroid3D extends PGraphics {
|
||||
/** Interface between Processing and OpenGL */
|
||||
protected PGL pgl;
|
||||
public PGL pgl;
|
||||
|
||||
/** The PApplet renderer. For the primary surface, pg == this. */
|
||||
protected PGraphicsAndroid3D pg;
|
||||
@@ -83,8 +83,6 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
/** Extensions used by Processing */
|
||||
static public boolean npotTexSupported;
|
||||
static public boolean mipmapGeneration;
|
||||
static public boolean vboSupported;
|
||||
static public boolean fboSupported;
|
||||
static public boolean fboMultisampleSupported;
|
||||
static public boolean blendEqSupported;
|
||||
|
||||
@@ -291,10 +289,6 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
protected PFramebuffer offscreenFramebufferMultisample;
|
||||
protected boolean offscreenMultisample;
|
||||
|
||||
/** These are public so they can be changed by advanced users. */
|
||||
public int offscreenDepthBits = 24;
|
||||
public int offscreenStencilBits = 8;
|
||||
|
||||
// ........................................................
|
||||
|
||||
// Utility variables:
|
||||
@@ -1507,17 +1501,17 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
pgl.glClearColor(0, 0, 0, 0);
|
||||
pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT | PGL.GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.beginOnscreenDraw(clearColorBuffer);
|
||||
} else {
|
||||
pgl.beginOffscreenDraw(clearColorBuffer);
|
||||
}
|
||||
|
||||
if (hints[DISABLE_DEPTH_MASK]) {
|
||||
pgl.glDepthMask(false);
|
||||
} else {
|
||||
pgl.glDepthMask(true);
|
||||
}
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.beginOnscreenDraw(clearColorBuffer, parent.frameCount);
|
||||
} else {
|
||||
pgl.beginOffscreenDraw(clearColorBuffer, parent.frameCount);
|
||||
}
|
||||
}
|
||||
|
||||
drawing = true;
|
||||
|
||||
@@ -1549,8 +1543,8 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
pgl.glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]);
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.glFlush();
|
||||
pgl.endOnscreenDraw(clearColorBuffer0);
|
||||
pgl.glFlush();
|
||||
} else {
|
||||
if (offscreenMultisample) {
|
||||
offscreenFramebufferMultisample.copy(offscreenFramebuffer);
|
||||
@@ -5602,8 +5596,8 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
// function used in multisampled (antialiased) offscreen rendering.
|
||||
if (PGraphicsAndroid3D.fboMultisampleSupported && 1 < antialias) {
|
||||
offscreenFramebufferMultisample = new PFramebuffer(parent, texture.glWidth, texture.glHeight, antialias, 0,
|
||||
offscreenDepthBits, offscreenStencilBits,
|
||||
offscreenDepthBits == 24 && offscreenStencilBits == 8, false);
|
||||
PGL.DEFAULT_DEPTH_BITS, PGL.DEFAULT_STENCIL_BITS,
|
||||
PGL.DEFAULT_DEPTH_BITS == 24 && PGL.DEFAULT_STENCIL_BITS == 8, false);
|
||||
|
||||
offscreenFramebufferMultisample.clear();
|
||||
offscreenMultisample = true;
|
||||
@@ -5617,8 +5611,8 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
} else {
|
||||
antialias = 0;
|
||||
offscreenFramebuffer = new PFramebuffer(parent, texture.glWidth, texture.glHeight, 1, 1,
|
||||
offscreenDepthBits, offscreenStencilBits,
|
||||
offscreenDepthBits == 24 && offscreenStencilBits == 8, false);
|
||||
PGL.DEFAULT_DEPTH_BITS, PGL.DEFAULT_STENCIL_BITS,
|
||||
PGL.DEFAULT_DEPTH_BITS == 24 && PGL.DEFAULT_STENCIL_BITS == 8, false);
|
||||
offscreenMultisample = false;
|
||||
}
|
||||
|
||||
@@ -5635,8 +5629,6 @@ public class PGraphicsAndroid3D extends PGraphics {
|
||||
|
||||
npotTexSupported = -1 < OPENGL_EXTENSIONS.indexOf("texture_non_power_of_two");
|
||||
mipmapGeneration = -1 < OPENGL_EXTENSIONS.indexOf("generate_mipmap");
|
||||
vboSupported = -1 < OPENGL_EXTENSIONS.indexOf("vertex_buffer_object");
|
||||
fboSupported = -1 < OPENGL_EXTENSIONS.indexOf("framebuffer_object");
|
||||
fboMultisampleSupported = -1 < OPENGL_EXTENSIONS.indexOf("framebuffer_multisample");
|
||||
|
||||
try {
|
||||
|
||||
@@ -26,6 +26,7 @@ package processing.core;
|
||||
import java.io.IOException;
|
||||
import java.net.URL;
|
||||
|
||||
|
||||
/**
|
||||
* This class encapsulates a GLSL shader program, including a vertex
|
||||
* and a fragment shader. Originally based in the code by JohnG
|
||||
@@ -42,6 +43,9 @@ public class PShader {
|
||||
|
||||
protected String vertexFilename;
|
||||
protected String fragmentFilename;
|
||||
|
||||
protected String vertexShaderSource;
|
||||
protected String fragmentShaderSource;
|
||||
|
||||
protected int programObject;
|
||||
protected int vertexShader;
|
||||
@@ -292,32 +296,61 @@ public class PShader {
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
if (programObject == 0 || contextIsOutdated()) {
|
||||
|
||||
if (programObject == 0 || contextIsOutdated()) {
|
||||
context = pgl.getContext();
|
||||
programObject = pg.createGLSLProgramObject();
|
||||
|
||||
boolean hasVert = false;
|
||||
if (vertexFilename != null) {
|
||||
loadVertexShader(vertexFilename);
|
||||
hasVert = loadVertexShader(vertexFilename);
|
||||
} else if (vertexURL != null) {
|
||||
loadVertexShader(vertexURL);
|
||||
hasVert = loadVertexShader(vertexURL);
|
||||
} else {
|
||||
PGraphics.showException("Vertex shader filenames and URLs are both null!");
|
||||
}
|
||||
|
||||
boolean hasFrag = false;
|
||||
if (fragmentFilename != null) {
|
||||
loadFragmentShader(fragmentFilename);
|
||||
hasFrag = loadFragmentShader(fragmentFilename);
|
||||
} else if (fragmentURL != null) {
|
||||
loadFragmentShader(fragmentURL);
|
||||
hasFrag = loadFragmentShader(fragmentURL);
|
||||
} else {
|
||||
PGraphics.showException("Fragment shader filenames and URLs are both null!");
|
||||
}
|
||||
|
||||
checkLogInfo("Vertex shader " + vertexFilename + " compilation: ", vertexShader);
|
||||
checkLogInfo("Fragment shader " + fragmentFilename + " compilation: ", fragmentShader);
|
||||
boolean vertRes = true;
|
||||
if (hasVert) {
|
||||
vertRes = compileVertexShader();
|
||||
}
|
||||
|
||||
boolean fragRes = true;
|
||||
if (hasFrag) {
|
||||
fragRes = compileFragmentShader();
|
||||
}
|
||||
|
||||
pgl.glLinkProgram(programObject);
|
||||
pgl.glValidateProgram(programObject);
|
||||
if (vertRes && fragRes) {
|
||||
if (hasVert) {
|
||||
pgl.glAttachShader(programObject, vertexShader);
|
||||
}
|
||||
if (hasFrag) {
|
||||
pgl.glAttachShader(programObject, fragmentShader);
|
||||
}
|
||||
pgl.glLinkProgram(programObject);
|
||||
|
||||
int[] linked = new int[1];
|
||||
pgl.glGetProgramiv(programObject, PGL.GL_LINK_STATUS, linked, 0);
|
||||
if (linked[0] == PGL.GL_FALSE) {
|
||||
PGraphics.showException("Cannot link shader program:\n" + pgl.glGetProgramInfoLog(programObject));
|
||||
}
|
||||
|
||||
pgl.glValidateProgram(programObject);
|
||||
|
||||
int[] validated = new int[1];
|
||||
pgl.glGetProgramiv(programObject, PGL.GL_VALIDATE_STATUS, validated, 0);
|
||||
if (validated[0] == PGL.GL_FALSE) {
|
||||
PGraphics.showException("Cannot validate shader program:\n" + pgl.glGetProgramInfoLog(programObject));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -338,9 +371,9 @@ public class PShader {
|
||||
*
|
||||
* @param file String
|
||||
*/
|
||||
protected void loadVertexShader(String filename) {
|
||||
String shaderSource = PApplet.join(parent.loadStrings(filename), "\n");
|
||||
attachVertexShader(shaderSource);
|
||||
protected boolean loadVertexShader(String filename) {
|
||||
vertexShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
|
||||
return vertexShaderSource != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,12 +381,13 @@ public class PShader {
|
||||
*
|
||||
* @param file String
|
||||
*/
|
||||
protected void loadVertexShader(URL url) {
|
||||
protected boolean loadVertexShader(URL url) {
|
||||
try {
|
||||
String shaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
|
||||
attachVertexShader(shaderSource);
|
||||
vertexShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
|
||||
return vertexShaderSource != null;
|
||||
} catch (IOException e) {
|
||||
PGraphics.showException("Cannot load shader " + url.getFile());
|
||||
PGraphics.showException("Cannot load vertex shader " + url.getFile());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -362,9 +396,9 @@ public class PShader {
|
||||
*
|
||||
* @param file String
|
||||
*/
|
||||
protected void loadFragmentShader(String filename) {
|
||||
String shaderSource = PApplet.join(parent.loadStrings(filename), "\n");
|
||||
attachFragmentShader(shaderSource);
|
||||
protected boolean loadFragmentShader(String filename) {
|
||||
fragmentShaderSource = PApplet.join(parent.loadStrings(filename), "\n");
|
||||
return fragmentShaderSource != null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -372,51 +406,53 @@ public class PShader {
|
||||
*
|
||||
* @param url URL
|
||||
*/
|
||||
protected void loadFragmentShader(URL url) {
|
||||
protected boolean loadFragmentShader(URL url) {
|
||||
try {
|
||||
String shaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
|
||||
attachFragmentShader(shaderSource);
|
||||
fragmentShaderSource = PApplet.join(PApplet.loadStrings(url.openStream()), "\n");
|
||||
return fragmentShaderSource != null;
|
||||
} catch (IOException e) {
|
||||
PGraphics.showException("Cannot load shader " + url.getFile());
|
||||
PGraphics.showException("Cannot load fragment shader " + url.getFile());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param shaderSource a string containing the shader's code
|
||||
*/
|
||||
protected void attachVertexShader(String shaderSource) {
|
||||
protected boolean compileVertexShader() {
|
||||
vertexShader = pg.createGLSLVertShaderObject();
|
||||
|
||||
pgl.glShaderSource(vertexShader, shaderSource);
|
||||
pgl.glShaderSource(vertexShader, vertexShaderSource);
|
||||
pgl.glCompileShader(vertexShader);
|
||||
|
||||
pgl.glAttachShader(programObject, vertexShader);
|
||||
|
||||
int[] compiled = new int[1];
|
||||
pgl.glGetShaderiv(vertexShader, PGL.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == PGL.GL_FALSE) {
|
||||
PGraphics.showException("Cannot compile vertex shader:\n" + pgl.glGetShaderInfoLog(vertexShader));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param shaderSource a string containing the shader's code
|
||||
*/
|
||||
protected void attachFragmentShader(String shaderSource) {
|
||||
protected boolean compileFragmentShader() {
|
||||
fragmentShader = pg.createGLSLFragShaderObject();
|
||||
|
||||
pgl.glShaderSource(fragmentShader, shaderSource);
|
||||
pgl.glShaderSource(fragmentShader, fragmentShaderSource);
|
||||
pgl.glCompileShader(fragmentShader);
|
||||
|
||||
pgl.glAttachShader(programObject, fragmentShader);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check the log error for the opengl object obj. Prints error
|
||||
* message if needed.
|
||||
*/
|
||||
protected void checkLogInfo(String title, int obj) {
|
||||
String log = pgl.getShaderLog(obj);
|
||||
if (!log.equals("")) {
|
||||
System.out.println(title);
|
||||
System.out.println(log);
|
||||
}
|
||||
int[] compiled = new int[1];
|
||||
pgl.glGetShaderiv(fragmentShader, PGL.GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == PGL.GL_FALSE) {
|
||||
PGraphics.showException("Cannot compile fragment shader:\n" + pgl.glGetShaderInfoLog(fragmentShader));
|
||||
return false;
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -434,4 +470,4 @@ public class PShader {
|
||||
programObject = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -289,23 +289,13 @@ public class PTexture implements PConstants {
|
||||
tempFbo = new PFramebuffer(parent, glWidth, glHeight);
|
||||
}
|
||||
|
||||
if (PGraphicsAndroid3D.fboSupported) {
|
||||
// Attaching the texture to the color buffer of a FBO, binding the FBO and reading the pixels
|
||||
// from the current draw buffer (which is the color buffer of the FBO).
|
||||
tempFbo.setColorBuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(tempFbo);
|
||||
tempFbo.readPixels();
|
||||
pg.popFramebuffer();
|
||||
} else {
|
||||
// Here we don't have FBOs, so the method above is of no use. What we do instead is
|
||||
// to draw the texture to the screen framebuffer, and then grab the pixels from there.
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(tempFbo);
|
||||
pg.drawTexture(this, 0, 0, glWidth, glHeight, 0, 0, glWidth, glHeight);
|
||||
tempFbo.readPixels();
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
// Attaching the texture to the color buffer of a FBO, binding the FBO and reading the pixels
|
||||
// from the current draw buffer (which is the color buffer of the FBO).
|
||||
tempFbo.setColorBuffer(this);
|
||||
pg.pushFramebuffer();
|
||||
pg.setFramebuffer(tempFbo);
|
||||
tempFbo.readPixels();
|
||||
pg.popFramebuffer();
|
||||
|
||||
if (tempPixels == null) {
|
||||
tempPixels = new int[size];
|
||||
@@ -484,15 +474,6 @@ public class PTexture implements PConstants {
|
||||
////////////////////////////////////////////////////////////
|
||||
|
||||
// Utilities
|
||||
|
||||
// bit shifting this might be more efficient
|
||||
protected int nextPowerOfTwo(int val) {
|
||||
int ret = 1;
|
||||
while (ret < val) {
|
||||
ret <<= 1;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
@@ -741,8 +722,8 @@ public class PTexture implements PConstants {
|
||||
glWidth = w;
|
||||
glHeight = h;
|
||||
} else {
|
||||
glWidth = nextPowerOfTwo(w);
|
||||
glHeight = nextPowerOfTwo(h);
|
||||
glWidth = PGL.nextPowerOfTwo(w);
|
||||
glHeight = PGL.nextPowerOfTwo(h);
|
||||
}
|
||||
|
||||
if ((glWidth > PGraphicsAndroid3D.maxTextureSize) || (glHeight > PGraphicsAndroid3D.maxTextureSize)) {
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
|
||||
uniform sampler2D textureSampler;
|
||||
|
||||
uniform vec2 texcoordOffset;
|
||||
|
||||
varying vec4 vertColor;
|
||||
varying vec4 vertTexcoord;
|
||||
|
||||
|
||||
@@ -264,7 +264,7 @@ public class PFramebuffer implements PConstants {
|
||||
pgl.glFramebufferTexture2D(PGL.GL_FRAMEBUFFER, PGL.GL_COLOR_ATTACHMENT0 + i, colorBufferTex[i].glTarget, colorBufferTex[i].glID, 0);
|
||||
}
|
||||
|
||||
validateFbo();
|
||||
pgl.validateFramebuffer();
|
||||
|
||||
pg.popFramebuffer();
|
||||
}
|
||||
@@ -457,36 +457,4 @@ public class PFramebuffer implements PConstants {
|
||||
pixelBuffer = IntBuffer.allocate(width * height);
|
||||
pixelBuffer.rewind();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////
|
||||
|
||||
// Utilities.
|
||||
|
||||
// Internal copy to texture method.
|
||||
protected void copyToTexture(IntBuffer buffer, int glid, int gltarget) {
|
||||
pgl.enableTexturing(gltarget);
|
||||
pgl.glBindTexture(gltarget, glid);
|
||||
pgl.glTexSubImage2D(gltarget, 0, 0, 0, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, buffer);
|
||||
pgl.glBindTexture(gltarget, 0);
|
||||
pgl.disableTexturing(gltarget);
|
||||
}
|
||||
|
||||
public boolean validateFbo() {
|
||||
int status = pgl.glCheckFramebufferStatus(PGL.GL_FRAMEBUFFER);
|
||||
if (status == PGL.GL_FRAMEBUFFER_COMPLETE) {
|
||||
return true;
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_INCOMPLETE_FORMATS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == PGL.GL_FRAMEBUFFER_UNSUPPORTED) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_UNSUPPORTED" + Integer.toHexString(status));
|
||||
} else {
|
||||
throw new RuntimeException("PFramebuffer: unknown framebuffer error (" + Integer.toHexString(status) + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,7 +28,10 @@ import java.awt.Canvas;
|
||||
import java.nio.Buffer;
|
||||
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.util.Arrays;
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
@@ -117,8 +120,9 @@ public class PGL {
|
||||
|
||||
public static final int GL_VIEWPORT = GL.GL_VIEWPORT;
|
||||
|
||||
public static final int GL_SCISSOR_TEST = GL.GL_SCISSOR_TEST;
|
||||
public static final int GL_DEPTH_TEST = GL.GL_DEPTH_TEST;
|
||||
public static final int GL_SCISSOR_TEST = GL.GL_SCISSOR_TEST;
|
||||
public static final int GL_DEPTH_TEST = GL.GL_DEPTH_TEST;
|
||||
public static final int GL_DEPTH_WRITEMASK = GL.GL_DEPTH_WRITEMASK;
|
||||
|
||||
public static final int GL_COLOR_BUFFER_BIT = GL.GL_COLOR_BUFFER_BIT;
|
||||
public static final int GL_DEPTH_BUFFER_BIT = GL.GL_DEPTH_BUFFER_BIT;
|
||||
@@ -287,6 +291,41 @@ public class PGL {
|
||||
/** Desired target framerate */
|
||||
protected float targetFramerate = 60;
|
||||
protected boolean setFramerate = false;
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Texture rendering
|
||||
|
||||
protected boolean loadedTexShader = false;
|
||||
protected int texShaderProgram;
|
||||
protected int texVertShader;
|
||||
protected int texFragShader;
|
||||
|
||||
protected int texVertLoc;
|
||||
protected int texTCoordLoc;
|
||||
|
||||
protected float[] texCoords = {
|
||||
// X, Y, U, V
|
||||
-1.0f, -1.0f, 0.0f, 0.0f,
|
||||
+1.0f, -1.0f, 1.0f, 0.0f,
|
||||
-1.0f, +1.0f, 0.0f, 1.0f,
|
||||
+1.0f, +1.0f, 1.0f, 1.0f
|
||||
};
|
||||
protected FloatBuffer texData;
|
||||
|
||||
protected String texVertShaderSource = "attribute vec2 inVertex;" +
|
||||
"attribute vec2 inTexcoord;" +
|
||||
"varying vec2 vertTexcoord;" +
|
||||
"void main() {" +
|
||||
" gl_Position = vec4(inVertex, 0, 1);" +
|
||||
" vertTexcoord = inTexcoord;" +
|
||||
"}";
|
||||
|
||||
protected String texFragShaderSource = "uniform sampler2D textureSampler;" +
|
||||
"varying vec2 vertTexcoord;" +
|
||||
"void main() {" +
|
||||
" gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" +
|
||||
"}";
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -408,7 +447,7 @@ public class PGL {
|
||||
// Frame rendering
|
||||
|
||||
|
||||
public void beginOnscreenDraw(boolean clear, int frame) {
|
||||
public void beginOnscreenDraw(boolean clear) {
|
||||
}
|
||||
|
||||
|
||||
@@ -416,7 +455,7 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void beginOffscreenDraw(boolean clear, int frame) {
|
||||
public void beginOffscreenDraw(boolean clear) {
|
||||
}
|
||||
|
||||
|
||||
@@ -455,6 +494,19 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glGetBooleanv(int name, boolean[] values, int offset) {
|
||||
if (-1 < name) {
|
||||
byte[] bvalues = new byte[values.length];
|
||||
gl.glGetBooleanv(name, bvalues, offset);
|
||||
for (int i = 0; i < values.length; i++) {
|
||||
values[i] = bvalues[i] != 0;
|
||||
}
|
||||
} else {
|
||||
Arrays.fill(values, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Enable/disable caps
|
||||
@@ -604,6 +656,11 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glDrawArrays(int mode, int first, int count) {
|
||||
gl.glDrawArrays(mode, first, count);
|
||||
}
|
||||
|
||||
|
||||
public void glDrawElements(int mode, int count, int type, int offset) {
|
||||
gl.glDrawElements(mode, count, type, offset);
|
||||
}
|
||||
@@ -624,6 +681,11 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void glVertexAttribPointer(int loc, int size, int type, boolean normalized, int stride, Buffer data) {
|
||||
gl2.glVertexAttribPointer(loc, size, type, normalized, stride, data);
|
||||
}
|
||||
|
||||
|
||||
public ByteBuffer glMapBuffer(int target, int access) {
|
||||
return gl2.glMapBuffer(target, access);
|
||||
}
|
||||
@@ -1085,6 +1147,93 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public void drawTexture(int target, int id, int width, int height,
|
||||
int texX0, int texY0, int texX1, int texY1,
|
||||
int scrX0, int scrY0, int scrX1, int scrY1) {
|
||||
|
||||
if (!loadedTexShader) {
|
||||
texVertShader = createShader(GL_VERTEX_SHADER, texVertShaderSource);
|
||||
texFragShader = createShader(GL_FRAGMENT_SHADER, texFragShaderSource);
|
||||
if (0 < texVertShader && 0 < texFragShader) {
|
||||
texShaderProgram = createProgram(texVertShader, texFragShader);
|
||||
}
|
||||
if (0 < texShaderProgram) {
|
||||
texVertLoc = glGetAttribLocation(texShaderProgram, "inVertex");
|
||||
texTCoordLoc = glGetAttribLocation(texShaderProgram, "inTexcoord");
|
||||
}
|
||||
texData = ByteBuffer.allocateDirect(texCoords.length * SIZEOF_FLOAT).order(ByteOrder.nativeOrder()).asFloatBuffer();
|
||||
loadedTexShader = true;
|
||||
}
|
||||
|
||||
if (0 < texShaderProgram) {
|
||||
// When drawing the texture we don't write to the
|
||||
// depth mask, so the texture remains in the background
|
||||
// and can be occluded by anything drawn later, even if
|
||||
// if it is behind it.
|
||||
boolean[] val = new boolean[1];
|
||||
glGetBooleanv(GL_DEPTH_WRITEMASK, val, 0);
|
||||
boolean writeMask = val[0];
|
||||
glDepthMask(false);
|
||||
|
||||
glUseProgram(texShaderProgram);
|
||||
|
||||
glEnableVertexAttribArray(texVertLoc);
|
||||
glEnableVertexAttribArray(texTCoordLoc);
|
||||
|
||||
// Vertex coordinates of the textured quad are specified
|
||||
// in normalized screen space (-1, 1):
|
||||
|
||||
// Corner 1
|
||||
texCoords[ 0] = 2 * (float)scrX0 / pg.width - 1;
|
||||
texCoords[ 1] = 2 * (float)scrY0 / pg.height - 1;
|
||||
texCoords[ 2] = (float)texX0 / width;
|
||||
texCoords[ 3] = (float)texY0 / height;
|
||||
|
||||
// Corner 2
|
||||
texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1;
|
||||
texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1;
|
||||
texCoords[ 6] = (float)texX1 / width;
|
||||
texCoords[ 7] = (float)texY0 / height;
|
||||
|
||||
// Corner 3
|
||||
texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1;
|
||||
texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1;
|
||||
texCoords[10] = (float)texX0 / width;
|
||||
texCoords[11] = (float)texY1 / height;
|
||||
|
||||
// Corner 4
|
||||
texCoords[12] = 2 * (float)scrX1 / pg.width - 1;
|
||||
texCoords[13] = 2 * (float)scrY1 / pg.height - 1;
|
||||
texCoords[14] = (float)texX1 / width;
|
||||
texCoords[15] = (float)texY1 / height;
|
||||
|
||||
texData.rewind();
|
||||
texData.put(texCoords);
|
||||
|
||||
enableTexturing(target);
|
||||
glActiveTexture(target);
|
||||
glBindTexture(target, id);
|
||||
|
||||
texData.position(0);
|
||||
glVertexAttribPointer(texVertLoc, 2, GL_FLOAT, false, 4 * SIZEOF_FLOAT, texData);
|
||||
texData.position(2);
|
||||
glVertexAttribPointer(texTCoordLoc, 2, GL_FLOAT, false, 4 * SIZEOF_FLOAT, texData);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
|
||||
glBindTexture(target, 0);
|
||||
disableTexturing(target);
|
||||
|
||||
glDisableVertexAttribArray(texVertLoc);
|
||||
glDisableVertexAttribArray(texTCoordLoc);
|
||||
|
||||
glUseProgram(0);
|
||||
|
||||
glDepthMask(writeMask);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// bit shifting this might be more efficient
|
||||
static public int nextPowerOfTwo(int val) {
|
||||
int ret = 1;
|
||||
@@ -1095,6 +1244,63 @@ public class PGL {
|
||||
}
|
||||
|
||||
|
||||
public int createShader(int shaderType, String source) {
|
||||
int shader = glCreateShader(shaderType);
|
||||
if (shader != 0) {
|
||||
glShaderSource(shader, source);
|
||||
glCompileShader(shader);
|
||||
int[] compiled = new int[1];
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, compiled, 0);
|
||||
if (compiled[0] == GL_FALSE) {
|
||||
System.err.println("Could not compile shader " + shaderType + ":");
|
||||
System.err.println(glGetShaderInfoLog(shader));
|
||||
glDeleteShader(shader);
|
||||
shader = 0;
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
|
||||
public int createProgram(int vertexShader, int fragmentShader) {
|
||||
int program = glCreateProgram();
|
||||
if (program != 0) {
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
int[] linked = new int[1];
|
||||
glGetProgramiv(program, GL_LINK_STATUS, linked, 0);
|
||||
if (linked[0] == GL_FALSE) {
|
||||
System.err.println("Could not link program: ");
|
||||
System.err.println(glGetProgramInfoLog(program));
|
||||
glDeleteProgram(program);
|
||||
program = 0;
|
||||
}
|
||||
}
|
||||
return program;
|
||||
}
|
||||
|
||||
|
||||
public boolean validateFramebuffer() {
|
||||
int status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status == GL_FRAMEBUFFER_COMPLETE) {
|
||||
return true;
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_INCOMPLETE_FORMATS) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_INCOMPLETE_FORMATS (" + Integer.toHexString(status) + ")");
|
||||
} else if (status == GL_FRAMEBUFFER_UNSUPPORTED) {
|
||||
throw new RuntimeException("PFramebuffer: GL_FRAMEBUFFER_UNSUPPORTED" + Integer.toHexString(status));
|
||||
} else {
|
||||
throw new RuntimeException("PFramebuffer: unknown framebuffer error (" + Integer.toHexString(status) + ")");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// Java specific stuff
|
||||
|
||||
@@ -1507,17 +1507,17 @@ public class PGraphicsOpenGL extends PGraphics {
|
||||
pgl.glClearColor(0, 0, 0, 0);
|
||||
pgl.glClear(PGL.GL_DEPTH_BUFFER_BIT | PGL.GL_STENCIL_BUFFER_BIT);
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.beginOnscreenDraw(clearColorBuffer);
|
||||
} else {
|
||||
pgl.beginOffscreenDraw(clearColorBuffer);
|
||||
}
|
||||
|
||||
if (hints[DISABLE_DEPTH_MASK]) {
|
||||
pgl.glDepthMask(false);
|
||||
} else {
|
||||
pgl.glDepthMask(true);
|
||||
}
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.beginOnscreenDraw(clearColorBuffer, parent.frameCount);
|
||||
} else {
|
||||
pgl.beginOffscreenDraw(clearColorBuffer, parent.frameCount);
|
||||
}
|
||||
}
|
||||
|
||||
drawing = true;
|
||||
|
||||
@@ -1548,9 +1548,9 @@ public class PGraphicsOpenGL extends PGraphics {
|
||||
// Restoring previous viewport.
|
||||
pgl.glViewport(savedViewport[0], savedViewport[1], savedViewport[2], savedViewport[3]);
|
||||
|
||||
if (primarySurface) {
|
||||
pgl.glFlush();
|
||||
if (primarySurface) {
|
||||
pgl.endOnscreenDraw(clearColorBuffer0);
|
||||
pgl.glFlush();
|
||||
} else {
|
||||
if (offscreenMultisample) {
|
||||
offscreenFramebufferMultisample.copy(offscreenFramebuffer);
|
||||
|
||||
Reference in New Issue
Block a user