Fixing several problems with the handling of offsecreen surfaces

This commit is contained in:
codeanticode
2013-05-27 13:01:29 -04:00
parent b7abfe8447
commit 62d7076a59
6 changed files with 167 additions and 136 deletions
@@ -149,7 +149,6 @@ public class FrameBuffer implements PConstants {
@Override
protected void finalize() throws Throwable {
try {
// PApplet.println("finalize FBO");
if (!screenFb) {
if (glFbo != 0) {
PGraphicsOpenGL.finalizeFrameBufferObject(glFbo, context);
+5
View File
@@ -18,6 +18,11 @@
Boston, MA 02111-1307 USA
*/
#ifdef GL_ES
precision mediump float;
precision mediump int;
#endif
#define PROCESSING_TEXTURE_SHADER
uniform sampler2D texture;
+37 -32
View File
@@ -965,7 +965,8 @@ public class PGL {
// Render previous back texture (now is the front) as background,
// because no background() is being used ("incremental drawing")
drawTexture(TEXTURE_2D, glColorTex.get(frontTex),
fboWidth, fboHeight, 0, 0, pg.width, pg.height,
fboWidth, fboHeight, pg.width, pg.height,
0, 0, pg.width, pg.height,
0, 0, pg.width, pg.height);
}
@@ -997,6 +998,7 @@ public class PGL {
gl.glDisable(GL.GL_BLEND);
drawTexture(GL.GL_TEXTURE_2D, backTexAttach.getName(),
backTexAttach.getWidth(), backTexAttach.getHeight(),
pg.width, pg.height,
0, 0, pg.width, pg.height, 0, 0, pg.width, pg.height);
backFBO.bind(gl);
}
@@ -1014,7 +1016,8 @@ public class PGL {
// Render current back texture to screen, without blending.
disable(BLEND);
drawTexture(TEXTURE_2D, glColorTex.get(backTex),
fboWidth, fboHeight, 0, 0, pg.width, pg.height,
fboWidth, fboHeight, pg.width, pg.height,
0, 0, pg.width, pg.height,
0, 0, pg.width, pg.height);
// Swapping front and back textures.
@@ -1329,26 +1332,28 @@ public class PGL {
protected void drawTexture(int target, int id, int width, int height,
int X0, int Y0, int X1, int Y1) {
drawTexture(target, id, width, height, X0, Y0, X1, Y1, X0, Y0, X1, Y1);
drawTexture(target, id, width, height, width, height,
X0, Y0, X1, Y1, X0, Y0, X1, Y1);
}
protected void drawTexture(int target, int id, int width, int height,
protected void drawTexture(int target, int id,
int texW, int texH, int scrW, int scrH,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
if (target == TEXTURE_2D) {
drawTexture2D(id, width, height,
drawTexture2D(id, texW, texH, scrW, scrH,
texX0, texY0, texX1, texY1,
scrX0, scrY0, scrX1, scrY1);
} else if (target == TEXTURE_RECTANGLE) {
drawTextureRect(id, width, height,
drawTextureRect(id, texW, texH, scrW, scrH,
texX0, texY0, texX1, texY1,
scrX0, scrY0, scrX1, scrY1);
}
}
protected void drawTexture2D(int id, int width, int height,
protected void drawTexture2D(int id, int texW, int texH, int scrW, int scrH,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
if (!loadedTex2DShader ||
@@ -1390,25 +1395,25 @@ public class PGL {
// 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;
texCoords[ 0] = 2 * (float)scrX0 / scrW - 1;
texCoords[ 1] = 2 * (float)scrY0 / scrH - 1;
texCoords[ 2] = (float)texX0 / texW;
texCoords[ 3] = (float)texY0 / texH;
// 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;
texCoords[ 4] = 2 * (float)scrX1 / scrW - 1;
texCoords[ 5] = 2 * (float)scrY0 / scrH - 1;
texCoords[ 6] = (float)texX1 / texW;
texCoords[ 7] = (float)texY0 / texH;
// 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;
texCoords[ 8] = 2 * (float)scrX0 / scrW - 1;
texCoords[ 9] = 2 * (float)scrY1 / scrH - 1;
texCoords[10] = (float)texX0 / texW;
texCoords[11] = (float)texY1 / texH;
// 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;
texCoords[12] = 2 * (float)scrX1 / scrW - 1;
texCoords[13] = 2 * (float)scrY1 / scrH - 1;
texCoords[14] = (float)texX1 / texW;
texCoords[15] = (float)texY1 / texH;
texData.rewind();
texData.put(texCoords);
@@ -1452,7 +1457,7 @@ public class PGL {
}
protected void drawTextureRect(int id, int width, int height,
protected void drawTextureRect(int id, int texW, int texH, int scrW, int scrH,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
if (!loadedTexRectShader ||
@@ -1495,23 +1500,23 @@ public class PGL {
// 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[ 0] = 2 * (float)scrX0 / scrW - 1;
texCoords[ 1] = 2 * (float)scrY0 / scrH - 1;
texCoords[ 2] = texX0;
texCoords[ 3] = texY0;
// Corner 2
texCoords[ 4] = 2 * (float)scrX1 / pg.width - 1;
texCoords[ 5] = 2 * (float)scrY0 / pg.height - 1;
texCoords[ 4] = 2 * (float)scrX1 / scrW - 1;
texCoords[ 5] = 2 * (float)scrY0 / scrH - 1;
texCoords[ 6] = texX1;
texCoords[ 7] = texY0;
// Corner 3
texCoords[ 8] = 2 * (float)scrX0 / pg.width - 1;
texCoords[ 9] = 2 * (float)scrY1 / pg.height - 1;
texCoords[ 8] = 2 * (float)scrX0 / scrW - 1;
texCoords[ 9] = 2 * (float)scrY1 / scrH - 1;
texCoords[10] = texX0;
texCoords[11] = texY1;
// Corner 4
texCoords[12] = 2 * (float)scrX1 / pg.width - 1;
texCoords[13] = 2 * (float)scrY1 / pg.height - 1;
texCoords[12] = 2 * (float)scrX1 / scrW - 1;
texCoords[13] = 2 * (float)scrY1 / scrH - 1;
texCoords[14] = texX1;
texCoords[15] = texY1;
+112 -50
View File
@@ -667,8 +667,6 @@ public class PGraphicsOpenGL extends PGraphics {
@Override
protected void finalize() throws Throwable {
try {
// PApplet.println("finalize surface");
deletePolyBuffers();
deleteLineBuffers();
deletePointBuffers();
@@ -797,7 +795,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glTextureObjects.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " texture objects, " + glTextureObjects.size() + " remaining");
}
protected static void removeTextureObject(int id, int context) {
@@ -862,7 +859,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glVertexBuffers.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " vertex buffer objects, " + glVertexBuffers.size() + " remaining");
}
protected static void removeVertexBufferObject(int id, int context) {
@@ -929,7 +925,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glFrameBuffers.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " framebuffer objects, " + glFrameBuffers.size() + " remaining");
}
protected static void removeFrameBufferObject(int id, int context) {
@@ -994,7 +989,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glRenderBuffers.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " renderbuffer objects, " + glRenderBuffers.size() + " remaining");
}
protected static void removeRenderBufferObject(int id, int context) {
@@ -1055,7 +1049,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glslPrograms.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " GLSL program objects, " + glslPrograms.size() + " remaining");
}
protected static void removeGLSLProgramObject(int id, int context) {
@@ -1117,7 +1110,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glslVertexShaders.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " GLSL vertex shader objects, " + glslVertexShaders.size() + " remaining");
}
protected static void removeGLSLVertShaderObject(int id, int context) {
@@ -1179,7 +1171,6 @@ public class PGraphicsOpenGL extends PGraphics {
for (GLResource res : finalized) {
glslFragmentShaders.remove(res);
}
// PApplet.println("Deleted " + finalized.size() + " GLSL fragment shader objects, " + glslFragmentShaders.size() + " remaining");
}
protected static void removeGLSLFragShaderObject(int id, int context) {
@@ -1637,6 +1628,12 @@ public class PGraphicsOpenGL extends PGraphics {
if (primarySurface) {
beginOnscreenDraw();
} else {
if (pgPrimary.texCache.containsTexture(this)) {
// This offscreen surface is being used as a texture earlier in draw,
// so we should update the rendering up to this point since it will
// modified.
pgPrimary.flush();
}
beginOffscreenDraw();
}
setDefaults();
@@ -1644,9 +1641,15 @@ public class PGraphicsOpenGL extends PGraphics {
pgCurrent = this;
drawing = true;
clearCalled = false;
clearColorBuffer0 = clearColorBuffer;
clearColorBuffer = false;
report("bot beginDraw()");
}
boolean clearCalled;
boolean clearEveryFrame;
@Override
public void endDraw() {
@@ -1657,6 +1660,10 @@ public class PGraphicsOpenGL extends PGraphics {
return;
}
if (!clearCalled && 0 < parent.frameCount) {
clearEveryFrame = false;
}
// Flushing any remaining geometry.
flush();
@@ -1945,6 +1952,7 @@ public class PGraphicsOpenGL extends PGraphics {
manipulatingCamera = false;
clearColorBuffer = false;
clearEveryFrame = true;
// easiest for beginners
textureMode(IMAGE);
@@ -4899,6 +4907,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (0 < parent.frameCount) {
clearColorBuffer = true;
}
clearCalled = true;
}
@@ -4920,6 +4929,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (0 < parent.frameCount) {
clearColorBuffer = true;
}
clearCalled = true;
}
@@ -5278,11 +5288,11 @@ public class PGraphicsOpenGL extends PGraphics {
}
public void drawTexture(int target, int id, int width, int height,
public void drawTexture(int target, int id, int texW, int texH,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
beginPGL();
pgl.drawTexture(target, id, width, height,
pgl.drawTexture(target, id, texW, texH, width, height,
texX0, texY0, texX1, texY1,
scrX0, scrY0, scrX1, scrY1);
endPGL();
@@ -5300,20 +5310,27 @@ public class PGraphicsOpenGL extends PGraphics {
pgPrimary.setCache(this, texture);
if (!primarySurface) {
ptexture = new Texture(width, height, params);
ptexture.invertedY(true);
ptexture.colorBuffer(true);
createPTexture();
}
}
}
protected void createPTexture() {
ptexture = new Texture(width, height, texture.getParameters());
ptexture.invertedY(true);
ptexture.colorBuffer(true);
}
protected void swapTextures() {
int temp = texture.glName;
texture.glName = ptexture.glName;
ptexture.glName = temp;
if (!primarySurface) {
offscreenFramebuffer.setColorBuffer(texture);
if (ptexture != null) {
int temp = texture.glName;
texture.glName = ptexture.glName;
ptexture.glName = temp;
if (!primarySurface) {
offscreenFramebuffer.setColorBuffer(texture);
}
}
}
@@ -5334,13 +5351,40 @@ public class PGraphicsOpenGL extends PGraphics {
// invert the y coordinates of the screen rectangle.
pgl.disable(PGL.BLEND);
pgl.drawTexture(texture.glTarget, texture.glName,
texture.glWidth, texture.glHeight,
texture.glWidth, texture.glHeight, width, height,
x, y, x + w, y + h,
x, height - (y + h), x + w, height - y);
pgl.enable(PGL.BLEND);
}
protected void drawPTexture() {
if (ptexture != null) {
// No blend so the texure replaces wherever is on the screen,
// irrespective of the alpha
pgl.disable(PGL.BLEND);
pgl.drawTexture(ptexture.glTarget, ptexture.glName,
ptexture.glWidth, ptexture.glHeight,
0, 0, width, height);
pgl.enable(PGL.BLEND);
}
}
protected void drawPTexture(int x, int y, int w, int h) {
if (ptexture != null) {
// Processing Y axis is inverted with respect to OpenGL, so we need to
// invert the y coordinates of the screen rectangle.
pgl.disable(PGL.BLEND);
pgl.drawTexture(ptexture.glTarget, ptexture.glName,
ptexture.glWidth, ptexture.glHeight, width, height,
x, y, x + w, y + h,
x, height - (y + h), x + w, height - y);
pgl.enable(PGL.BLEND);
}
}
//////////////////////////////////////////////////////////////
// MASK
@@ -5409,8 +5453,14 @@ public class PGraphicsOpenGL extends PGraphics {
return;
}
pgl.needFBOLayer();
boolean needEndDraw = false;
if (primarySurface) pgl.needFBOLayer();
else if (!drawing) {
beginDraw();
needEndDraw = true;
}
loadTexture();
if (filterTexture == null || filterTexture.contextIsOutdated()) {
filterTexture = new Texture(texture.width, texture.height,
texture.getParameters());
@@ -5418,6 +5468,7 @@ public class PGraphicsOpenGL extends PGraphics {
filterImage = wrapTexture(filterTexture);
}
filterTexture.set(texture);
// filterTexture.set(ptexture);
// Disable writing to the depth buffer, so that after applying the filter we
// can still use the depth information to keep adding geometry to the scene.
@@ -5438,10 +5489,11 @@ public class PGraphicsOpenGL extends PGraphics {
textureMode = NORMAL;
boolean prevStroke = stroke;
stroke = false;
// int prevBlendMode = blendMode;
// blendMode(REPLACE);
int prevBlendMode = blendMode;
blendMode(REPLACE);
TextureShader prevTexShader = textureShader;
textureShader = (TextureShader) shader;
beginShape(QUADS);
texture(filterImage);
vertex(0, 0, 0, 0);
@@ -5451,13 +5503,12 @@ public class PGraphicsOpenGL extends PGraphics {
endShape();
end2D();
textureShader = prevTexShader;
// Restoring previous configuration.
textureShader = prevTexShader;
stroke = prevStroke;
lights = prevLights;
textureMode = prevTextureMode;
// blendMode(prevBlendMode);
blendMode(prevBlendMode);
if (!hints[DISABLE_DEPTH_TEST]) {
pgl.enable(PGL.DEPTH_TEST);
@@ -5465,6 +5516,10 @@ public class PGraphicsOpenGL extends PGraphics {
if (!hints[DISABLE_DEPTH_MASK]) {
pgl.depthMask(true);
}
if (needEndDraw) {
endDraw();
}
}
@@ -5696,6 +5751,7 @@ public class PGraphicsOpenGL extends PGraphics {
if (primarySurface) {
pgl.bindFrontTexture();
} else {
if (ptexture == null) createPTexture();
ptexture.bind();
}
}
@@ -5952,9 +6008,17 @@ public class PGraphicsOpenGL extends PGraphics {
protected void beginOffscreenDraw() {
updateOffscreen();
// Just in case the texture was recreated (in a resize event for example)
offscreenFramebuffer.setColorBuffer(texture);
/*
if (!clearColorBuffer) {
// Render previous back texture (now is the front) as background,
// because no background() is being used ("incremental drawing")
drawPTexture();
}
if (!clearEveryFrame) {
drawPTexture();
}
*/
drawPTexture();
// Restoring the clipping configuration of the offscreen surface.
if (clip) {
@@ -5971,22 +6035,6 @@ public class PGraphicsOpenGL extends PGraphics {
multisampleFramebuffer.copy(offscreenFramebuffer, currentFramebuffer);
}
if (!clearColorBuffer0) {
// Draw the back texture into the front texture, which will be used as
// front texture in the next frame. Otherwise flickering will occur if
// the sketch uses "incremental drawing" (background() not called).
if (offscreenMultisample) {
pushFramebuffer();
setFramebuffer(offscreenFramebuffer);
}
offscreenFramebuffer.setColorBuffer(ptexture);
drawTexture();
offscreenFramebuffer.setColorBuffer(texture);
if (offscreenMultisample) {
popFramebuffer();
}
}
popFramebuffer();
texture.updateTexels(); // Mark all texels in screen texture as modified.
@@ -6109,9 +6157,6 @@ public class PGraphicsOpenGL extends PGraphics {
modified = false;
setgetPixels = false;
clearColorBuffer0 = clearColorBuffer;
clearColorBuffer = false;
}
@@ -6879,6 +6924,11 @@ public class PGraphicsOpenGL extends PGraphics {
setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset);
}
@Override
public int getLastTexUnit() {
return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit();
}
@Override
public void setTexture(Texture tex) {
float scaleu = 1;
@@ -6915,7 +6965,7 @@ public class PGraphicsOpenGL extends PGraphics {
setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
if (-1 < textureLoc) {
texUnit = bufferUnit + 1;
texUnit = getLastTexUnit() + 1;
setUniformValue(textureLoc, texUnit);
pgl.activeTexture(PGL.TEXTURE0 + texUnit);
tex.bind();
@@ -6999,6 +7049,11 @@ public class PGraphicsOpenGL extends PGraphics {
setAttributeVBO(texCoordLoc, vboId, size, type, false, stride, offset);
}
@Override
public int getLastTexUnit() {
return -1 < bufferUnit ? bufferUnit : super.getLastTexUnit();
}
@Override
public void setTexture(Texture tex) {
float scaleu = 1;
@@ -7035,7 +7090,7 @@ public class PGraphicsOpenGL extends PGraphics {
setUniformValue(texOffsetLoc, 1.0f / tex.width, 1.0f / tex.height);
if (-1 < textureLoc) {
texUnit = bufferUnit + 1;
texUnit = getLastTexUnit() + 1;
setUniformValue(textureLoc, texUnit);
pgl.activeTexture(PGL.TEXTURE0 + texUnit);
tex.bind();
@@ -7313,6 +7368,13 @@ public class PGraphicsOpenGL extends PGraphics {
hasTextures = false;
}
boolean containsTexture(PImage img) {
for (int i = 0; i < size; i++) {
if (textures[i] == img) return true;
}
return false;
}
PImage getTextureImage(int i) {
return textures[i];
}
-35
View File
@@ -84,7 +84,6 @@ public class PShader {
protected IntBuffer intBuffer;
protected FloatBuffer floatBuffer;
public PShader() {
parent = null;
pgMain = null;
@@ -100,8 +99,6 @@ public class PShader {
glVertex = 0;
glFragment = 0;
// firstTexUnit = 0;
intBuffer = PGL.allocateIntBuffer(1);
floatBuffer = PGL.allocateFloatBuffer(1);
@@ -927,36 +924,4 @@ public class PShader {
this.value = value;
}
}
/*
// The individual attribute setters are not really needed, read this:
// http://stackoverflow.com/questions/7718976/what-is-glvertexattrib-versus-glvertexattribpointer-used-for
// except for setting a constant vertex attribute value.
public void set1FloatAttribute(int loc, float x) {
if (-1 < loc) {
pgl.glVertexAttrib1f(loc, x);
}
}
public void set2FloatAttribute(int loc, float x, float y) {
if (-1 < loc) {
pgl.glVertexAttrib2f(loc, x, y);
}
}
public void set3FloatAttribute(int loc, float x, float y, float z) {
if (-1 < loc) {
pgl.glVertexAttrib3f(loc, x, y, z);
}
}
public void set4FloatAttribute(int loc, float x, float y, float z, float w) {
if (-1 < loc) {
pgl.glVertexAttrib4f(loc, x, y, z, w);
}
}
*/
}
+13 -18
View File
@@ -80,7 +80,7 @@ public class Texture implements PConstants {
protected PGL pgl; // The interface between Processing and OpenGL.
protected int context; // The context that created this texture.
protected boolean colorBuffer; // true if it is the color attachment of
protected boolean colorBuffer; // true if it is the color attachment of
// FrameBuffer object.
protected boolean usingMipmaps;
@@ -270,18 +270,6 @@ public class Texture implements PConstants {
// Set methods
// public void set(PImage tex) {
// Texture tex = (Texture)pg.getCache(img);
// set(tex);
// }
// public void set(PImage img, int x, int y, int w, int h) {
// Texture tex = (Texture)pg.getCache(img);
// set(tex, x, y, w, h);
// }
public void set(Texture tex) {
copyTexture(tex, 0, 0, tex.width, tex.height, true);
}
@@ -851,6 +839,7 @@ public class Texture implements PConstants {
pixelBuffer = PGL.updateIntBuffer(pixelBuffer, pixels, true);
}
////////////////////////////////////////////////////////////
// Buffer sink interface.
@@ -1135,7 +1124,6 @@ public class Texture implements PConstants {
}
///////////////////////////////////////////////////////////
// Allocate/release texture.
@@ -1281,18 +1269,21 @@ public class Texture implements PConstants {
if (scale) {
// Rendering tex into "this", and scaling the source rectangle
// to cover the entire destination region.
pgl.drawTexture(tex.glTarget, tex.glName, tex.glWidth, tex.glHeight,
pgl.drawTexture(tex.glTarget, tex.glName,
tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
x, y, w, h, 0, 0, width, height);
} else {
// Rendering tex into "this" but without scaling so the contents
// of the source texture fall in the corresponding texels of the
// destination.
pgl.drawTexture(tex.glTarget, tex.glName, tex.glWidth, tex.glHeight,
pgl.drawTexture(tex.glTarget, tex.glName,
tex.glWidth, tex.glHeight, tempFbo.width, tempFbo.height,
x, y, w, h, x, y, w, h);
}
PGraphicsOpenGL.popFramebuffer();
updateTexels(x, y, w, h);
PApplet.println(width + " " + height + " " + tempFbo.width + " " + tempFbo.height);
}
@@ -1314,18 +1305,22 @@ public class Texture implements PConstants {
if (scale) {
// Rendering tex into "this", and scaling the source rectangle
// to cover the entire destination region.
pgl.drawTexture(texTarget, texName, texWidth, texHeight,
pgl.drawTexture(texTarget, texName,
texWidth, texHeight, tempFbo.width, tempFbo.height,
x, y, w, h, 0, 0, width, height);
} else {
// Rendering tex into "this" but without scaling so the contents
// of the source texture fall in the corresponding texels of the
// destination.
pgl.drawTexture(texTarget, texName, texWidth, texHeight,
pgl.drawTexture(texTarget, texName,
texWidth, texHeight, tempFbo.width, tempFbo.height,
x, y, w, h, x, y, w, h);
}
PGraphicsOpenGL.popFramebuffer();
updateTexels(x, y, w, h);
PApplet.println(width + " " + height + " " + tempFbo.width + " " + tempFbo.height);
}