protected void createTexture() { tex = ctx.createTexture(texWidth, texHeight, false, false, false); fbuf = ctx.createFramebuffer(tex); ctx.bindFramebuffer(fbuf, texWidth, texHeight); ctx.clear(0, 0, 0, 0); }
protected void clearTexture() { ctx.destroyTexture(tex); tex = 0; ctx.deleteFramebuffer(fbuf); fbuf = 0; }
public void bindFramebuffer(int fbuf, int width, int height) { if (fbuf != lastFramebuffer) { flush(true); // flush and deactivate any shader rendering to the old framebuffer checkGLError("bindFramebuffer"); bindFramebufferImpl(lastFramebuffer = fbuf, curFbufWidth = width, curFbufHeight = height); } }
/** * Makes the supplied shader the current shader, flushing any previous shader. */ public boolean useShader(GLShader shader) { if (curShader == shader) return false; checkGLError("useShader"); flush(true); curShader = shader; return true; }
protected static int convertToRepTex(GLContext ctx, int tex, int width, int height, boolean repeatX, boolean repeatY, boolean mipmapped) { int reptex = ctx.createTexture(width, height, repeatX, repeatY, mipmapped); int fbuf = ctx.createFramebuffer(reptex); ctx.pushFramebuffer(fbuf, width, height); try { // render the non-repeated texture into the framebuffer properly scaled ctx.clear(0, 0, 0, 0); GLShader shader = ctx.quadShader(null).prepareTexture(tex, Tint.NOOP_TINT); shader.addQuad(ctx.createTransform(), 0, height, width, 0, 0, 0, 1, 1); shader.flush(); // if we're mipmapped, we can now generate our mipmaps if (mipmapped) ctx.generateMipmap(reptex); return reptex; } finally { // we no longer need this framebuffer; rebind the previous framebuffer and delete ours ctx.popFramebuffer(); ctx.deleteFramebuffer(fbuf); } } }
@Override public void onSurfaceCreated() { createTexture(); if (cachedPixels != null) { try { AndroidGLContext actx = (AndroidGLContext) ctx; ByteBuffer pixelBuffer = ByteBuffer.allocate(texWidth * texHeight * 4); FileInputStream in = new FileInputStream(cachedPixels); in.read(pixelBuffer.array()); in.close(); int bufferTex = actx.createTexture(false, false, false); actx.gl.glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, texWidth, texHeight, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, pixelBuffer); // bind our surface framebuffer and render the saved texture data into it bindFramebuffer(); ctx.quadShader(null).prepareTexture(bufferTex, Tint.NOOP_TINT).addQuad( StockInternalTransform.IDENTITY, 0, texHeight, texWidth, 0, 0, 0, 1, 1); // rebind the default frame buffer (which will flush the rendering operation) ctx.bindFramebuffer(); ctx.destroyTexture(bufferTex); pixelBuffer = null; cachedPixels.delete(); cachedPixels = null; } catch (IOException e) { PlayN.reportError("Error reading cached surface pixels from file.", e); } } }
/** Returns the supplied shader if non-null, or the default quad shader if null. */ public GLShader quadShader (GLShader custom) { return custom == null ? quadShader() : custom; }
float wy = dy * (width / 2) / length; InternalTransform l = ctx.createTransform(); l.setRotation(FloatMath.atan2(dy, dx)); l.setTranslation(x0 + wy, y0 - wx); l.preConcatenate(topTransform()); GLShader shader = ctx.quadShader(this.shader); if (fillPattern != null) { int tex = fillPattern.ensureTexture(); int tex = ctx.fillImage().ensureTexture(); shader.prepareTexture(tex, Tint.combine(fillColor, tint)); shader.addQuad(l, 0, 0, length, width, 0, 0, 1, 1);
/** Creates a framebuffer that will render into the supplied texture. <em>NOTE:</em> this must be * followed immediately by a call to {@link #bindFramebuffer(int,int,int)} or {@link * #pushFramebuffer}. */ public int createFramebuffer(int tex) { flush(true); // flush any pending rendering calls, because createFramebufferImpl (necessarily) // binds the new framebuffer in order to bind it to the specified texture (meh) return createFramebufferImpl(tex); }
public void bindFramebuffer() { bindFramebuffer(defaultFramebuffer(), defaultFbufWidth, defaultFbufHeight); }
/** Stores the metadata for the currently bound frame buffer, and binds the supplied framebuffer. * This must be followed by a call to {@link #popFramebuffer}. Also, it is not allowed to push a * framebuffer if a framebuffer is already pushed. Only one level of nesting is supported. */ public void pushFramebuffer(int fbuf, int width, int height) { assert pushedFramebuffer == -1 : "Already have a pushed framebuffer"; pushedFramebuffer = lastFramebuffer; pushedWidth = curFbufWidth; pushedHeight = curFbufHeight; bindFramebuffer(fbuf, width, height); }
@Override public void clearTexture() { if (tex > 0) { ctx.destroyTexture(tex); tex = 0; } }
private int scaleTexture() { int scaledWidth = scale.scaledCeil(width()); int scaledHeight = scale.scaledCeil(height()); // GL requires pow2 on axes that repeat int width = GLUtil.nextPowerOfTwo(scaledWidth), height = GLUtil.nextPowerOfTwo(scaledHeight); // TODO: if width/height > platform_max_size, repeatedly scale by 0.5 until within bounds // platform_max_size = 1024 for iOS, GL10.GL_MAX_TEXTURE_SIZE on android, etc. // no need to scale if our source data is already a power of two if ((width == 0) && (height == 0)) { int reptex = createPow2RepTex(scaledWidth, scaledHeight, repeatX, repeatY, mipmapped); if (mipmapped) ctx.generateMipmap(reptex); return reptex; } // otherwise we need to scale our non-repeated texture, so load that normally int tex = createMainTex(); // width/height == 0 => already a power of two. if (width == 0) width = scaledWidth; if (height == 0) height = scaledHeight; // create our texture and point a new framebuffer at it try { return convertToRepTex(ctx, tex, width, height, repeatX, repeatY, mipmapped); } finally { // delete the non-repeated texture ctx.destroyTexture(tex); } }
@Override public Surface fillRect(float x, float y, float width, float height) { bindFramebuffer(); GLShader shader = ctx.quadShader(this.shader); if (fillPattern != null) { int tex = fillPattern.ensureTexture(); if (tex > 0) { shader.prepareTexture(tex, tint); float tw = fillPattern.width(), th = fillPattern.height(), r = x+width, b = y+height; shader.addQuad(topTransform(), x, y, x+width, y+height, x / tw, y / th, r / tw, b / th); } } else { int tex = ctx.fillImage().ensureTexture(); shader.prepareTexture(tex, Tint.combine(fillColor, tint)); shader.addQuad(topTransform(), x, y, x+width, y+height, 0, 0, 1, 1); } return this; }
public void flush() { flush(false); }
public ITCore(String vertShader, String fragShader) { super(vertShader, fragShader); // determine our various shader program locations uScreenSize = prog.getUniform2f("u_ScreenSize"); aMatrix = prog.getAttrib("a_Matrix", 4, GL20.GL_FLOAT); aTranslation = prog.getAttrib("a_Translation", 2, GL20.GL_FLOAT); aColor = prog.getAttrib("a_Color", 2, GL20.GL_FLOAT); aPosition = prog.getAttrib("a_Position", 2, GL20.GL_FLOAT); aTexCoord = prog.getAttrib("a_TexCoord", 2, GL20.GL_FLOAT); // create our vertex and index buffers stableAttrs = new float[stableAttrsSize()]; vertices = ctx.createFloatBuffer(START_VERTS*vertexSize()); elements = ctx.createShortBuffer(START_ELEMS); }
/** Called before each primitive to update the current color. */ public void prepare(int tex, int tint, boolean justActivated) { ctx.checkGLError("textureShader.prepare start"); boolean stateChanged = (tex != lastTex); if (!justActivated && stateChanged) { GLShader.this.flush(); ctx.checkGLError("textureShader.prepare flush"); } if (stateChanged) { lastTex = tex; ctx.checkGLError("textureShader.prepare end"); } if (justActivated) { ctx.activeTexture(GL20.GL_TEXTURE0); uTexture.bind(0); } }
@Override public void flush() { super.flush(); if (vertices.position() == 0) return; ctx.checkGLError("Shader.flush"); if (delayedBinding) { // see comments in activate() bindAttribsBufs(); ctx.checkGLError("Shader.flush bind"); } vertices.send(GL20.GL_ARRAY_BUFFER, GL20.GL_STREAM_DRAW); int elems = elements.send(GL20.GL_ELEMENT_ARRAY_BUFFER, GL20.GL_STREAM_DRAW); ctx.checkGLError("Shader.flush BufferData"); elements.drawElements(GL20.GL_TRIANGLES, elems); ctx.checkGLError("Shader.flush DrawElements"); }
/** Flushes this core's queued geometry to the GPU. */ public void flush() { ctx.bindTexture(lastTex); }
@Override public Surface clear() { bindFramebuffer(); ctx.clear(0, 0, 0, 0); return this; }