Faster pixel get/set in P3D

This commit is contained in:
codeanticode
2012-03-29 05:05:07 +00:00
parent 1edda6d771
commit bdfcd8e16e
5 changed files with 535 additions and 690 deletions
@@ -250,7 +250,7 @@ class PFontTexture implements PConstants {
int[] rgba = new int[w * h];
int t = 0;
int p = 0;
if (PGraphicsOpenGL.BIG_ENDIAN) {
if (PGL.BIG_ENDIAN) {
java.util.Arrays.fill(rgba, 0, w, 0xFFFFFF00); // Set the first row to blank pixels.
t = w;
for (int y = 0; y < glyph.height; y++) {
@@ -103,6 +103,34 @@ public class PGL {
/** Maximum dimension of a texture used to hold font data. **/
public static final int MAX_FONT_TEX_SIZE = 256;
/** Minimum array size to use arrayCopy method(). **/
static protected final int MIN_ARRAYCOPY_SIZE = 2;
/** Machine Epsilon for float precision. **/
static public 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).
*/
static public boolean BIG_ENDIAN = ByteOrder.nativeOrder() == ByteOrder.BIG_ENDIAN;
protected static final String SHADER_PREPROCESSOR_DIRECTIVE = "#ifdef GL_ES\n" +
"precision mediump float;\n" +
"precision mediump int;\n" +
"#endif;\n";
///////////////////////////////////////////////////////////////////////////////////
// OpenGL constants
@@ -151,10 +179,12 @@ public class PGL {
public static final int GL_RGBA8 = GL.GL_RGBA8;
public static final int GL_DEPTH24_STENCIL8 = GL.GL_DEPTH24_STENCIL8;
public static final int GL_DEPTH_COMPONENT = GL2.GL_DEPTH_COMPONENT;
public static final int GL_DEPTH_COMPONENT16 = GL.GL_DEPTH_COMPONENT16;
public static final int GL_DEPTH_COMPONENT24 = GL.GL_DEPTH_COMPONENT24;
public static final int GL_DEPTH_COMPONENT32 = GL.GL_DEPTH_COMPONENT32;
public static final int GL_STENCIL_INDEX = GL2.GL_STENCIL_INDEX;
public static final int GL_STENCIL_INDEX1 = GL.GL_STENCIL_INDEX1;
public static final int GL_STENCIL_INDEX4 = GL.GL_STENCIL_INDEX4;
public static final int GL_STENCIL_INDEX8 = GL.GL_STENCIL_INDEX8;
@@ -325,7 +355,8 @@ public class PGL {
" vertTexcoord = inTexcoord;" +
"}";
protected String texFragShaderSource = "uniform sampler2D textureSampler;" +
protected String texFragShaderSource = SHADER_PREPROCESSOR_DIRECTIVE +
"uniform sampler2D textureSampler;" +
"varying vec2 vertTexcoord;" +
"void main() {" +
" gl_FragColor = texture2D(textureSampler, vertTexcoord.st);" +
@@ -357,11 +388,21 @@ public class PGL {
" gl_Position = vec4(inVertex, 0, 1);" +
"}";
protected String rectFragShaderSource = "uniform vec4 rectColor;" +
protected String rectFragShaderSource = SHADER_PREPROCESSOR_DIRECTIVE +
"uniform vec4 rectColor;" +
"void main() {" +
" gl_FragColor = rectColor;" +
"}";
///////////////////////////////////////////////////////////////////////////////////
// 1-pixel color, depth, stencil buffers
protected IntBuffer colorBuffer;
protected FloatBuffer depthBuffer;
protected ByteBuffer stencilBuffer;
///////////////////////////////////////////////////////////////////////////////////
// Intialization, finalization
@@ -1186,21 +1227,30 @@ public class PGL {
public void enableTexturing(int target) {
gl.glEnable(target);
glEnable(target);
}
public void disableTexturing(int target) {
gl.glDisable(target);
glDisable(target);
}
public void initTexture(int target, int width, int height, int format, int type) {
public void initTexture(int target, int format, int width, int height) {
int[] texels = new int[width * height];
gl.glTexSubImage2D(target, 0, 0, 0, width, height, format, type, IntBuffer.wrap(texels));
glTexSubImage2D(target, 0, 0, 0, width, height, format, GL_UNSIGNED_BYTE, IntBuffer.wrap(texels));
}
public void copyToTexture(int target, int format, int id, int x, int y, int w, int h, IntBuffer buffer) {
enableTexturing(target);
glBindTexture(target, id);
glTexSubImage2D(target, 0, x, y, w, h, format, GL_UNSIGNED_BYTE, buffer);
glBindTexture(target, 0);
disableTexturing(target);
}
public void drawTexture(int target, int id, int width, int height,
int texX0, int texY0, int texX1, int texY1,
int scrX0, int scrY0, int scrX1, int scrY1) {
@@ -1352,7 +1402,36 @@ public class PGL {
glDepthMask(writeMask);
}
}
public int getColorValue(int scrX, int scrY) {
if (colorBuffer == null) {
colorBuffer = IntBuffer.allocate(1);
}
colorBuffer.rewind();
glReadPixels(scrX, pg.height - scrY - 1, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, colorBuffer);
return colorBuffer.get();
}
public float getDepthValue(int scrX, int scrY) {
if (depthBuffer == null) {
depthBuffer = FloatBuffer.allocate(1);
}
depthBuffer.rewind();
glReadPixels(scrX, pg.height - scrY - 1, 1, 1, GL_DEPTH_COMPONENT, GL_FLOAT, depthBuffer);
return depthBuffer.get(0);
}
public byte getStencilValue(int scrX, int scrY) {
if (stencilBuffer == null) {
stencilBuffer = ByteBuffer.allocate(1);
}
glReadPixels(scrX, pg.height - scrY - 1, 1, 1, GL_STENCIL_INDEX, GL.GL_UNSIGNED_BYTE, stencilBuffer);
return stencilBuffer.get(0);
}
// bit shifting this might be more efficient
static public int nextPowerOfTwo(int val) {
@@ -1363,6 +1442,238 @@ public class PGL {
return ret;
}
/**
* Convert native OpenGL format into palatable ARGB format. This function
* leaves alone (ignores) the alpha component. Also flips the image
* vertically, since images are upside-down in GL.
*/
static public void nativeToJavaRGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
int temp = pixels[index];
// ignores alpha component, just sets it opaque
pixels[index] = 0xff000000 | ((pixels[yindex] >> 8) & 0x00ffffff);
pixels[yindex] = 0xff000000 | ((temp >> 8) & 0x00ffffff);
index++;
yindex++;
}
} else { // LITTLE_ENDIAN, convert ABGR to ARGB
for (int x = 0; x < width; x++) {
int temp = pixels[index];
// identical to endPixels because only two
// components are being swapped
pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
(pixels[yindex] & 0xff00) |
((pixels[yindex] >> 16) & 0xff);
pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
(temp & 0xff00) |
((temp >> 16) & 0xff);
index++;
yindex++;
}
}
yindex -= width * 2;
}
// When height is an odd number, the middle line needs to be
// endian swapped, but not y-swapped.
// http://dev.processing.org/bugs/show_bug.cgi?id=944
if ((height % 2) == 1) {
index = (height / 2) * width;
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
pixels[index] = 0xff000000 | ((pixels[index] >> 8) & 0x00ffffff);
index++;
}
} else {
for (int x = 0; x < width; x++) {
pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
(pixels[index] & 0xff00) |
((pixels[index] >> 16) & 0xff);
index++;
}
}
}
}
/**
* Convert native OpenGL format into palatable ARGB format. This function
* leaves alone (ignores) the alpha component. Also flips the image
* vertically, since images are upside-down in GL.
*/
static public void nativeToJavaARGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
int temp = pixels[index];
// ignores alpha component, just sets it opaque
pixels[index] = (pixels[yindex] & 0xff000000) |
((pixels[yindex] >> 8) & 0x00ffffff);
pixels[yindex] = (temp & 0xff000000) |
((temp >> 8) & 0x00ffffff);
index++;
yindex++;
}
} else { // LITTLE_ENDIAN, convert ABGR to ARGB
for (int x = 0; x < width; x++) {
int temp = pixels[index];
pixels[index] = (pixels[yindex] & 0xff000000) |
((pixels[yindex] << 16) & 0xff0000) |
(pixels[yindex] & 0xff00) |
((pixels[yindex] >> 16) & 0xff);
pixels[yindex] = (temp & 0xff000000) |
((temp << 16) & 0xff0000) |
(temp & 0xff00) |
((temp >> 16) & 0xff);
index++;
yindex++;
}
}
yindex -= width * 2;
}
if ((height % 2) == 1) {
index = (height / 2) * width;
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
pixels[index] = (pixels[index] & 0xff000000) |
((pixels[index] >> 8) & 0x00ffffff);
index++;
}
} else {
for (int x = 0; x < width; x++) {
pixels[index] = (pixels[index] & 0xff000000) |
((pixels[index] << 16) & 0xff0000) |
(pixels[index] & 0xff00) |
((pixels[index] >> 16) & 0xff);
index++;
}
}
}
}
/**
* Convert ARGB (Java/Processing) data to native OpenGL format. This function
* leaves alone (ignores) the alpha component. Also flips the image
* vertically, since images are upside-down in GL.
*/
static public void javaToNativeRGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
if (BIG_ENDIAN) {
// and convert ARGB back to opengl RGBA components (big endian)
for (int x = 0; x < width; x++) {
int temp = pixels[index];
pixels[index] = ((pixels[yindex] << 8) & 0xffffff00) | 0xff;
pixels[yindex] = ((temp << 8) & 0xffffff00) | 0xff;
index++;
yindex++;
}
} else {
// convert ARGB back to native little endian ABGR
for (int x = 0; x < width; x++) {
int temp = pixels[index];
pixels[index] = 0xff000000 | ((pixels[yindex] << 16) & 0xff0000) |
(pixels[yindex] & 0xff00) |
((pixels[yindex] >> 16) & 0xff);
pixels[yindex] = 0xff000000 | ((temp << 16) & 0xff0000) |
(temp & 0xff00) |
((temp >> 16) & 0xff);
index++;
yindex++;
}
}
yindex -= width * 2;
}
if ((height % 2) == 1) {
index = (height / 2) * width;
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
pixels[index] = ((pixels[index] << 8) & 0xffffff00) | 0xff;
index++;
}
} else {
for (int x = 0; x < width; x++) {
pixels[index] = 0xff000000 | ((pixels[index] << 16) & 0xff0000) |
(pixels[index] & 0xff00) |
((pixels[index] >> 16) & 0xff);
index++;
}
}
}
}
/**
* Convert Java ARGB to native OpenGL format. Also flips the image vertically,
* since images are upside-down in GL.
*/
static public void javaToNativeARGB(int[] pixels, int width, int height) {
int index = 0;
int yindex = (height - 1) * width;
for (int y = 0; y < height / 2; y++) {
if (BIG_ENDIAN) {
// and convert ARGB back to opengl RGBA components (big endian)
for (int x = 0; x < width; x++) {
int temp = pixels[index];
pixels[index] = ((pixels[yindex] >> 24) & 0xff) |
((pixels[yindex] << 8) & 0xffffff00);
pixels[yindex] = ((temp >> 24) & 0xff) |
((temp << 8) & 0xffffff00);
index++;
yindex++;
}
} else {
// convert ARGB back to native little endian ABGR
for (int x = 0; x < width; x++) {
int temp = pixels[index];
pixels[index] = (pixels[yindex] & 0xff000000) |
((pixels[yindex] << 16) & 0xff0000) |
(pixels[yindex] & 0xff00) |
((pixels[yindex] >> 16) & 0xff);
pixels[yindex] = (pixels[yindex] & 0xff000000) |
((temp << 16) & 0xff0000) |
(temp & 0xff00) |
((temp >> 16) & 0xff);
index++;
yindex++;
}
}
yindex -= width * 2;
}
if ((height % 2) == 1) {
index = (height / 2) * width;
if (BIG_ENDIAN) {
for (int x = 0; x < width; x++) {
pixels[index] = ((pixels[index] >> 24) & 0xff) |
((pixels[index] << 8) & 0xffffff00);
index++;
}
} else {
for (int x = 0; x < width; x++) {
pixels[index] = (pixels[index] & 0xff000000) |
((pixels[index] << 16) & 0xff0000) |
(pixels[index] & 0xff00) |
((pixels[index] >> 16) & 0xff);
index++;
}
}
}
}
public int createShader(int shaderType, String source) {
int shader = glCreateShader(shaderType);
File diff suppressed because it is too large Load Diff
@@ -3952,7 +3952,7 @@ public class PShape3D extends PShape {
expand(newSize);
}
if (dataSize <= PGraphicsOpenGL.MIN_ARRAYCOPY_SIZE) {
if (dataSize <= PGL.MIN_ARRAYCOPY_SIZE) {
// Copying elements one by one instead of using arrayCopy is more efficient for
// few vertices...
for (int i = 0; i < dataSize; i++) {
@@ -3995,7 +3995,7 @@ public class PShape3D extends PShape {
expand(newSize);
}
if (dataSize <= PGraphicsOpenGL.MIN_ARRAYCOPY_SIZE) {
if (dataSize <= PGL.MIN_ARRAYCOPY_SIZE) {
// Copying elements one by one instead of using arrayCopy is more efficient for
// few vertices...
for (int i = 0; i < dataSize; i++) {
@@ -542,7 +542,7 @@ public class PTexture implements PConstants {
* @param h int
*/
protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat, int w, int h) {
if (PGraphicsOpenGL.BIG_ENDIAN) {
if (PGL.BIG_ENDIAN) {
switch (arrayFormat) {
case ALPHA:
@@ -682,7 +682,7 @@ public class PTexture implements PConstants {
protected void convertToARGB(int[] intArray, int[] tIntArray) {
int t = 0;
int p = 0;
if (PGraphicsOpenGL.BIG_ENDIAN) {
if (PGL.BIG_ENDIAN) {
// RGBA to ARGB conversion: shifting RGB 8 bits to the right,
// and placing A 24 bits to the left.
@@ -768,7 +768,7 @@ public class PTexture implements PConstants {
pgl.glTexImage2D(glTarget, 0, glFormat, glWidth, glHeight, 0, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE, null);
// Makes sure that the texture buffer in video memory doesn't contain any garbage.
pgl.initTexture(glTarget, width, height, PGL.GL_RGBA, PGL.GL_UNSIGNED_BYTE);
pgl.initTexture(glTarget, PGL.GL_RGBA, width, height);
pgl.glBindTexture(glTarget, 0);
pgl.disableTexturing(glTarget);
@@ -819,12 +819,15 @@ public class PTexture implements PConstants {
if (scale) {
// Rendering tex into "this", and scaling the source rectangle
// to cover the entire destination region.
pg.drawTexture(tex, x, y, w, h, 0, 0, width, height);
pgl.drawTexture(tex.glTarget, tex.glID, tex.glWidth, tex.glHeight,
x, y, w, h, 0, 0, width, height);
} else {
// Rendering tex into "this" but without scaling so the contents
// of the source texture fall in the corresponding texels of the
// destination.
pg.drawTexture(tex, x, y, w, h, x, y, w, h);
pgl.drawTexture(tex.glTarget, tex.glID, tex.glWidth, tex.glHeight,
x, y, w, h, x, y, w, h);
}
pg.popFramebuffer();
}