package processing.opengl; import javax.media.opengl.GL; import javax.media.opengl.GL2; import javax.media.opengl.glu.GLU; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PGraphics; import processing.core.PMatrix3D; public class GLPersist implements PConstants{ private PApplet app; private int glMipmappingMode = GL.GL_NEAREST; private float COPYQUALITY = 1f; private boolean COPYQUALITYNOTONE = false; private int GlTargetDrawBuffer = -1; private int TEXIMAGEH = -1, TEXIMAGEW = -1; private int lastImgStored = -1; private int xRect1, yRect1; private int gWidth, gHeight; public GLPersist(PApplet app){ this.app = app; } private boolean inPersist = false; public void beginPersist(float Quality, int x1, int y1, int x2, int y2){ beginPersist(Quality,GL.GL_NEAREST,x1,y1,x2,y2); } public void beginPersist(float Quality, int GLMipMappingMode, int x1, int y1, int x2, int y2){ if (inPersist){ app.die("Nested persistance is not allowed."); } glMipmappingMode = GLMipMappingMode; inPersist = true; COPYQUALITY = Quality; COPYQUALITYNOTONE = COPYQUALITY!=1f; xRect1 = x1; gHeight = y2-y1; yRect1 = app.height-y2; gWidth = x2-x1; PGraphics g = app.g; GL2 gl = ((PGraphicsOpenGL)g).gl; int ViewWidth= (int)(gWidth*COPYQUALITY); int ViewHeight = (int)(COPYQUALITY*gHeight); gl.glViewport(xRect1,yRect1,ViewWidth,ViewHeight); if (lastImgStored==-1){ int[] res = new int[1]; gl.glGetIntegerv(gl.GL_DRAW_BUFFER,res,0); GlTargetDrawBuffer = res[0]; int[] txtnumber = new int[1]; gl.glGenTextures(1, txtnumber, 0); // Create 1 Texture lastImgStored = txtnumber[0]; copy(); } setSetColor(1,1,1); } private void checkPersist(){ if(!inPersist) app.die("This method may only be called after beginPersist"); } public void copy(){ checkPersist(); PGraphics g = app.g; GL2 gl = ((PGraphicsOpenGL)g).gl; g.flush(); int useWidth = (int)(gWidth * COPYQUALITY); int useHeight = (int)(gHeight * COPYQUALITY); CopyBuffer(gl, xRect1, yRect1, useWidth, useHeight); //Copies upwards } public void set(){ checkPersist(); set(0,0,1); } public interface GLPersistCB{ public void transform(GL2 gl); } public void set(float xOffset, float yOffset, float alpha){ set(xOffset,yOffset,alpha,null); } public void set(float xOffset, float yOffset, float alpha, GLPersistCB cb){ checkPersist(); PGraphics g = app.g; GL2 gl = ((PGraphicsOpenGL)g).gl; screen2D4GL(app.g,gWidth,gHeight); xOffset/=gWidth; yOffset/=gHeight; xOffset/=COPYQUALITY; yOffset/=COPYQUALITY; gl.glClear(GL.GL_DEPTH_BUFFER_BIT); if (cb!=null){ gl.glPushMatrix(); cb.transform(gl); } drawToScreen(gl, lastImgStored, xOffset, yOffset, alpha); if (cb!=null){ gl.glPopMatrix(); } gl.glClear(GL.GL_DEPTH_BUFFER_BIT); unScreen2D4GL(g,gl); } public void endPersist(){ checkPersist(); PGraphics g = app.g; GL2 gl = ((PGraphicsOpenGL)g).gl; if (COPYQUALITYNOTONE){ copy(); //Fill viewport with copy. gl.glViewport(xRect1, yRect1, gWidth, gHeight); set(); } //Go back to full viewport. gl.glViewport(0,0,g.width,g.height); inPersist = false; } //////METHODS private void unScreen2D4GL(PGraphics g, GL2 gl) { gl.glMatrixMode(GL2.GL_PROJECTION); gl.glLoadIdentity(); //projection.print(); PMatrix3D projection = ((PGraphicsOpenGL)g).projection; float[] projectionFloats = new float[] { projection.m00, projection.m10, projection.m20, projection.m30, projection.m01, projection.m11, projection.m21, projection.m31, projection.m02, projection.m12, projection.m22, projection.m32, projection.m03, projection.m13, projection.m23, projection.m33 }; gl.glLoadMatrixf(projectionFloats, 0); gl.glMatrixMode(GL2.GL_MODELVIEW); gl.glLoadIdentity(); // Flip Y-axis to make y count from 0 downwards gl.glScalef(1, -1, 1); } public void setSetColor(float r, float g, float b){ this.setR = r; this.setG = g; this.setB = b; } private float setR = 1f, setG = 1f, setB = 1f; private void drawToScreen(GL2 gl, int whichTex, float xoff, float yoff, float alpha) // Draw The Blurred Image { float texMaxActualW = gWidth/((float)TEXIMAGEW/COPYQUALITY); float texMaxActualH = gHeight/((float)TEXIMAGEH/COPYQUALITY); xoff*=texMaxActualW; yoff*=texMaxActualH; xoff*=-1; yoff*=-1; gl.glEnable(GL.GL_TEXTURE_2D); if (whichTex!=-1) gl.glBindTexture(GL.GL_TEXTURE_2D, whichTex); float spost = 0; // Starting Alpha Value //Note: recode this so that it doesn't clip the vertices outside of the viewport? gl.glBegin(GL2.GL_QUADS); // Begin Drawing Quads gl.glColor4f(setR, setG, setB, alpha); // Set The Alpha Value (Starts At 0.2) gl.glTexCoord2f(0+xoff, texMaxActualH+yoff); // Texture Coordinate ( 0, 1 ) gl.glVertex2f(spost, spost); // First Vertex ( 0, 0 ) gl.glTexCoord2f(0+xoff, 0+yoff); // Texture Coordinate ( 0, 0 ) gl.glVertex2f(0+spost, 1-spost); // Second Vertex ( 0, 480 ) gl.glTexCoord2f(texMaxActualW+xoff, 0+yoff); // Texture Coordinate ( 1, 0 ) gl.glVertex2f(1-spost, 1-spost); // Third Vertex ( 640, 480 ) gl.glTexCoord2f(texMaxActualW+xoff, texMaxActualH+yoff); // Texture Coordinate ( 1, 1 ) gl.glVertex2f(1-spost, spost); // Fourth Vertex ( 640, 0 ) gl.glEnd(); // Done Drawing Quads gl.glDisable(GL.GL_TEXTURE_2D); // Disable 2D Texture Mapping gl.glBindTexture(GL.GL_TEXTURE_2D, 0); // Unbind The Blur Texture } private void view3D(PGraphics g, float wantedWidth, float wantedHeight){ GLU glu = ((PGraphicsOpenGL)g).glu; GL2 gl = ((PGraphicsOpenGL)g).gl; gl.glMatrixMode(gl.GL_PROJECTION); // Select The Projection Matrix gl.glLoadIdentity(); // Reset The Projection Matrix glu.gluPerspective(45.0f,wantedWidth/wantedHeight,0.1f,100f); // Reset The Current Modelview Matrix gl.glMatrixMode(gl.GL_MODELVIEW); gl.glLoadIdentity(); gl.glTranslatef(0.0f, 0.0f,-(float)Math.sqrt(2)-1); // Center The Triangle } private void CopyBuffer(GL2 gl, int offX, int offY, int useWidth, int useHeight) { gl.glReadBuffer(GlTargetDrawBuffer); int powTwoUseWidth = getNextPowerOfTwo(useWidth); int powTwoUseHeight = getNextPowerOfTwo(useHeight); if ((TEXIMAGEW!=powTwoUseWidth) || (TEXIMAGEH!=powTwoUseHeight)){ //Note: must handle resizes!!! gl.glBindTexture(GL.GL_TEXTURE_2D, lastImgStored); gl.glCopyTexImage2D(GL.GL_TEXTURE_2D, 0, GL.GL_RGB,offX, offY,TEXIMAGEW=powTwoUseWidth,TEXIMAGEH=powTwoUseHeight,0); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MIN_FILTER, glMipmappingMode); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_MAG_FILTER, glMipmappingMode); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_S, GL2.GL_CLAMP); gl.glTexParameteri(GL.GL_TEXTURE_2D, GL.GL_TEXTURE_WRAP_T, GL2.GL_CLAMP); } else { // Copy Our ViewPort To The Blur Texture (From 0,0 To useWidth,useHeight... No Border) gl.glBindTexture(GL.GL_TEXTURE_2D, lastImgStored); gl.glCopyTexSubImage2D(GL.GL_TEXTURE_2D, 0, 0, 0, offX, offY, useWidth, useHeight); } } private int getNextPowerOfTwo(int x){ int test = 1; while(test < x){ test <<= 1; } return test; } private void screen2D4GL(PGraphics g, float wantedWidth, float wantedHeight) { GL2 gl = ((PGraphicsOpenGL)g).gl; /* screen2D(); */ float[] vals = g.getMatrix().get(null); //gl.glTranslatef(vals[3],vals[7],vals[11]); view3D(g, wantedWidth, wantedHeight); gl.glScalef(1/(wantedHeight/wantedWidth),-1,1); //NOTE: IS UPSIDE DOWN! gl.glTranslatef(-1,-1,0); gl.glScalef(2,2,1/vals[11]); } public void cleanup() { GL2 gl = ((PGraphicsOpenGL)app.g).gl; gl.glDeleteTextures(1, new int[]{lastImgStored}, 0); } }