Files
processing4/core/src/processing/opengl/PGL.java
2013-10-20 19:15:04 -04:00

2607 lines
84 KiB
Java

/* -*- mode: java; c-basic-offset: 2; indent-tabs-mode: nil -*- */
/*
Part of the Processing project - http://processing.org
Copyright (c) 2011-13 Ben Fry and Casey Reas
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General
Public License along with this library; if not, write to the
Free Software Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA 02111-1307 USA
*/
package processing.opengl;
import processing.core.PApplet;
import java.nio.Buffer;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.nio.FloatBuffer;
import java.nio.IntBuffer;
import java.nio.ShortBuffer;
import java.util.Arrays;
/**
* Processing-OpenGL abstraction layer. Needs to be implemented by subclasses
* using specific OpenGL-Java bindings.
*
* It includes a full GLES 2.0 interface.
*
*/
public abstract class PGL {
// ........................................................
// Basic fields
/** The PGraphics object using this interface */
protected PGraphicsOpenGL pg;
/** OpenGL thread */
protected static Thread glThread;
/** ID of the GL context associated to the surface **/
protected static int glContext;
// ........................................................
// Parameters
protected static boolean USE_FBOLAYER_BY_DEFAULT = false;
protected static int REQUESTED_DEPTH_BITS = 24;
protected static int REQUESTED_STENCIL_BITS = 8;
protected static int REQUESTED_ALPHA_BITS = 8;
/** Switches between the use of regular and direct buffers. */
protected static boolean USE_DIRECT_BUFFERS = true;
protected static int MIN_DIRECT_BUFFER_SIZE = 1;
/** This flag enables/disables a hack to make sure that anything drawn
* in setup will be maintained even a renderer restart (e.g.: smooth change).
* See the code and comments involving this constant in
* PGraphicsOpenGL.endDraw().
*/
protected static boolean SAVE_SURFACE_TO_PIXELS_HACK = true;
/** Enables/disables mipmap use. */
protected static boolean MIPMAPS_ENABLED = true;
/** Initial sizes for arrays of input and tessellated data. */
protected static int DEFAULT_IN_VERTICES = 64;
protected static int DEFAULT_IN_EDGES = 128;
protected static int DEFAULT_IN_TEXTURES = 64;
protected static int DEFAULT_TESS_VERTICES = 64;
protected static int DEFAULT_TESS_INDICES = 128;
/** Maximum lights by default is 8, the minimum defined by OpenGL. */
protected static int MAX_LIGHTS = 8;
/** Maximum index value of a tessellated vertex. GLES restricts the vertex
* indices to be of type unsigned short. Since Java only supports signed
* shorts as primitive type we have 2^15 = 32768 as the maximum number of
* vertices that can be referred to within a single VBO.
*/
protected static int MAX_VERTEX_INDEX = 32767;
protected static int MAX_VERTEX_INDEX1 = MAX_VERTEX_INDEX + 1;
/** Count of tessellated fill, line or point vertices that will
* trigger a flush in the immediate mode. It doesn't necessarily
* be equal to MAX_VERTEX_INDEX1, since the number of vertices can
* be effectively much large since the renderer uses offsets to
* refer to vertices beyond the MAX_VERTEX_INDEX limit.
*/
protected static int FLUSH_VERTEX_COUNT = MAX_VERTEX_INDEX1;
/** Minimum/maximum dimensions of a texture used to hold font data. */
protected static int MIN_FONT_TEX_SIZE = 256;
protected static int MAX_FONT_TEX_SIZE = 1024;
/** Minimum stroke weight needed to apply the full path stroking
* algorithm that properly generates caps and joins.
*/
protected static float MIN_CAPS_JOINS_WEIGHT = 2f;
/** Maximum length of linear paths to be stroked with the
* full algorithm that generates accurate caps and joins.
*/
protected static int MAX_CAPS_JOINS_LENGTH = 5000;
/** Minimum array size to use arrayCopy method(). */
protected static int MIN_ARRAYCOPY_SIZE = 2;
/** Factor used to displace the stroke vertices towards the camera in
* order to make sure the lines are always on top of the fill geometry */
protected static float STROKE_DISPLACEMENT = 0.999f;
// ........................................................
// FBO layer
protected static boolean fboLayerRequested = false;
protected static boolean fboLayerCreated = false;
protected static boolean fboLayerInUse = false;
protected static boolean firstFrame = true;
protected static int reqNumSamples;
protected static int numSamples;
protected static IntBuffer glColorFbo;
protected static IntBuffer glMultiFbo;
protected static IntBuffer glColorBuf;
protected static IntBuffer glColorTex;
protected static IntBuffer glDepthStencil;
protected static IntBuffer glDepth;
protected static IntBuffer glStencil;
protected static int fboWidth, fboHeight;
protected static int backTex, frontTex;
/** Flags used to handle the creation of a separate front texture */
protected boolean usingFrontTex = false;
protected boolean needSepFrontTex = false;
// ........................................................
// Texture rendering
protected static boolean loadedTex2DShader = false;
protected static int tex2DShaderProgram;
protected static int tex2DVertShader;
protected static int tex2DFragShader;
protected static int tex2DShaderContext;
protected static int tex2DVertLoc;
protected static int tex2DTCoordLoc;
protected static boolean loadedTexRectShader = false;
protected static int texRectShaderProgram;
protected static int texRectVertShader;
protected static int texRectFragShader;
protected static int texRectShaderContext;
protected static int texRectVertLoc;
protected static int texRectTCoordLoc;
protected static 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 static FloatBuffer texData;
protected static final String SHADER_PREPROCESSOR_DIRECTIVE =
"#ifdef GL_ES\n" +
"precision mediump float;\n" +
"precision mediump int;\n" +
"#endif\n";
protected static String[] texVertShaderSource = {
"attribute vec2 inVertex;\n" +
"attribute vec2 inTexcoord;\n" +
"varying vec2 vertTexcoord;\n" +
"void main() {\n" +
" gl_Position = vec4(inVertex, 0, 1);\n" +
" vertTexcoord = inTexcoord;\n" +
"}\n",
"#version 150\n" +
"in vec2 inVertex;\n" +
"in vec2 inTexcoord;\n" +
"out vec2 vertTexcoord;" +
"void main() {\n" +
" gl_Position = vec4(inVertex, 0, 1);\n" +
" vertTexcoord = inTexcoord;\n" +
"}\n"
};
protected static String[] tex2DFragShaderSource = {
SHADER_PREPROCESSOR_DIRECTIVE +
"uniform sampler2D textureSampler;\n" +
"varying vec2 vertTexcoord;\n" +
"void main() {\n" +
" gl_FragColor = texture2D(textureSampler, vertTexcoord.st);\n" +
"}\n",
"#version 150\n" +
SHADER_PREPROCESSOR_DIRECTIVE +
"uniform sampler2D textureSampler;\n" +
"in vec2 vertTexcoord;\n" +
"out vec4 fragColor;\n" +
"void main() {\n" +
" fragColor = texture(textureSampler, vertTexcoord.st);\n" +
"}\n"
};
protected static String[] texRectFragShaderSource = {
SHADER_PREPROCESSOR_DIRECTIVE +
"uniform sampler2DRect textureSampler;" +
"varying vec2 vertTexcoord;" +
"void main() {" +
" gl_FragColor = texture2DRect(textureSampler, vertTexcoord.st);" +
"}",
"#version 150\n" +
SHADER_PREPROCESSOR_DIRECTIVE +
"uniform sampler2DRect textureSampler;\n" +
"in vec2 vertTexcoord;\n" +
"out vec4 fragColor;\n" +
"void main() {\n" +
" fragColor = texture(textureSampler, vertTexcoord.st);\n" +
"}\n"
};
protected static int shaderSource = 0;
/** Which texturing targets are enabled */
protected static boolean[] texturingTargets = { false, false };
/** Used to keep track of which textures are bound to each target */
protected static int maxTexUnits;
protected static int activeTexUnit = 0;
protected static int[][] boundTextures;
// ........................................................
// Framerate handling
protected float targetFps = 60;
protected float currentFps = 60;
protected boolean setFps = false;
// ........................................................
// Utility buffers
protected ByteBuffer byteBuffer;
protected IntBuffer intBuffer;
protected IntBuffer viewBuffer;
protected IntBuffer colorBuffer;
protected FloatBuffer depthBuffer;
protected ByteBuffer stencilBuffer;
// ........................................................
// Error messages
protected static final String WIKI =
" Read http://wiki.processing.org/w/OpenGL_Issues for help.";
protected static final String FRAMEBUFFER_ERROR =
"Framebuffer error (%1$s), rendering will probably not work as expected" + WIKI;
protected static final String MISSING_FBO_ERROR =
"Framebuffer objects are not supported by this hardware (or driver)" + WIKI;
protected static final String MISSING_GLSL_ERROR =
"GLSL shaders are not supported by this hardware (or driver)" + WIKI;
protected static final String MISSING_GLFUNC_ERROR =
"GL function %1$s is not available on this hardware (or driver)" + WIKI;
protected static final String TEXUNIT_ERROR =
"Number of texture units not supported by this hardware (or driver)" + WIKI;
// ........................................................
// Constants
/** Size of different types in bytes */
protected static int SIZEOF_SHORT = Short.SIZE / 8;
protected static int SIZEOF_INT = Integer.SIZE / 8;
protected static int SIZEOF_FLOAT = Float.SIZE / 8;
protected static int SIZEOF_BYTE = Byte.SIZE / 8;
protected static int SIZEOF_INDEX = SIZEOF_SHORT;
protected static int INDEX_TYPE = 0x1403; // GL_UNSIGNED_SHORT
/** Machine Epsilon for float precision. */
protected static float FLOAT_EPS = Float.MIN_VALUE;
// Calculation of the Machine Epsilon for float precision. From:
// http://en.wikipedia.org/wiki/Machine_epsilon#Approximation_using_Java
static {
float eps = 1.0f;
do {
eps /= 2.0f;
} while ((float)(1.0 + (eps / 2.0)) != 1.0);
FLOAT_EPS = eps;
}
/**
* Set to true if the host system is big endian (PowerPC, MIPS, SPARC), false
* if little endian (x86 Intel for Mac or PC).
*/
protected static boolean BIG_ENDIAN =
ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
///////////////////////////////////////////////////////////////
// Initialization, finalization
public PGL() { }
public PGL(PGraphicsOpenGL pg) {
this.pg = pg;
if (glColorTex == null) {
glColorTex = allocateIntBuffer(2);
glColorFbo = allocateIntBuffer(1);
glMultiFbo = allocateIntBuffer(1);
glColorBuf = allocateIntBuffer(1);
glDepthStencil = allocateIntBuffer(1);
glDepth = allocateIntBuffer(1);
glStencil = allocateIntBuffer(1);
fboLayerCreated = false;
fboLayerInUse = false;
firstFrame = false;
}
byteBuffer = allocateByteBuffer(1);
intBuffer = allocateIntBuffer(1);
viewBuffer = allocateIntBuffer(4);
}
protected abstract void setFps(float fps);
protected abstract void initSurface(int antialias);
protected abstract void reinitSurface();
protected abstract void registerListeners();
protected void deleteSurface() {
if (threadIsCurrent() && fboLayerCreated) {
deleteTextures(2, glColorTex);
deleteFramebuffers(1, glColorFbo);
deleteFramebuffers(1, glMultiFbo);
deleteRenderbuffers(1, glColorBuf);
deleteRenderbuffers(1, glDepthStencil);
deleteRenderbuffers(1, glDepth);
deleteRenderbuffers(1, glStencil);
}
fboLayerCreated = false;
fboLayerInUse = false;
firstFrame = false;
}
protected int getReadFramebuffer() {
return fboLayerInUse ? glColorFbo.get(0) : 0;
}
protected int getDrawFramebuffer() {
if (fboLayerInUse) return 1 < numSamples ? glMultiFbo.get(0) :
glColorFbo.get(0);
else return 0;
}
protected int getDefaultDrawBuffer() {
return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT;
}
protected int getDefaultReadBuffer() {
return fboLayerInUse ? COLOR_ATTACHMENT0 : FRONT;
}
protected boolean isFBOBacked() {
return fboLayerInUse;
}
protected void requestFBOLayer() {
fboLayerRequested = true;
}
protected boolean isMultisampled() {
return 1 < numSamples;
}
protected int getDepthBits() {
intBuffer.rewind();
getIntegerv(DEPTH_BITS, intBuffer);
return intBuffer.get(0);
}
protected int getStencilBits() {
intBuffer.rewind();
getIntegerv(STENCIL_BITS, intBuffer);
return intBuffer.get(0);
}
protected boolean getDepthTest() {
intBuffer.rewind();
getBooleanv(DEPTH_TEST, intBuffer);
return intBuffer.get(0) == 0 ? false : true;
}
protected boolean getDepthWriteMask() {
intBuffer.rewind();
getBooleanv(DEPTH_WRITEMASK, intBuffer);
return intBuffer.get(0) == 0 ? false : true;
}
protected Texture wrapBackTexture(Texture texture) {
if (texture == null) {
texture = new Texture();
texture.init(pg.width, pg.height,
glColorTex.get(backTex), TEXTURE_2D, RGBA,
fboWidth, fboHeight, NEAREST, NEAREST,
CLAMP_TO_EDGE, CLAMP_TO_EDGE);
texture.invertedY(true);
texture.colorBuffer(true);
pg.setCache(pg, texture);
} else {
texture.glName = glColorTex.get(backTex);
}
return texture;
}
protected Texture wrapFrontTexture(Texture texture) {
if (texture == null) {
texture = new Texture();
texture.init(pg.width, pg.height,
glColorTex.get(frontTex), TEXTURE_2D, RGBA,
fboWidth, fboHeight, NEAREST, NEAREST,
CLAMP_TO_EDGE, CLAMP_TO_EDGE);
texture.invertedY(true);
texture.colorBuffer(true);
} else {
texture.glName = glColorTex.get(frontTex);
}
return texture;
}
protected void bindFrontTexture() {
usingFrontTex = true;
if (!texturingIsEnabled(TEXTURE_2D)) {
enableTexturing(TEXTURE_2D);
}
bindTexture(TEXTURE_2D, glColorTex.get(frontTex));
}
protected void unbindFrontTexture() {
if (textureIsBound(TEXTURE_2D, glColorTex.get(frontTex))) {
// We don't want to unbind another texture
// that might be bound instead of this one.
if (!texturingIsEnabled(TEXTURE_2D)) {
enableTexturing(TEXTURE_2D);
bindTexture(TEXTURE_2D, 0);
disableTexturing(TEXTURE_2D);
} else {
bindTexture(TEXTURE_2D, 0);
}
}
}
protected void syncBackTexture() {
if (usingFrontTex) needSepFrontTex = true;
if (1 < numSamples) {
bindFramebuffer(READ_FRAMEBUFFER, glMultiFbo.get(0));
bindFramebuffer(DRAW_FRAMEBUFFER, glColorFbo.get(0));
blitFramebuffer(0, 0, fboWidth, fboHeight,
0, 0, fboWidth, fboHeight,
COLOR_BUFFER_BIT, NEAREST);
}
}
protected int qualityToSamples(int quality) {
if (quality <= 1) {
return 1;
} else {
// Number of samples is always an even number:
int n = 2 * (quality / 2);
return n;
}
}
protected void createFBOLayer() {
String ext = getString(EXTENSIONS);
if (-1 < ext.indexOf("texture_non_power_of_two")) {
fboWidth = pg.width;
fboHeight = pg.height;
} else {
fboWidth = nextPowerOfTwo(pg.width);
fboHeight = nextPowerOfTwo(pg.height);
}
int maxs = maxSamples();
if (-1 < ext.indexOf("_framebuffer_multisample") && 1 < maxs) {
numSamples = PApplet.min(reqNumSamples, maxs);
} else {
numSamples = 1;
}
boolean multisample = 1 < numSamples;
boolean packed = ext.indexOf("packed_depth_stencil") != -1;
int depthBits = getDepthBits();
int stencilBits = getStencilBits();
genTextures(2, glColorTex);
for (int i = 0; i < 2; i++) {
bindTexture(TEXTURE_2D, glColorTex.get(i));
texParameteri(TEXTURE_2D, TEXTURE_MIN_FILTER, NEAREST);
texParameteri(TEXTURE_2D, TEXTURE_MAG_FILTER, NEAREST);
texParameteri(TEXTURE_2D, TEXTURE_WRAP_S, CLAMP_TO_EDGE);
texParameteri(TEXTURE_2D, TEXTURE_WRAP_T, CLAMP_TO_EDGE);
texImage2D(TEXTURE_2D, 0, RGBA, fboWidth, fboHeight, 0,
RGBA, UNSIGNED_BYTE, null);
initTexture(TEXTURE_2D, RGBA, fboWidth, fboHeight, pg.backgroundColor);
}
bindTexture(TEXTURE_2D, 0);
backTex = 0;
frontTex = 1;
genFramebuffers(1, glColorFbo);
bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0, TEXTURE_2D,
glColorTex.get(backTex), 0);
if (multisample) {
// Creating multisampled FBO
genFramebuffers(1, glMultiFbo);
bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
// color render buffer...
genRenderbuffers(1, glColorBuf);
bindRenderbuffer(RENDERBUFFER, glColorBuf.get(0));
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
RGBA8, fboWidth, fboHeight);
framebufferRenderbuffer(FRAMEBUFFER, COLOR_ATTACHMENT0,
RENDERBUFFER, glColorBuf.get(0));
}
// Creating depth and stencil buffers
if (packed && depthBits == 24 && stencilBits == 8) {
// packed depth+stencil buffer
genRenderbuffers(1, glDepthStencil);
bindRenderbuffer(RENDERBUFFER, glDepthStencil.get(0));
if (multisample) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
DEPTH24_STENCIL8, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, DEPTH24_STENCIL8,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT, RENDERBUFFER,
glDepthStencil.get(0));
framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT, RENDERBUFFER,
glDepthStencil.get(0));
} else {
// separate depth and stencil buffers
if (0 < depthBits) {
int depthComponent = DEPTH_COMPONENT16;
if (depthBits == 32) {
depthComponent = DEPTH_COMPONENT32;
} else if (depthBits == 24) {
depthComponent = DEPTH_COMPONENT24;
} else if (depthBits == 16) {
depthComponent = DEPTH_COMPONENT16;
}
genRenderbuffers(1, glDepth);
bindRenderbuffer(RENDERBUFFER, glDepth.get(0));
if (multisample) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
depthComponent, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, depthComponent,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, DEPTH_ATTACHMENT,
RENDERBUFFER, glDepth.get(0));
}
if (0 < stencilBits) {
int stencilIndex = STENCIL_INDEX1;
if (stencilBits == 8) {
stencilIndex = STENCIL_INDEX8;
} else if (stencilBits == 4) {
stencilIndex = STENCIL_INDEX4;
} else if (stencilBits == 1) {
stencilIndex = STENCIL_INDEX1;
}
genRenderbuffers(1, glStencil);
bindRenderbuffer(RENDERBUFFER, glStencil.get(0));
if (multisample) {
renderbufferStorageMultisample(RENDERBUFFER, numSamples,
stencilIndex, fboWidth, fboHeight);
} else {
renderbufferStorage(RENDERBUFFER, stencilIndex,
fboWidth, fboHeight);
}
framebufferRenderbuffer(FRAMEBUFFER, STENCIL_ATTACHMENT,
RENDERBUFFER, glStencil.get(0));
}
}
validateFramebuffer();
// Clear all buffers.
clearDepth(1);
clearStencil(0);
int argb = pg.backgroundColor;
float a = ((argb >> 24) & 0xff) / 255.0f;
float r = ((argb >> 16) & 0xff) / 255.0f;
float g = ((argb >> 8) & 0xff) / 255.0f;
float b = ((argb) & 0xff) / 255.0f;
clearColor(r, g, b, a);
clear(DEPTH_BUFFER_BIT | STENCIL_BUFFER_BIT | COLOR_BUFFER_BIT);
bindFramebuffer(FRAMEBUFFER, 0);
fboLayerCreated = true;
}
///////////////////////////////////////////////////////////
// Frame rendering
protected void beginDraw(boolean clear0) {
if (needFBOLayer(clear0)) {
if (!fboLayerCreated) createFBOLayer();
bindFramebuffer(FRAMEBUFFER, glColorFbo.get(0));
framebufferTexture2D(FRAMEBUFFER, COLOR_ATTACHMENT0,
TEXTURE_2D, glColorTex.get(backTex), 0);
if (1 < numSamples) {
bindFramebuffer(FRAMEBUFFER, glMultiFbo.get(0));
}
if (firstFrame) {
// No need to draw back color buffer because we are in the first frame.
int argb = pg.backgroundColor;
float a = ((argb >> 24) & 0xff) / 255.0f;
float r = ((argb >> 16) & 0xff) / 255.0f;
float g = ((argb >> 8) & 0xff) / 255.0f;
float b = ((argb) & 0xff) / 255.0f;
clearColor(r, g, b, a);
clear(COLOR_BUFFER_BIT);
} else if (!clear0) {
// 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, pg.width, pg.height,
0, 0, pg.width, pg.height,
0, 0, pg.width, pg.height);
}
fboLayerInUse = true;
} else {
fboLayerInUse = false;
}
if (firstFrame) {
firstFrame = false;
}
if (!USE_FBOLAYER_BY_DEFAULT) {
// The result of this assignment is the following: if the user requested
// at some point the use of the FBO layer, but subsequently didn't
// request it again, then the rendering won't render to the FBO layer if
// not needed by the condif, since it is slower than simple onscreen
// rendering.
fboLayerRequested = false;
}
}
protected void endDraw(boolean clear0) {
if (fboLayerInUse) {
syncBackTexture();
// Draw the contents of the back texture to the screen framebuffer.
bindFramebuffer(FRAMEBUFFER, 0);
clearDepth(1);
clearColor(0, 0, 0, 0);
clear(COLOR_BUFFER_BIT | DEPTH_BUFFER_BIT);
// Render current back texture to screen, without blending.
disable(BLEND);
drawTexture(TEXTURE_2D, glColorTex.get(backTex),
fboWidth, fboHeight, pg.width, pg.height,
0, 0, pg.width, pg.height,
0, 0, pg.width, pg.height);
// Swapping front and back textures.
int temp = frontTex;
frontTex = backTex;
backTex = temp;
}
}
protected abstract boolean canDraw();
protected abstract void requestFocus();
protected abstract void requestDraw();
protected abstract void swapBuffers();
protected boolean threadIsCurrent() {
return Thread.currentThread() == glThread;
}
protected boolean needFBOLayer(boolean clear0) {
return !clear0 || fboLayerRequested || 1 < numSamples;
}
protected void beginGL() { }
protected void endGL() { }
///////////////////////////////////////////////////////////
// Context interface
protected int createEmptyContext() {
return -1;
}
protected int getCurrentContext() {
return glContext;
}
///////////////////////////////////////////////////////////
// Utility functions
protected boolean contextIsCurrent(int other) {
return other == -1 || other == glContext;
}
protected void enableTexturing(int target) {
enable(target);
if (target == TEXTURE_2D) {
texturingTargets[0] = true;
} else if (target == TEXTURE_RECTANGLE) {
texturingTargets[1] = true;
}
}
protected void disableTexturing(int target) {
disable(target);
if (target == TEXTURE_2D) {
texturingTargets[0] = false;
} else if (target == TEXTURE_RECTANGLE) {
texturingTargets[1] = false;
}
}
protected boolean texturingIsEnabled(int target) {
if (target == TEXTURE_2D) {
return texturingTargets[0];
} else if (target == TEXTURE_RECTANGLE) {
return texturingTargets[1];
} else {
return false;
}
}
protected boolean textureIsBound(int target, int id) {
if (boundTextures == null) return false;
if (target == TEXTURE_2D) {
return boundTextures[activeTexUnit][0] == id;
} else if (target == TEXTURE_RECTANGLE) {
return boundTextures[activeTexUnit][1] == id;
} else {
return false;
}
}
protected void initTexture(int target, int format, int width, int height) {
initTexture(target, format, width, height, 0);
}
protected void initTexture(int target, int format, int width, int height,
int initColor) {
int[] glcolor = new int[16 * 16];
Arrays.fill(glcolor, javaToNativeARGB(initColor));
IntBuffer texels = PGL.allocateDirectIntBuffer(16 * 16);
texels.put(glcolor);
texels.rewind();
for (int y = 0; y < height; y += 16) {
int h = PApplet.min(16, height - y);
for (int x = 0; x < width; x += 16) {
int w = PApplet.min(16, width - x);
texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, texels);
}
}
}
protected void copyToTexture(int target, int format, int id, int x, int y,
int w, int h, IntBuffer buffer) {
activeTexture(TEXTURE0);
boolean enabledTex = false;
if (!texturingIsEnabled(target)) {
enableTexturing(target);
enabledTex = true;
}
bindTexture(target, id);
texSubImage2D(target, 0, x, y, w, h, format, UNSIGNED_BYTE, buffer);
bindTexture(target, 0);
if (enabledTex) {
disableTexturing(target);
}
}
/**
* Not an approved function, this will change or be removed in the future.
*/
public void drawTexture(int target, int id, int width, int height,
int X0, int Y0, int X1, int Y1) {
drawTexture(target, id, width, height, width, height,
X0, Y0, X1, Y1, X0, Y0, X1, Y1);
}
/**
* Not an approved function, this will change or be removed in the future.
*/
public 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, texW, texH, scrW, scrH,
texX0, texY0, texX1, texY1,
scrX0, scrY0, scrX1, scrY1);
} else if (target == TEXTURE_RECTANGLE) {
drawTextureRect(id, texW, texH, scrW, scrH,
texX0, texY0, texX1, texY1,
scrX0, scrY0, scrX1, scrY1);
}
}
int texGeoVBO;
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 || tex2DShaderContext != glContext) {
tex2DVertShader = createShader(VERTEX_SHADER, texVertShaderSource[shaderSource]);
tex2DFragShader = createShader(FRAGMENT_SHADER, tex2DFragShaderSource[shaderSource]);
if (0 < tex2DVertShader && 0 < tex2DFragShader) {
tex2DShaderProgram = createProgram(tex2DVertShader, tex2DFragShader);
}
if (0 < tex2DShaderProgram) {
tex2DVertLoc = getAttribLocation(tex2DShaderProgram, "inVertex");
tex2DTCoordLoc = getAttribLocation(tex2DShaderProgram, "inTexcoord");
}
loadedTex2DShader = true;
tex2DShaderContext = glContext;
genBuffers(1, intBuffer);
texGeoVBO = intBuffer.get(0);
bindBuffer(ARRAY_BUFFER, texGeoVBO);
bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
}
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
}
if (0 < tex2DShaderProgram) {
// The texture overwrites anything drawn earlier.
boolean depthTest = getDepthTest();
disable(DEPTH_TEST);
// 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 depthMask = getDepthWriteMask();
depthMask(false);
// Making sure that the viewport matches the provided screen dimensions
viewBuffer.rewind();
getIntegerv(VIEWPORT, viewBuffer);
viewport(0, 0, scrW, scrH);
useProgram(tex2DShaderProgram);
enableVertexAttribArray(tex2DVertLoc);
enableVertexAttribArray(tex2DTCoordLoc);
// Vertex coordinates of the textured quad are specified
// in normalized screen space (-1, 1):
// Corner 1
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 / 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 / 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 / scrW - 1;
texCoords[13] = 2 * (float)scrY1 / scrH - 1;
texCoords[14] = (float)texX1 / texW;
texCoords[15] = (float)texY1 / texH;
texData.rewind();
texData.put(texCoords);
activeTexture(TEXTURE0);
boolean enabledTex = false;
if (!texturingIsEnabled(TEXTURE_2D)) {
enableTexturing(TEXTURE_2D);
enabledTex = true;
}
bindTexture(TEXTURE_2D, id);
texData.position(0);
bindBuffer(PGL.ARRAY_BUFFER, texGeoVBO);
bufferData(PGL.ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, PGL.STATIC_DRAW);
pg.report("HERE 1");
vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 2 * SIZEOF_FLOAT);
// texData.position(0);
// vertexAttribPointer(tex2DVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
// texData);
// texData.position(2);
// vertexAttribPointer(tex2DTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
// texData);
// pg.report("HERE 2");
drawArrays(TRIANGLE_STRIP, 0, 4);
pg.report("HERE 3");
bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
bindTexture(TEXTURE_2D, 0);
if (enabledTex) {
disableTexturing(TEXTURE_2D);
}
disableVertexAttribArray(tex2DVertLoc);
disableVertexAttribArray(tex2DTCoordLoc);
useProgram(0);
if (depthTest) {
enable(DEPTH_TEST);
} else {
disable(DEPTH_TEST);
}
depthMask(depthMask);
viewport(viewBuffer.get(0), viewBuffer.get(1),
viewBuffer.get(2),viewBuffer.get(3));
}
}
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 || texRectShaderContext != glContext) {
texRectVertShader = createShader(VERTEX_SHADER, texVertShaderSource[shaderSource]);
texRectFragShader = createShader(FRAGMENT_SHADER, texRectFragShaderSource[shaderSource]);
if (0 < texRectVertShader && 0 < texRectFragShader) {
texRectShaderProgram = createProgram(texRectVertShader,
texRectFragShader);
}
if (0 < texRectShaderProgram) {
texRectVertLoc = getAttribLocation(texRectShaderProgram, "inVertex");
texRectTCoordLoc = getAttribLocation(texRectShaderProgram, "inTexcoord");
}
loadedTexRectShader = true;
texRectShaderContext = glContext;
genBuffers(1, intBuffer);
texGeoVBO = intBuffer.get(0);
bindBuffer(ARRAY_BUFFER, texGeoVBO);
bufferData(ARRAY_BUFFER, 16 * SIZEOF_FLOAT, null, STATIC_DRAW);
}
if (texData == null) {
texData = allocateDirectFloatBuffer(texCoords.length);
}
if (0 < texRectShaderProgram) {
// The texture overwrites anything drawn earlier.
boolean depthTest = getDepthTest();
disable(DEPTH_TEST);
// 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 depthMask = getDepthWriteMask();
depthMask(false);
// Making sure that the viewport matches the provided screen dimensions
viewBuffer.rewind();
getIntegerv(VIEWPORT, viewBuffer);
viewport(0, 0, scrW, scrH);
useProgram(texRectShaderProgram);
enableVertexAttribArray(texRectVertLoc);
enableVertexAttribArray(texRectTCoordLoc);
// Vertex coordinates of the textured quad are specified
// in normalized screen space (-1, 1):
// Corner 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 / scrW - 1;
texCoords[ 5] = 2 * (float)scrY0 / scrH - 1;
texCoords[ 6] = texX1;
texCoords[ 7] = texY0;
// Corner 3
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 / scrW - 1;
texCoords[13] = 2 * (float)scrY1 / scrH - 1;
texCoords[14] = texX1;
texCoords[15] = texY1;
texData.rewind();
texData.put(texCoords);
activeTexture(TEXTURE0);
boolean enabledTex = false;
if (!texturingIsEnabled(TEXTURE_RECTANGLE)) {
enableTexturing(TEXTURE_RECTANGLE);
enabledTex = true;
}
bindTexture(TEXTURE_RECTANGLE, id);
texData.position(0);
bindBuffer(PGL.ARRAY_BUFFER, texGeoVBO);
bufferData(PGL.ARRAY_BUFFER, 16 * SIZEOF_FLOAT, texData, PGL.STATIC_DRAW);
pg.report("HERE 1");
vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 0);
vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT, 2 * SIZEOF_FLOAT);
// texData.position(0);
// vertexAttribPointer(texRectVertLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
// texData);
// texData.position(2);
// vertexAttribPointer(texRectTCoordLoc, 2, FLOAT, false, 4 * SIZEOF_FLOAT,
// texData);
drawArrays(TRIANGLE_STRIP, 0, 4);
bindBuffer(ARRAY_BUFFER, 0); // Making sure that no VBO is bound at this point.
bindTexture(TEXTURE_RECTANGLE, 0);
if (enabledTex) {
disableTexturing(TEXTURE_RECTANGLE);
}
disableVertexAttribArray(texRectVertLoc);
disableVertexAttribArray(texRectTCoordLoc);
useProgram(0);
if (depthTest) {
enable(DEPTH_TEST);
} else {
disable(DEPTH_TEST);
}
depthMask(depthMask);
viewport(viewBuffer.get(0), viewBuffer.get(1),
viewBuffer.get(2),viewBuffer.get(3));
}
}
protected int getColorValue(int scrX, int scrY) {
if (colorBuffer == null) {
colorBuffer = IntBuffer.allocate(1);
}
colorBuffer.rewind();
readPixels(scrX, pg.height - scrY - 1, 1, 1, RGBA, UNSIGNED_BYTE,
colorBuffer);
return colorBuffer.get();
}
protected float getDepthValue(int scrX, int scrY) {
if (depthBuffer == null) {
depthBuffer = FloatBuffer.allocate(1);
}
depthBuffer.rewind();
readPixels(scrX, pg.height - scrY - 1, 1, 1, DEPTH_COMPONENT, FLOAT,
depthBuffer);
return depthBuffer.get(0);
}
protected byte getStencilValue(int scrX, int scrY) {
if (stencilBuffer == null) {
stencilBuffer = ByteBuffer.allocate(1);
}
readPixels(scrX, pg.height - scrY - 1, 1, 1, STENCIL_INDEX,
UNSIGNED_BYTE, stencilBuffer);
return stencilBuffer.get(0);
}
// bit shifting this might be more efficient
protected static int nextPowerOfTwo(int val) {
int ret = 1;
while (ret < val) {
ret <<= 1;
}
return ret;
}
/**
* Converts input native OpenGL value (RGBA on big endian, ABGR on little
* endian) to Java ARGB.
*/
protected static int nativeToJavaARGB(int color) {
if (PGL.BIG_ENDIAN) { // RGBA to ARGB
return (color >>> 8) | ((color << 24) & 0xFF000000);
// equivalent to
// ((color >> 8) & 0x00FFFFFF) | ((color << 24) & 0xFF000000)
} else { // ABGR to ARGB
return ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16) |
(color & 0xFF00FF00);
}
}
/**
* Converts input array of native OpenGL values (RGBA on big endian, ABGR on
* little endian) representing an image of width x height resolution to Java
* ARGB. It also rearranges the elements in the array so that the image is
* flipped vertically.
*/
protected static void nativeToJavaARGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
for (int x = 0; x < width; x++) {
int pixy = pixels[yindex];
int pixi = pixels[index];
if (BIG_ENDIAN) { // RGBA to ARGB
pixels[index] = (pixy >>> 8) | ((pixy << 24) & 0xFF000000);
pixels[yindex] = (pixi >>> 8) | ((pixi << 24) & 0xFF000000);
} else { // ABGR to ARGB
pixels[index] = ((pixy & 0xFF) << 16) | ((pixy & 0xFF0000) >> 16) |
(pixy & 0xFF00FF00);
pixels[yindex] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
(pixi & 0xFF00FF00);
}
index++;
yindex++;
}
yindex -= width * 2;
}
if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
for (int x = 0; x < width; x++) {
int pixi = pixels[index];
if (BIG_ENDIAN) { // RGBA to ARGB
pixels[index] = (pixi >>> 8) | ((pixi << 24) & 0xFF000000);
} else { // ABGR to ARGB
pixels[index] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
(pixi & 0xFF00FF00);
}
index++;
}
}
}
/**
* Converts input native OpenGL value (RGBA on big endian, ABGR on little
* endian) to Java RGB, so that the alpha component of the result is set
* to opaque (255).
*/
protected static int nativeToJavaRGB(int color) {
if (BIG_ENDIAN) { // RGBA to ARGB
return (color >>> 8) | 0xFF000000;
} else { // ABGR to ARGB
return ((color & 0xFF) << 16) | ((color & 0xFF0000) >> 16) |
(color & 0xFF00FF00) | 0xFF000000;
}
}
/**
* Converts input array of native OpenGL values (RGBA on big endian, ABGR on
* little endian) representing an image of width x height resolution to Java
* RGB, so that the alpha component of all pixels is set to opaque (255). It
* also rearranges the elements in the array so that the image is flipped
* vertically.
*/
protected static void nativeToJavaRGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
for (int x = 0; x < width; x++) {
int pixy = pixels[yindex];
int pixi = pixels[index];
if (BIG_ENDIAN) { // RGBA to ARGB
pixels[index] = (pixy >>> 8) | 0xFF000000;
pixels[yindex] = (pixi >>> 8) | 0xFF000000;
} else { // ABGR to ARGB
pixels[index] = ((pixy & 0xFF) << 16) | ((pixy & 0xFF0000) >> 16) |
(pixy & 0xFF00FF00) | 0xFF000000;
pixels[yindex] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
(pixi & 0xFF00FF00) | 0xFF000000;
}
index++;
yindex++;
}
yindex -= width * 2;
}
if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
for (int x = 0; x < width; x++) {
int pixi = pixels[index];
if (BIG_ENDIAN) { // RGBA to ARGB
pixels[index] = (pixi >>> 8) | 0xFF000000;
} else { // ABGR to ARGB
pixels[index] = ((pixi & 0xFF) << 16) | ((pixi & 0xFF0000) >> 16) |
(pixi & 0xFF00FF00) | 0xFF000000;
}
index++;
}
}
}
/**
* Converts input Java ARGB value to native OpenGL format (RGBA on big endian,
* BGRA on little endian).
*/
protected static int javaToNativeARGB(int color) {
if (BIG_ENDIAN) { // ARGB to RGBA
return ((color >> 24) & 0xFF) | ((color << 8) & 0xFFFFFF00);
} else { // ARGB to ABGR
return (color & 0xFF000000) | ((color << 16) & 0xFF0000) |
(color & 0xFF00) | ((color >> 16) & 0xFF);
}
}
/**
* Converts input array of Java ARGB values representing an image of width x
* height resolution to native OpenGL format (RGBA on big endian, BGRA on
* little endian). It also rearranges the elements in the array so that the
* image is flipped vertically.
*/
protected static void javaToNativeARGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
for (int x = 0; x < width; x++) {
int pixy = pixels[yindex];
int pixi = pixels[index];
if (BIG_ENDIAN) { // ARGB to RGBA
pixels[index] = ((pixy >> 24) & 0xFF) | ((pixy << 8) & 0xFFFFFF00);
pixels[yindex] = ((pixi >> 24) & 0xFF) | ((pixi << 8) & 0xFFFFFF00);
} else { // ARGB to ABGR
pixels[index] = (pixy & 0xFF000000) | ((pixy << 16) & 0xFF0000) |
(pixy & 0xFF00) | ((pixy >> 16) & 0xFF);
pixels[yindex] = (pixi & 0xFF000000) | ((pixi << 16) & 0xFF0000) |
(pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
index++;
yindex++;
}
yindex -= width * 2;
}
if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
for (int x = 0; x < width; x++) {
int pixi = pixels[index];
if (BIG_ENDIAN) { // ARGB to RGBA
pixels[index] = ((pixi >> 24) & 0xFF) | ((pixi << 8) & 0xFFFFFF00);
} else { // ARGB to ABGR
pixels[index] = (pixi & 0xFF000000) | ((pixi << 16) & 0xFF0000) |
(pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
index++;
}
}
}
/**
* Converts input Java ARGB value to native OpenGL format (RGBA on big endian,
* BGRA on little endian), setting alpha component to opaque (255).
*/
protected static int javaToNativeRGB(int color) {
if (BIG_ENDIAN) { // ARGB to RGB
return 0xFF | ((color << 8) & 0xFFFFFF00);
} else { // ARGB to BGR
return 0xFF000000 | ((color << 16) & 0xFF0000) |
(color & 0xFF00) | ((color >> 16) & 0xFF);
}
}
/**
* Converts input array of Java ARGB values representing an image of width x
* height resolution to native OpenGL format (RGBA on big endian, BGRA on
* little endian), while setting alpha component of all pixels to opaque
* (255). It also rearranges the elements in the array so that the image is
* flipped vertically.
*/
protected static void javaToNativeRGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
for (int x = 0; x < width; x++) {
int pixy = pixels[yindex];
int pixi = pixels[index];
if (BIG_ENDIAN) { // ARGB to RGB
pixels[index] = 0xFF | ((pixy << 8) & 0xFFFFFF00);
pixels[yindex] = 0xFF | ((pixi << 8) & 0xFFFFFF00);
} else { // ARGB to BGR
pixels[index] = 0xFF000000 | ((pixy << 16) & 0xFF0000) |
(pixy & 0xFF00) | ((pixy >> 16) & 0xFF);
pixels[yindex] = 0xFF000000 | ((pixi << 16) & 0xFF0000) |
(pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
index++;
yindex++;
}
yindex -= width * 2;
}
if ((height % 2) == 1) { // Converts center row
index = (height / 2) * width;
for (int x = 0; x < width; x++) {
int pixi = pixels[index];
if (BIG_ENDIAN) { // ARGB to RGB
pixels[index] = 0xFF | ((pixi << 8) & 0xFFFFFF00);
} else { // ARGB to BGR
pixels[index] = 0xFF000000 | ((pixi << 16) & 0xFF0000) |
(pixi & 0xFF00) | ((pixi >> 16) & 0xFF);
}
index++;
}
}
}
protected int createShader(int shaderType, String source) {
int shader = createShader(shaderType);
if (shader != 0) {
shaderSource(shader, source);
compileShader(shader);
if (!compiled(shader)) {
System.err.println("Could not compile shader " + shaderType + ":");
System.err.println(getShaderInfoLog(shader));
deleteShader(shader);
shader = 0;
}
}
return shader;
}
protected int createProgram(int vertexShader, int fragmentShader) {
int program = createProgram();
if (program != 0) {
attachShader(program, vertexShader);
attachShader(program, fragmentShader);
linkProgram(program);
if (!linked(program)) {
System.err.println("Could not link program: ");
System.err.println(getProgramInfoLog(program));
deleteProgram(program);
program = 0;
}
}
return program;
}
protected boolean compiled(int shader) {
intBuffer.rewind();
getShaderiv(shader, COMPILE_STATUS, intBuffer);
return intBuffer.get(0) == 0 ? false : true;
}
protected boolean linked(int program) {
intBuffer.rewind();
getProgramiv(program, LINK_STATUS, intBuffer);
return intBuffer.get(0) == 0 ? false : true;
}
protected boolean validateFramebuffer() {
int status = checkFramebufferStatus(FRAMEBUFFER);
if (status == FRAMEBUFFER_COMPLETE) {
return true;
} else if (status == FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"incomplete attachment"));
} else if (status == FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"incomplete missing attachment"));
} else if (status == FRAMEBUFFER_INCOMPLETE_DIMENSIONS) {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"incomplete dimensions"));
} else if (status == FRAMEBUFFER_INCOMPLETE_FORMATS) {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"incomplete formats"));
} else if (status == FRAMEBUFFER_UNSUPPORTED) {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"framebuffer unsupported"));
} else {
System.err.println(String.format(FRAMEBUFFER_ERROR,
"unknown error"));
}
return false;
}
protected int[] getGLVersion() {
String version = getString(VERSION).trim();
int[] res = {0, 0, 0};
String[] parts = version.split(" ");
for (int i = 0; i < parts.length; i++) {
if (0 < parts[i].indexOf(".")) {
String nums[] = parts[i].split("\\.");
try {
res[0] = Integer.parseInt(nums[0]);
} catch (NumberFormatException e) { }
if (1 < nums.length) {
try {
res[1] = Integer.parseInt(nums[1]);
} catch (NumberFormatException e) { }
}
if (2 < nums.length) {
try {
res[2] = Integer.parseInt(nums[2]);
} catch (NumberFormatException e) { }
}
break;
}
}
return res;
}
protected boolean hasFBOs() {
// FBOs might still be available through extensions.
int major = getGLVersion()[0];
if (major < 2) {
String ext = getString(EXTENSIONS);
return ext.indexOf("_framebuffer_object") != -1 &&
ext.indexOf("_vertex_shader") != -1 &&
ext.indexOf("_shader_objects") != -1 &&
ext.indexOf("_shading_language") != -1;
} else {
return true;
}
}
protected boolean hasShaders() {
// GLSL might still be available through extensions. For instance,
// GLContext.hasGLSL() gives false for older intel integrated chipsets on
// OSX, where OpenGL is 1.4 but shaders are available.
int major = getGLVersion()[0];
if (major < 2) {
String ext = getString(EXTENSIONS);
return ext.indexOf("_fragment_shader") != -1 &&
ext.indexOf("_vertex_shader") != -1 &&
ext.indexOf("_shader_objects") != -1 &&
ext.indexOf("_shading_language") != -1;
} else {
return true;
}
}
protected int maxSamples() {
intBuffer.rewind();
getIntegerv(MAX_SAMPLES, intBuffer);
return intBuffer.get(0);
}
protected int getMaxTexUnits() {
intBuffer.rewind();
getIntegerv(MAX_TEXTURE_IMAGE_UNITS, intBuffer);
return intBuffer.get(0);
}
protected static ByteBuffer allocateDirectByteBuffer(int size) {
int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_BYTE;
return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder());
}
protected static ByteBuffer allocateByteBuffer(int size) {
if (USE_DIRECT_BUFFERS) {
return allocateDirectByteBuffer(size);
} else {
return ByteBuffer.allocate(size);
}
}
protected static ByteBuffer allocateByteBuffer(byte[] arr) {
if (USE_DIRECT_BUFFERS) {
return PGL.allocateDirectByteBuffer(arr.length);
} else {
return ByteBuffer.wrap(arr);
}
}
protected static ByteBuffer updateByteBuffer(ByteBuffer buf, byte[] arr,
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
buf = PGL.allocateDirectByteBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
} else {
if (wrap) {
buf = ByteBuffer.wrap(arr);
} else {
if (buf == null || buf.capacity() < arr.length) {
buf = ByteBuffer.allocate(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
return buf;
}
protected static void updateByteBuffer(ByteBuffer buf, byte[] arr,
int offset, int size) {
if (USE_DIRECT_BUFFERS || (buf.hasArray() && buf.array() != arr)) {
buf.position(offset);
buf.put(arr, offset, size);
buf.rewind();
}
}
protected static void getByteArray(ByteBuffer buf, byte[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.get(arr);
buf.rewind();
}
}
protected static void putByteArray(ByteBuffer buf, byte[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
protected static void fillByteBuffer(ByteBuffer buf, int i0, int i1,
byte val) {
int n = i1 - i0;
byte[] temp = new byte[n];
Arrays.fill(temp, 0, n, val);
buf.position(i0);
buf.put(temp, 0, n);
buf.rewind();
}
protected static ShortBuffer allocateDirectShortBuffer(int size) {
int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_SHORT;
return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
asShortBuffer();
}
protected static ShortBuffer allocateShortBuffer(int size) {
if (USE_DIRECT_BUFFERS) {
return allocateDirectShortBuffer(size);
} else {
return ShortBuffer.allocate(size);
}
}
protected static ShortBuffer allocateShortBuffer(short[] arr) {
if (USE_DIRECT_BUFFERS) {
return PGL.allocateDirectShortBuffer(arr.length);
} else {
return ShortBuffer.wrap(arr);
}
}
protected static ShortBuffer updateShortBuffer(ShortBuffer buf, short[] arr,
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
buf = PGL.allocateDirectShortBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
} else {
if (wrap) {
buf = ShortBuffer.wrap(arr);
} else {
if (buf == null || buf.capacity() < arr.length) {
buf = ShortBuffer.allocate(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
return buf;
}
protected static void updateShortBuffer(ShortBuffer buf, short[] arr,
int offset, int size) {
if (USE_DIRECT_BUFFERS || (buf.hasArray() && buf.array() != arr)) {
buf.position(offset);
buf.put(arr, offset, size);
buf.rewind();
}
}
protected static void getShortArray(ShortBuffer buf, short[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.get(arr);
buf.rewind();
}
}
protected static void putShortArray(ShortBuffer buf, short[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
protected static void fillShortBuffer(ShortBuffer buf, int i0, int i1,
short val) {
int n = i1 - i0;
short[] temp = new short[n];
Arrays.fill(temp, 0, n, val);
buf.position(i0);
buf.put(temp, 0, n);
buf.rewind();
}
protected static IntBuffer allocateDirectIntBuffer(int size) {
int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_INT;
return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
asIntBuffer();
}
protected static IntBuffer allocateIntBuffer(int size) {
if (USE_DIRECT_BUFFERS) {
return allocateDirectIntBuffer(size);
} else {
return IntBuffer.allocate(size);
}
}
protected static IntBuffer allocateIntBuffer(int[] arr) {
if (USE_DIRECT_BUFFERS) {
return PGL.allocateDirectIntBuffer(arr.length);
} else {
return IntBuffer.wrap(arr);
}
}
protected static IntBuffer updateIntBuffer(IntBuffer buf, int[] arr,
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
buf = PGL.allocateDirectIntBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
} else {
if (wrap) {
buf = IntBuffer.wrap(arr);
} else {
if (buf == null || buf.capacity() < arr.length) {
buf = IntBuffer.allocate(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
return buf;
}
protected static void updateIntBuffer(IntBuffer buf, int[] arr,
int offset, int size) {
if (USE_DIRECT_BUFFERS || (buf.hasArray() && buf.array() != arr)) {
buf.position(offset);
buf.put(arr, offset, size);
buf.rewind();
}
}
protected static void getIntArray(IntBuffer buf, int[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.get(arr);
buf.rewind();
}
}
protected static void putIntArray(IntBuffer buf, int[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
protected static void fillIntBuffer(IntBuffer buf, int i0, int i1, int val) {
int n = i1 - i0;
int[] temp = new int[n];
Arrays.fill(temp, 0, n, val);
buf.position(i0);
buf.put(temp, 0, n);
buf.rewind();
}
protected static FloatBuffer allocateDirectFloatBuffer(int size) {
int bytes = PApplet.max(MIN_DIRECT_BUFFER_SIZE, size) * SIZEOF_FLOAT;
return ByteBuffer.allocateDirect(bytes).order(ByteOrder.nativeOrder()).
asFloatBuffer();
}
protected static FloatBuffer allocateFloatBuffer(int size) {
if (USE_DIRECT_BUFFERS) {
return allocateDirectFloatBuffer(size);
} else {
return FloatBuffer.allocate(size);
}
}
protected static FloatBuffer allocateFloatBuffer(float[] arr) {
if (USE_DIRECT_BUFFERS) {
return PGL.allocateDirectFloatBuffer(arr.length);
} else {
return FloatBuffer.wrap(arr);
}
}
protected static FloatBuffer updateFloatBuffer(FloatBuffer buf, float[] arr,
boolean wrap) {
if (USE_DIRECT_BUFFERS) {
if (buf == null || buf.capacity() < arr.length) {
buf = PGL.allocateDirectFloatBuffer(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
} else {
if (wrap) {
buf = FloatBuffer.wrap(arr);
} else {
if (buf == null || buf.capacity() < arr.length) {
buf = FloatBuffer.allocate(arr.length);
}
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
return buf;
}
protected static void updateFloatBuffer(FloatBuffer buf, float[] arr,
int offset, int size) {
if (USE_DIRECT_BUFFERS || (buf.hasArray() && buf.array() != arr)) {
buf.position(offset);
buf.put(arr, offset, size);
buf.rewind();
}
}
protected static void getFloatArray(FloatBuffer buf, float[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.get(arr);
buf.rewind();
}
}
protected static void putFloatArray(FloatBuffer buf, float[] arr) {
if (!buf.hasArray() || buf.array() != arr) {
buf.position(0);
buf.put(arr);
buf.rewind();
}
}
protected static void fillFloatBuffer(FloatBuffer buf, int i0, int i1,
float val) {
int n = i1 - i0;
float[] temp = new float[n];
Arrays.fill(temp, 0, n, val);
buf.position(i0);
buf.put(temp, 0, n);
buf.rewind();
}
// TODO: the next three functions shouldn't be here...
protected int getFontAscent(Object font) {
return 0;
}
protected int getFontDescent(Object font) {
return 0;
}
protected int getTextWidth(Object font, char buffer[], int start, int stop) {
return 0;
}
protected Object getDerivedFont(Object font, float size) {
return null;
}
///////////////////////////////////////////////////////////
// Tessellator interface
protected abstract Tessellator createTessellator(TessellatorCallback callback);
protected interface Tessellator {
public void beginPolygon();
public void endPolygon();
public void setWindingRule(int rule);
public void beginContour();
public void endContour();
public void addVertex(double[] v);
}
protected interface TessellatorCallback {
public void begin(int type);
public void end();
public void vertex(Object data);
public void combine(double[] coords, Object[] data,
float[] weight, Object[] outData);
public void error(int errnum);
}
protected String tessError(int err) {
return "";
}
///////////////////////////////////////////////////////////
// FontOutline interface
protected static boolean SHAPE_TEXT_SUPPORTED;
protected static int SEG_MOVETO;
protected static int SEG_LINETO;
protected static int SEG_QUADTO;
protected static int SEG_CUBICTO;
protected static int SEG_CLOSE;
protected abstract FontOutline createFontOutline(char ch, Object font);
protected interface FontOutline {
public boolean isDone();
public int currentSegment(float coords[]);
public void next();
}
//////////////////////////////////////////////////////////////////////////////
//
// OpenGL ES 2.0 API, with a few additional functions for multisampling and
// and buffer mapping from OpenGL 2.1+.
//
// The functions are organized following the groups in the GLES 2.0 reference
// card:
// http://www.khronos.org/opengles/sdk/docs/reference_cards/OpenGL-ES-2_0-Reference-card.pdf
//
// The entire GLES 2.0 specification is available below:
// http://www.khronos.org/opengles/2_X/
//
// Implementations of the PGL functions for specific OpenGL bindings (JOGL,
// LWJGL) should simply call the corresponding GL function in the bindings.
// readPixels(), activeTexture() and bindTexture() are special cases, please
// read their comments.
// Also, keep in mind the note about the PGL constants below.
//
//////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////
// Constants
// Very important note: set the GL constants in your PGL subclass by using an
// static initialization block as follows:
// static {
// FALSE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_FALSE;
// TRUE = SUPER_DUPER_JAVA_OPENGL_BINDINGS.GL_TRUE;
// ...
// }
// and not by re-declaring the constants, because doing so will lead to
// errors when the constants are accessed through PGL because they are not
// overridden but hidden by the new declarations, and hence they keep their
// initial values (all zeroes) when accessed through the superclass.
public static int FALSE;
public static int TRUE;
public static int INT;
public static int BYTE;
public static int SHORT;
public static int FLOAT;
public static int BOOL;
public static int UNSIGNED_INT;
public static int UNSIGNED_BYTE;
public static int UNSIGNED_SHORT;
public static int RGB;
public static int RGBA;
public static int ALPHA;
public static int LUMINANCE;
public static int LUMINANCE_ALPHA;
public static int UNSIGNED_SHORT_5_6_5;
public static int UNSIGNED_SHORT_4_4_4_4;
public static int UNSIGNED_SHORT_5_5_5_1;
public static int RGBA4;
public static int RGB5_A1;
public static int RGB565;
public static int READ_ONLY;
public static int WRITE_ONLY;
public static int READ_WRITE;
public static int TESS_WINDING_NONZERO;
public static int TESS_WINDING_ODD;
public static int GENERATE_MIPMAP_HINT;
public static int FASTEST;
public static int NICEST;
public static int DONT_CARE;
public static int VENDOR;
public static int RENDERER;
public static int VERSION;
public static int EXTENSIONS;
public static int SHADING_LANGUAGE_VERSION;
public static int MAX_SAMPLES;
public static int SAMPLES;
public static int ALIASED_LINE_WIDTH_RANGE;
public static int ALIASED_POINT_SIZE_RANGE;
public static int DEPTH_BITS;
public static int STENCIL_BITS;
public static int CCW;
public static int CW;
public static int VIEWPORT;
public static int ARRAY_BUFFER;
public static int ELEMENT_ARRAY_BUFFER;
public static int MAX_VERTEX_ATTRIBS;
public static int STATIC_DRAW;
public static int DYNAMIC_DRAW;
public static int STREAM_DRAW;
public static int BUFFER_SIZE;
public static int BUFFER_USAGE;
public static int POINTS;
public static int LINE_STRIP;
public static int LINE_LOOP;
public static int LINES;
public static int TRIANGLE_FAN;
public static int TRIANGLE_STRIP;
public static int TRIANGLES;
public static int CULL_FACE;
public static int FRONT;
public static int BACK;
public static int FRONT_AND_BACK;
public static int POLYGON_OFFSET_FILL;
public static int UNPACK_ALIGNMENT;
public static int PACK_ALIGNMENT;
public static int TEXTURE_2D;
public static int TEXTURE_RECTANGLE;
public static int TEXTURE_BINDING_2D;
public static int TEXTURE_BINDING_RECTANGLE;
public static int MAX_TEXTURE_SIZE;
public static int TEXTURE_MAX_ANISOTROPY;
public static int MAX_TEXTURE_MAX_ANISOTROPY;
public static int MAX_VERTEX_TEXTURE_IMAGE_UNITS;
public static int MAX_TEXTURE_IMAGE_UNITS;
public static int MAX_COMBINED_TEXTURE_IMAGE_UNITS;
public static int NUM_COMPRESSED_TEXTURE_FORMATS;
public static int COMPRESSED_TEXTURE_FORMATS;
public static int NEAREST;
public static int LINEAR;
public static int LINEAR_MIPMAP_NEAREST;
public static int LINEAR_MIPMAP_LINEAR;
public static int CLAMP_TO_EDGE;
public static int REPEAT;
public static int TEXTURE0;
public static int TEXTURE1;
public static int TEXTURE2;
public static int TEXTURE3;
public static int TEXTURE_MIN_FILTER;
public static int TEXTURE_MAG_FILTER;
public static int TEXTURE_WRAP_S;
public static int TEXTURE_WRAP_T;
public static int TEXTURE_WRAP_R;
public static int TEXTURE_CUBE_MAP;
public static int TEXTURE_CUBE_MAP_POSITIVE_X;
public static int TEXTURE_CUBE_MAP_POSITIVE_Y;
public static int TEXTURE_CUBE_MAP_POSITIVE_Z;
public static int TEXTURE_CUBE_MAP_NEGATIVE_X;
public static int TEXTURE_CUBE_MAP_NEGATIVE_Y;
public static int TEXTURE_CUBE_MAP_NEGATIVE_Z;
public static int VERTEX_SHADER;
public static int FRAGMENT_SHADER;
public static int INFO_LOG_LENGTH;
public static int SHADER_SOURCE_LENGTH;
public static int COMPILE_STATUS;
public static int LINK_STATUS;
public static int VALIDATE_STATUS;
public static int SHADER_TYPE;
public static int DELETE_STATUS;
public static int FLOAT_VEC2;
public static int FLOAT_VEC3;
public static int FLOAT_VEC4;
public static int FLOAT_MAT2;
public static int FLOAT_MAT3;
public static int FLOAT_MAT4;
public static int INT_VEC2;
public static int INT_VEC3;
public static int INT_VEC4;
public static int BOOL_VEC2;
public static int BOOL_VEC3;
public static int BOOL_VEC4;
public static int SAMPLER_2D;
public static int SAMPLER_CUBE;
public static int LOW_FLOAT;
public static int MEDIUM_FLOAT;
public static int HIGH_FLOAT;
public static int LOW_INT;
public static int MEDIUM_INT;
public static int HIGH_INT;
public static int CURRENT_VERTEX_ATTRIB;
public static int VERTEX_ATTRIB_ARRAY_BUFFER_BINDING;
public static int VERTEX_ATTRIB_ARRAY_ENABLED;
public static int VERTEX_ATTRIB_ARRAY_SIZE;
public static int VERTEX_ATTRIB_ARRAY_STRIDE;
public static int VERTEX_ATTRIB_ARRAY_TYPE;
public static int VERTEX_ATTRIB_ARRAY_NORMALIZED;
public static int VERTEX_ATTRIB_ARRAY_POINTER;
public static int BLEND;
public static int ONE;
public static int ZERO;
public static int SRC_ALPHA;
public static int DST_ALPHA;
public static int ONE_MINUS_SRC_ALPHA;
public static int ONE_MINUS_DST_COLOR;
public static int ONE_MINUS_SRC_COLOR;
public static int DST_COLOR;
public static int SRC_COLOR;
public static int SAMPLE_ALPHA_TO_COVERAGE;
public static int SAMPLE_COVERAGE;
public static int KEEP;
public static int REPLACE;
public static int INCR;
public static int DECR;
public static int INVERT;
public static int INCR_WRAP;
public static int DECR_WRAP;
public static int NEVER;
public static int ALWAYS;
public static int EQUAL;
public static int LESS;
public static int LEQUAL;
public static int GREATER;
public static int GEQUAL;
public static int NOTEQUAL;
public static int FUNC_ADD;
public static int FUNC_MIN;
public static int FUNC_MAX;
public static int FUNC_REVERSE_SUBTRACT;
public static int FUNC_SUBTRACT;
public static int DITHER;
public static int CONSTANT_COLOR;
public static int CONSTANT_ALPHA;
public static int ONE_MINUS_CONSTANT_COLOR;
public static int ONE_MINUS_CONSTANT_ALPHA;
public static int SRC_ALPHA_SATURATE;
public static int SCISSOR_TEST;
public static int STENCIL_TEST;
public static int DEPTH_TEST;
public static int DEPTH_WRITEMASK;
public static int ALPHA_TEST;
public static int COLOR_BUFFER_BIT;
public static int DEPTH_BUFFER_BIT;
public static int STENCIL_BUFFER_BIT;
public static int FRAMEBUFFER;
public static int COLOR_ATTACHMENT0;
public static int COLOR_ATTACHMENT1;
public static int COLOR_ATTACHMENT2;
public static int COLOR_ATTACHMENT3;
public static int RENDERBUFFER;
public static int DEPTH_ATTACHMENT;
public static int STENCIL_ATTACHMENT;
public static int READ_FRAMEBUFFER;
public static int DRAW_FRAMEBUFFER;
public static int RGBA8;
public static int DEPTH24_STENCIL8;
public static int DEPTH_COMPONENT;
public static int DEPTH_COMPONENT16;
public static int DEPTH_COMPONENT24;
public static int DEPTH_COMPONENT32;
public static int STENCIL_INDEX;
public static int STENCIL_INDEX1;
public static int STENCIL_INDEX4;
public static int STENCIL_INDEX8;
public static int DEPTH_STENCIL;
public static int FRAMEBUFFER_COMPLETE;
public static int FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
public static int FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
public static int FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
public static int FRAMEBUFFER_INCOMPLETE_FORMATS;
public static int FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER;
public static int FRAMEBUFFER_INCOMPLETE_READ_BUFFER;
public static int FRAMEBUFFER_UNSUPPORTED;
public static int FRAMEBUFFER_ATTACHMENT_OBJECT_TYPE;
public static int FRAMEBUFFER_ATTACHMENT_OBJECT_NAME;
public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL;
public static int FRAMEBUFFER_ATTACHMENT_TEXTURE_CUBE_MAP_FACE;
public static int RENDERBUFFER_WIDTH;
public static int RENDERBUFFER_HEIGHT;
public static int RENDERBUFFER_RED_SIZE;
public static int RENDERBUFFER_GREEN_SIZE;
public static int RENDERBUFFER_BLUE_SIZE;
public static int RENDERBUFFER_ALPHA_SIZE;
public static int RENDERBUFFER_DEPTH_SIZE;
public static int RENDERBUFFER_STENCIL_SIZE;
public static int RENDERBUFFER_INTERNAL_FORMAT;
public static int MULTISAMPLE;
public static int POINT_SMOOTH;
public static int LINE_SMOOTH;
public static int POLYGON_SMOOTH;
///////////////////////////////////////////////////////////
// Special Functions
public abstract void flush();
public abstract void finish();
public abstract void hint(int target, int hint);
///////////////////////////////////////////////////////////
// State and State Requests
public abstract void enable(int value);
public abstract void disable(int value);
public abstract void getBooleanv(int value, IntBuffer data);
public abstract void getIntegerv(int value, IntBuffer data);
public abstract void getFloatv(int value, FloatBuffer data);
public abstract boolean isEnabled(int value);
public abstract String getString(int name);
///////////////////////////////////////////////////////////
// Error Handling
public abstract int getError();
public abstract String errorString(int err);
//////////////////////////////////////////////////////////////////////////////
// Buffer Objects
public abstract void genBuffers(int n, IntBuffer buffers);
public abstract void deleteBuffers(int n, IntBuffer buffers);
public abstract void bindBuffer(int target, int buffer);
public abstract void bufferData(int target, int size, Buffer data, int usage);
public abstract void bufferSubData(int target, int offset, int size, Buffer data);
public abstract void isBuffer(int buffer);
public abstract void getBufferParameteriv(int target, int value, IntBuffer data);
public abstract ByteBuffer mapBuffer(int target, int access);
public abstract ByteBuffer mapBufferRange(int target, int offset, int length, int access);
public abstract void unmapBuffer(int target);
//////////////////////////////////////////////////////////////////////////////
// Viewport and Clipping
public abstract void depthRangef(float n, float f);
public abstract void viewport(int x, int y, int w, int h);
//////////////////////////////////////////////////////////////////////////////
// Reading Pixels
// This is a special case: because the renderer might be using an FBO even on
// the main surface, some extra handling might be needed before and after
// reading the pixels. To make this transparent to the user, the actual call
// to glReadPixels() should be done in readPixelsImpl().
public void readPixels(int x, int y, int width, int height, int format, int type, Buffer buffer){
boolean needEndBegin = format != STENCIL_INDEX &&
format != DEPTH_COMPONENT && format != DEPTH_STENCIL;
if (needEndBegin) pg.beginReadPixels();
readPixelsImpl(x, y, width, height, format, type, buffer);
if (needEndBegin) pg.endReadPixels();
}
protected abstract void readPixelsImpl(int x, int y, int width, int height, int format, int type, Buffer buffer);
//////////////////////////////////////////////////////////////////////////////
// Vertices
public abstract void vertexAttrib1f(int index, float value);
public abstract void vertexAttrib2f(int index, float value0, float value1);
public abstract void vertexAttrib3f(int index, float value0, float value1, float value2);
public abstract void vertexAttrib4f(int index, float value0, float value1, float value2, float value3);
public abstract void vertexAttrib1fv(int index, FloatBuffer values);
public abstract void vertexAttrib2fv(int index, FloatBuffer values);
public abstract void vertexAttrib3fv(int index, FloatBuffer values);
public abstract void vertexAttri4fv(int index, FloatBuffer values);
public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, int offset);
//public abstract void vertexAttribPointer(int index, int size, int type, boolean normalized, int stride, Buffer data);
public abstract void enableVertexAttribArray(int index);
public abstract void disableVertexAttribArray(int index);
public abstract void drawArrays(int mode, int first, int count);
public abstract void drawElements(int mode, int count, int type, int offset);
//public abstract void drawElements(int mode, int count, int type, Buffer indices);
//////////////////////////////////////////////////////////////////////////////
// Rasterization
public abstract void lineWidth(float width);
public abstract void frontFace(int dir);
public abstract void cullFace(int mode);
public abstract void polygonOffset(float factor, float units);
//////////////////////////////////////////////////////////////////////////////
// Pixel Rectangles
public abstract void pixelStorei(int pname, int param);
///////////////////////////////////////////////////////////
// Texturing
public abstract void texImage2D(int target, int level, int internalFormat, int width, int height, int border, int format, int type, Buffer data);
public abstract void copyTexImage2D(int target, int level, int internalFormat, int x, int y, int width, int height, int border);
public abstract void texSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int type, Buffer data);
public abstract void copyTexSubImage2D(int target, int level, int xOffset, int yOffset, int x, int y, int width, int height);
public abstract void compressedTexImage2D(int target, int level, int internalFormat, int width, int height, int border, int imageSize, Buffer data);
public abstract void compressedTexSubImage2D(int target, int level, int xOffset, int yOffset, int width, int height, int format, int imageSize, Buffer data);
public abstract void texParameteri(int target, int pname, int param);
public abstract void texParameterf(int target, int pname, float param);
public abstract void texParameteriv(int target, int pname, IntBuffer params);
public abstract void texParameterfv(int target, int pname, FloatBuffer params);
public abstract void generateMipmap(int target);
public abstract void genTextures(int n, IntBuffer textures);
public abstract void deleteTextures(int n, IntBuffer textures);
public abstract void getTexParameteriv(int target, int pname, IntBuffer params);
public abstract void getTexParameterfv(int target, int pname, FloatBuffer params);
public abstract boolean isTexture(int texture);
// activeTexture() and bindTexture() have some extra logic to keep track of
// the bound textures, so the actual GL call should go in activeTextureImpl()
// and bindTextureImpl().
public void activeTexture(int texture) {
activeTexUnit = texture - TEXTURE0;
activeTextureImpl(texture);
}
protected abstract void activeTextureImpl(int texture);
public void bindTexture(int target, int texture) {
bindTextureImpl(target, texture);
if (boundTextures == null) {
maxTexUnits = getMaxTexUnits();
boundTextures = new int[maxTexUnits][2];
}
if (maxTexUnits <= activeTexUnit) {
throw new RuntimeException(TEXUNIT_ERROR);
}
if (target == TEXTURE_2D) {
boundTextures[activeTexUnit][0] = texture;
} else if (target == TEXTURE_RECTANGLE) {
boundTextures[activeTexUnit][1] = texture;
}
}
protected abstract void bindTextureImpl(int target, int texture);
///////////////////////////////////////////////////////////
// Shaders and Programs
public abstract int createShader(int type);
public abstract void shaderSource(int shader, String source);
public abstract void compileShader(int shader);
public abstract void releaseShaderCompiler();
public abstract void deleteShader(int shader);
public abstract void shaderBinary(int count, IntBuffer shaders, int binaryFormat, Buffer binary, int length);
public abstract int createProgram();
public abstract void attachShader(int program, int shader);
public abstract void detachShader(int program, int shader);
public abstract void linkProgram(int program);
public abstract void useProgram(int program);
public abstract void deleteProgram(int program);
public abstract String getActiveAttrib(int program, int index, IntBuffer size, IntBuffer type);
public abstract int getAttribLocation(int program, String name);
public abstract void bindAttribLocation(int program, int index, String name);
public abstract int getUniformLocation(int program, String name);
public abstract String getActiveUniform(int program, int index, IntBuffer size, IntBuffer type);
public abstract void uniform1i(int location, int value);
public abstract void uniform2i(int location, int value0, int value1);
public abstract void uniform3i(int location, int value0, int value1, int value2);
public abstract void uniform4i(int location, int value0, int value1, int value2, int value3);
public abstract void uniform1f(int location, float value);
public abstract void uniform2f(int location, float value0, float value1);
public abstract void uniform3f(int location, float value0, float value1, float value2);
public abstract void uniform4f(int location, float value0, float value1, float value2, float value3);
public abstract void uniform1iv(int location, int count, IntBuffer v);
public abstract void uniform2iv(int location, int count, IntBuffer v);
public abstract void uniform3iv(int location, int count, IntBuffer v);
public abstract void uniform4iv(int location, int count, IntBuffer v);
public abstract void uniform1fv(int location, int count, FloatBuffer v);
public abstract void uniform2fv(int location, int count, FloatBuffer v);
public abstract void uniform3fv(int location, int count, FloatBuffer v);
public abstract void uniform4fv(int location, int count, FloatBuffer v);
public abstract void uniformMatrix2fv(int location, int count, boolean transpose, FloatBuffer mat);
public abstract void uniformMatrix3fv(int location, int count, boolean transpose, FloatBuffer mat);
public abstract void uniformMatrix4fv(int location, int count, boolean transpose, FloatBuffer mat);
public abstract void validateProgram(int program);
public abstract boolean isShader(int shader);
public abstract void getShaderiv(int shader, int pname, IntBuffer params);
public abstract void getAttachedShaders(int program, int maxCount, IntBuffer count, IntBuffer shaders);
public abstract String getShaderInfoLog(int shader);
public abstract String getShaderSource(int shader);
public abstract void getShaderPrecisionFormat(int shaderType, int precisionType, IntBuffer range, IntBuffer precision);
public abstract void getVertexAttribfv(int index, int pname, FloatBuffer params);
public abstract void getVertexAttribiv(int index, int pname, IntBuffer params);
public abstract void getVertexAttribPointerv(int index, int pname, ByteBuffer data);
public abstract void getUniformfv(int program, int location, FloatBuffer params);
public abstract void getUniformiv(int program, int location, IntBuffer params);
public abstract boolean isProgram(int program);
public abstract void getProgramiv(int program, int pname, IntBuffer params);
public abstract String getProgramInfoLog(int program);
///////////////////////////////////////////////////////////
// Per-Fragment Operations
public abstract void scissor(int x, int y, int w, int h);
public abstract void sampleCoverage(float value, boolean invert);
public abstract void stencilFunc(int func, int ref, int mask);
public abstract void stencilFuncSeparate(int face, int func, int ref, int mask);
public abstract void stencilOp(int sfail, int dpfail, int dppass);
public abstract void stencilOpSeparate(int face, int sfail, int dpfail, int dppass);
public abstract void depthFunc(int func);
public abstract void blendEquation(int mode);
public abstract void blendEquationSeparate(int modeRGB, int modeAlpha);
public abstract void blendFunc(int src, int dst);
public abstract void blendFuncSeparate(int srcRGB, int dstRGB, int srcAlpha, int dstAlpha);
public abstract void blendColor(float red, float green, float blue, float alpha);
public abstract void alphaFunc(int func, float ref);
///////////////////////////////////////////////////////////
// Whole Framebuffer Operations
public abstract void colorMask(boolean r, boolean g, boolean b, boolean a);
public abstract void depthMask(boolean mask);
public abstract void stencilMask(int mask);
public abstract void stencilMaskSeparate(int face, int mask);
public abstract void clear(int buf);
public abstract void clearColor(float r, float g, float b, float a);
public abstract void clearDepth(float d);
public abstract void clearStencil(int s);
///////////////////////////////////////////////////////////
// Framebuffers Objects
public abstract void bindFramebuffer(int target, int framebuffer);
public abstract void deleteFramebuffers(int n, IntBuffer framebuffers);
public abstract void genFramebuffers(int n, IntBuffer framebuffers);
public abstract void bindRenderbuffer(int target, int renderbuffer);
public abstract void deleteRenderbuffers(int n, IntBuffer renderbuffers);
public abstract void genRenderbuffers(int n, IntBuffer renderbuffers);
public abstract void renderbufferStorage(int target, int internalFormat, int width, int height);
public abstract void framebufferRenderbuffer(int target, int attachment, int rendbuferfTarget, int renderbuffer);
public abstract void framebufferTexture2D(int target, int attachment, int texTarget, int texture, int level);
public abstract int checkFramebufferStatus(int target);
public abstract boolean isFramebuffer(int framebuffer);
public abstract void getFramebufferAttachmentParameteriv(int target, int attachment, int pname, IntBuffer params);
public abstract boolean isRenderbuffer(int renderbuffer);
public abstract void getRenderbufferParameteriv(int target, int pname, IntBuffer params);
public abstract void blitFramebuffer(int srcX0, int srcY0, int srcX1, int srcY1, int dstX0, int dstY0, int dstX1, int dstY1, int mask, int filter);
public abstract void renderbufferStorageMultisample(int target, int samples, int format, int width, int height);
public abstract void readBuffer(int buf);
public abstract void drawBuffer(int buf);
}