Improved color conversion in PTexture, added YUV420 mode (android specific), finished implementation of blending modes (closes issue 290)

This commit is contained in:
codeanticode
2010-11-18 01:56:53 +00:00
parent aa0407e6e4
commit 8ed10cedb6
4 changed files with 218 additions and 104 deletions
@@ -55,7 +55,6 @@ public interface PConstants {
static public final int EDGE = 12;
// stroke
/** stroke argb values */
@@ -67,9 +66,6 @@ public interface PConstants {
/** stroke weight */
static public final int SW = 17;
// transformations (2D and 3D)
static public final int TX = 18; // transformed xyzw
static public final int TY = 19;
static public final int TZ = 20;
@@ -79,12 +75,6 @@ public interface PConstants {
static public final int VZ = 23;
static public final int VW = 24;
// material properties
// TODO: check whether we still need them in PGraphicsAndroid3D and if yes
// how the work in combination with the global material properties (ambient, diffuse,
// emissive, specular colors).
// Ambient color (usually to be kept the same as diffuse)
// fill(_) sets both ambient and diffuse.
static public final int AR = 25;
@@ -198,11 +188,12 @@ public interface PConstants {
// for colors and/or images
static final int RGB = 1; // image & color
static final int ARGB = 2; // image
static final int HSB = 3; // color
static final int ALPHA = 4; // image
static final int CMYK = 5; // image & color (someday)
static final int RGB = 1; // image & color
static final int ARGB = 2; // image
static final int HSB = 3; // color
static final int ALPHA = 4; // image
static final int CMYK = 5; // image & color (someday)
static final int YUV420 = 6; // android video preview.
// image file types
@@ -1043,7 +1043,7 @@ public class PGraphics extends PImage implements PConstants {
vertex[EG] = emissiveG;
vertex[EB] = emissiveB;
}
if (stroke) {
vertex[SR] = strokeR;
vertex[SG] = strokeG;
@@ -1061,7 +1061,8 @@ public class PGraphics extends PImage implements PConstants {
if (norm2 < EPSILON) {
vertex[HAS_NORMAL] = 0;
} else {
if (Math.abs(norm2 - 1) < EPSILON) {
if (Math.abs(norm2 - 1) > EPSILON) {
// The normal vector is not normalized.
float norm = PApplet.sqrt(norm2);
normalX /= norm;
normalY /= norm;
@@ -1607,9 +1607,9 @@ public class PGraphicsAndroid3D extends PGraphics {
int n = 0;
for (int i = start; i < stop; i++) {
float[] a = vertices[points[i][VERTEX1]];
vertexArray[3 * n + 0] = toFixed32(a[VX]);
vertexArray[3 * n + 1] = toFixed32(a[VY]);
vertexArray[3 * n + 2] = toFixed32(a[VZ]);
vertexArray[3 * n + 0] = toFixed32(a[X]);
vertexArray[3 * n + 1] = toFixed32(a[Y]);
vertexArray[3 * n + 2] = toFixed32(a[Z]);
colorArray[4 * n + 0] = toFixed32(a[SR]);
colorArray[4 * n + 1] = toFixed32(a[SG]);
colorArray[4 * n + 2] = toFixed32(a[SB]);
@@ -5082,11 +5082,14 @@ public class PGraphicsAndroid3D extends PGraphics {
/**
* Allows to set custom blend modes for the entire scene, using openGL.
* Reference article about blending modes:
* http://www.pegtop.net/delphi/articles/blendmodes/
*/
public void blend(int mode) {
blend = true;
blendMode = mode;
gl.glEnable(GL10.GL_BLEND);
if (mode == REPLACE) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_ONE, GL10.GL_ZERO);
@@ -5096,19 +5099,9 @@ public class PGraphicsAndroid3D extends PGraphics {
} else if (mode == ADD) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_ONE);
} else if (mode == MULTIPLY) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_DST_COLOR, GL10.GL_SRC_COLOR);
} else if (mode == SUBTRACT) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_ONE_MINUS_DST_COLOR, GL10.GL_ZERO);
} else if (mode == DARKEST) {
if (blendEqSupported) {
gl11xp.glBlendEquation(GL_MIN_EXT);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_DST_ALPHA);
} else {
PGraphics.showWarning("A3D: This blend mode is currently unsupported.");
}
} else if (mode == LIGHTEST) {
if (blendEqSupported) {
gl11xp.glBlendEquation(GL_MAX_EXT);
@@ -5116,6 +5109,13 @@ public class PGraphicsAndroid3D extends PGraphics {
} else {
PGraphics.showWarning("A3D: This blend mode is currently unsupported.");
}
} else if (mode == DARKEST) {
if (blendEqSupported) {
gl11xp.glBlendEquation(GL_MIN_EXT);
gl.glBlendFunc(GL10.GL_SRC_ALPHA, GL10.GL_DST_ALPHA);
} else {
PGraphics.showWarning("A3D: This blend mode is currently unsupported.");
}
} else if (mode == DIFFERENCE) {
if (blendEqSupported) {
gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_REVERSE_SUBTRACT);
@@ -5123,28 +5123,19 @@ public class PGraphicsAndroid3D extends PGraphics {
} else {
PGraphics.showWarning("A3D: This blend mode is currently unsupported.");
}
}
//gl11xp.glBlendEquation(arg0)
//gl11xp.glBlendEquationSeparate(arg0, arg1)
//gl11xp.glBlendFuncSeparate(arg0, arg1, arg2, arg3)
// TODO: implement all these other blending modes:
// else if (blend)
// else if (blendMode == EXCLUSION)
// else if (blendMode == SCREEN)
// else if (blendMode == OVERLAY)
// else if (blendMode == HARD_LIGHT)
// else if (blendMode == SOFT_LIGHT)
// else if (blendMode == DODGE)
// else if (blendMode == BURN)
// All the blending modes are explained here:
// http://www.pegtop.net/delphi/articles/blendmodes/
} else if (mode == EXCLUSION) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_ONE_MINUS_DST_COLOR, GL10.GL_ONE_MINUS_SRC_COLOR);
} else if (mode == MULTIPLY) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_DST_COLOR, GL10.GL_SRC_COLOR);
} else if (mode == SCREEN) {
if (blendEqSupported) gl11xp.glBlendEquation(GL11ExtensionPack.GL_FUNC_ADD);
gl.glBlendFunc(GL10.GL_ONE_MINUS_DST_COLOR, GL10.GL_ONE);
}
// HARD_LIGHT, SOFT_LIGHT, OVERLAY, DODGE, BURN modes cannot be implemented/
// in fixed-function pipeline because they require conditional blending and
// non-linear blending equations.
}
public void noBlend() {
+183 -52
View File
@@ -283,7 +283,7 @@ public class PTexture implements PConstants {
if (usingMipmaps) {
if (a3d.gl11 != null && PGraphicsAndroid3D.mipmapSupported) {
int[] rgbaPixels = new int[w * h];
convertToRGBA(pixels, rgbaPixels, format);
convertToRGBA(pixels, rgbaPixels, format, w, h);
gl.glTexParameterf(GL11.GL_TEXTURE_2D, GL11.GL_GENERATE_MIPMAP, GL11.GL_TRUE);
setTexels(x, y, w, h, rgbaPixels);
} else {
@@ -298,7 +298,7 @@ public class PTexture implements PConstants {
int w0 = glWidth;
int h0 = glHeight;
int[] argbPixels = new int[w0 * h0];
copyARGB(pixels, argbPixels);
convertToARGB(pixels, argbPixels, format);
int level = 0;
// We create a Bitmap because then we use its built-in filtered downsampling
@@ -330,7 +330,7 @@ public class PTexture implements PConstants {
}
} else {
int[] rgbaPixels = new int[w * h];
convertToRGBA(pixels, rgbaPixels, format);
convertToRGBA(pixels, rgbaPixels, format, w, h);
setTexels(x, y, w, h, rgbaPixels);
}
@@ -608,17 +608,22 @@ public class PTexture implements PConstants {
/**
* Reorders a pixel array in ARGB format into the order required by OpenGL (RGBA).
* Both arrays are assumed to be of the same length.
* Reorders a pixel array in the given format into the order required by OpenGL (RGBA).
* Both arrays are assumed to be of the same length. The width and height parameters
* are used in the YUV420 to RBGBA conversion.
* @param intArray int[]
* @param tIntArray int[]
* @param arrayFormat int
* @param w int
* @param h int
*/
protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat) {
protected void convertToRGBA(int[] intArray, int[] tIntArray, int arrayFormat, int w, int h) {
if (PGraphicsAndroid3D.BIG_ENDIAN) {
switch (arrayFormat) {
case ALPHA:
// Converting from xxxA into RGBA. RGB is set to white
// (0xFFFFFF, i.e.: (255, 255, 255))
for (int i = 0; i< intArray.length; i++) {
tIntArray[i] = 0xFFFFFF00 | intArray[i];
}
@@ -626,21 +631,54 @@ public class PTexture implements PConstants {
case RGB:
// Converting xRGB into RGBA. A is set to 0xFF (255, full opacity).
for (int i = 0; i< intArray.length; i++) {
int pixel = intArray[i];
tIntArray[i] = (pixel << 8) | 0xff;
tIntArray[i] = (pixel << 8) | 0xFF;
}
break;
case ARGB:
// Converting ARGB into RGBA. Shifting RGB to 8 bits to the left,
// and bringing A to the first byte.
for (int i = 0; i< intArray.length; i++) {
int pixel = intArray[i];
tIntArray[i] = (pixel << 8) | ((pixel >> 24) & 0xff);
tIntArray[i] = (pixel << 8) | ((pixel >> 24) & 0xFF);
}
break;
}
case YUV420:
// YUV420 to RGBA conversion.
int frameSize = w * h;
for (int j = 0, yp = 0; j < h; j++) {
int uvp = frameSize + (j >> 1) * w, u = 0, v = 0;
for (int i = 0; i < w; i++, yp++) {
int y = (0xFF & ((int) intArray[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xFF & intArray[uvp++]) - 128;
u = (0xFF & intArray[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
// Output is RGBA:
tIntArray[yp] = ((r << 6) & 0xFF000000) | ((g >> 2) & 0xFF0000) | ((b >> 10) & 0xFF00) | 0xFF;
}
}
break;
}
} else {
// LITTLE_ENDIAN
// ARGB native, and RGBA opengl means ABGR on windows
@@ -651,18 +689,19 @@ public class PTexture implements PConstants {
switch (arrayFormat) {
case ALPHA:
// Converting xxxA into ARGB, with RGB set to white.
for (int i = 0; i< intArray.length; i++) {
tIntArray[i] = (intArray[i] << 24) | 0x00FFFFFF;
}
break;
case RGB:
// We need to convert xRGB into ABGR,
// so R and B must be swapped, and the x just made 0xFF.
for (int i = 0; i< intArray.length; i++) {
int pixel = intArray[i];
// needs to be ABGR, stored in memory xRGB
// so R and B must be swapped, and the x just made FF
tIntArray[i] = 0xff000000 | // force opacity for good measure
int pixel = intArray[i];
tIntArray[i] = 0xFF000000 |
((pixel & 0xFF) << 16) |
((pixel & 0xFF0000) >> 16) |
(pixel & 0x0000FF00);
@@ -671,81 +710,173 @@ public class PTexture implements PConstants {
case ARGB:
// We need to convert ARGB into ABGR,
// so R and B must be swapped, A and G just brought back in.
for (int i = 0; i< intArray.length; i++) {
int pixel = intArray[i];
// needs to be ABGR stored in memory ARGB
// so R and B must be swapped, A and G just brought back in
tIntArray[i] = ((pixel & 0xFF) << 16) |
((pixel & 0xFF0000) >> 16) |
(pixel & 0xFF00FF00);
}
break;
case YUV420:
// YUV420 to ABGR conversion.
int frameSize = w * h;
for (int j = 0, yp = 0; j < h; j++) {
int uvp = frameSize + (j >> 1) * w, u = 0, v = 0;
for (int i = 0; i < w; i++, yp++) {
int y = (0xFF & ((int) intArray[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xFF & intArray[uvp++]) - 128;
u = (0xFF & intArray[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
// Output is ABGR:
tIntArray[yp] = 0xFF000000 | ((b << 6) & 0xFF0000) | ((g >> 2) & 0xFF00) | ((r >> 10) & 0xFF);
}
}
break;
}
}
}
/**
* Reorders a pixel array in RGBA format into ARGB. The input array must be
* of size glWidth * glHeight, while the resulting array will be of size width * height.
* Reorders a pixel array in a given format into ARGB. The input array must be
* of size width * height, while the output array must be of glWidth * glHeight.
* @param intArray int[]
* @param intArray int[]
* @param arrayFormat int
*/
protected void convertToARGB(int[] intArray, int[] tIntArray, int arrayFormat) {
int t = 0;
int p = 0;
int pixel;
switch (arrayFormat) {
case ALPHA:
// xxxA to ARGB, setting RGB to black.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixel = intArray[p++];
tIntArray[t++] = (pixel << 24) & 0xFF000000;
}
t += glWidth - width;
}
break;
case RGB:
// xRGB to ARGB, setting A to be 0xFF.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
pixel = intArray[p++];
tIntArray[t++] = pixel | 0xFF000000;
}
t += glWidth - width;
}
break;
case ARGB:
// ARGB to ARGB, where the source is smaller than the destination.
for (int y = 0; y < height; y++) {
PApplet.arrayCopy(intArray, width * y, tIntArray, glWidth * y, width);
}
break;
case YUV420:
// YUV420 to ARGB conversion.
int frameSize = width * height;
for (int j = 0, yp = 0, yt = 0; j < height; j++) {
int uvp = frameSize + (j >> 1) * width, u = 0, v = 0;
for (int i = 0; i < width; i++, yp++) {
int y = (0xFF & ((int) intArray[yp])) - 16;
if (y < 0) y = 0;
if ((i & 1) == 0) {
v = (0xFF & intArray[uvp++]) - 128;
u = (0xFF & intArray[uvp++]) - 128;
}
int y1192 = 1192 * y;
int r = (y1192 + 1634 * v);
int g = (y1192 - 833 * v - 400 * u);
int b = (y1192 + 2066 * u);
if (r < 0) r = 0; else if (r > 262143) r = 262143;
if (g < 0) g = 0; else if (g > 262143) g = 262143;
if (b < 0) b = 0; else if (b > 262143) b = 262143;
// Output is ARGB:
tIntArray[yt++] = 0xFF000000 | ((r << 6) & 0xFF0000) | ((g >> 2) & 0xFF00) | ((b >> 10) & 0xFF);
}
yt += glWidth - width;
}
break;
}
}
/**
* Reorders an OpenGL pixel array (RGBA) into ARGB. The input array must be
* of size glWidth * glHeight, while the resulting array of size width * height.
* @param intArray int[]
* @param intArray int[]
*/
protected void convertToARGB(int[] intArray, int[] tIntArray) {
int t = 0;
int p = 0;
if (PGraphicsAndroid3D.BIG_ENDIAN) {
// RGBA to ARGB conversion: shifting RGB 8 bits to the right,
// and placing A 24 bits to the left.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = intArray[p++];
tIntArray[t++] = (pixel >> 8) | ((pixel << 24) & 0xff);
tIntArray[t++] = (pixel >> 8) | ((pixel << 24) & 0xFF000000);
}
p += glWidth - width;
}
} else {
// LITTLE_ENDIAN
// ARGB native, and RGBA opengl means ABGR on windows
// for the most part just need to swap two components here
// the sun.cpu.endian here might be "false", oddly enough..
// (that's why just using an "else", rather than check for "little")
// We have to convert ABGR into ARGB, so R and B must be swapped,
// A and G just brought back in.
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
int pixel = intArray[p++];
// needs to be ARGB stored in memory ABGR (RGBA = ABGR -> ARGB)
// so R and B must be swapped, A and G just brought back in
tIntArray[t++] = ((pixel & 0xFF) << 16) |
((pixel & 0xFF0000) >> 16) |
(pixel & 0xFF00FF00);
((pixel & 0xFF0000) >> 16) |
(pixel & 0xFF00FF00);
}
p += glWidth - width;
}
}
}
/**
* Copies the pixel array in ARGB intArray into cIntArray. The size of the incoming
* array is assumed to be width * height, and the size of the returned array is
* glWidth * glHeight.
* @param intArray int[]
* @param cIntArray int[]
*/
protected void copyARGB(int[] intArray, int[] cIntArray) {
int t = 0;
int p = 0;
for (int y = 0; y < height; y++) {
for (int x = 0; x < width; x++) {
cIntArray[t++] = intArray[p++];
}
t += glWidth - width;
}
}
}
///////////////////////////////////////////////////////////