/** Binds our current texture. Subclasses need to call this in {@link #flush}. */ protected void bindTexture () { gl.glBindTexture(GL20.GL_TEXTURE_2D, curTexId); gl.checkError("QuadBatch glBindTexture"); } }
@Override public void begin (float fbufWidth, float fbufHeight, boolean flip) { super.begin(fbufWidth, fbufHeight, flip); program.activate(); // TODO: apparently we can avoid glUniform calls because they're part of the program state; so // we can cache the last set values for all these glUniform calls and only set them anew if // they differ... gl.glUniform2f(uHScreenSize, fbufWidth/2f, fbufHeight/2f); gl.glUniform1f(uFlip, flip ? -1 : 1); gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId); gl.glEnableVertexAttribArray(aVertex); gl.glVertexAttribPointer(aVertex, VERTEX_SIZE, GL_SHORT, false, 0, 0); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementsId); gl.glActiveTexture(GL_TEXTURE0); gl.glUniform1i(uTexture, 0); gl.checkError("UniformQuadBatch begin"); }
/** Ends a series of drawing commands that were clipped per a call to {@link #startClipped}. */ public void endClipped () { batch.flush(); // flush our clipped calls with SCISSOR_TEST still enabled Rectangle r = popScissorState(); if (r == null) batch.gl.glDisable(GL20.GL_SCISSOR_TEST); else batch.gl.glScissor(r.x, r.y, r.width, r.height); batch.gl.checkError("endClipped"); }
@Override public void end () { super.end(); gl.glDisableVertexAttribArray(aMatrix); gl.glDisableVertexAttribArray(aTranslation); gl.glDisableVertexAttribArray(aColor); gl.glDisableVertexAttribArray(aPosition); gl.glDisableVertexAttribArray(aTexCoord); gl.checkError("TriangleBatch end"); }
int createTexture (Texture.Config config) { int id = gl.glGenTexture(); gl.glBindTexture(GL_TEXTURE_2D, id); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, config.magFilter); int minFilter = mipmapify(config.minFilter, config.mipmaps); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, minFilter); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, config.repeatX ? GL_REPEAT : GL_CLAMP_TO_EDGE); gl.glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, config.repeatY ? GL_REPEAT : GL_CLAMP_TO_EDGE); return id; }
id = gl.glCreateProgram(); if (id == 0) throw new RuntimeException("Failed to create program: " + gl.glGetError()); gl.checkError("glCreateProgram"); gl.glAttachShader(id, vertexShader); gl.checkError("glAttachShader / vertex"); gl.glAttachShader(id, fragmentShader); gl.checkError("glAttachShader / fragment"); gl.glLinkProgram(id); int[] linkStatus = new int[1]; gl.glGetProgramiv(id, GL20.GL_LINK_STATUS, linkStatus, 0); if (linkStatus[0] == GL20.GL_FALSE) { String log = gl.glGetProgramInfoLog(id); gl.glDeleteProgram(id); throw new RuntimeException("Failed to link program: " + log); if (id != 0) gl.glDeleteProgram(id); if (vertexShader != 0) gl.glDeleteShader(vertexShader); if (fragmentShader != 0) gl.glDeleteShader(fragmentShader);
@Override public void begin (float fbufWidth, float fbufHeight, boolean flip) { super.begin(fbufWidth, fbufHeight, flip); program.activate(); gl.glUniform2f(uHScreenSize, fbufWidth/2f, fbufHeight/2f); gl.glUniform1f(uFlip, flip ? -1 : 1); // certain graphics cards (I'm looking at you, Intel) exhibit broken behavior if we bind our // attributes once during activation, so for those cards we bind every time in flush() if (!delayedBinding) bindAttribsBufs(); gl.checkError("TriangleBatch begin"); }
/** Creates a render target that renders to {@code texture}. */ public static RenderTarget create (Graphics gfx, final Texture tex) { GL20 gl = gfx.gl; final int fb = gl.glGenFramebuffer(); if (fb == 0) throw new RuntimeException("Failed to gen framebuffer: " + gl.glGetError()); gl.glBindFramebuffer(GL_FRAMEBUFFER, fb); gl.glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tex.id, 0); gl.checkError("RenderTarget.create"); return new RenderTarget (gfx) { public int id () { return fb; } public int width () { return tex.pixelWidth; } public int height () { return tex.pixelHeight; } public float xscale () { return tex.pixelWidth / tex.displayWidth; } public float yscale () { return tex.pixelHeight / tex.displayHeight; } public boolean flip () { return false; } }; }
@Override public void close () { super.close(); program.close(); gl.glDeleteBuffers(2, new int[] { verticesId, elementsId }, 0); gl.checkError("UniformQuadBatch close"); }
/** Starts a series of drawing commands that are clipped to the specified rectangle (in view * coordinates, not OpenGL coordinates). Thus must be followed by a call to {@link #endClipped} * when the clipped drawing commands are done. * * @return whether the resulting clip rectangle is non-empty. <em>Note:</em> the caller may wish * to skip their drawing if this returns false, but they must still call {@link #endClipped}. */ public boolean startClipped (int x, int y, int width, int height) { batch.flush(); // flush any pending unclipped calls Rectangle r = pushScissorState(x, target.flip() ? target.height()-y-height : y, width, height); batch.gl.glScissor(r.x, r.y, r.width, r.height); if (scissorDepth == 1) batch.gl.glEnable(GL20.GL_SCISSOR_TEST); batch.gl.checkError("startClipped"); return !r.isEmpty(); }
gl.glGenBuffers(2, ids, 0); verticesId = ids[0]; elementsId = ids[1]; gl.glBindBuffer(GL_ARRAY_BUFFER, verticesId); gl.bufs.setShortBuffer(verts, 0, verts.length); gl.glBufferData(GL_ARRAY_BUFFER, verts.length*2, gl.bufs.shortBuffer, GL_STATIC_DRAW); gl.glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, elementsId); gl.bufs.setShortBuffer(elems, 0, elems.length); gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elems.length*2, gl.bufs.shortBuffer, GL_STATIC_DRAW); gl.checkError("UniformQuadBatch end ctor");
protected void upload (Graphics gfx, int tex, int width, int height, IntPtr data) { gfx.gl.glBindTexture(GL20.GL_TEXTURE_2D, tex); gfx.gl.glPixelStorei(GL20.GL_UNPACK_ALIGNMENT, 1); OpenGLES.glTexImage2Dp(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, width, height, 0, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, data); }
void updateTexture(int tex, ImageElement img) { gl.glBindTexture(GL20.GL_TEXTURE_2D, tex); ((HtmlGL20)gl).glTexImage2D(GL20.GL_TEXTURE_2D, 0, GL20.GL_RGBA, GL20.GL_RGBA, GL20.GL_UNSIGNED_BYTE, img); }
@Override public void flush () { super.flush(); if (quadCounter > 0) { bindTexture(); gl.glUniform4fv(uData, quadCounter * vec4sPerQuad(), data, 0); gl.glDrawElements(GL_TRIANGLES, quadCounter*ELEMENTS_PER_QUAD, GL_UNSIGNED_SHORT, 0); gl.checkError("UniformQuadBatch flush"); quadCounter = 0; } }
@Override public void flush () { super.flush(); if (vertPos > 0) { bindTexture(); if (delayedBinding) { bindAttribsBufs(); // see comments in activate() gl.checkError("TriangleBatch.flush bind"); } gl.bufs.setFloatBuffer(vertices, 0, vertPos); gl.glBufferData(GL_ARRAY_BUFFER, vertPos*4, gl.bufs.floatBuffer, GL_STREAM_DRAW); gl.bufs.setShortBuffer(elements, 0, elemPos); gl.glBufferData(GL_ELEMENT_ARRAY_BUFFER, elemPos*2, gl.bufs.shortBuffer, GL_STREAM_DRAW); gl.checkError("TriangleBatch.flush BufferData"); gl.glDrawElements(GL_TRIANGLES, elemPos, GL_UNSIGNED_SHORT, 0); gl.checkError("TriangleBatch.flush DrawElements"); vertPos = 0; elemPos = 0; } }
/** Creates a triangle batch with the supplied custom shader program. */ public TriangleBatch (GL20 gl, Source source) { super(gl); delayedBinding = "Intel".equals(gl.glGetString(GL20.GL_VENDOR)); program = new GLProgram(gl, source.vertex(), source.fragment()); uTexture = program.getUniformLocation("u_Texture"); uHScreenSize = program.getUniformLocation("u_HScreenSize"); uFlip = program.getUniformLocation("u_Flip"); aMatrix = program.getAttribLocation("a_Matrix"); aTranslation = program.getAttribLocation("a_Translation"); aColor = program.getAttribLocation("a_Color"); aPosition = program.getAttribLocation("a_Position"); aTexCoord = program.getAttribLocation("a_TexCoord"); // create our vertex and index buffers stableAttrs = new float[stableAttrsSize()]; vertices = new float[START_VERTS*vertexSize()]; elements = new short[START_ELEMS]; // create our GL buffers int[] ids = new int[2]; gl.glGenBuffers(2, ids, 0); verticesId = ids[0]; elementsId = ids[1]; gl.checkError("TriangleBatch end ctor"); }
@Override public void begin (float fbufWidth, float fbufHeight, boolean flip) { super.begin(fbufWidth, fbufHeight, flip); gl.glUniform1f(uAngle, elapsed * FloatMath.PI); gl.glUniform2f(uEye, eyeX, eyeY); } }
public SceneGame (Platform plat, int updateRate) { super(plat, updateRate); GL20 gl = plat.graphics().gl; gl.glDisable(GL20.GL_CULL_FACE); gl.glEnable(GL20.GL_BLEND); gl.glBlendFunc(GL20.GL_ONE, GL20.GL_ONE_MINUS_SRC_ALPHA); defaultBatch = createDefaultBatch(gl); viewSurf = new Surface(plat.graphics(), plat.graphics().defaultRenderTarget, defaultBatch); rootLayer = new RootLayer(); paint.connect(new Slot<Clock>() { public void onEmit (Clock clock) { paintScene(); } }).atPrio(scenePaintPrio()); }
private static int usableMaxUniformVectors (GL20 gl) { // this returns the maximum number of vec4s; then we subtract one vec2 to account for the // uHScreenSize uniform, and two more because some GPUs seem to need one for our vec3 attr int maxVecs = gl.glGetInteger(GL_MAX_VERTEX_UNIFORM_VECTORS) - 3; // we have to check errors always in this case, because if GL failed to return a value we would // otherwise return the value of uninitialized memory which could be some huge number which we // might turn around and try to compile into a shader causing GL to crash (you might think from // such a careful description that such a thing has in fact come to pass, and you would not be // incorrect) int glErr = gl.glGetError(); if (glErr != GL20.GL_NO_ERROR) throw new RuntimeException( "Unable to query GL_MAX_VERTEX_UNIFORM_VECTORS, error " + glErr); return maxVecs; }
@Override public void begin (float fbufWidth, float fbufHeight, boolean flip) { super.begin(fbufWidth, fbufHeight, flip); program.activate(); gl.glUniform1f(uAngle, angle); }