diff options
Diffstat (limited to 'graphics')
97 files changed, 10609 insertions, 3334 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index dd83c3b..12dc93c 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -19,7 +19,6 @@ package android.graphics; import android.os.Parcel; import android.os.Parcelable; import android.util.DisplayMetrics; - import java.io.OutputStream; import java.nio.Buffer; import java.nio.ByteBuffer; @@ -27,6 +26,7 @@ import java.nio.IntBuffer; import java.nio.ShortBuffer; public final class Bitmap implements Parcelable { + /** * Indicates that the bitmap was created for an unknown pixel density. * @@ -35,9 +35,25 @@ public final class Bitmap implements Parcelable { */ public static final int DENSITY_NONE = 0; - // Note: mNativeBitmap is used by FaceDetector_jni.cpp - // Don't change/rename without updating FaceDetector_jni.cpp - private final int mNativeBitmap; + /** + * Note: mNativeBitmap is used by FaceDetector_jni.cpp + * Don't change/rename without updating FaceDetector_jni.cpp + * + * @hide + */ + public final int mNativeBitmap; + + /** + * Backing buffer for the Bitmap. + * Made public for quick access from drawing methods -- do NOT modify + * from outside this class. + * + * @hide + */ + public byte[] mBuffer; + + @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) // Keep to finalize native resources + private final BitmapFinalizer mFinalizer; private final boolean mIsMutable; private byte[] mNinePatchChunk; // may be null @@ -51,7 +67,7 @@ public final class Bitmap implements Parcelable { private static volatile Matrix sScaleMatrix; private static volatile int sDefaultDensity = -1; - + /** * For backwards compatibility, allows the app layer to change the default * density when running old apps. @@ -77,14 +93,17 @@ public final class Bitmap implements Parcelable { This can be called from JNI code. */ - private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk, + private Bitmap(int nativeBitmap, byte[] buffer, boolean isMutable, byte[] ninePatchChunk, int density) { if (nativeBitmap == 0) { throw new RuntimeException("internal error: native bitmap is 0"); } + mBuffer = buffer; // we delete this in our finalizer mNativeBitmap = nativeBitmap; + mFinalizer = new BitmapFinalizer(nativeBitmap); + mIsMutable = isMutable; mNinePatchChunk = ninePatchChunk; if (density >= 0) { @@ -145,16 +164,19 @@ public final class Bitmap implements Parcelable { } /** - * Free up the memory associated with this bitmap's pixels, and mark the - * bitmap as "dead", meaning it will throw an exception if getPixels() or - * setPixels() is called, and will draw nothing. This operation cannot be - * reversed, so it should only be called if you are sure there are no + * Free the native object associated with this bitmap, and clear the + * reference to the pixel data. This will not free the pixel data synchronously; + * it simply allows it to be garbage collected if there are no other references. + * The bitmap is marked as "dead", meaning it will throw an exception if + * getPixels() or setPixels() is called, and will draw nothing. This operation + * cannot be reversed, so it should only be called if you are sure there are no * further uses for the bitmap. This is an advanced call, and normally need * not be called, since the normal GC process will free up this memory when * there are no more references to this bitmap. */ public void recycle() { if (!mRecycled) { + mBuffer = null; nativeRecycle(mNativeBitmap); mNinePatchChunk = null; mRecycled = true; @@ -172,6 +194,17 @@ public final class Bitmap implements Parcelable { } /** + * Returns the generation ID of this bitmap. The generation ID changes + * whenever the bitmap is modified. This can be used as an efficient way to + * check if a bitmap has changed. + * + * @return The current generation ID for this bitmap. + */ + public int getGenerationId() { + return nativeGenerationId(mNativeBitmap); + } + + /** * This is called by methods that want to throw an exception if the bitmap * has already been recycled. */ @@ -211,25 +244,80 @@ public final class Bitmap implements Parcelable { } } + /** + * Possible bitmap configurations. A bitmap configuration describes + * how pixels are stored. This affects the quality (color depth) as + * well as the ability to display transparent/translucent colors. + */ public enum Config { // these native values must match up with the enum in SkBitmap.h + + /** + * Each pixel is stored as a single translucency (alpha) channel. + * This is very useful to efficiently store masks for instance. + * No color information is stored. + * With this configuration, each pixel requires 1 byte of memory. + */ ALPHA_8 (2), + + /** + * Each pixel is stored on 2 bytes and only the RGB channels are + * encoded: red is stored with 5 bits of precision (32 possible + * values), green is stored with 6 bits of precision (64 possible + * values) and blue is stored with 5 bits of precision. + * + * This configuration can produce slight visual artifacts depending + * on the configuration of the source. For instance, without + * dithering, the result might show a greenish tint. To get better + * results dithering should be applied. + * + * This configuration may be useful when using opaque bitmaps + * that do not require high color fidelity. + */ RGB_565 (4), + + /** + * Each pixel is stored on 2 bytes. The three RGB color channels + * and the alpha channel (translucency) are stored with a 4 bits + * precision (16 possible values.) + * + * This configuration is mostly useful if the application needs + * to store translucency information but also needs to save + * memory. + * + * It is recommended to use {@link #ARGB_8888} instead of this + * configuration. + * + * @deprecated Because of the poor quality of this configuration, + * it is advised to use {@link #ARGB_8888} instead. + */ + @Deprecated ARGB_4444 (5), + + /** + * Each pixel is stored on 4 bytes. Each channel (RGB and alpha + * for translucency) is stored with 8 bits of precision (256 + * possible values.) + * + * This configuration is very flexible and offers the best + * quality. It should be used whenever possible. + */ ARGB_8888 (6); + final int nativeInt; + + @SuppressWarnings({"deprecation"}) + private static Config sConfigs[] = { + null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 + }; + Config(int ni) { this.nativeInt = ni; } - final int nativeInt; - /* package */ static Config nativeToConfig(int ni) { + static Config nativeToConfig(int ni) { return sConfigs[ni]; } - - private static Config sConfigs[] = { - null, null, ALPHA_8, null, RGB_565, ARGB_4444, ARGB_8888 - }; } /** @@ -253,7 +341,7 @@ public final class Bitmap implements Parcelable { } long bufferSize = (long)elements << shift; - long pixelSize = (long)getRowBytes() * getHeight(); + long pixelSize = getByteCount(); if (bufferSize < pixelSize) { throw new RuntimeException("Buffer not large enough for pixels"); @@ -289,7 +377,7 @@ public final class Bitmap implements Parcelable { } long bufferBytes = (long)elements << shift; - long bitmapBytes = (long)getRowBytes() * getHeight(); + long bitmapBytes = getByteCount(); if (bufferBytes < bitmapBytes) { throw new RuntimeException("Buffer not large enough for pixels"); @@ -428,28 +516,47 @@ public final class Bitmap implements Parcelable { Rect srcR = new Rect(x, y, x + width, y + height); RectF dstR = new RectF(0, 0, width, height); + Config newConfig = Config.ARGB_8888; + final Config config = source.getConfig(); + // GIF files generate null configs, assume ARGB_8888 + if (config != null) { + switch (config) { + case RGB_565: + newConfig = Config.RGB_565; + break; + case ALPHA_8: + newConfig = Config.ALPHA_8; + break; + //noinspection deprecation + case ARGB_4444: + case ARGB_8888: + default: + newConfig = Config.ARGB_8888; + break; + } + } + if (m == null || m.isIdentity()) { - bitmap = createBitmap(neww, newh, - source.hasAlpha() ? Config.ARGB_8888 : Config.RGB_565); + bitmap = createBitmap(neww, newh, newConfig, source.hasAlpha()); paint = null; // not needed } else { - /* the dst should have alpha if the src does, or if our matrix - doesn't preserve rectness - */ - boolean hasAlpha = source.hasAlpha() || !m.rectStaysRect(); + final boolean transformed = !m.rectStaysRect(); + RectF deviceR = new RectF(); m.mapRect(deviceR, dstR); + neww = Math.round(deviceR.width()); newh = Math.round(deviceR.height()); - bitmap = createBitmap(neww, newh, hasAlpha ? Config.ARGB_8888 : Config.RGB_565); - if (hasAlpha) { - bitmap.eraseColor(0); - } + + bitmap = createBitmap(neww, newh, transformed ? Config.ARGB_8888 : newConfig, + transformed || source.hasAlpha()); + canvas.translate(-deviceR.left, -deviceR.top); canvas.concat(m); + paint = new Paint(); paint.setFilterBitmap(filter); - if (!m.rectStaysRect()) { + if (transformed) { paint.setAntiAlias(true); } } @@ -474,8 +581,33 @@ public final class Bitmap implements Parcelable { * @throws IllegalArgumentException if the width or height are <= 0 */ public static Bitmap createBitmap(int width, int height, Config config) { + return createBitmap(width, height, config, true); + } + + /** + * Returns a mutable bitmap with the specified width and height. Its + * initial density is as per {@link #getDensity}. + * + * @param width The width of the bitmap + * @param height The height of the bitmap + * @param config The bitmap config to create. + * @param hasAlpha If the bitmap is ARGB_8888 this flag can be used to mark the + * bitmap as opaque. Doing so will clear the bitmap in black + * instead of transparent. + * + * @throws IllegalArgumentException if the width or height are <= 0 + */ + private static Bitmap createBitmap(int width, int height, Config config, boolean hasAlpha) { + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("width and height must be > 0"); + } Bitmap bm = nativeCreate(null, 0, width, width, height, config.nativeInt, true); - bm.eraseColor(0); // start with black/transparent pixels + if (config == Config.ARGB_8888 && !hasAlpha) { + bm.eraseColor(0xff000000); + nativeSetHasAlpha(bm.mNativeBitmap, hasAlpha); + } else { + bm.eraseColor(0); + } return bm; } @@ -510,6 +642,9 @@ public final class Bitmap implements Parcelable { (lastScanline + width > length)) { throw new ArrayIndexOutOfBoundsException(); } + if (width <= 0 || height <= 0) { + throw new IllegalArgumentException("width and height must be > 0"); + } return nativeCreate(colors, offset, stride, width, height, config.nativeInt, false); } @@ -670,7 +805,7 @@ public final class Bitmap implements Parcelable { } // Scale by tdensity / sdensity, rounding up. - return ( (size * tdensity) + (sdensity >> 1) ) / sdensity; + return ((size * tdensity) + (sdensity >> 1)) / sdensity; } /** @@ -686,6 +821,14 @@ public final class Bitmap implements Parcelable { } /** + * Returns the number of bytes used to store this bitmap's pixels. + */ + public final int getByteCount() { + // int result permits bitmaps up to 46,340 x 46,340 + return getRowBytes() * getHeight(); + } + + /** * If the bitmap's internal config is in one of the public formats, return * that config, otherwise return null. */ @@ -708,14 +851,12 @@ public final class Bitmap implements Parcelable { /** * Tell the bitmap if all of the pixels are known to be opaque (false) * or if some of the pixels may contain non-opaque alpha values (true). - * Note, for some configs (e.g. RGB_565) this call is ignore, since it does - * not support per-pixel alpha values. + * Note, for some configs (e.g. RGB_565) this call is ignored, since it + * does not support per-pixel alpha values. * * This is meant as a drawing hint, as in some cases a bitmap that is known * to be opaque can take a faster drawing case than one that may have * non-opaque per-pixel alpha values. - * - * @hide */ public void setHasAlpha(boolean hasAlpha) { nativeSetHasAlpha(mNativeBitmap, hasAlpha); @@ -984,13 +1125,9 @@ public final class Bitmap implements Parcelable { * Given another bitmap, return true if it has the same dimensions, config, * and pixel data as this bitmap. If any of those differ, return false. * If other is null, return false. - * - * @hide (just needed internally right now) */ public boolean sameAs(Bitmap other) { - return this == other || - (other != null && - nativeSameAs(mNativeBitmap, other.mNativeBitmap)); + return this == other || (other != null && nativeSameAs(mNativeBitmap, other.mNativeBitmap)); } /** @@ -1008,12 +1145,22 @@ public final class Bitmap implements Parcelable { nativePrepareToDraw(mNativeBitmap); } - @Override - protected void finalize() throws Throwable { - try { - nativeDestructor(mNativeBitmap); - } finally { - super.finalize(); + private static class BitmapFinalizer { + private final int mNativeBitmap; + + BitmapFinalizer(int nativeBitmap) { + mNativeBitmap = nativeBitmap; + } + + @Override + public void finalize() { + try { + super.finalize(); + } catch (Throwable t) { + // Ignore + } finally { + nativeDestructor(mNativeBitmap); + } } } @@ -1050,6 +1197,7 @@ public final class Bitmap implements Parcelable { private static native void nativeCopyPixelsToBuffer(int nativeBitmap, Buffer dst); private static native void nativeCopyPixelsFromBuffer(int nb, Buffer src); + private static native int nativeGenerationId(int nativeBitmap); private static native Bitmap nativeCreateFromParcel(Parcel p); // returns true on success @@ -1065,7 +1213,7 @@ public final class Bitmap implements Parcelable { private static native void nativePrepareToDraw(int nativeBitmap); private static native void nativeSetHasAlpha(int nBitmap, boolean hasAlpha); private static native boolean nativeSameAs(int nb0, int nb1); - + /* package */ final int ni() { return mNativeBitmap; } diff --git a/graphics/java/android/graphics/BitmapFactory.java b/graphics/java/android/graphics/BitmapFactory.java index 3f1a566..8d17561 100644 --- a/graphics/java/android/graphics/BitmapFactory.java +++ b/graphics/java/android/graphics/BitmapFactory.java @@ -18,7 +18,6 @@ package android.graphics; import android.content.res.AssetManager; import android.content.res.Resources; -import android.os.MemoryFile; import android.util.DisplayMetrics; import android.util.TypedValue; @@ -44,6 +43,35 @@ public class BitmapFactory { } /** + * If set, decode methods that take the Options object will attempt to + * reuse this bitmap when loading content. If the decode operation cannot + * use this bitmap, the decode method will return <code>null</code> and + * will throw an IllegalArgumentException. The + * current implementation necessitates that the reused bitmap be of the + * same size as the source content and in jpeg or png format (whether as a + * resource or as a stream). The {@link android.graphics.Bitmap.Config + * configuration} of the reused bitmap will override the setting of + * {@link #inPreferredConfig}, if set. + * + * <p>You should still always use the returned Bitmap of the decode + * method and not assume that reusing the bitmap worked, due to the + * constraints outlined above and failure situations that can occur. + * Checking whether the return value matches the value of the inBitmap + * set in the Options structure is a way to see if the bitmap was reused, + * but in all cases you should use the returned Bitmap to make sure + * that you are using the bitmap that was used as the decode destination.</p> + */ + public Bitmap inBitmap; + + /** + * If set, decode methods will always return a mutable Bitmap instead of + * an immutable one. This can be used for instance to programmatically apply + * effects to a Bitmap loaded through BitmapFactory. + */ + @SuppressWarnings({"UnusedDeclaration"}) // used in native code + public boolean inMutable; + + /** * If set to true, the decoder will return null (no bitmap), but * the out... fields will still be set, allowing the caller to query * the bitmap without having to allocate the memory for its pixels. @@ -84,7 +112,7 @@ public class BitmapFactory { /** * The pixel density to use for the bitmap. This will always result * in the returned bitmap having a density set for it (see - * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)). In addition, + * {@link Bitmap#setDensity(int) Bitmap.setDensity(int)}). In addition, * if {@link #inScaled} is set (which it is by default} and this * density does not match {@link #inTargetDensity}, then the bitmap * will be scaled to the target density before being returned. @@ -193,19 +221,6 @@ public class BitmapFactory { public boolean inInputShareable; /** - * Normally bitmap allocations count against the dalvik heap, which - * means they help trigger GCs when a lot have been allocated. However, - * in rare cases, the caller may want to allocate the bitmap outside of - * that heap. To request that, set inNativeAlloc to true. In these - * rare instances, it is solely up to the caller to ensure that OOM is - * managed explicitly by calling bitmap.recycle() as soon as such a - * bitmap is no longer needed. - * - * @hide pending API council approval - */ - public boolean inNativeAlloc; - - /** * If inPreferQualityOverSpeed is set to true, the decoder will try to * decode the reconstructed image to a higher quality even at the * expense of the decoding speed. Currently the field only affects JPEG @@ -225,7 +240,7 @@ public class BitmapFactory { /** * The resulting height of the bitmap, set independent of the state of * inJustDecodeBounds. However, if there is an error trying to decode, - * outHeight will be set to -1. + * outHeight will be set to -1. */ public int outHeight; @@ -370,6 +385,10 @@ public class BitmapFactory { } } + if (bm == null && opts != null && opts.inBitmap != null) { + throw new IllegalArgumentException("Problem decoding into existing bitmap"); + } + return bm; } @@ -402,7 +421,11 @@ public class BitmapFactory { if ((offset | length) < 0 || data.length < offset + length) { throw new ArrayIndexOutOfBoundsException(); } - return nativeDecodeByteArray(data, offset, length, opts); + Bitmap bm = nativeDecodeByteArray(data, offset, length, opts); + if (bm == null && opts != null && opts.inBitmap != null) { + throw new IllegalArgumentException("Problem decoding into existing bitmap"); + } + return bm; } /** @@ -469,6 +492,9 @@ public class BitmapFactory { if (tempStorage == null) tempStorage = new byte[16 * 1024]; bm = nativeDecodeStream(is, tempStorage, outPadding, opts); } + if (bm == null && opts != null && opts.inBitmap != null) { + throw new IllegalArgumentException("Problem decoding into existing bitmap"); + } return finishDecode(bm, outPadding, opts); } @@ -505,7 +531,7 @@ public class BitmapFactory { } bm.setDensity(targetDensity); } - + return bm; } @@ -517,9 +543,7 @@ public class BitmapFactory { * * @param is The input stream that holds the raw data to be decoded into a * bitmap. - * @return The decoded bitmap, or null if the image data could not be - * decoded, or, if opts is non-null, if opts requested only the - * size be returned (in opts.outWidth and opts.outHeight) + * @return The decoded bitmap, or null if the image data could not be decoded. */ public static Bitmap decodeStream(InputStream is) { return decodeStream(is, null, null); @@ -540,20 +564,22 @@ public class BitmapFactory { * @return the decoded bitmap, or null */ public static Bitmap decodeFileDescriptor(FileDescriptor fd, Rect outPadding, Options opts) { - try { - if (MemoryFile.isMemoryFile(fd)) { - int mappedlength = MemoryFile.getSize(fd); - MemoryFile file = new MemoryFile(fd, mappedlength, "r"); - InputStream is = file.getInputStream(); - Bitmap bm = decodeStream(is, outPadding, opts); - return finishDecode(bm, outPadding, opts); + if (nativeIsSeekable(fd)) { + Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts); + if (bm == null && opts != null && opts.inBitmap != null) { + throw new IllegalArgumentException("Problem decoding into existing bitmap"); + } + return finishDecode(bm, outPadding, opts); + } else { + FileInputStream fis = new FileInputStream(fd); + try { + return decodeStream(fis, outPadding, opts); + } finally { + try { + fis.close(); + } catch (Throwable t) {/* ignore */} } - } catch (IOException ex) { - // invalid filedescriptor, no need to call nativeDecodeFileDescriptor() - return null; } - Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts); - return finishDecode(bm, outPadding, opts); } /** @@ -600,4 +626,5 @@ public class BitmapFactory { private static native Bitmap nativeDecodeByteArray(byte[] data, int offset, int length, Options opts); private static native byte[] nativeScaleNinePatch(byte[] chunk, float scale, Rect pad); + private static native boolean nativeIsSeekable(FileDescriptor fd); } diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 612b0ab..f74d0ef 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -16,10 +16,17 @@ package android.graphics; +/** + * Shader used to draw a bitmap as a texture. The bitmap can be repeated or + * mirrored by setting the tiling mode. + */ public class BitmapShader extends Shader { - - // we hold on just for the GC, since our native counterpart is using it - private Bitmap mBitmap; + /** + * Prevent garbage collection. + * @hide + */ + @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) + public final Bitmap mBitmap; /** * Call this to create a new shader that will draw with a bitmap. @@ -30,12 +37,13 @@ public class BitmapShader extends Shader { */ public BitmapShader(Bitmap bitmap, TileMode tileX, TileMode tileY) { mBitmap = bitmap; - native_instance = nativeCreate(bitmap.ni(), - tileX.nativeInt, tileY.nativeInt); + final int b = bitmap.ni(); + native_instance = nativeCreate(b, tileX.nativeInt, tileY.nativeInt); + native_shader = nativePostCreate(native_instance, b, tileX.nativeInt, tileY.nativeInt); } - private static native int nativeCreate(int native_bitmap, - int shaderTileModeX, - int shaderTileModeY); + private static native int nativeCreate(int native_bitmap, int shaderTileModeX, + int shaderTileModeY); + private static native int nativePostCreate(int native_shader, int native_bitmap, + int shaderTileModeX, int shaderTileModeY); } - diff --git a/graphics/java/android/graphics/Camera.java b/graphics/java/android/graphics/Camera.java index 530655f..7ef35a9 100644 --- a/graphics/java/android/graphics/Camera.java +++ b/graphics/java/android/graphics/Camera.java @@ -16,24 +16,115 @@ package android.graphics; - +/** + * A camera instance can be used to compute 3D transformations and + * generate a matrix that can be applied, for instance, on a + * {@link Canvas}. + */ public class Camera { - + /** + * Creates a new camera, with empty transformations. + */ public Camera() { nativeConstructor(); } + /** + * Saves the camera state. Each save should be balanced + * with a call to {@link #restore()}. + * + * @see #save() + */ public native void save(); + + /** + * Restores the saved state, if any. + * + * @see #restore() + */ public native void restore(); + /** + * Applies a translation transform on all three axis. + * + * @param x The distance to translate by on the X axis + * @param y The distance to translate by on the Y axis + * @param z The distance to translate by on the Z axis + */ public native void translate(float x, float y, float z); + + /** + * Applies a rotation transform around the X axis. + * + * @param deg The angle of rotation around the X axis, in degrees + * + * @see #rotateY(float) + * @see #rotateZ(float) + * @see #rotate(float, float, float) + */ public native void rotateX(float deg); + + /** + * Applies a rotation transform around the Y axis. + * + * @param deg The angle of rotation around the Y axis, in degrees + * + * @see #rotateX(float) + * @see #rotateZ(float) + * @see #rotate(float, float, float) + */ public native void rotateY(float deg); + + /** + * Applies a rotation transform around the Z axis. + * + * @param deg The angle of rotation around the Z axis, in degrees + * + * @see #rotateX(float) + * @see #rotateY(float) + * @see #rotate(float, float, float) + */ public native void rotateZ(float deg); + /** + * Applies a rotation transform around all three axis. + * + * @param x The angle of rotation around the X axis, in degrees + * @param y The angle of rotation around the Y axis, in degrees + * @param z The angle of rotation around the Z axis, in degrees + * + * @see #rotateX(float) + * @see #rotateY(float) + * @see #rotateZ(float) + */ + public native void rotate(float x, float y, float z); + + /** + * Sets the location of the camera. The default location is set at + * 0, 0, -8. + * + * @param x The x location of the camera + * @param y The y location of the camera + * @param z The z location of the camera + */ + public native void setLocation(float x, float y, float z); + + /** + * Computes the matrix corresponding to the current transformation + * and copies it to the supplied matrix object. + * + * @param matrix The matrix to copy the current transforms into + */ public void getMatrix(Matrix matrix) { nativeGetMatrix(matrix.native_instance); } + + /** + * Computes the matrix corresponding to the current transformation + * and applies it to the specified Canvas. + * + * @param canvas The Canvas to set the transform matrix onto + */ public void applyToCanvas(Canvas canvas) { nativeApplyToCanvas(canvas.mNativeCanvas); } @@ -41,7 +132,11 @@ public class Camera { public native float dotWithNormal(float dx, float dy, float dz); protected void finalize() throws Throwable { - nativeDestructor(); + try { + nativeDestructor(); + } finally { + super.finalize(); + } } private native void nativeConstructor(); @@ -51,4 +146,3 @@ public class Camera { int native_instance; } - diff --git a/graphics/java/android/graphics/Canvas.java b/graphics/java/android/graphics/Canvas.java index a587d0d..965abe9 100644 --- a/graphics/java/android/graphics/Canvas.java +++ b/graphics/java/android/graphics/Canvas.java @@ -16,11 +16,10 @@ package android.graphics; -import android.text.TextUtils; -import android.text.SpannedString; -import android.text.SpannableString; import android.text.GraphicsOperations; -import android.util.DisplayMetrics; +import android.text.SpannableString; +import android.text.SpannedString; +import android.text.TextUtils; import javax.microedition.khronos.opengles.GL; @@ -43,22 +42,62 @@ public class Canvas { for both to be null. */ private Bitmap mBitmap; // if not null, mGL must be null - private GL mGL; // if not null, mBitmap must be null // optional field set by the caller - private DrawFilter mDrawFilter; + private DrawFilter mDrawFilter; - // Package-scoped for quick access. - /*package*/ int mDensity = Bitmap.DENSITY_NONE; + /** + * @hide + */ + protected int mDensity = Bitmap.DENSITY_NONE; - // Used to determine when compatibility scaling is in effect. - private int mScreenDensity = Bitmap.DENSITY_NONE; + /** + * Used to determine when compatibility scaling is in effect. + * + * @hide + */ + protected int mScreenDensity = Bitmap.DENSITY_NONE; // Used by native code @SuppressWarnings({"UnusedDeclaration"}) private int mSurfaceFormat; /** + * Flag for drawTextRun indicating left-to-right run direction. + * @hide + */ + public static final int DIRECTION_LTR = 0; + + /** + * Flag for drawTextRun indicating right-to-left run direction. + * @hide + */ + public static final int DIRECTION_RTL = 1; + + // This field is used to finalize the native Canvas properly + @SuppressWarnings({"UnusedDeclaration"}) + private final CanvasFinalizer mFinalizer; + + private static class CanvasFinalizer { + private final int mNativeCanvas; + + public CanvasFinalizer(int nativeCanvas) { + mNativeCanvas = nativeCanvas; + } + + @Override + protected void finalize() throws Throwable { + try { + if (mNativeCanvas != 0) { + finalizer(mNativeCanvas); + } + } finally { + super.finalize(); + } + } + } + + /** * Construct an empty raster canvas. Use setBitmap() to specify a bitmap to * draw into. The initial target density is {@link Bitmap#DENSITY_NONE}; * this will typically be replaced when a target bitmap is set for the @@ -67,6 +106,7 @@ public class Canvas { public Canvas() { // 0 means no native bitmap mNativeCanvas = initRaster(0); + mFinalizer = new CanvasFinalizer(mNativeCanvas); } /** @@ -85,51 +125,45 @@ public class Canvas { } throwIfRecycled(bitmap); mNativeCanvas = initRaster(bitmap.ni()); + mFinalizer = new CanvasFinalizer(mNativeCanvas); mBitmap = bitmap; mDensity = bitmap.mDensity; } - /*package*/ Canvas(int nativeCanvas) { + Canvas(int nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); } mNativeCanvas = nativeCanvas; + mFinalizer = new CanvasFinalizer(nativeCanvas); mDensity = Bitmap.getDefaultDensity(); } - + /** - * Construct a canvas with the specified gl context. All drawing through - * this canvas will be redirected to OpenGL. Note: some features may not - * be supported in this mode (e.g. some GL implementations may not support - * antialiasing or certain effects like ColorMatrix or certain Xfermodes). - * However, no exception will be thrown in those cases. + * Returns null. * - * <p>The initial target density of the canvas is the same as the initial - * density of bitmaps as per {@link Bitmap#getDensity() Bitmap.getDensity()}. - */ - public Canvas(GL gl) { - mNativeCanvas = initGL(); - mGL = gl; - mDensity = Bitmap.getDefaultDensity(); - } - - /** - * Return the GL object associated with this canvas, or null if it is not - * backed by GL. + * @deprecated This method is not supported and should not be invoked. + * + * @hide */ - public GL getGL() { - return mGL; + @Deprecated + protected GL getGL() { + return null; } - + /** - * Call this to free up OpenGL resources that may be cached or allocated - * on behalf of the Canvas. Any subsequent drawing with a GL-backed Canvas - * will have to recreate those resources. + * Indicates whether this Canvas uses hardware acceleration. + * + * Note that this method does not define what type of hardware acceleration + * may or may not be used. + * + * @return True if drawing operations are hardware accelerated, + * false otherwise. */ - public static void freeGlCaches() { - freeCaches(); + public boolean isHardwareAccelerated() { + return false; } - + /** * Specify a bitmap for the canvas to draw into. As a side-effect, also * updates the canvas's target density to match that of the bitmap. @@ -143,7 +177,7 @@ public class Canvas { if (!bitmap.isMutable()) { throw new IllegalStateException(); } - if (mGL != null) { + if (isHardwareAccelerated()) { throw new RuntimeException("Can't set a bitmap device on a GL canvas"); } throwIfRecycled(bitmap); @@ -157,13 +191,12 @@ public class Canvas { * Set the viewport dimensions if this canvas is GL based. If it is not, * this method is ignored and no exception is thrown. * - * @param width The width of the viewport - * @param height The height of the viewport + * @param width The width of the viewport + * @param height The height of the viewport + * + * @hide */ public void setViewport(int width, int height) { - if (mGL != null) { - nativeSetViewport(mNativeCanvas, width, height); - } } /** @@ -377,8 +410,8 @@ public class Canvas { * * @param sx The amount to scale in X * @param sy The amount to scale in Y - * @param px The x-coord for the pivot point (unchanged by the rotation) - * @param py The y-coord for the pivot point (unchanged by the rotation) + * @param px The x-coord for the pivot point (unchanged by the scale) + * @param py The y-coord for the pivot point (unchanged by the scale) */ public final void scale(float sx, float sy, float px, float py) { translate(px, py); @@ -442,6 +475,17 @@ public class Canvas { public void getMatrix(Matrix ctm) { native_getCTM(mNativeCanvas, ctm.native_instance); } + + /** + * Returns a pointer to an internal 4x4 native matrix. The returned + * pointer is a pointer to an array of 16 floats. + * + * @hide + */ + @SuppressWarnings({"UnusedDeclaration"}) + public int getNativeMatrix() { + return 0; + } /** * Return a new matrix with a copy of the canvas' current transformation @@ -621,7 +665,11 @@ public class Canvas { EdgeType(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } /** @@ -900,10 +948,19 @@ public class Canvas { } /** - * Draw the specified arc, which will be scaled to fit inside the - * specified oval. If the sweep angle is >= 360, then the oval is drawn + * <p>Draw the specified arc, which will be scaled to fit inside the + * specified oval.</p> + * + * <p>If the start angle is negative or >= 360, the start angle is treated + * as start angle modulo 360.</p> + * + * <p>If the sweep angle is >= 360, then the oval is drawn * completely. Note that this differs slightly from SkPath::arcTo, which - * treats the sweep angle mod 360. + * treats the sweep angle modulo 360. If the sweep angle is negative, + * the sweep angle is treated as sweep angle modulo 360</p> + * + * <p>The arc is drawn clockwise. An angle of 0 degrees correspond to the + * geometric angle of 0 degrees (3 o'clock on a watch.)</p> * * @param oval The bounds of oval used to define the shape and size * of the arc @@ -958,6 +1015,21 @@ public class Canvas { } /** + * Draws the specified bitmap as an N-patch (most often, a 9-patches.) + * + * Note: Only supported by hardware accelerated canvas at the moment. + * + * @param bitmap The bitmap to draw as an N-patch + * @param chunks The patches information (matches the native struct Res_png_9patch) + * @param dst The destination rectangle. + * @param paint The paint to draw the bitmap with. may be null + * + * @hide + */ + public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) { + } + + /** * Draw the specified bitmap, with its top/left corner at (x,y), using * the specified paint, transformed by the current matrix. * @@ -1115,8 +1187,11 @@ public class Canvas { nativeDrawBitmapMatrix(mNativeCanvas, bitmap.ni(), matrix.ni(), paint != null ? paint.mNativePaint : 0); } - - private static void checkRange(int length, int offset, int count) { + + /** + * @hide + */ + protected static void checkRange(int length, int offset, int count) { if ((offset | count) < 0 || offset + count > length) { throw new ArrayIndexOutOfBoundsException(); } @@ -1177,7 +1252,11 @@ public class Canvas { VertexMode(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } /** @@ -1246,8 +1325,8 @@ public class Canvas { (text.length - index - count)) < 0) { throw new IndexOutOfBoundsException(); } - native_drawText(mNativeCanvas, text, index, count, x, y, - paint.mNativePaint); + native_drawText(mNativeCanvas, text, index, count, x, y, paint.mBidiFlags, + paint.mNativePaint); } /** @@ -1259,7 +1338,10 @@ public class Canvas { * @param y The y-coordinate of the origin of the text being drawn * @param paint The paint used for the text (e.g. color, size, style) */ - public native void drawText(String text, float x, float y, Paint paint); + public void drawText(String text, float x, float y, Paint paint) { + native_drawText(mNativeCanvas, text, 0, text.length(), x, y, paint.mBidiFlags, + paint.mNativePaint); + } /** * Draw the text, with origin at (x,y), using the specified paint. @@ -1277,8 +1359,8 @@ public class Canvas { if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } - native_drawText(mNativeCanvas, text, start, end, x, y, - paint.mNativePaint); + native_drawText(mNativeCanvas, text, start, end, x, y, paint.mBidiFlags, + paint.mNativePaint); } /** @@ -1299,16 +1381,108 @@ public class Canvas { if (text instanceof String || text instanceof SpannedString || text instanceof SpannableString) { native_drawText(mNativeCanvas, text.toString(), start, end, x, y, - paint.mNativePaint); - } - else if (text instanceof GraphicsOperations) { + paint.mBidiFlags, paint.mNativePaint); + } else if (text instanceof GraphicsOperations) { ((GraphicsOperations) text).drawText(this, start, end, x, y, paint); - } - else { + } else { char[] buf = TemporaryBuffer.obtain(end - start); TextUtils.getChars(text, start, end, buf, 0); - drawText(buf, 0, end - start, x, y, paint); + native_drawText(mNativeCanvas, buf, 0, end - start, x, y, + paint.mBidiFlags, paint.mNativePaint); + TemporaryBuffer.recycle(buf); + } + } + + /** + * Render a run of all LTR or all RTL text, with shaping. This does not run + * bidi on the provided text, but renders it as a uniform right-to-left or + * left-to-right run, as indicated by dir. Alignment of the text is as + * determined by the Paint's TextAlign value. + * + * @param text the text to render + * @param index the start of the text to render + * @param count the count of chars to render + * @param contextIndex the start of the context for shaping. Must be + * no greater than index. + * @param contextCount the number of characters in the context for shaping. + * ContexIndex + contextCount must be no less than index + * + count. + * @param x the x position at which to draw the text + * @param y the y position at which to draw the text + * @param dir the run direction, either {@link #DIRECTION_LTR} or + * {@link #DIRECTION_RTL}. + * @param paint the paint + * @hide + */ + public void drawTextRun(char[] text, int index, int count, + int contextIndex, int contextCount, float x, float y, int dir, + Paint paint) { + + if (text == null) { + throw new NullPointerException("text is null"); + } + if (paint == null) { + throw new NullPointerException("paint is null"); + } + if ((index | count | text.length - index - count) < 0) { + throw new IndexOutOfBoundsException(); + } + if (dir != DIRECTION_LTR && dir != DIRECTION_RTL) { + throw new IllegalArgumentException("unknown dir: " + dir); + } + + native_drawTextRun(mNativeCanvas, text, index, count, + contextIndex, contextCount, x, y, dir, paint.mNativePaint); + } + + /** + * Render a run of all LTR or all RTL text, with shaping. This does not run + * bidi on the provided text, but renders it as a uniform right-to-left or + * left-to-right run, as indicated by dir. Alignment of the text is as + * determined by the Paint's TextAlign value. + * + * @param text the text to render + * @param start the start of the text to render. Data before this position + * can be used for shaping context. + * @param end the end of the text to render. Data at or after this + * position can be used for shaping context. + * @param x the x position at which to draw the text + * @param y the y position at which to draw the text + * @param dir the run direction, either 0 for LTR or 1 for RTL. + * @param paint the paint + * @hide + */ + public void drawTextRun(CharSequence text, int start, int end, + int contextStart, int contextEnd, float x, float y, int dir, + Paint paint) { + + if (text == null) { + throw new NullPointerException("text is null"); + } + if (paint == null) { + throw new NullPointerException("paint is null"); + } + if ((start | end | end - start | text.length() - end) < 0) { + throw new IndexOutOfBoundsException(); + } + + int flags = dir == 0 ? 0 : 1; + + if (text instanceof String || text instanceof SpannedString || + text instanceof SpannableString) { + native_drawTextRun(mNativeCanvas, text.toString(), start, end, + contextStart, contextEnd, x, y, flags, paint.mNativePaint); + } else if (text instanceof GraphicsOperations) { + ((GraphicsOperations) text).drawTextRun(this, start, end, + contextStart, contextEnd, x, y, flags, paint); + } else { + int contextLen = contextEnd - contextStart; + int len = end - start; + char[] buf = TemporaryBuffer.obtain(contextLen); + TextUtils.getChars(text, contextStart, contextEnd, buf, 0); + native_drawTextRun(mNativeCanvas, buf, start - contextStart, len, + 0, contextLen, x, y, flags, paint.mNativePaint); TemporaryBuffer.recycle(buf); } } @@ -1368,7 +1542,7 @@ public class Canvas { } native_drawTextOnPath(mNativeCanvas, text, index, count, path.ni(), hOffset, vOffset, - paint.mNativePaint); + paint.mBidiFlags, paint.mNativePaint); } /** @@ -1388,7 +1562,8 @@ public class Canvas { float vOffset, Paint paint) { if (text.length() > 0) { native_drawTextOnPath(mNativeCanvas, text, path.ni(), - hOffset, vOffset, paint.mNativePaint); + hOffset, vOffset, paint.mBidiFlags, + paint.mNativePaint); } } @@ -1431,28 +1606,16 @@ public class Canvas { drawPicture(picture); restore(); } - - protected void finalize() throws Throwable { - super.finalize(); - // If the constructor threw an exception before setting mNativeCanvas, the native finalizer - // must not be invoked. - if (mNativeCanvas != 0) { - finalizer(mNativeCanvas); - } - } /** - * Free up as much memory as possible from private caches (e.g. fonts, - * images) + * Free up as much memory as possible from private caches (e.g. fonts, images) * - * @hide - for now + * @hide */ public static native void freeCaches(); private static native int initRaster(int nativeBitmapOrZero); - private static native int initGL(); private static native void native_setBitmap(int nativeCanvas, int bitmap); - private static native void nativeSetViewport(int nCanvas, int w, int h); private static native int native_saveLayer(int nativeCanvas, RectF bounds, int paint, int layerFlags); private static native int native_saveLayer(int nativeCanvas, float l, @@ -1555,10 +1718,19 @@ public class Canvas { private static native void native_drawText(int nativeCanvas, char[] text, int index, int count, float x, - float y, int paint); + float y, int flags, int paint); private static native void native_drawText(int nativeCanvas, String text, int start, int end, float x, - float y, int paint); + float y, int flags, int paint); + + private static native void native_drawTextRun(int nativeCanvas, String text, + int start, int end, int contextStart, int contextEnd, + float x, float y, int flags, int paint); + + private static native void native_drawTextRun(int nativeCanvas, char[] text, + int start, int count, int contextStart, int contextCount, + float x, float y, int flags, int paint); + private static native void native_drawPosText(int nativeCanvas, char[] text, int index, int count, float[] pos, @@ -1570,11 +1742,13 @@ public class Canvas { char[] text, int index, int count, int path, float hOffset, - float vOffset, int paint); + float vOffset, int bidiFlags, + int paint); private static native void native_drawTextOnPath(int nativeCanvas, String text, int path, - float hOffset, - float vOffset, int paint); + float hOffset, + float vOffset, + int flags, int paint); private static native void native_drawPicture(int nativeCanvas, int nativePicture); private static native void finalizer(int nativeCanvas); diff --git a/graphics/java/android/graphics/ColorFilter.java b/graphics/java/android/graphics/ColorFilter.java index 76f2c7f..e5cf830 100644 --- a/graphics/java/android/graphics/ColorFilter.java +++ b/graphics/java/android/graphics/ColorFilter.java @@ -23,12 +23,20 @@ package android.graphics; public class ColorFilter { + int native_instance; + + /** + * @hide + */ + public int nativeColorFilter; protected void finalize() throws Throwable { - finalizer(native_instance); + try { + super.finalize(); + } finally { + finalizer(native_instance, nativeColorFilter); + } } - private static native void finalizer(int native_instance); - - int native_instance; + private static native void finalizer(int native_instance, int nativeColorFilter); } diff --git a/graphics/java/android/graphics/ColorMatrixColorFilter.java b/graphics/java/android/graphics/ColorMatrixColorFilter.java index 5d73cff..4f32342 100644 --- a/graphics/java/android/graphics/ColorMatrixColorFilter.java +++ b/graphics/java/android/graphics/ColorMatrixColorFilter.java @@ -25,7 +25,9 @@ public class ColorMatrixColorFilter extends ColorFilter { * is constructed will not be reflected in the filter. */ public ColorMatrixColorFilter(ColorMatrix matrix) { - native_instance = nativeColorMatrixFilter(matrix.getArray()); + final float[] colorMatrix = matrix.getArray(); + native_instance = nativeColorMatrixFilter(colorMatrix); + nativeColorFilter = nColorMatrixFilter(native_instance, colorMatrix); } /** @@ -40,7 +42,9 @@ public class ColorMatrixColorFilter extends ColorFilter { throw new ArrayIndexOutOfBoundsException(); } native_instance = nativeColorMatrixFilter(array); + nativeColorFilter = nColorMatrixFilter(native_instance, array); } private static native int nativeColorMatrixFilter(float[] array); + private static native int nColorMatrixFilter(int nativeFilter, float[] array); } diff --git a/graphics/java/android/graphics/ComposeShader.java b/graphics/java/android/graphics/ComposeShader.java index a06d30b..241ab17 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -20,32 +20,59 @@ package android.graphics; an {@link android.graphics.Xfermode} subclass. */ public class ComposeShader extends Shader { + /** + * Hold onto the shaders to avoid GC. + */ + @SuppressWarnings({"UnusedDeclaration"}) + private final Shader mShaderA; + @SuppressWarnings({"UnusedDeclaration"}) + private final Shader mShaderB; + /** Create a new compose shader, given shaders A, B, and a combining mode. When the mode is applied, it will be given the result from shader A as its - "dst", and the result of from shader B as its "src". + "dst", and the result from shader B as its "src". @param shaderA The colors from this shader are seen as the "dst" by the mode @param shaderB The colors from this shader are seen as the "src" by the mode @param mode The mode that combines the colors from the two shaders. If mode is null, then SRC_OVER is assumed. */ public ComposeShader(Shader shaderA, Shader shaderB, Xfermode mode) { + mShaderA = shaderA; + mShaderB = shaderB; native_instance = nativeCreate1(shaderA.native_instance, shaderB.native_instance, - (mode != null) ? mode.native_instance : 0); + (mode != null) ? mode.native_instance : 0); + if (mode instanceof PorterDuffXfermode) { + PorterDuff.Mode pdMode = ((PorterDuffXfermode) mode).mode; + native_shader = nativePostCreate2(native_instance, shaderA.native_shader, + shaderB.native_shader, pdMode != null ? pdMode.nativeInt : 0); + } else { + native_shader = nativePostCreate1(native_instance, shaderA.native_shader, + shaderB.native_shader, mode != null ? mode.native_instance : 0); + } } /** Create a new compose shader, given shaders A, B, and a combining PorterDuff mode. When the mode is applied, it will be given the result from shader A as its - "dst", and the result of from shader B as its "src". + "dst", and the result from shader B as its "src". @param shaderA The colors from this shader are seen as the "dst" by the mode @param shaderB The colors from this shader are seen as the "src" by the mode @param mode The PorterDuff mode that combines the colors from the two shaders. */ public ComposeShader(Shader shaderA, Shader shaderB, PorterDuff.Mode mode) { + mShaderA = shaderA; + mShaderB = shaderB; native_instance = nativeCreate2(shaderA.native_instance, shaderB.native_instance, - mode.nativeInt); + mode.nativeInt); + native_shader = nativePostCreate2(native_instance, shaderA.native_shader, + shaderB.native_shader, mode.nativeInt); } - private static native int nativeCreate1(int native_shaderA, int native_shaderB, int native_mode); - private static native int nativeCreate2(int native_shaderA, int native_shaderB, int porterDuffMode); + private static native int nativeCreate1(int native_shaderA, int native_shaderB, + int native_mode); + private static native int nativeCreate2(int native_shaderA, int native_shaderB, + int porterDuffMode); + private static native int nativePostCreate1(int native_shader, int native_skiaShaderA, + int native_skiaShaderB, int native_mode); + private static native int nativePostCreate2(int native_shader, int native_skiaShaderA, + int native_skiaShaderB, int porterDuffMode); } - diff --git a/graphics/java/android/graphics/ImageFormat.java b/graphics/java/android/graphics/ImageFormat.java index 3f9f961..b8e9384 100644 --- a/graphics/java/android/graphics/ImageFormat.java +++ b/graphics/java/android/graphics/ImageFormat.java @@ -17,83 +17,93 @@ package android.graphics; public class ImageFormat { - /* - * these constants are chosen to be binary compatible with their previous - * location in PixelFormat.java - */ + /* + * these constants are chosen to be binary compatible with their previous + * location in PixelFormat.java + */ - public static final int UNKNOWN = 0; + public static final int UNKNOWN = 0; - /** - * RGB format used for pictures encoded as RGB_565 see - * {@link android.hardware.Camera.Parameters#setPictureFormat(int)}. - */ - public static final int RGB_565 = 4; + /** + * RGB format used for pictures encoded as RGB_565 see + * {@link android.hardware.Camera.Parameters#setPictureFormat(int)}. + */ + public static final int RGB_565 = 4; - /** - * Planar 4:2:0 YCrCb format. This format assumes an horizontal stride of 16 - * pixels for all planes and an implicit vertical stride of the image - * height's next multiple of two. - * y_size = stride * ALIGN(height, 2) - * c_size = ALIGN(stride/2, 16) * height - * size = y_size + c_size * 2 - * cr_offset = y_size - * cb_offset = y_size + c_size - * - * Whether this format is supported by the camera hardware can be determined - * by - * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. - */ - public static final int YV12 = 0x32315659; + /** + * Android YUV format: + * + * This format is exposed to software decoders and applications. + * + * YV12 is a 4:2:0 YCrCb planar format comprised of a WxH Y plane followed + * by (W/2) x (H/2) Cr and Cb planes. + * + * This format assumes + * - an even width + * - an even height + * - a horizontal stride multiple of 16 pixels + * - a vertical stride equal to the height + * + * y_size = stride * height + * c_size = ALIGN(stride/2, 16) * height/2 + * size = y_size + c_size * 2 + * cr_offset = y_size + * cb_offset = y_size + c_size + * + * Whether this format is supported by the camera hardware can be determined + * by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int YV12 = 0x32315659; - /** - * YCbCr format, used for video. Whether this format is supported by the - * camera hardware can be determined by - * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. - */ - public static final int NV16 = 0x10; + /** + * YCbCr format, used for video. Whether this format is supported by the + * camera hardware can be determined by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int NV16 = 0x10; - /** - * YCrCb format used for images, which uses the NV21 encoding format. This - * is the default format for camera preview images, when not otherwise set - * with {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}. - */ - public static final int NV21 = 0x11; + /** + * YCrCb format used for images, which uses the NV21 encoding format. This + * is the default format for camera preview images, when not otherwise set + * with {@link android.hardware.Camera.Parameters#setPreviewFormat(int)}. + */ + public static final int NV21 = 0x11; - /** - * YCbCr format used for images, which uses YUYV (YUY2) encoding format. - * This is an alternative format for camera preview images. Whether this - * format is supported by the camera hardware can be determined by - * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. - */ - public static final int YUY2 = 0x14; + /** + * YCbCr format used for images, which uses YUYV (YUY2) encoding format. + * This is an alternative format for camera preview images. Whether this + * format is supported by the camera hardware can be determined by + * {@link android.hardware.Camera.Parameters#getSupportedPreviewFormats()}. + */ + public static final int YUY2 = 0x14; - /** - * Encoded formats. These are not necessarily supported by the hardware. - */ - public static final int JPEG = 0x100; + /** + * Encoded formats. These are not necessarily supported by the hardware. + */ + public static final int JPEG = 0x100; - /** - * Use this function to retrieve the number of bits per pixel of an - * ImageFormat. - * - * @param format - * @return the number of bits per pixel of the given format or -1 if the - * format doesn't exist or is not supported. - */ - public static int getBitsPerPixel(int format) { - switch (format) { - case RGB_565: - return 16; - case NV16: - return 16; - case YUY2: - return 16; - case YV12: - return 12; - case NV21: - return 12; - } - return -1; - } + /** + * Use this function to retrieve the number of bits per pixel of an + * ImageFormat. + * + * @param format + * @return the number of bits per pixel of the given format or -1 if the + * format doesn't exist or is not supported. + */ + public static int getBitsPerPixel(int format) { + switch (format) { + case RGB_565: + return 16; + case NV16: + return 16; + case YUY2: + return 16; + case YV12: + return 12; + case NV21: + return 12; + } + return -1; + } } diff --git a/graphics/java/android/graphics/LightingColorFilter.java b/graphics/java/android/graphics/LightingColorFilter.java index 5562389..c621de6 100644 --- a/graphics/java/android/graphics/LightingColorFilter.java +++ b/graphics/java/android/graphics/LightingColorFilter.java @@ -30,7 +30,9 @@ public class LightingColorFilter extends ColorFilter { */ public LightingColorFilter(int mul, int add) { native_instance = native_CreateLightingFilter(mul, add); + nativeColorFilter = nCreateLightingFilter(native_instance, mul, add); } private static native int native_CreateLightingFilter(int mul, int add); + private static native int nCreateLightingFilter(int nativeFilter, int mul, int add); } diff --git a/graphics/java/android/graphics/LinearGradient.java b/graphics/java/android/graphics/LinearGradient.java index e3db105..82ed199 100644 --- a/graphics/java/android/graphics/LinearGradient.java +++ b/graphics/java/android/graphics/LinearGradient.java @@ -17,7 +17,6 @@ package android.graphics; public class LinearGradient extends Shader { - /** Create a shader that draws a linear gradient along a line. @param x0 The x-coordinate for the start of the gradient line @param y0 The y-coordinate for the start of the gradient line @@ -38,6 +37,8 @@ public class LinearGradient extends Shader { throw new IllegalArgumentException("color and position arrays must be of equal length"); } native_instance = nativeCreate1(x0, y0, x1, y1, colors, positions, tile.nativeInt); + native_shader = nativePostCreate1(native_instance, x0, y0, x1, y1, colors, positions, + tile.nativeInt); } /** Create a shader that draws a linear gradient along a line. @@ -52,12 +53,16 @@ public class LinearGradient extends Shader { public LinearGradient(float x0, float y0, float x1, float y1, int color0, int color1, TileMode tile) { native_instance = nativeCreate2(x0, y0, x1, y1, color0, color1, tile.nativeInt); + native_shader = nativePostCreate2(native_instance, x0, y0, x1, y1, color0, color1, + tile.nativeInt); } - - private static native int nativeCreate1(float x0, float y0, float x1, float y1, - int colors[], float positions[], int tileMode); - private static native int nativeCreate2(float x0, float y0, float x1, float y1, - int color0, int color1, int tileMode); + private native int nativeCreate1(float x0, float y0, float x1, float y1, + int colors[], float positions[], int tileMode); + private native int nativeCreate2(float x0, float y0, float x1, float y1, + int color0, int color1, int tileMode); + private native int nativePostCreate1(int native_shader, float x0, float y0, float x1, float y1, + int colors[], float positions[], int tileMode); + private native int nativePostCreate2(int native_shader, float x0, float y0, float x1, float y1, + int color0, int color1, int tileMode); } - diff --git a/graphics/java/android/graphics/Matrix.java b/graphics/java/android/graphics/Matrix.java index f549900..66ed104 100644 --- a/graphics/java/android/graphics/Matrix.java +++ b/graphics/java/android/graphics/Matrix.java @@ -37,7 +37,10 @@ public class Matrix { public static final int MPERSP_1 = 7; //!< use with getValues/setValues public static final int MPERSP_2 = 8; //!< use with getValues/setValues - /* package */ int native_instance; + /** + * @hide + */ + public int native_instance; /** * Create an identity matrix @@ -419,6 +422,10 @@ public class Matrix { * the transformed vectors into the array of vectors specified by dst. The * two arrays represent their "vectors" as pairs of floats [x, y]. * + * Note: this method does not apply the translation associated with the matrix. Use + * {@link Matrix#mapPoints(float[], int, float[], int, int)} if you want the translation + * to be applied. + * * @param dst The array of dst vectors (x,y pairs) * @param dstIndex The index of the first [x,y] pair of dst floats * @param src The array of src vectors (x,y pairs) @@ -452,6 +459,9 @@ public class Matrix { * the transformed vectors into the array of vectors specified by dst. The * two arrays represent their "vectors" as pairs of floats [x, y]. * + * Note: this method does not apply the translation associated with the matrix. Use + * {@link Matrix#mapPoints(float[], float[])} if you want the translation to be applied. + * * @param dst The array of dst vectors (x,y pairs) * @param src The array of src vectors (x,y pairs) */ @@ -475,6 +485,10 @@ public class Matrix { /** * Apply this matrix to the array of 2D vectors, and write the transformed * vectors back into the array. + * + * Note: this method does not apply the translation associated with the matrix. Use + * {@link Matrix#mapPoints(float[])} if you want the translation to be applied. + * * @param vecs The array [x0, y0, x1, y1, ...] of vectors to transform. */ public void mapVectors(float[] vecs) { diff --git a/graphics/java/android/graphics/NinePatch.java b/graphics/java/android/graphics/NinePatch.java index 88dfd67..6de4d84 100644 --- a/graphics/java/android/graphics/NinePatch.java +++ b/graphics/java/android/graphics/NinePatch.java @@ -35,6 +35,12 @@ package android.graphics; * </p> */ public class NinePatch { + private final Bitmap mBitmap; + private final byte[] mChunk; + private Paint mPaint; + private String mSrcName; // Useful for debugging + private final RectF mRect = new RectF(); + /** * Create a drawable projection from a bitmap to nine patches. * @@ -74,10 +80,14 @@ public class NinePatch { * @param location Where to draw the bitmap. */ public void draw(Canvas canvas, RectF location) { - nativeDraw(canvas.mNativeCanvas, location, - mBitmap.ni(), mChunk, - mPaint != null ? mPaint.mNativePaint : 0, - canvas.mDensity, mBitmap.mDensity); + if (!canvas.isHardwareAccelerated()) { + nativeDraw(canvas.mNativeCanvas, location, + mBitmap.ni(), mChunk, + mPaint != null ? mPaint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); + } else { + canvas.drawPatch(mBitmap, mChunk, location, mPaint); + } } /** @@ -87,10 +97,15 @@ public class NinePatch { * @param location Where to draw the bitmap. */ public void draw(Canvas canvas, Rect location) { - nativeDraw(canvas.mNativeCanvas, location, - mBitmap.ni(), mChunk, - mPaint != null ? mPaint.mNativePaint : 0, - canvas.mDensity, mBitmap.mDensity); + if (!canvas.isHardwareAccelerated()) { + nativeDraw(canvas.mNativeCanvas, location, + mBitmap.ni(), mChunk, + mPaint != null ? mPaint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); + } else { + mRect.set(location); + canvas.drawPatch(mBitmap, mChunk, mRect, mPaint); + } } /** @@ -101,9 +116,14 @@ public class NinePatch { * @param paint The Paint to draw through. */ public void draw(Canvas canvas, Rect location, Paint paint) { - nativeDraw(canvas.mNativeCanvas, location, - mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0, - canvas.mDensity, mBitmap.mDensity); + if (!canvas.isHardwareAccelerated()) { + nativeDraw(canvas.mNativeCanvas, location, + mBitmap.ni(), mChunk, paint != null ? paint.mNativePaint : 0, + canvas.mDensity, mBitmap.mDensity); + } else { + mRect.set(location); + canvas.drawPatch(mBitmap, mChunk, mRect, paint); + } } /** @@ -133,11 +153,6 @@ public class NinePatch { public native static boolean isNinePatchChunk(byte[] chunk); - private final Bitmap mBitmap; - private final byte[] mChunk; - private Paint mPaint; - private String mSrcName; // Useful for debugging - private static native void validateNinePatchChunk(int bitmap, byte[] chunk); private static native void nativeDraw(int canvas_instance, RectF loc, int bitmap_instance, byte[] c, int paint_instance_or_null, diff --git a/graphics/java/android/graphics/Paint.java b/graphics/java/android/graphics/Paint.java index 3e3f87b..0a23bae 100644 --- a/graphics/java/android/graphics/Paint.java +++ b/graphics/java/android/graphics/Paint.java @@ -16,10 +16,10 @@ package android.graphics; -import android.text.TextUtils; +import android.text.GraphicsOperations; import android.text.SpannableString; import android.text.SpannedString; -import android.text.GraphicsOperations; +import android.text.TextUtils; /** * The Paint class holds the style and color information about how to draw @@ -27,7 +27,11 @@ import android.text.GraphicsOperations; */ public class Paint { - /*package*/ int mNativePaint; + /** + * @hide + */ + public int mNativePaint; + private ColorFilter mColorFilter; private MaskFilter mMaskFilter; private PathEffect mPathEffect; @@ -39,6 +43,32 @@ public class Paint { private boolean mHasCompatScaling; private float mCompatScaling; private float mInvCompatScaling; + + /** + * @hide + */ + public boolean hasShadow; + /** + * @hide + */ + public float shadowDx; + /** + * @hide + */ + public float shadowDy; + /** + * @hide + */ + public float shadowRadius; + /** + * @hide + */ + public int shadowColor; + + /** + * @hide + */ + public int mBidiFlags = BIDI_DEFAULT_LTR; private static final Style[] sStyleArray = { Style.FILL, Style.STROKE, Style.FILL_AND_STROKE @@ -76,8 +106,116 @@ public class Paint { private static final int DEFAULT_PAINT_FLAGS = DEV_KERN_TEXT_FLAG; /** - * The Style specifies if the primitive being drawn is filled, - * stroked, or both (in the same color). The default is FILL. + * Bidi flag to set LTR paragraph direction. + * + * @hide + */ + public static final int BIDI_LTR = 0x0; + + /** + * Bidi flag to set RTL paragraph direction. + * + * @hide + */ + public static final int BIDI_RTL = 0x1; + + /** + * Bidi flag to detect paragraph direction via heuristics, defaulting to + * LTR. + * + * @hide + */ + public static final int BIDI_DEFAULT_LTR = 0x2; + + /** + * Bidi flag to detect paragraph direction via heuristics, defaulting to + * RTL. + * + * @hide + */ + public static final int BIDI_DEFAULT_RTL = 0x3; + + /** + * Bidi flag to override direction to all LTR (ignore bidi). + * + * @hide + */ + public static final int BIDI_FORCE_LTR = 0x4; + + /** + * Bidi flag to override direction to all RTL (ignore bidi). + * + * @hide + */ + public static final int BIDI_FORCE_RTL = 0x5; + + /** + * Maximum Bidi flag value. + * @hide + */ + private static final int BIDI_MAX_FLAG_VALUE = BIDI_FORCE_RTL; + + /** + * Mask for bidi flags. + * @hide + */ + private static final int BIDI_FLAG_MASK = 0x7; + + /** + * Flag for getTextRunAdvances indicating left-to-right run direction. + * @hide + */ + public static final int DIRECTION_LTR = 0; + + /** + * Flag for getTextRunAdvances indicating right-to-left run direction. + * @hide + */ + public static final int DIRECTION_RTL = 1; + + /** + * Option for getTextRunCursor to compute the valid cursor after + * offset or the limit of the context, whichever is less. + * @hide + */ + public static final int CURSOR_AFTER = 0; + + /** + * Option for getTextRunCursor to compute the valid cursor at or after + * the offset or the limit of the context, whichever is less. + * @hide + */ + public static final int CURSOR_AT_OR_AFTER = 1; + + /** + * Option for getTextRunCursor to compute the valid cursor before + * offset or the start of the context, whichever is greater. + * @hide + */ + public static final int CURSOR_BEFORE = 2; + + /** + * Option for getTextRunCursor to compute the valid cursor at or before + * offset or the start of the context, whichever is greater. + * @hide + */ + public static final int CURSOR_AT_OR_BEFORE = 3; + + /** + * Option for getTextRunCursor to return offset if the cursor at offset + * is valid, or -1 if it isn't. + * @hide + */ + public static final int CURSOR_AT = 4; + + /** + * Maximum cursor option value. + */ + private static final int CURSOR_OPT_MAX_VALUE = CURSOR_AT; + + /** + * The Style specifies if the primitive being drawn is filled, stroked, or + * both (in the same color). The default is FILL. */ public enum Style { /** @@ -93,7 +231,9 @@ public class Paint { /** * Geometry and text drawn with this style will be both filled and * stroked at the same time, respecting the stroke-related fields on - * the paint. + * the paint. This mode can give unexpected results if the geometry + * is oriented counter-clockwise. This restriction does not apply to + * either FILL or STROKE. */ FILL_AND_STROKE (2); @@ -208,6 +348,7 @@ public class Paint { mHasCompatScaling = paint.mHasCompatScaling; mCompatScaling = paint.mCompatScaling; mInvCompatScaling = paint.mInvCompatScaling; + mBidiFlags = paint.mBidiFlags; } /** Restores the paint to its default settings. */ @@ -216,6 +357,7 @@ public class Paint { setFlags(DEFAULT_PAINT_FLAGS); mHasCompatScaling = false; mCompatScaling = mInvCompatScaling = 1; + mBidiFlags = BIDI_DEFAULT_LTR; } /** @@ -238,6 +380,7 @@ public class Paint { mHasCompatScaling = src.mHasCompatScaling; mCompatScaling = src.mCompatScaling; mInvCompatScaling = src.mInvCompatScaling; + mBidiFlags = src.mBidiFlags; } } @@ -252,10 +395,33 @@ public class Paint { mInvCompatScaling = 1.0f/factor; } } - + + /** + * Return the bidi flags on the paint. + * + * @return the bidi flags on the paint + * @hide + */ + public int getBidiFlags() { + return mBidiFlags; + } + + /** + * Set the bidi flags on the paint. + * @hide + */ + public void setBidiFlags(int flags) { + // only flag value is the 3-bit BIDI control setting + flags &= BIDI_FLAG_MASK; + if (flags > BIDI_MAX_FLAG_VALUE) { + throw new IllegalArgumentException("unknown bidi flag: " + flags); + } + mBidiFlags = flags; + } + /** * Return the paint's flags. Use the Flag enum to test flag values. - * + * * @return the paint's flags (see enums ending in _Flag for bit masks) */ public native int getFlags(); @@ -393,7 +559,7 @@ public class Paint { } /** - * Helper for setFlags(), setting or clearing the STRIKE_THRU_TEXT_FLAG bit + * Helper for setFlags(), setting or clearing the FAKE_BOLD_TEXT_FLAG bit * * @param fakeBoldText true to set the fakeBoldText bit in the paint's * flags, false to clear it. @@ -787,18 +953,27 @@ public class Paint { } /** - * Temporary API to expose layer drawing. This draws a shadow layer below - * the main layer, with the specified offset and color, and blur radius. - * If radius is 0, then the shadow layer is removed. + * This draws a shadow layer below the main layer, with the specified + * offset and color, and blur radius. If radius is 0, then the shadow + * layer is removed. */ - public native void setShadowLayer(float radius, float dx, float dy, - int color); + public void setShadowLayer(float radius, float dx, float dy, int color) { + hasShadow = radius > 0.0f; + shadowRadius = radius; + shadowDx = dx; + shadowDy = dy; + shadowColor = color; + nSetShadowLayer(radius, dx, dy, color); + } + + private native void nSetShadowLayer(float radius, float dx, float dy, int color); /** - * Temporary API to clear the shadow layer. + * Clear the shadow layer. */ public void clearShadowLayer() { - setShadowLayer(0, 0, 0, 0); + hasShadow = false; + nSetShadowLayer(0, 0, 0, 0); } /** @@ -1079,9 +1254,7 @@ public class Paint { * @param text The text to measure * @param index The offset into text to begin measuring at * @param count The number of maximum number of entries to measure. If count - * is negative, then the characters before index are measured - * in reverse order. This allows for measuring the end of - * string. + * is negative, then the characters are measured in reverse order. * @param maxWidth The maximum width to accumulate. * @param measuredWidth Optional. If not null, returns the actual width * measured. @@ -1232,10 +1405,10 @@ public class Paint { } char[] buf = TemporaryBuffer.obtain(end - start); - TextUtils.getChars(text, start, end, buf, 0); - int result = getTextWidths(buf, 0, end - start, widths); + TextUtils.getChars(text, start, end, buf, 0); + int result = getTextWidths(buf, 0, end - start, widths); TemporaryBuffer.recycle(buf); - return result; + return result; } /** @@ -1282,6 +1455,284 @@ public class Paint { } /** + * Convenience overload that takes a char array instead of a + * String. + * + * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int) + * @hide + */ + public float getTextRunAdvances(char[] chars, int index, int count, + int contextIndex, int contextCount, int flags, float[] advances, + int advancesIndex) { + + if ((index | count | contextIndex | contextCount | advancesIndex + | (index - contextIndex) + | ((contextIndex + contextCount) - (index + count)) + | (chars.length - (contextIndex + contextCount)) + | (advances == null ? 0 : + (advances.length - (advancesIndex + count)))) < 0) { + throw new IndexOutOfBoundsException(); + } + if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { + throw new IllegalArgumentException("unknown flags value: " + flags); + } + + if (!mHasCompatScaling) { + return native_getTextRunAdvances(mNativePaint, chars, index, count, + contextIndex, contextCount, flags, advances, advancesIndex); + } + + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); + float res = native_getTextRunAdvances(mNativePaint, chars, index, count, + contextIndex, contextCount, flags, advances, advancesIndex); + setTextSize(oldSize); + + if (advances != null) { + for (int i = advancesIndex, e = i + count; i < e; i++) { + advances[i] *= mInvCompatScaling; + } + } + return res * mInvCompatScaling; // assume errors are not significant + } + + /** + * Convenience overload that takes a CharSequence instead of a + * String. + * + * @see #getTextRunAdvances(String, int, int, int, int, int, float[], int) + * @hide + */ + public float getTextRunAdvances(CharSequence text, int start, int end, + int contextStart, int contextEnd, int flags, float[] advances, + int advancesIndex) { + + if (text instanceof String) { + return getTextRunAdvances((String) text, start, end, + contextStart, contextEnd, flags, advances, advancesIndex); + } + if (text instanceof SpannedString || + text instanceof SpannableString) { + return getTextRunAdvances(text.toString(), start, end, + contextStart, contextEnd, flags, advances, advancesIndex); + } + if (text instanceof GraphicsOperations) { + return ((GraphicsOperations) text).getTextRunAdvances(start, end, + contextStart, contextEnd, flags, advances, advancesIndex, this); + } + + int contextLen = contextEnd - contextStart; + int len = end - start; + char[] buf = TemporaryBuffer.obtain(contextLen); + TextUtils.getChars(text, start, end, buf, 0); + float result = getTextRunAdvances(buf, start - contextStart, len, + 0, contextLen, flags, advances, advancesIndex); + TemporaryBuffer.recycle(buf); + return result; + } + + /** + * Returns the total advance width for the characters in the run + * between start and end, and if advances is not null, the advance + * assigned to each of these characters (java chars). + * + * <p>The trailing surrogate in a valid surrogate pair is assigned + * an advance of 0. Thus the number of returned advances is + * always equal to count, not to the number of unicode codepoints + * represented by the run. + * + * <p>In the case of conjuncts or combining marks, the total + * advance is assigned to the first logical character, and the + * following characters are assigned an advance of 0. + * + * <p>This generates the sum of the advances of glyphs for + * characters in a reordered cluster as the width of the first + * logical character in the cluster, and 0 for the widths of all + * other characters in the cluster. In effect, such clusters are + * treated like conjuncts. + * + * <p>The shaping bounds limit the amount of context available + * outside start and end that can be used for shaping analysis. + * These bounds typically reflect changes in bidi level or font + * metrics across which shaping does not occur. + * + * @param text the text to measure + * @param start the index of the first character to measure + * @param end the index past the last character to measure + * @param contextStart the index of the first character to use for shaping context, + * must be <= start + * @param contextEnd the index past the last character to use for shaping context, + * must be >= end + * @param flags the flags to control the advances, either {@link #DIRECTION_LTR} + * or {@link #DIRECTION_RTL} + * @param advances array to receive the advances, must have room for all advances, + * can be null if only total advance is needed + * @param advancesIndex the position in advances at which to put the + * advance corresponding to the character at start + * @return the total advance + * + * @hide + */ + public float getTextRunAdvances(String text, int start, int end, int contextStart, + int contextEnd, int flags, float[] advances, int advancesIndex) { + + if ((start | end | contextStart | contextEnd | advancesIndex | (end - start) + | (start - contextStart) | (contextEnd - end) + | (text.length() - contextEnd) + | (advances == null ? 0 : + (advances.length - advancesIndex - (end - start)))) < 0) { + throw new IndexOutOfBoundsException(); + } + if (flags != DIRECTION_LTR && flags != DIRECTION_RTL) { + throw new IllegalArgumentException("unknown flags value: " + flags); + } + + if (!mHasCompatScaling) { + return native_getTextRunAdvances(mNativePaint, text, start, end, + contextStart, contextEnd, flags, advances, advancesIndex); + } + + final float oldSize = getTextSize(); + setTextSize(oldSize * mCompatScaling); + float totalAdvance = native_getTextRunAdvances(mNativePaint, text, start, end, + contextStart, contextEnd, flags, advances, advancesIndex); + setTextSize(oldSize); + + if (advances != null) { + for (int i = advancesIndex, e = i + (end - start); i < e; i++) { + advances[i] *= mInvCompatScaling; + } + } + return totalAdvance * mInvCompatScaling; // assume errors are insignificant + } + + /** + * Returns the next cursor position in the run. This avoids placing the + * cursor between surrogates, between characters that form conjuncts, + * between base characters and combining marks, or within a reordering + * cluster. + * + * <p>ContextStart and offset are relative to the start of text. + * The context is the shaping context for cursor movement, generally + * the bounds of the metric span enclosing the cursor in the direction of + * movement. + * + * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid + * cursor position, this returns -1. Otherwise this will never return a + * value before contextStart or after contextStart + contextLength. + * + * @param text the text + * @param contextStart the start of the context + * @param contextLength the length of the context + * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param offset the cursor position to move from + * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, + * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, + * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} + * @return the offset of the next position, or -1 + * @hide + */ + public int getTextRunCursor(char[] text, int contextStart, int contextLength, + int flags, int offset, int cursorOpt) { + int contextEnd = contextStart + contextLength; + if (((contextStart | contextEnd | offset | (contextEnd - contextStart) + | (offset - contextStart) | (contextEnd - offset) + | (text.length - contextEnd) | cursorOpt) < 0) + || cursorOpt > CURSOR_OPT_MAX_VALUE) { + throw new IndexOutOfBoundsException(); + } + + return native_getTextRunCursor(mNativePaint, text, + contextStart, contextLength, flags, offset, cursorOpt); + } + + /** + * Returns the next cursor position in the run. This avoids placing the + * cursor between surrogates, between characters that form conjuncts, + * between base characters and combining marks, or within a reordering + * cluster. + * + * <p>ContextStart, contextEnd, and offset are relative to the start of + * text. The context is the shaping context for cursor movement, generally + * the bounds of the metric span enclosing the cursor in the direction of + * movement. + * + * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid + * cursor position, this returns -1. Otherwise this will never return a + * value before contextStart or after contextEnd. + * + * @param text the text + * @param contextStart the start of the context + * @param contextEnd the end of the context + * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param offset the cursor position to move from + * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, + * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, + * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} + * @return the offset of the next position, or -1 + * @hide + */ + public int getTextRunCursor(CharSequence text, int contextStart, + int contextEnd, int flags, int offset, int cursorOpt) { + + if (text instanceof String || text instanceof SpannedString || + text instanceof SpannableString) { + return getTextRunCursor(text.toString(), contextStart, contextEnd, + flags, offset, cursorOpt); + } + if (text instanceof GraphicsOperations) { + return ((GraphicsOperations) text).getTextRunCursor( + contextStart, contextEnd, flags, offset, cursorOpt, this); + } + + int contextLen = contextEnd - contextStart; + char[] buf = TemporaryBuffer.obtain(contextLen); + TextUtils.getChars(text, contextStart, contextEnd, buf, 0); + int result = getTextRunCursor(buf, 0, contextLen, flags, offset - contextStart, cursorOpt); + TemporaryBuffer.recycle(buf); + return result; + } + + /** + * Returns the next cursor position in the run. This avoids placing the + * cursor between surrogates, between characters that form conjuncts, + * between base characters and combining marks, or within a reordering + * cluster. + * + * <p>ContextStart, contextEnd, and offset are relative to the start of + * text. The context is the shaping context for cursor movement, generally + * the bounds of the metric span enclosing the cursor in the direction of + * movement. + * + * <p>If cursorOpt is {@link #CURSOR_AT} and the offset is not a valid + * cursor position, this returns -1. Otherwise this will never return a + * value before contextStart or after contextEnd. + * + * @param text the text + * @param contextStart the start of the context + * @param contextEnd the end of the context + * @param flags either {@link #DIRECTION_RTL} or {@link #DIRECTION_LTR} + * @param offset the cursor position to move from + * @param cursorOpt how to move the cursor, one of {@link #CURSOR_AFTER}, + * {@link #CURSOR_AT_OR_AFTER}, {@link #CURSOR_BEFORE}, + * {@link #CURSOR_AT_OR_BEFORE}, or {@link #CURSOR_AT} + * @return the offset of the next position, or -1 + * @hide + */ + public int getTextRunCursor(String text, int contextStart, int contextEnd, + int flags, int offset, int cursorOpt) { + if (((contextStart | contextEnd | offset | (contextEnd - contextStart) + | (offset - contextStart) | (contextEnd - offset) + | (text.length() - contextEnd) | cursorOpt) < 0) + || cursorOpt > CURSOR_OPT_MAX_VALUE) { + throw new IndexOutOfBoundsException(); + } + + return native_getTextRunCursor(mNativePaint, text, + contextStart, contextEnd, flags, offset, cursorOpt); + } + + /** * Return the path (outline) for the specified text. * Note: just like Canvas.drawText, this will respect the Align setting in * the paint. @@ -1299,7 +1750,8 @@ public class Paint { if ((index | count) < 0 || index + count > text.length) { throw new ArrayIndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, text, index, count, x, y, path.ni()); + native_getTextPath(mNativePaint, mBidiFlags, text, index, count, x, y, + path.ni()); } /** @@ -1320,7 +1772,8 @@ public class Paint { if ((start | end | (end - start) | (text.length() - end)) < 0) { throw new IndexOutOfBoundsException(); } - native_getTextPath(mNativePaint, text, start, end, x, y, path.ni()); + native_getTextPath(mNativePaint, mBidiFlags, text, start, end, x, y, + path.ni()); } /** @@ -1363,6 +1816,7 @@ public class Paint { nativeGetCharArrayBounds(mNativePaint, text, index, count, bounds); } + @Override protected void finalize() throws Throwable { finalizer(mNativePaint); } @@ -1404,9 +1858,22 @@ public class Paint { char[] text, int index, int count, float[] widths); private static native int native_getTextWidths(int native_object, String text, int start, int end, float[] widths); - private static native void native_getTextPath(int native_object, + + private static native float native_getTextRunAdvances(int native_object, + char[] text, int index, int count, int contextIndex, int contextCount, + int flags, float[] advances, int advancesIndex); + private static native float native_getTextRunAdvances(int native_object, + String text, int start, int end, int contextStart, int contextEnd, + int flags, float[] advances, int advancesIndex); + + private native int native_getTextRunCursor(int native_object, char[] text, + int contextStart, int contextLength, int flags, int offset, int cursorOpt); + private native int native_getTextRunCursor(int native_object, String text, + int contextStart, int contextEnd, int flags, int offset, int cursorOpt); + + private static native void native_getTextPath(int native_object, int bidiFlags, char[] text, int index, int count, float x, float y, int path); - private static native void native_getTextPath(int native_object, + private static native void native_getTextPath(int native_object, int bidiFlags, String text, int start, int end, float x, float y, int path); private static native void nativeGetStringBounds(int nativePaint, String text, int start, int end, Rect bounds); @@ -1414,4 +1881,3 @@ public class Paint { char[] text, int index, int count, Rect bounds); private static native void finalizer(int nativePaint); } - diff --git a/graphics/java/android/graphics/Path.java b/graphics/java/android/graphics/Path.java index 281823a..1324431 100644 --- a/graphics/java/android/graphics/Path.java +++ b/graphics/java/android/graphics/Path.java @@ -16,6 +16,8 @@ package android.graphics; +import android.view.HardwareRenderer; + /** * The Path class encapsulates compound (multiple contour) geometric paths * consisting of straight line segments, quadratic curves, and cubic curves. @@ -24,12 +26,27 @@ package android.graphics; * text on a path. */ public class Path { + /** + * @hide + */ + public final int mNativePath; + + /** + * @hide + */ + public boolean isSimplePath = true; + /** + * @hide + */ + public Region rects; + private boolean mDetectSimplePaths; /** * Create an empty path */ public Path() { mNativePath = init1(); + mDetectSimplePaths = HardwareRenderer.isAvailable(); } /** @@ -43,6 +60,7 @@ public class Path { valNative = src.mNativePath; } mNativePath = init2(valNative); + mDetectSimplePaths = HardwareRenderer.isAvailable(); } /** @@ -50,6 +68,10 @@ public class Path { * This does NOT change the fill-type setting. */ public void reset() { + isSimplePath = true; + if (mDetectSimplePaths) { + if (rects != null) rects.setEmpty(); + } native_reset(mNativePath); } @@ -58,6 +80,10 @@ public class Path { * keeps the internal data structure for faster reuse. */ public void rewind() { + isSimplePath = true; + if (mDetectSimplePaths) { + if (rects != null) rects.setEmpty(); + } native_rewind(mNativePath); } @@ -65,6 +91,7 @@ public class Path { */ public void set(Path src) { if (this != src) { + isSimplePath = src.isSimplePath; native_set(mNativePath, src.mNativePath); } } @@ -160,6 +187,7 @@ public class Path { * @param bounds Returns the computed bounds of the path's control points. * @param exact This parameter is no longer used. */ + @SuppressWarnings({"UnusedDeclaration"}) public void computeBounds(RectF bounds, boolean exact) { native_computeBounds(mNativePath, bounds); } @@ -208,6 +236,7 @@ public class Path { * @param y The y-coordinate of the end of a line */ public void lineTo(float x, float y) { + isSimplePath = false; native_lineTo(mNativePath, x, y); } @@ -222,6 +251,7 @@ public class Path { * this contour, to specify a line */ public void rLineTo(float dx, float dy) { + isSimplePath = false; native_rLineTo(mNativePath, dx, dy); } @@ -236,6 +266,7 @@ public class Path { * @param y2 The y-coordinate of the end point on a quadratic curve */ public void quadTo(float x1, float y1, float x2, float y2) { + isSimplePath = false; native_quadTo(mNativePath, x1, y1, x2, y2); } @@ -254,6 +285,7 @@ public class Path { * this contour, for the end point of a quadratic curve */ public void rQuadTo(float dx1, float dy1, float dx2, float dy2) { + isSimplePath = false; native_rQuadTo(mNativePath, dx1, dy1, dx2, dy2); } @@ -271,6 +303,7 @@ public class Path { */ public void cubicTo(float x1, float y1, float x2, float y2, float x3, float y3) { + isSimplePath = false; native_cubicTo(mNativePath, x1, y1, x2, y2, x3, y3); } @@ -281,6 +314,7 @@ public class Path { */ public void rCubicTo(float x1, float y1, float x2, float y2, float x3, float y3) { + isSimplePath = false; native_rCubicTo(mNativePath, x1, y1, x2, y2, x3, y3); } @@ -299,6 +333,7 @@ public class Path { */ public void arcTo(RectF oval, float startAngle, float sweepAngle, boolean forceMoveTo) { + isSimplePath = false; native_arcTo(mNativePath, oval, startAngle, sweepAngle, forceMoveTo); } @@ -314,6 +349,7 @@ public class Path { * @param sweepAngle Sweep angle (in degrees) measured clockwise */ public void arcTo(RectF oval, float startAngle, float sweepAngle) { + isSimplePath = false; native_arcTo(mNativePath, oval, startAngle, sweepAngle, false); } @@ -322,6 +358,7 @@ public class Path { * first point of the contour, a line segment is automatically added. */ public void close() { + isSimplePath = false; native_close(mNativePath); } @@ -351,6 +388,11 @@ public class Path { if (rect == null) { throw new NullPointerException("need rect parameter"); } + if (mDetectSimplePaths) { + if (rects == null) rects = new Region(); + rects.op((int) rect.left, (int) rect.top, (int) rect.right, (int) rect.bottom, + Region.Op.UNION); + } native_addRect(mNativePath, rect, dir.nativeInt); } @@ -363,8 +405,11 @@ public class Path { * @param bottom The bottom of a rectangle to add to the path * @param dir The direction to wind the rectangle's contour */ - public void addRect(float left, float top, float right, float bottom, - Direction dir) { + public void addRect(float left, float top, float right, float bottom, Direction dir) { + if (mDetectSimplePaths) { + if (rects == null) rects = new Region(); + rects.op((int) left, (int) top, (int) right, (int) bottom, Region.Op.UNION); + } native_addRect(mNativePath, left, top, right, bottom, dir.nativeInt); } @@ -378,6 +423,7 @@ public class Path { if (oval == null) { throw new NullPointerException("need oval parameter"); } + isSimplePath = false; native_addOval(mNativePath, oval, dir.nativeInt); } @@ -390,6 +436,7 @@ public class Path { * @param dir The direction to wind the circle's contour */ public void addCircle(float x, float y, float radius, Direction dir) { + isSimplePath = false; native_addCircle(mNativePath, x, y, radius, dir.nativeInt); } @@ -404,6 +451,7 @@ public class Path { if (oval == null) { throw new NullPointerException("need oval parameter"); } + isSimplePath = false; native_addArc(mNativePath, oval, startAngle, sweepAngle); } @@ -419,6 +467,7 @@ public class Path { if (rect == null) { throw new NullPointerException("need rect parameter"); } + isSimplePath = false; native_addRoundRect(mNativePath, rect, rx, ry, dir.nativeInt); } @@ -438,6 +487,7 @@ public class Path { if (radii.length < 8) { throw new ArrayIndexOutOfBoundsException("radii[] needs 8 values"); } + isSimplePath = false; native_addRoundRect(mNativePath, rect, radii, dir.nativeInt); } @@ -448,6 +498,7 @@ public class Path { * @param dx The amount to translate the path in X as it is added */ public void addPath(Path src, float dx, float dy) { + isSimplePath = false; native_addPath(mNativePath, src.mNativePath, dx, dy); } @@ -457,6 +508,7 @@ public class Path { * @param src The path that is appended to the current path */ public void addPath(Path src) { + isSimplePath = false; native_addPath(mNativePath, src.mNativePath); } @@ -466,6 +518,7 @@ public class Path { * @param src The path to add as a new contour */ public void addPath(Path src, Matrix matrix) { + if (!src.isSimplePath) isSimplePath = false; native_addPath(mNativePath, src.mNativePath, matrix.native_instance); } @@ -502,6 +555,7 @@ public class Path { * @param dy The new Y coordinate for the last point */ public void setLastPoint(float dx, float dy) { + isSimplePath = false; native_setLastPoint(mNativePath, dx, dy); } @@ -537,8 +591,8 @@ public class Path { super.finalize(); } } - - /*package*/ final int ni() { + + final int ni() { return mNativePath; } @@ -592,6 +646,4 @@ public class Path { int dst_path); private static native void native_transform(int nPath, int matrix); private static native void finalizer(int nPath); - - private final int mNativePath; } diff --git a/graphics/java/android/graphics/PorterDuff.java b/graphics/java/android/graphics/PorterDuff.java index 3904234..2ef1662 100644 --- a/graphics/java/android/graphics/PorterDuff.java +++ b/graphics/java/android/graphics/PorterDuff.java @@ -53,11 +53,18 @@ public class PorterDuff { /** [Sa * Da, Sc * Dc] */ MULTIPLY (14), /** [Sa + Da - Sa * Da, Sc + Dc - Sc * Dc] */ - SCREEN (15); + SCREEN (15), + /** Saturate(S + D) */ + ADD (16), + OVERLAY (17); Mode(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } } diff --git a/graphics/java/android/graphics/PorterDuffColorFilter.java b/graphics/java/android/graphics/PorterDuffColorFilter.java index 06724bd..ecc7c24 100644 --- a/graphics/java/android/graphics/PorterDuffColorFilter.java +++ b/graphics/java/android/graphics/PorterDuffColorFilter.java @@ -25,10 +25,11 @@ public class PorterDuffColorFilter extends ColorFilter { * @param mode The porter-duff mode that is applied */ public PorterDuffColorFilter(int srcColor, PorterDuff.Mode mode) { - native_instance = native_CreatePorterDuffFilter(srcColor, - mode.nativeInt); + native_instance = native_CreatePorterDuffFilter(srcColor, mode.nativeInt); + nativeColorFilter = nCreatePorterDuffFilter(native_instance, srcColor, mode.nativeInt); } - private static native int native_CreatePorterDuffFilter(int srcColor, - int porterDuffMode); + private static native int native_CreatePorterDuffFilter(int srcColor, int porterDuffMode); + private static native int nCreatePorterDuffFilter(int nativeFilter, int srcColor, + int porterDuffMode); } diff --git a/graphics/java/android/graphics/PorterDuffXfermode.java b/graphics/java/android/graphics/PorterDuffXfermode.java index cb127fd..6ba064c 100644 --- a/graphics/java/android/graphics/PorterDuffXfermode.java +++ b/graphics/java/android/graphics/PorterDuffXfermode.java @@ -18,11 +18,17 @@ package android.graphics; public class PorterDuffXfermode extends Xfermode { /** + * @hide + */ + public final PorterDuff.Mode mode; + + /** * Create an xfermode that uses the specified porter-duff mode. * * @param mode The porter-duff mode that is applied */ public PorterDuffXfermode(PorterDuff.Mode mode) { + this.mode = mode; native_instance = nativeCreateXfermode(mode.nativeInt); } diff --git a/graphics/java/android/graphics/RadialGradient.java b/graphics/java/android/graphics/RadialGradient.java index b4e902d..897762c 100644 --- a/graphics/java/android/graphics/RadialGradient.java +++ b/graphics/java/android/graphics/RadialGradient.java @@ -40,6 +40,8 @@ public class RadialGradient extends Shader { throw new IllegalArgumentException("color and position arrays must be of equal length"); } native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt); + native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions, + tile.nativeInt); } /** Create a shader that draws a radial gradient given the center and radius. @@ -56,11 +58,18 @@ public class RadialGradient extends Shader { throw new IllegalArgumentException("radius must be > 0"); } native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt); + native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1, + tile.nativeInt); } private static native int nativeCreate1(float x, float y, float radius, - int colors[], float positions[], int tileMode); + int colors[], float positions[], int tileMode); private static native int nativeCreate2(float x, float y, float radius, - int color0, int color1, int tileMode); + int color0, int color1, int tileMode); + + private static native int nativePostCreate1(int native_shader, float x, float y, float radius, + int colors[], float positions[], int tileMode); + private static native int nativePostCreate2(int native_shader, float x, float y, float radius, + int color0, int color1, int tileMode); } diff --git a/graphics/java/android/graphics/Region.java b/graphics/java/android/graphics/Region.java index 2b080aa..27ea0f0 100644 --- a/graphics/java/android/graphics/Region.java +++ b/graphics/java/android/graphics/Region.java @@ -20,6 +20,10 @@ import android.os.Parcel; import android.os.Parcelable; public class Region implements Parcelable { + /** + * @hide + */ + public final int mNativeRegion; // the native values for these must match up with the enum in SkRegion.h public enum Op { @@ -33,7 +37,11 @@ public class Region implements Parcelable { Op(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } /** Create an empty region @@ -279,6 +287,10 @@ public class Region implements Parcelable { region2.mNativeRegion, op.nativeInt); } + public String toString() { + return nativeToString(mNativeRegion); + } + ////////////////////////////////////////////////////////////////////////// public static final Parcelable.Creator<Region> CREATOR @@ -325,10 +337,14 @@ public class Region implements Parcelable { } protected void finalize() throws Throwable { - nativeDestructor(mNativeRegion); + try { + nativeDestructor(mNativeRegion); + } finally { + super.finalize(); + } } - /*package*/ Region(int ni) { + Region(int ni) { if (ni == 0) { throw new RuntimeException(); } @@ -341,10 +357,12 @@ public class Region implements Parcelable { this(ni); } - /*package*/ final int ni() { + final int ni() { return mNativeRegion; } + private static native boolean nativeEquals(int native_r1, int native_r2); + private static native int nativeConstructor(); private static native void nativeDestructor(int native_region); @@ -369,7 +387,5 @@ public class Region implements Parcelable { private static native boolean nativeWriteToParcel(int native_region, Parcel p); - private static native boolean nativeEquals(int native_r1, int native_r2); - - private final int mNativeRegion; + private static native String nativeToString(int native_region); } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index ae0304e..43758e7 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -23,9 +23,18 @@ package android.graphics; * drawn with that paint will get its color(s) from the shader. */ public class Shader { + /** + * This is set by subclasses, but don't make it public. + * + * @hide + */ + public int native_instance; + /** + * @hide + */ + public int native_shader; - // this is set by subclasses, but don't make it public - /* package */ int native_instance; + private Matrix mLocalMatrix; public enum TileMode { /** @@ -55,7 +64,11 @@ public class Shader { * @return true if the shader has a non-identity local matrix */ public boolean getLocalMatrix(Matrix localM) { - return nativeGetLocalMatrix(native_instance, localM.native_instance); + if (mLocalMatrix != null) { + localM.set(mLocalMatrix); + return !mLocalMatrix.isIdentity(); + } + return false; } /** @@ -64,17 +77,20 @@ public class Shader { * @param localM The shader's new local matrix, or null to specify identity */ public void setLocalMatrix(Matrix localM) { - nativeSetLocalMatrix(native_instance, - localM != null ? localM.native_instance : 0); + mLocalMatrix = localM; + nativeSetLocalMatrix(native_instance, native_shader, + localM == null ? 0 : localM.native_instance); } protected void finalize() throws Throwable { - nativeDestructor(native_instance); + try { + super.finalize(); + } finally { + nativeDestructor(native_instance, native_shader); + } } - private static native void nativeDestructor(int native_shader); - private static native boolean nativeGetLocalMatrix(int native_shader, - int matrix_instance); + private static native void nativeDestructor(int native_shader, int native_skiaShader); private static native void nativeSetLocalMatrix(int native_shader, - int matrix_instance); + int native_skiaShader, int matrix_instance); } diff --git a/graphics/java/android/graphics/SurfaceTexture.java b/graphics/java/android/graphics/SurfaceTexture.java new file mode 100644 index 0000000..970b207 --- /dev/null +++ b/graphics/java/android/graphics/SurfaceTexture.java @@ -0,0 +1,193 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import java.lang.ref.WeakReference; +import android.os.Handler; +import android.os.Looper; +import android.os.Message; + +/** + * Captures frames from an image stream as an OpenGL ES texture. + * + * <p>The image stream may come from either camera preview or video decode. A SurfaceTexture + * may be used in place of a SurfaceHolder when specifying the output destination of a + * {@link android.hardware.Camera} or {@link android.media.MediaPlayer} + * object. Doing so will cause all the frames from the image stream to be sent to the + * SurfaceTexture object rather than to the device's display. When {@link #updateTexImage} is + * called, the contents of the texture object specified when the SurfaceTexture was created are + * updated to contain the most recent image from the image stream. This may cause some frames of + * the stream to be skipped. + * + * <p>When sampling from the texture one should first transform the texture coordinates using the + * matrix queried via {@link #getTransformMatrix}. The transform matrix may change each time {@link + * #updateTexImage} is called, so it should be re-queried each time the texture image is updated. + * This matrix transforms traditional 2D OpenGL ES texture coordinate column vectors of the form (s, + * t, 0, 1) where s and t are on the inclusive interval [0, 1] to the proper sampling location in + * the streamed texture. This transform compensates for any properties of the image stream source + * that cause it to appear different from a traditional OpenGL ES texture. For example, sampling + * from the bottom left corner of the image can be accomplished by transforming the column vector + * (0, 0, 0, 1) using the queried matrix, while sampling from the top right corner of the image can + * be done by transforming (1, 1, 0, 1). + * + * <p>The texture object uses the GL_TEXTURE_EXTERNAL_OES texture target, which is defined by the + * <a href="http://www.khronos.org/registry/gles/extensions/OES/OES_EGL_image_external.txt"> + * GL_OES_EGL_image_external</a> OpenGL ES extension. This limits how the texture may be used. + * Each time the texture is bound it must be bound to the GL_TEXTURE_EXTERNAL_OES target rather than + * the GL_TEXTURE_2D target. Additionally, any OpenGL ES 2.0 shader that samples from the texture + * must declare its use of this extension using, for example, an "#extension + * GL_OES_EGL_image_external : require" directive. Such shaders must also access the texture using + * the samplerExternalOES GLSL sampler type. + * + * <p>SurfaceTexture objects may be created on any thread. {@link #updateTexImage} may only be + * called on the thread with the OpenGL ES context that contains the texture object. The + * frame-available callback is called on an arbitrary thread, so unless special care is taken {@link + * #updateTexImage} should not be called directly from the callback. + */ +public class SurfaceTexture { + + private EventHandler mEventHandler; + private OnFrameAvailableListener mOnFrameAvailableListener; + + @SuppressWarnings("unused") + private int mSurfaceTexture; + + /** + * Callback interface for being notified that a new stream frame is available. + */ + public interface OnFrameAvailableListener { + void onFrameAvailable(SurfaceTexture surfaceTexture); + } + + /** + * Exception thrown when a surface couldn't be created or resized + */ + public static class OutOfResourcesException extends Exception { + public OutOfResourcesException() { + } + public OutOfResourcesException(String name) { + super(name); + } + } + + /** + * Construct a new SurfaceTexture to stream images to a given OpenGL texture. + * + * @param texName the OpenGL texture object name (e.g. generated via glGenTextures) + */ + public SurfaceTexture(int texName) { + Looper looper; + if ((looper = Looper.myLooper()) != null) { + mEventHandler = new EventHandler(looper); + } else if ((looper = Looper.getMainLooper()) != null) { + mEventHandler = new EventHandler(looper); + } else { + mEventHandler = null; + } + nativeInit(texName, new WeakReference<SurfaceTexture>(this)); + } + + /** + * Register a callback to be invoked when a new image frame becomes available to the + * SurfaceTexture. Note that this callback may be called on an arbitrary thread, so it is not + * safe to call {@link #updateTexImage} without first binding the OpenGL ES context to the + * thread invoking the callback. + */ + public void setOnFrameAvailableListener(OnFrameAvailableListener l) { + mOnFrameAvailableListener = l; + } + + /** + * Update the texture image to the most recent frame from the image stream. This may only be + * called while the OpenGL ES context that owns the texture is bound to the thread. It will + * implicitly bind its texture to the GL_TEXTURE_EXTERNAL_OES texture target. + */ + public void updateTexImage() { + nativeUpdateTexImage(); + } + + /** + * Retrieve the 4x4 texture coordinate transform matrix associated with the texture image set by + * the most recent call to updateTexImage. + * + * This transform matrix maps 2D homogeneous texture coordinates of the form (s, t, 0, 1) with s + * and t in the inclusive range [0, 1] to the texture coordinate that should be used to sample + * that location from the texture. Sampling the texture outside of the range of this transform + * is undefined. + * + * The matrix is stored in column-major order so that it may be passed directly to OpenGL ES via + * the glLoadMatrixf or glUniformMatrix4fv functions. + * + * @param mtx the array into which the 4x4 matrix will be stored. The array must have exactly + * 16 elements. + */ + public void getTransformMatrix(float[] mtx) { + // Note we intentionally don't check mtx for null, so this will result in a + // NullPointerException. But it's safe because it happens before the call to native. + if (mtx.length != 16) { + throw new IllegalArgumentException(); + } + nativeGetTransformMatrix(mtx); + } + + protected void finalize() throws Throwable { + try { + nativeFinalize(); + } finally { + super.finalize(); + } + } + + private class EventHandler extends Handler { + public EventHandler(Looper looper) { + super(looper); + } + + @Override + public void handleMessage(Message msg) { + if (mOnFrameAvailableListener != null) { + mOnFrameAvailableListener.onFrameAvailable(SurfaceTexture.this); + } + return; + } + } + + private static void postEventFromNative(Object selfRef) { + WeakReference weakSelf = (WeakReference)selfRef; + SurfaceTexture st = (SurfaceTexture)weakSelf.get(); + if (st == null) { + return; + } + + if (st.mEventHandler != null) { + Message m = st.mEventHandler.obtainMessage(); + st.mEventHandler.sendMessage(m); + } + } + + private native void nativeInit(int texName, Object weakSelf); + private native void nativeFinalize(); + private native void nativeGetTransformMatrix(float[] mtx); + private native void nativeUpdateTexImage(); + + /* + * We use a class initializer to allow the native code to cache some + * field offsets. + */ + private static native void nativeClassInit(); + static { nativeClassInit(); } +} diff --git a/graphics/java/android/graphics/SweepGradient.java b/graphics/java/android/graphics/SweepGradient.java index 7456993..2afdd4d 100644 --- a/graphics/java/android/graphics/SweepGradient.java +++ b/graphics/java/android/graphics/SweepGradient.java @@ -42,6 +42,7 @@ public class SweepGradient extends Shader { "color and position arrays must be of equal length"); } native_instance = nativeCreate1(cx, cy, colors, positions); + native_shader = nativePostCreate1(native_instance, cx, cy, colors, positions); } /** @@ -54,11 +55,15 @@ public class SweepGradient extends Shader { */ public SweepGradient(float cx, float cy, int color0, int color1) { native_instance = nativeCreate2(cx, cy, color0, color1); + native_shader = nativePostCreate2(native_instance, cx, cy, color0, color1); } - private static native int nativeCreate1(float x, float y, - int colors[], float positions[]); - private static native int nativeCreate2(float x, float y, - int color0, int color1); + private static native int nativeCreate1(float x, float y, int colors[], float positions[]); + private static native int nativeCreate2(float x, float y, int color0, int color1); + + private static native int nativePostCreate1(int native_shader, float cx, float cy, + int[] colors, float[] positions); + private static native int nativePostCreate2(int native_shader, float cx, float cy, + int color0, int color1); } diff --git a/graphics/java/android/graphics/TemporaryBuffer.java b/graphics/java/android/graphics/TemporaryBuffer.java index 1d7fe01..c5b8143 100644 --- a/graphics/java/android/graphics/TemporaryBuffer.java +++ b/graphics/java/android/graphics/TemporaryBuffer.java @@ -18,9 +18,11 @@ package android.graphics; import com.android.internal.util.ArrayUtils; -/* package */ class TemporaryBuffer -{ - /* package */ static char[] obtain(int len) { +/** + * @hide + */ +public class TemporaryBuffer { + public static char[] obtain(int len) { char[] buf; synchronized (TemporaryBuffer.class) { @@ -28,15 +30,15 @@ import com.android.internal.util.ArrayUtils; sTemp = null; } - if (buf == null || buf.length < len) + if (buf == null || buf.length < len) { buf = new char[ArrayUtils.idealCharArraySize(len)]; + } return buf; } - /* package */ static void recycle(char[] temp) { - if (temp.length > 1000) - return; + public static void recycle(char[] temp) { + if (temp.length > 1000) return; synchronized (TemporaryBuffer.class) { sTemp = temp; diff --git a/graphics/java/android/graphics/Xfermode.java b/graphics/java/android/graphics/Xfermode.java index 42c410e..2467bdc 100644 --- a/graphics/java/android/graphics/Xfermode.java +++ b/graphics/java/android/graphics/Xfermode.java @@ -31,7 +31,11 @@ package android.graphics; public class Xfermode { protected void finalize() throws Throwable { - finalizer(native_instance); + try { + finalizer(native_instance); + } finally { + super.finalize(); + } } private static native void finalizer(int native_instance); diff --git a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java index 49f497c..94a8488 100644 --- a/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java +++ b/graphics/java/android/graphics/drawable/AnimatedRotateDrawable.java @@ -159,20 +159,23 @@ public class AnimatedRotateDrawable extends Drawable implements Drawable.Callbac } public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } diff --git a/graphics/java/android/graphics/drawable/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 501374b..6e62ab3 100644 --- a/graphics/java/android/graphics/drawable/BitmapDrawable.java +++ b/graphics/java/android/graphics/drawable/BitmapDrawable.java @@ -174,11 +174,14 @@ public class BitmapDrawable extends Drawable { } private void setBitmap(Bitmap bitmap) { - mBitmap = bitmap; - if (bitmap != null) { - computeBitmapSize(); - } else { - mBitmapWidth = mBitmapHeight = -1; + if (bitmap != mBitmap) { + mBitmap = bitmap; + if (bitmap != null) { + computeBitmapSize(); + } else { + mBitmapWidth = mBitmapHeight = -1; + } + invalidateSelf(); } } @@ -205,10 +208,7 @@ public class BitmapDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(DisplayMetrics metrics) { - mTargetDensity = metrics.densityDpi; - if (mBitmap != null) { - computeBitmapSize(); - } + setTargetDensity(metrics.densityDpi); } /** @@ -220,9 +220,12 @@ public class BitmapDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(int density) { - mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; - if (mBitmap != null) { - computeBitmapSize(); + if (mTargetDensity != density) { + mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; + if (mBitmap != null) { + computeBitmapSize(); + } + invalidateSelf(); } } @@ -239,22 +242,28 @@ public class BitmapDrawable extends Drawable { * @param gravity the gravity */ public void setGravity(int gravity) { - mBitmapState.mGravity = gravity; - mApplyGravity = true; + if (mBitmapState.mGravity != gravity) { + mBitmapState.mGravity = gravity; + mApplyGravity = true; + invalidateSelf(); + } } public void setAntiAlias(boolean aa) { mBitmapState.mPaint.setAntiAlias(aa); + invalidateSelf(); } @Override public void setFilterBitmap(boolean filter) { mBitmapState.mPaint.setFilterBitmap(filter); + invalidateSelf(); } @Override public void setDither(boolean dither) { mBitmapState.mPaint.setDither(dither); + invalidateSelf(); } public Shader.TileMode getTileModeX() { @@ -280,6 +289,7 @@ public class BitmapDrawable extends Drawable { state.mTileModeX = xmode; state.mTileModeY = ymode; mRebuildShader = true; + invalidateSelf(); } } @@ -336,11 +346,13 @@ public class BitmapDrawable extends Drawable { @Override public void setAlpha(int alpha) { mBitmapState.mPaint.setAlpha(alpha); + invalidateSelf(); } @Override public void setColorFilter(ColorFilter cf) { mBitmapState.mPaint.setColorFilter(cf); + invalidateSelf(); } /** diff --git a/graphics/java/android/graphics/drawable/ClipDrawable.java b/graphics/java/android/graphics/drawable/ClipDrawable.java index 2b3bd80..b333e01 100644 --- a/graphics/java/android/graphics/drawable/ClipDrawable.java +++ b/graphics/java/android/graphics/drawable/ClipDrawable.java @@ -111,20 +111,23 @@ public class ClipDrawable extends Drawable implements Drawable.Callback { // overrides from Drawable.Callback public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } diff --git a/graphics/java/android/graphics/drawable/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index 0985c1b..4418e02 100644 --- a/graphics/java/android/graphics/drawable/ColorDrawable.java +++ b/graphics/java/android/graphics/drawable/ColorDrawable.java @@ -26,10 +26,8 @@ import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; /** - * A specialized Drawable that fills the Canvas with a specified color, - * with respect to the clip region. Note that a ColorDrawable ignores the ColorFilter. - * It also ignores the Bounds, meaning it will draw everywhere in the current clip, - * even if setBounds(...) was called with a smaller area. + * A specialized Drawable that fills the Canvas with a specified color. + * Note that a ColorDrawable ignores the ColorFilter. * * <p>It can be defined in an XML file with the <code><color></code> element.</p> * @@ -37,6 +35,7 @@ import java.io.IOException; */ public class ColorDrawable extends Drawable { private ColorState mState; + private final Paint mPaint = new Paint(); /** * Creates a new black ColorDrawable. @@ -52,7 +51,7 @@ public class ColorDrawable extends Drawable { */ public ColorDrawable(int color) { this(null); - mState.mBaseColor = mState.mUseColor = color; + setColor(color); } private ColorDrawable(ColorState state) { @@ -66,7 +65,32 @@ public class ColorDrawable extends Drawable { @Override public void draw(Canvas canvas) { - canvas.drawColor(mState.mUseColor); + if ((mState.mUseColor >>> 24) != 0) { + mPaint.setColor(mState.mUseColor); + canvas.drawRect(getBounds(), mPaint); + } + } + + /** + * Gets the drawable's color value. + * + * @return int The color to draw. + */ + public int getColor() { + return mState.mUseColor; + } + + /** + * Sets the drawable's color value. This action will clobber the results of prior calls to + * {@link #setAlpha(int)} on this object, which side-affected the underlying color. + * + * @param color The color to draw. + */ + public void setColor(int color) { + if (mState.mBaseColor != color || mState.mUseColor != color) { + invalidateSelf(); + mState.mBaseColor = mState.mUseColor = color; + } } /** @@ -88,6 +112,7 @@ public class ColorDrawable extends Drawable { int baseAlpha = mState.mBaseColor >>> 24; int useAlpha = baseAlpha * alpha >> 8; mState.mUseColor = (mState.mBaseColor << 8 >>> 8) | (useAlpha << 24); + invalidateSelf(); } /** @@ -129,7 +154,7 @@ public class ColorDrawable extends Drawable { } final static class ColorState extends ConstantState { - int mBaseColor; // initial color. never changes + int mBaseColor; // base color, independent of setAlpha() int mUseColor; // basecolor modulated by setAlpha() int mChangingConfigurations; diff --git a/graphics/java/android/graphics/drawable/Drawable.java b/graphics/java/android/graphics/drawable/Drawable.java index 9655125..159f371e 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -16,21 +16,31 @@ package android.graphics.drawable; -import java.io.InputStream; -import java.io.IOException; -import java.util.Arrays; - import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.*; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.NinePatch; +import android.graphics.PixelFormat; +import android.graphics.PorterDuff; +import android.graphics.PorterDuffColorFilter; +import android.graphics.Rect; +import android.graphics.Region; import android.util.AttributeSet; import android.util.DisplayMetrics; import android.util.StateSet; -import android.util.Xml; import android.util.TypedValue; +import android.util.Xml; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.WeakReference; +import java.util.Arrays; /** * A Drawable is a general abstraction for "something that can be drawn." Most @@ -103,7 +113,7 @@ public abstract class Drawable { private int mLevel = 0; private int mChangingConfigurations = 0; private Rect mBounds = ZERO_BOUNDS_RECT; // lazily becomes a new Rect() - /*package*/ Callback mCallback = null; + private WeakReference<Callback> mCallback = null; private boolean mVisible = true; /** @@ -282,22 +292,41 @@ public abstract class Drawable { * that want to support animated drawables. * * @param cb The client's Callback implementation. + * + * @see #getCallback() */ public final void setCallback(Callback cb) { - mCallback = cb; + mCallback = new WeakReference<Callback>(cb); } /** + * Return the current {@link Callback} implementation attached to this + * Drawable. + * + * @return A {@link Callback} instance or null if no callback was set. + * + * @see #setCallback(android.graphics.drawable.Drawable.Callback) + */ + public Callback getCallback() { + if (mCallback != null) { + return mCallback.get(); + } + return null; + } + + /** * Use the current {@link Callback} implementation to have this Drawable * redrawn. Does nothing if there is no Callback attached to the * Drawable. * * @see Callback#invalidateDrawable + * @see #getCallback() + * @see #setCallback(android.graphics.drawable.Drawable.Callback) */ - public void invalidateSelf() - { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + public void invalidateSelf() { + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } @@ -311,10 +340,10 @@ public abstract class Drawable { * * @see Callback#scheduleDrawable */ - public void scheduleSelf(Runnable what, long when) - { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + public void scheduleSelf(Runnable what, long when) { + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } @@ -327,10 +356,10 @@ public abstract class Drawable { * * @see Callback#unscheduleDrawable */ - public void unscheduleSelf(Runnable what) - { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + public void unscheduleSelf(Runnable what) { + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } @@ -414,6 +443,13 @@ public abstract class Drawable { } /** + * If this Drawable does transition animations between states, ask that + * it immediately jump to the current state and skip any active animations. + */ + public void jumpToCurrentState() { + } + + /** * @return The current drawable that will be used by this drawable. For simple drawables, this * is just the drawable itself. For drawables that change state like * {@link StateListDrawable} and {@link LevelListDrawable} this will be the child drawable @@ -472,7 +508,10 @@ public abstract class Drawable { */ public boolean setVisible(boolean visible, boolean restart) { boolean changed = mVisible != visible; - mVisible = visible; + if (changed) { + mVisible = visible; + invalidateSelf(); + } return changed; } @@ -645,6 +684,8 @@ public abstract class Drawable { * Calling this method on a mutable Drawable will have no effect. * * @return This drawable. + * @see ConstantState + * @see #getConstantState() */ public Drawable mutate() { return this; @@ -749,6 +790,10 @@ public abstract class Drawable { drawable = new StateListDrawable(); } else if (name.equals("level-list")) { drawable = new LevelListDrawable(); + /* Probably not doing this. + } else if (name.equals("mipmap")) { + drawable = new MipmapDrawable(); + */ } else if (name.equals("layer-list")) { drawable = new LayerDrawable(); } else if (name.equals("transition")) { @@ -770,7 +815,7 @@ public abstract class Drawable { } else if (name.equals("inset")) { drawable = new InsetDrawable(); } else if (name.equals("bitmap")) { - drawable = new BitmapDrawable(); + drawable = new BitmapDrawable(r); if (r != null) { ((BitmapDrawable) drawable).setTargetDensity(r.getDisplayMetrics()); } @@ -805,6 +850,9 @@ public abstract class Drawable { return null; } + /** + * Inflate this Drawable from an XML resource. + */ public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) throws XmlPullParserException, IOException { @@ -813,6 +861,12 @@ public abstract class Drawable { a.recycle(); } + /** + * Inflate a Drawable from an XML resource. + * + * @throws XmlPullParserException + * @throws IOException + */ void inflateWithAttributes(Resources r, XmlPullParser parser, TypedArray attrs, int visibleAttr) throws XmlPullParserException, IOException { @@ -820,12 +874,27 @@ public abstract class Drawable { mVisible = attrs.getBoolean(visibleAttr, mVisible); } + /** + * This abstract class is used by {@link Drawable}s to store shared constant state and data + * between Drawables. {@link BitmapDrawable}s created from the same resource will for instance + * share a unique bitmap stored in their ConstantState. + * + * <p> + * {@link #newDrawable(Resources)} can be used as a factory to create new Drawable instances + * from this ConstantState. + * </p> + * + * Use {@link Drawable#getConstantState()} to retrieve the ConstantState of a Drawable. Calling + * {@link Drawable#mutate()} on a Drawable should typically create a new ConstantState for that + * Drawable. + */ public static abstract class ConstantState { /** * Create a new drawable without supplying resources the caller * is running in. Note that using this means the density-dependent * drawables (like bitmaps) will not be able to update their target - * density correctly. + * density correctly. One should use {@link #newDrawable(Resources)} + * instead to provide a resource. */ public abstract Drawable newDrawable(); /** @@ -844,6 +913,13 @@ public abstract class Drawable { public abstract int getChangingConfigurations(); } + /** + * Return a {@link ConstantState} instance that holds the shared state of this Drawable. + *q + * @return The ConstantState associated to that Drawable. + * @see ConstantState + * @see Drawable#mutate() + */ public ConstantState getConstantState() { return null; } diff --git a/graphics/java/android/graphics/drawable/DrawableContainer.java b/graphics/java/android/graphics/drawable/DrawableContainer.java index b13f26f..a9414e8 100644 --- a/graphics/java/android/graphics/drawable/DrawableContainer.java +++ b/graphics/java/android/graphics/drawable/DrawableContainer.java @@ -17,9 +17,20 @@ package android.graphics.drawable; import android.content.res.Resources; -import android.graphics.*; - +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.Rect; +import android.os.SystemClock; + +/** + * A helper class that contains several {@link Drawable}s and selects which one to use. + * + * You can subclass it to create your own DrawableContainers or directly use one its child classes. + */ public class DrawableContainer extends Drawable implements Drawable.Callback { + private static final boolean DEBUG = false; + private static final String TAG = "DrawableContainer"; /** * To be proper, we should have a getter for dither (and alpha, etc.) @@ -40,6 +51,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { private int mCurIndex = -1; private boolean mMutated; + // Animations. + private Runnable mAnimationRunnable; + private long mEnterAnimationEnd; + private long mExitAnimationEnd; + private Drawable mLastDrawable; + // overrides from Drawable @Override @@ -47,6 +64,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mCurrDrawable != null) { mCurrDrawable.draw(canvas); } + if (mLastDrawable != null) { + mLastDrawable.draw(canvas); + } } @Override @@ -75,7 +95,11 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { if (mAlpha != alpha) { mAlpha = alpha; if (mCurrDrawable != null) { - mCurrDrawable.setAlpha(alpha); + if (mEnterAnimationEnd == 0) { + mCurrDrawable.setAlpha(alpha); + } else { + animate(false); + } } } } @@ -100,8 +124,29 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + /** + * Change the global fade duration when a new drawable is entering + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setEnterFadeDuration(int ms) { + mDrawableContainerState.mEnterFadeDuration = ms; + } + + /** + * Change the global fade duration when a new drawable is leaving + * the scene. + * @param ms The amount of time to fade in milliseconds. + */ + public void setExitFadeDuration(int ms) { + mDrawableContainerState.mExitFadeDuration = ms; + } + @Override protected void onBoundsChange(Rect bounds) { + if (mLastDrawable != null) { + mLastDrawable.setBounds(bounds); + } if (mCurrDrawable != null) { mCurrDrawable.setBounds(bounds); } @@ -113,7 +158,34 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } @Override + public void jumpToCurrentState() { + boolean changed = false; + if (mLastDrawable != null) { + mLastDrawable.jumpToCurrentState(); + mLastDrawable = null; + changed = true; + } + if (mCurrDrawable != null) { + mCurrDrawable.jumpToCurrentState(); + } + if (mExitAnimationEnd != 0) { + mExitAnimationEnd = 0; + changed = true; + } + if (mEnterAnimationEnd != 0) { + mEnterAnimationEnd = 0; + changed = true; + } + if (changed) { + invalidateSelf(); + } + } + + @Override protected boolean onStateChange(int[] state) { + if (mLastDrawable != null) { + return mLastDrawable.setState(state); + } if (mCurrDrawable != null) { return mCurrDrawable.setState(state); } @@ -122,6 +194,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @Override protected boolean onLevelChange(int level) { + if (mLastDrawable != null) { + return mLastDrawable.setLevel(level); + } if (mCurrDrawable != null) { return mCurrDrawable.setLevel(level); } @@ -160,30 +235,30 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0; } - public void invalidateDrawable(Drawable who) - { - if (who == mCurrDrawable && mCallback != null) { - mCallback.invalidateDrawable(this); + public void invalidateDrawable(Drawable who) { + if (who == mCurrDrawable && getCallback() != null) { + getCallback().invalidateDrawable(this); } } - public void scheduleDrawable(Drawable who, Runnable what, long when) - { - if (who == mCurrDrawable && mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + public void scheduleDrawable(Drawable who, Runnable what, long when) { + if (who == mCurrDrawable && getCallback() != null) { + getCallback().scheduleDrawable(this, what, when); } } - public void unscheduleDrawable(Drawable who, Runnable what) - { - if (who == mCurrDrawable && mCallback != null) { - mCallback.unscheduleDrawable(this, what); + public void unscheduleDrawable(Drawable who, Runnable what) { + if (who == mCurrDrawable && getCallback() != null) { + getCallback().unscheduleDrawable(this, what); } } @Override public boolean setVisible(boolean visible, boolean restart) { boolean changed = super.setVisible(visible, restart); + if (mLastDrawable != null) { + mLastDrawable.setVisible(visible, restart); + } if (mCurrDrawable != null) { mCurrDrawable.setVisible(visible, restart); } @@ -196,21 +271,43 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDrawableContainerState.getOpacity(); } - public boolean selectDrawable(int idx) - { + public boolean selectDrawable(int idx) { if (idx == mCurIndex) { return false; } - if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { - Drawable d = mDrawableContainerState.mDrawables[idx]; + + final long now = SystemClock.uptimeMillis(); + + if (DEBUG) android.util.Log.i(TAG, toString() + " from " + mCurIndex + " to " + idx + + ": exit=" + mDrawableContainerState.mExitFadeDuration + + " enter=" + mDrawableContainerState.mEnterFadeDuration); + + if (mDrawableContainerState.mExitFadeDuration > 0) { + if (mLastDrawable != null) { + mLastDrawable.setVisible(false, false); + } if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); + mLastDrawable = mCurrDrawable; + mExitAnimationEnd = now + mDrawableContainerState.mExitFadeDuration; + } else { + mLastDrawable = null; + mExitAnimationEnd = 0; } + } else if (mCurrDrawable != null) { + mCurrDrawable.setVisible(false, false); + } + + if (idx >= 0 && idx < mDrawableContainerState.mNumChildren) { + Drawable d = mDrawableContainerState.mDrawables[idx]; mCurrDrawable = d; mCurIndex = idx; if (d != null) { + if (mDrawableContainerState.mEnterFadeDuration > 0) { + mEnterAnimationEnd = now + mDrawableContainerState.mEnterFadeDuration; + } else { + d.setAlpha(mAlpha); + } d.setVisible(isVisible(), true); - d.setAlpha(mAlpha); d.setDither(mDrawableContainerState.mDither); d.setColorFilter(mColorFilter); d.setState(getState()); @@ -218,16 +315,72 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { d.setBounds(getBounds()); } } else { - if (mCurrDrawable != null) { - mCurrDrawable.setVisible(false, false); - } mCurrDrawable = null; mCurIndex = -1; } + + if (mEnterAnimationEnd != 0 || mExitAnimationEnd != 0) { + if (mAnimationRunnable == null) { + mAnimationRunnable = new Runnable() { + @Override public void run() { + animate(true); + invalidateSelf(); + } + }; + } else { + unscheduleSelf(mAnimationRunnable); + } + // Compute first frame and schedule next animation. + animate(true); + } + invalidateSelf(); + return true; } + void animate(boolean schedule) { + final long now = SystemClock.uptimeMillis(); + boolean animating = false; + if (mCurrDrawable != null) { + if (mEnterAnimationEnd != 0) { + if (mEnterAnimationEnd <= now) { + mCurrDrawable.setAlpha(mAlpha); + mEnterAnimationEnd = 0; + } else { + int animAlpha = (int)((mEnterAnimationEnd-now)*255) + / mDrawableContainerState.mEnterFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " cur alpha " + animAlpha); + mCurrDrawable.setAlpha(((255-animAlpha)*mAlpha)/255); + animating = true; + } + } + } else { + mEnterAnimationEnd = 0; + } + if (mLastDrawable != null) { + if (mExitAnimationEnd != 0) { + if (mExitAnimationEnd <= now) { + mLastDrawable.setVisible(false, false); + mLastDrawable = null; + mExitAnimationEnd = 0; + } else { + int animAlpha = (int)((mExitAnimationEnd-now)*255) + / mDrawableContainerState.mExitFadeDuration; + if (DEBUG) android.util.Log.i(TAG, toString() + " last alpha " + animAlpha); + mLastDrawable.setAlpha((animAlpha*mAlpha)/255); + animating = true; + } + } + } else { + mExitAnimationEnd = 0; + } + + if (schedule && animating) { + scheduleSelf(mAnimationRunnable, now + 1000/60); + } + } + @Override public Drawable getCurrent() { return mCurrDrawable; @@ -255,6 +408,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return this; } + /** + * A ConstantState that can contain several {@link Drawable}s. + * + * This class was made public to enable testing, and its visibility may change in a future + * release. + */ public abstract static class DrawableContainerState extends ConstantState { final DrawableContainer mOwner; @@ -287,6 +446,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { boolean mDither = DEFAULT_DITHER; + int mEnterFadeDuration; + int mExitFadeDuration; + DrawableContainerState(DrawableContainerState orig, DrawableContainer owner, Resources res) { mOwner = owner; @@ -327,6 +489,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { mDither = orig.mDither; + mEnterFadeDuration = orig.mEnterFadeDuration; + mExitFadeDuration = orig.mExitFadeDuration; + } else { mDrawables = new Drawable[10]; mNumChildren = 0; @@ -443,12 +608,12 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mConstantMinimumHeight; } - private void computeConstantSize() { + protected void computeConstantSize() { mComputedConstantSize = true; final int N = getChildCount(); final Drawable[] drawables = mDrawables; - mConstantWidth = mConstantHeight = 0; + mConstantWidth = mConstantHeight = -1; mConstantMinimumWidth = mConstantMinimumHeight = 0; for (int i = 0; i < N; i++) { Drawable dr = drawables[i]; @@ -463,6 +628,22 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { } } + public final void setEnterFadeDuration(int duration) { + mEnterFadeDuration = duration; + } + + public final int getEnterFadeDuration() { + return mEnterFadeDuration; + } + + public final void setExitFadeDuration(int duration) { + mExitFadeDuration = duration; + } + + public final int getExitFadeDuration() { + return mExitFadeDuration; + } + public final int getOpacity() { if (mHaveOpacity) { return mOpacity; diff --git a/graphics/java/android/graphics/drawable/GradientDrawable.java b/graphics/java/android/graphics/drawable/GradientDrawable.java index 308fd08..33f050c 100644 --- a/graphics/java/android/graphics/drawable/GradientDrawable.java +++ b/graphics/java/android/graphics/drawable/GradientDrawable.java @@ -126,7 +126,7 @@ public class GradientDrawable extends Drawable { private boolean mRectIsDirty; // internal state private boolean mMutated; private Path mRingPath; - private boolean mPathIsDirty; + private boolean mPathIsDirty = true; /** * Controls how the gradient is oriented relative to the drawable's bounds @@ -179,6 +179,8 @@ public class GradientDrawable extends Drawable { */ public void setCornerRadii(float[] radii) { mGradientState.setCornerRadii(radii); + mPathIsDirty = true; + invalidateSelf(); } /** @@ -187,6 +189,8 @@ public class GradientDrawable extends Drawable { */ public void setCornerRadius(float radius) { mGradientState.setCornerRadius(radius); + mPathIsDirty = true; + invalidateSelf(); } /** @@ -212,32 +216,41 @@ public class GradientDrawable extends Drawable { e = new DashPathEffect(new float[] { dashWidth, dashGap }, 0); } mStrokePaint.setPathEffect(e); + invalidateSelf(); } public void setSize(int width, int height) { - mGradientState.setSize(width, height); + mGradientState.setSize(width, height); + mPathIsDirty = true; + invalidateSelf(); } public void setShape(int shape) { mRingPath = null; + mPathIsDirty = true; mGradientState.setShape(shape); + invalidateSelf(); } public void setGradientType(int gradient) { mGradientState.setGradientType(gradient); mRectIsDirty = true; + invalidateSelf(); } public void setGradientCenter(float x, float y) { mGradientState.setGradientCenter(x, y); + invalidateSelf(); } public void setGradientRadius(float gradientRadius) { mGradientState.setGradientRadius(gradientRadius); + invalidateSelf(); } public void setUseLevel(boolean useLevel) { mGradientState.mUseLevel = useLevel; + invalidateSelf(); } private int modulateAlpha(int alpha) { @@ -312,19 +325,20 @@ public class GradientDrawable extends Drawable { switch (st.mShape) { case RECTANGLE: if (st.mRadiusArray != null) { - mPath.reset(); - mPath.addRoundRect(mRect, st.mRadiusArray, - Path.Direction.CW); + if (mPathIsDirty || mRectIsDirty) { + mPath.reset(); + mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW); + mPathIsDirty = mRectIsDirty = false; + } canvas.drawPath(mPath, mFillPaint); if (haveStroke) { canvas.drawPath(mPath, mStrokePaint); } - } - else { + } else if (st.mRadius > 0.0f) { // since the caller is only giving us 1 value, we will force // it to be square if the rect is too small in one dimension // to show it. If we did nothing, Skia would clamp the rad - // independently along each axis, giving us a thin ellips + // independently along each axis, giving us a thin ellipse // if the rect were very wide but not very tall float rad = st.mRadius; float r = Math.min(mRect.width(), mRect.height()) * 0.5f; @@ -335,6 +349,11 @@ public class GradientDrawable extends Drawable { if (haveStroke) { canvas.drawRoundRect(mRect, rad, rad, mStrokePaint); } + } else { + canvas.drawRect(mRect, mFillPaint); + if (haveStroke) { + canvas.drawRect(mRect, mStrokePaint); + } } break; case OVAL: @@ -423,6 +442,7 @@ public class GradientDrawable extends Drawable { public void setColor(int argb) { mGradientState.setSolidColor(argb); mFillPaint.setColor(argb); + invalidateSelf(); } @Override @@ -433,17 +453,26 @@ public class GradientDrawable extends Drawable { @Override public void setAlpha(int alpha) { - mAlpha = alpha; + if (alpha != mAlpha) { + mAlpha = alpha; + invalidateSelf(); + } } @Override public void setDither(boolean dither) { - mDither = dither; + if (dither != mDither) { + mDither = dither; + invalidateSelf(); + } } @Override public void setColorFilter(ColorFilter cf) { - mColorFilter = cf; + if (cf != mColorFilter) { + mColorFilter = cf; + invalidateSelf(); + } } @Override @@ -595,6 +624,8 @@ public class GradientDrawable extends Drawable { int shapeType = a.getInt( com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE); + boolean dither = a.getBoolean( + com.android.internal.R.styleable.GradientDrawable_dither, false); if (shapeType == RING) { st.mInnerRadius = a.getDimensionPixelSize( @@ -616,10 +647,11 @@ public class GradientDrawable extends Drawable { a.recycle(); setShape(shapeType); - + setDither(dither); + int type; - final int innerDepth = parser.getDepth()+1; + final int innerDepth = parser.getDepth() + 1; int depth; while ((type=parser.next()) != XmlPullParser.END_DOCUMENT && ((depth=parser.getDepth()) >= innerDepth @@ -782,11 +814,12 @@ public class GradientDrawable extends Drawable { com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius); if (topLeftRadius != radius || topRightRadius != radius || bottomLeftRadius != radius || bottomRightRadius != radius) { + // The corner radii are specified in clockwise order (see Path.addRoundRect()) setCornerRadii(new float[] { topLeftRadius, topLeftRadius, topRightRadius, topRightRadius, - bottomLeftRadius, bottomLeftRadius, - bottomRightRadius, bottomRightRadius + bottomRightRadius, bottomRightRadius, + bottomLeftRadius, bottomLeftRadius }); } a.recycle(); diff --git a/graphics/java/android/graphics/drawable/InsetDrawable.java b/graphics/java/android/graphics/drawable/InsetDrawable.java index 67c928c..231234c 100644 --- a/graphics/java/android/graphics/drawable/InsetDrawable.java +++ b/graphics/java/android/graphics/drawable/InsetDrawable.java @@ -131,20 +131,23 @@ public class InsetDrawable extends Drawable implements Drawable.Callback // overrides from Drawable.Callback public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 234b80d..49dbbca 100644 --- a/graphics/java/android/graphics/drawable/LayerDrawable.java +++ b/graphics/java/android/graphics/drawable/LayerDrawable.java @@ -21,7 +21,10 @@ import org.xmlpull.v1.XmlPullParserException; import android.content.res.Resources; import android.content.res.TypedArray; -import android.graphics.*; +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.PixelFormat; +import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; @@ -46,6 +49,7 @@ import java.io.IOException; public class LayerDrawable extends Drawable implements Drawable.Callback { LayerState mLayerState; + private int mOpacityOverride = PixelFormat.UNKNOWN; private int[] mPaddingL; private int[] mPaddingT; private int[] mPaddingR; @@ -110,6 +114,13 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { int type; + TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.LayerDrawable); + + mOpacityOverride = a.getInt(com.android.internal.R.styleable.LayerDrawable_opacity, + PixelFormat.UNKNOWN); + + a.recycle(); + final int innerDepth = parser.getDepth() + 1; int depth; while ((type = parser.next()) != XmlPullParser.END_DOCUMENT @@ -122,7 +133,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { continue; } - TypedArray a = r.obtainAttributes(attrs, + a = r.obtainAttributes(attrs, com.android.internal.R.styleable.LayerDrawableItem); int left = a.getDimensionPixelOffset( @@ -266,6 +277,7 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { */ public boolean setDrawableByLayerId(int id, Drawable drawable) { final ChildDrawable[] layers = mLayerState.mChildren; + drawable.setCallback(this); for (int i = mLayerState.mNum - 1; i >= 0; i--) { if (layers[i].mId == id) { @@ -294,20 +306,23 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { // overrides from Drawable.Callback public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } @@ -387,9 +402,28 @@ public class LayerDrawable extends Drawable implements Drawable.Callback { array[i].mDrawable.setColorFilter(cf); } } + + /** + * Sets the opacity of this drawable directly, instead of collecting the states from + * the layers + * + * @param opacity The opacity to use, or {@link PixelFormat#UNKNOWN PixelFormat.UNKNOWN} + * for the default behavior + * + * @see PixelFormat#UNKNOWN + * @see PixelFormat#TRANSLUCENT + * @see PixelFormat#TRANSPARENT + * @see PixelFormat#OPAQUE + */ + public void setOpacity(int opacity) { + mOpacityOverride = opacity; + } @Override public int getOpacity() { + if (mOpacityOverride != PixelFormat.UNKNOWN) { + return mOpacityOverride; + } return mLayerState.getOpacity(); } diff --git a/graphics/java/android/graphics/drawable/MipmapDrawable.java b/graphics/java/android/graphics/drawable/MipmapDrawable.java new file mode 100644 index 0000000..cd39719 --- /dev/null +++ b/graphics/java/android/graphics/drawable/MipmapDrawable.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2006 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.res.Resources; +import android.content.res.TypedArray; +import android.graphics.Rect; +import android.util.AttributeSet; + +import java.io.IOException; + +/** + * @hide -- we are probably moving to do MipMaps in another way (more integrated + * with the resource system). + * + * A resource that manages a number of alternate Drawables, and which actually draws the one which + * size matches the most closely the drawing bounds. Providing several pre-scaled version of the + * drawable helps minimizing the aliasing artifacts that can be introduced by the scaling. + * + * <p> + * Use {@link #addDrawable(Drawable)} to define the different Drawables that will represent the + * mipmap levels of this MipmapDrawable. The mipmap Drawable that will actually be used when this + * MipmapDrawable is drawn is the one which has the smallest intrinsic height greater or equal than + * the bounds' height. This selection ensures that the best available mipmap level is scaled down to + * draw this MipmapDrawable. + * </p> + * + * If the bounds' height is larger than the largest mipmap, the largest mipmap will be scaled up. + * Note that Drawables without intrinsic height (i.e. with a negative value, such as Color) will + * only be used if no other mipmap Drawable are provided. The Drawables' intrinsic heights should + * not be changed after the Drawable has been added to this MipmapDrawable. + * + * <p> + * The different mipmaps' parameters (opacity, padding, color filter, gravity...) should typically + * be similar to ensure a continuous visual appearance when the MipmapDrawable is scaled. The aspect + * ratio of the different mipmaps should especially be equal. + * </p> + * + * A typical example use of a MipmapDrawable would be for an image which is intended to be scaled at + * various sizes, and for which one wants to provide pre-scaled versions to precisely control its + * appearance. + * + * <p> + * The intrinsic size of a MipmapDrawable are inferred from those of the largest mipmap (in terms of + * {@link Drawable#getIntrinsicHeight()}). On the opposite, its minimum + * size is defined by the smallest provided mipmap. + * </p> + + * It can be defined in an XML file with the <code><mipmap></code> element. + * Each mipmap Drawable is defined in a nested <code><item></code>. For example: + * <pre> + * <mipmap xmlns:android="http://schemas.android.com/apk/res/android"> + * <item android:drawable="@drawable/my_image_8" /> + * <item android:drawable="@drawable/my_image_32" /> + * <item android:drawable="@drawable/my_image_128" /> + * </mipmap> + *</pre> + * <p> + * With this XML saved into the res/drawable/ folder of the project, it can be referenced as + * the drawable for an {@link android.widget.ImageView}. Assuming that the heights of the provided + * drawables are respectively 8, 32 and 128 pixels, the first one will be scaled down when the + * bounds' height is lower or equal than 8 pixels. The second drawable will then be used up to a + * height of 32 pixels and the largest drawable will be used for greater heights. + * </p> + * @attr ref android.R.styleable#MipmapDrawableItem_drawable + */ +public class MipmapDrawable extends DrawableContainer { + private final MipmapContainerState mMipmapContainerState; + private boolean mMutated; + + public MipmapDrawable() { + this(null, null); + } + + /** + * Adds a Drawable to the list of available mipmap Drawables. The Drawable actually used when + * this MipmapDrawable is drawn is determined from its bounds. + * + * This method has no effect if drawable is null. + * + * @param drawable The Drawable that will be added to list of available mipmap Drawables. + */ + + public void addDrawable(Drawable drawable) { + if (drawable != null) { + mMipmapContainerState.addDrawable(drawable); + onDrawableAdded(); + } + } + + private void onDrawableAdded() { + // selectDrawable assumes that the container content does not change. + // When a Drawable is added, the same index can correspond to a new Drawable, and since + // selectDrawable has a fast exit case when oldIndex==newIndex, the new drawable could end + // up not being used in place of the previous one if they happen to share the same index. + // This make sure the new computed index can actually replace the previous one. + selectDrawable(-1); + onBoundsChange(getBounds()); + } + + // overrides from Drawable + + @Override + protected void onBoundsChange(Rect bounds) { + final int index = mMipmapContainerState.indexForBounds(bounds); + + // Will call invalidateSelf() if needed + selectDrawable(index); + + super.onBoundsChange(bounds); + } + + @Override + public void inflate(Resources r, XmlPullParser parser, AttributeSet attrs) + throws XmlPullParserException, IOException { + + super.inflate(r, parser, attrs); + + int type; + + final int innerDepth = parser.getDepth() + 1; + int depth; + while ((type = parser.next()) != XmlPullParser.END_DOCUMENT + && ((depth = parser.getDepth()) >= innerDepth + || type != XmlPullParser.END_TAG)) { + if (type != XmlPullParser.START_TAG) { + continue; + } + + if (depth > innerDepth || !parser.getName().equals("item")) { + continue; + } + + TypedArray a = r.obtainAttributes(attrs, + com.android.internal.R.styleable.MipmapDrawableItem); + + int drawableRes = a.getResourceId( + com.android.internal.R.styleable.MipmapDrawableItem_drawable, 0); + + a.recycle(); + + Drawable dr; + if (drawableRes != 0) { + dr = r.getDrawable(drawableRes); + } else { + while ((type = parser.next()) == XmlPullParser.TEXT) { + } + if (type != XmlPullParser.START_TAG) { + throw new XmlPullParserException( + parser.getPositionDescription() + + ": <item> tag requires a 'drawable' attribute or " + + "child tag defining a drawable"); + } + dr = Drawable.createFromXmlInner(r, parser, attrs); + } + + mMipmapContainerState.addDrawable(dr); + } + + onDrawableAdded(); + } + + @Override + public Drawable mutate() { + if (!mMutated && super.mutate() == this) { + mMipmapContainerState.mMipmapHeights = mMipmapContainerState.mMipmapHeights.clone(); + mMutated = true; + } + return this; + } + + private final static class MipmapContainerState extends DrawableContainerState { + private int[] mMipmapHeights; + + MipmapContainerState(MipmapContainerState orig, MipmapDrawable owner, Resources res) { + super(orig, owner, res); + + if (orig != null) { + mMipmapHeights = orig.mMipmapHeights; + } else { + mMipmapHeights = new int[getChildren().length]; + } + + // Change the default value + setConstantSize(true); + } + + /** + * Returns the index of the child mipmap drawable that will best fit the provided bounds. + * This index is determined by comparing bounds' height and children intrinsic heights. + * The returned mipmap index is the smallest mipmap which height is greater or equal than + * the bounds' height. If the bounds' height is larger than the largest mipmap, the largest + * mipmap index is returned. + * + * @param bounds The bounds of the MipMapDrawable. + * @return The index of the child Drawable that will best fit these bounds, or -1 if there + * are no children mipmaps. + */ + public int indexForBounds(Rect bounds) { + final int boundsHeight = bounds.height(); + final int N = getChildCount(); + for (int i = 0; i < N; i++) { + if (boundsHeight <= mMipmapHeights[i]) { + return i; + } + } + + // No mipmap larger than bounds found. Use largest one which will be scaled up. + if (N > 0) { + return N - 1; + } + // No Drawable mipmap at all + return -1; + } + + /** + * Adds a Drawable to the list of available mipmap Drawables. This list can be retrieved + * using {@link DrawableContainer.DrawableContainerState#getChildren()} and this method + * ensures that it is always sorted by increasing {@link Drawable#getIntrinsicHeight()}. + * + * @param drawable The Drawable that will be added to children list + */ + public void addDrawable(Drawable drawable) { + // Insert drawable in last position, correctly resetting cached values and + // especially mComputedConstantSize + int pos = addChild(drawable); + + // Bubble sort the last drawable to restore the sort by intrinsic height + final int drawableHeight = drawable.getIntrinsicHeight(); + + while (pos > 0) { + final Drawable previousDrawable = mDrawables[pos-1]; + final int previousIntrinsicHeight = previousDrawable.getIntrinsicHeight(); + + if (drawableHeight < previousIntrinsicHeight) { + mDrawables[pos] = previousDrawable; + mMipmapHeights[pos] = previousIntrinsicHeight; + + mDrawables[pos-1] = drawable; + mMipmapHeights[pos-1] = drawableHeight; + pos--; + } else { + break; + } + } + } + + /** + * Intrinsic sizes are those of the largest available mipmap. + * Minimum sizes are those of the smallest available mipmap. + */ + @Override + protected void computeConstantSize() { + final int N = getChildCount(); + if (N > 0) { + final Drawable smallestDrawable = mDrawables[0]; + mConstantMinimumWidth = smallestDrawable.getMinimumWidth(); + mConstantMinimumHeight = smallestDrawable.getMinimumHeight(); + + final Drawable largestDrawable = mDrawables[N-1]; + mConstantWidth = largestDrawable.getIntrinsicWidth(); + mConstantHeight = largestDrawable.getIntrinsicHeight(); + } else { + mConstantWidth = mConstantHeight = -1; + mConstantMinimumWidth = mConstantMinimumHeight = 0; + } + mComputedConstantSize = true; + } + + @Override + public Drawable newDrawable() { + return new MipmapDrawable(this, null); + } + + @Override + public Drawable newDrawable(Resources res) { + return new MipmapDrawable(this, res); + } + + @Override + public void growArray(int oldSize, int newSize) { + super.growArray(oldSize, newSize); + int[] newInts = new int[newSize]; + System.arraycopy(mMipmapHeights, 0, newInts, 0, oldSize); + mMipmapHeights = newInts; + } + } + + private MipmapDrawable(MipmapContainerState state, Resources res) { + MipmapContainerState as = new MipmapContainerState(state, this, res); + mMipmapContainerState = as; + setConstantState(as); + onDrawableAdded(); + } +} diff --git a/graphics/java/android/graphics/drawable/NinePatchDrawable.java b/graphics/java/android/graphics/drawable/NinePatchDrawable.java index 6768186..a5175c5 100644 --- a/graphics/java/android/graphics/drawable/NinePatchDrawable.java +++ b/graphics/java/android/graphics/drawable/NinePatchDrawable.java @@ -21,7 +21,6 @@ import android.content.res.Resources; import android.content.res.TypedArray; import android.util.AttributeSet; import android.util.DisplayMetrics; -import android.util.Log; import android.util.TypedValue; import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; @@ -99,7 +98,8 @@ public class NinePatchDrawable extends Drawable { mPadding = state.mPadding; mTargetDensity = res != null ? res.getDisplayMetrics().densityDpi : state.mTargetDensity; - if (DEFAULT_DITHER != state.mDither) { + //noinspection PointlessBooleanExpression + if (state.mDither != DEFAULT_DITHER) { // avoid calling the setter unless we need to, since it does a // lazy allocation of a paint setDither(state.mDither); @@ -132,10 +132,7 @@ public class NinePatchDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(DisplayMetrics metrics) { - mTargetDensity = metrics.densityDpi; - if (mNinePatch != null) { - computeBitmapSize(); - } + setTargetDensity(metrics.densityDpi); } /** @@ -147,9 +144,12 @@ public class NinePatchDrawable extends Drawable { * @see android.graphics.Bitmap#getDensity() */ public void setTargetDensity(int density) { - mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; - if (mNinePatch != null) { - computeBitmapSize(); + if (density != mTargetDensity) { + mTargetDensity = density == 0 ? DisplayMetrics.DENSITY_DEFAULT : density; + if (mNinePatch != null) { + computeBitmapSize(); + } + invalidateSelf(); } } @@ -177,16 +177,9 @@ public class NinePatchDrawable extends Drawable { } } } - - // overrides @Override public void draw(Canvas canvas) { - if (false) { - float[] pts = new float[2]; - canvas.getMatrix().mapPoints(pts); - Log.v("9patch", "Drawing 9-patch @ " + pts[0] + "," + pts[1] + ": " + getBounds()); - } mNinePatch.draw(canvas, getBounds(), mPaint); } @@ -204,16 +197,19 @@ public class NinePatchDrawable extends Drawable { @Override public void setAlpha(int alpha) { getPaint().setAlpha(alpha); + invalidateSelf(); } @Override public void setColorFilter(ColorFilter cf) { getPaint().setColorFilter(cf); + invalidateSelf(); } @Override public void setDither(boolean dither) { getPaint().setDither(dither); + invalidateSelf(); } @Override diff --git a/graphics/java/android/graphics/drawable/PaintDrawable.java b/graphics/java/android/graphics/drawable/PaintDrawable.java index c86fc46..c71cda1 100644 --- a/graphics/java/android/graphics/drawable/PaintDrawable.java +++ b/graphics/java/android/graphics/drawable/PaintDrawable.java @@ -66,6 +66,7 @@ public class PaintDrawable extends ShapeDrawable { } else { setShape(new RoundRectShape(radii, null, null)); } + invalidateSelf(); } @Override diff --git a/graphics/java/android/graphics/drawable/RotateDrawable.java b/graphics/java/android/graphics/drawable/RotateDrawable.java index 1428efa..4f74b37 100644 --- a/graphics/java/android/graphics/drawable/RotateDrawable.java +++ b/graphics/java/android/graphics/drawable/RotateDrawable.java @@ -117,20 +117,23 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { } public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + final Callback callback = getCallback(); + if (callback != null) { + callback.invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + final Callback callback = getCallback(); + if (callback != null) { + callback.scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + final Callback callback = getCallback(); + if (callback != null) { + callback.unscheduleDrawable(this, what); } } @@ -232,8 +235,6 @@ public class RotateDrawable extends Drawable implements Drawable.Callback { float toDegrees = a.getFloat( com.android.internal.R.styleable.RotateDrawable_toDegrees, 360.0f); - toDegrees = Math.max(fromDegrees, toDegrees); - int res = a.getResourceId( com.android.internal.R.styleable.RotateDrawable_drawable, 0); Drawable drawable = null; diff --git a/graphics/java/android/graphics/drawable/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index a95eb06..a7ed0d0 100644 --- a/graphics/java/android/graphics/drawable/ScaleDrawable.java +++ b/graphics/java/android/graphics/drawable/ScaleDrawable.java @@ -95,6 +95,8 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { float sw = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleWidth); float sh = getPercent(a, com.android.internal.R.styleable.ScaleDrawable_scaleHeight); int g = a.getInt(com.android.internal.R.styleable.ScaleDrawable_scaleGravity, Gravity.LEFT); + boolean min = a.getBoolean( + com.android.internal.R.styleable.ScaleDrawable_useIntrinsicSizeAsMinimum, false); Drawable dr = a.getDrawable(com.android.internal.R.styleable.ScaleDrawable_drawable); a.recycle(); @@ -116,6 +118,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { mScaleState.mScaleWidth = sw; mScaleState.mScaleHeight = sh; mScaleState.mGravity = g; + mScaleState.mUseIntrinsicSizeAsMin = min; if (dr != null) { dr.setCallback(this); } @@ -124,20 +127,20 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { // overrides from Drawable.Callback public void invalidateDrawable(Drawable who) { - if (mCallback != null) { - mCallback.invalidateDrawable(this); + if (getCallback() != null) { + getCallback().invalidateDrawable(this); } } public void scheduleDrawable(Drawable who, Runnable what, long when) { - if (mCallback != null) { - mCallback.scheduleDrawable(this, what, when); + if (getCallback() != null) { + getCallback().scheduleDrawable(this, what, when); } } public void unscheduleDrawable(Drawable who, Runnable what) { - if (mCallback != null) { - mCallback.unscheduleDrawable(this, what); + if (getCallback() != null) { + getCallback().unscheduleDrawable(this, what); } } @@ -206,15 +209,16 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { @Override protected void onBoundsChange(Rect bounds) { final Rect r = mTmpRect; + final boolean min = mScaleState.mUseIntrinsicSizeAsMin; int level = getLevel(); int w = bounds.width(); - final int iw = 0; //mScaleState.mDrawable.getIntrinsicWidth(); if (mScaleState.mScaleWidth > 0) { + final int iw = min ? mScaleState.mDrawable.getIntrinsicWidth() : 0; w -= (int) ((w - iw) * (10000 - level) * mScaleState.mScaleWidth / 10000); } int h = bounds.height(); - final int ih = 0; //mScaleState.mDrawable.getIntrinsicHeight(); if (mScaleState.mScaleHeight > 0) { + final int ih = min ? mScaleState.mDrawable.getIntrinsicHeight() : 0; h -= (int) ((h - ih) * (10000 - level) * mScaleState.mScaleHeight / 10000); } Gravity.apply(mScaleState.mGravity, w, h, bounds, r); @@ -258,6 +262,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { float mScaleWidth; float mScaleHeight; int mGravity; + boolean mUseIntrinsicSizeAsMin; private boolean mCheckedConstantState; private boolean mCanConstantState; @@ -273,6 +278,7 @@ public class ScaleDrawable extends Drawable implements Drawable.Callback { mScaleWidth = orig.mScaleWidth; mScaleHeight = orig.mScaleHeight; mGravity = orig.mGravity; + mUseIntrinsicSizeAsMin = orig.mUseIntrinsicSizeAsMin; mCheckedConstantState = mCanConstantState = true; } } diff --git a/graphics/java/android/graphics/drawable/ShapeDrawable.java b/graphics/java/android/graphics/drawable/ShapeDrawable.java index 0201fb0..4445b6a 100644 --- a/graphics/java/android/graphics/drawable/ShapeDrawable.java +++ b/graphics/java/android/graphics/drawable/ShapeDrawable.java @@ -129,6 +129,7 @@ public class ShapeDrawable extends Drawable { } mShapeState.mPadding.set(left, top, right, bottom); } + invalidateSelf(); } /** @@ -144,6 +145,7 @@ public class ShapeDrawable extends Drawable { } mShapeState.mPadding.set(padding); } + invalidateSelf(); } /** @@ -153,6 +155,7 @@ public class ShapeDrawable extends Drawable { */ public void setIntrinsicWidth(int width) { mShapeState.mIntrinsicWidth = width; + invalidateSelf(); } /** @@ -162,6 +165,7 @@ public class ShapeDrawable extends Drawable { */ public void setIntrinsicHeight(int height) { mShapeState.mIntrinsicHeight = height; + invalidateSelf(); } @Override @@ -236,11 +240,13 @@ public class ShapeDrawable extends Drawable { */ @Override public void setAlpha(int alpha) { mShapeState.mAlpha = alpha; + invalidateSelf(); } @Override public void setColorFilter(ColorFilter cf) { mShapeState.mPaint.setColorFilter(cf); + invalidateSelf(); } @Override @@ -264,6 +270,7 @@ public class ShapeDrawable extends Drawable { @Override public void setDither(boolean dither) { mShapeState.mPaint.setDither(dither); + invalidateSelf(); } @Override @@ -279,7 +286,7 @@ public class ShapeDrawable extends Drawable { protected boolean inflateTag(String name, Resources r, XmlPullParser parser, AttributeSet attrs) { - if (name.equals("padding")) { + if ("padding".equals(name)) { TypedArray a = r.obtainAttributes(attrs, com.android.internal.R.styleable.ShapeDrawablePadding); setPadding( @@ -308,7 +315,10 @@ public class ShapeDrawable extends Drawable { int color = mShapeState.mPaint.getColor(); color = a.getColor(com.android.internal.R.styleable.ShapeDrawable_color, color); mShapeState.mPaint.setColor(color); - + + boolean dither = a.getBoolean(com.android.internal.R.styleable.ShapeDrawable_dither, false); + mShapeState.mPaint.setDither(dither); + setIntrinsicWidth((int) a.getDimension(com.android.internal.R.styleable.ShapeDrawable_width, 0f)); setIntrinsicHeight((int) @@ -344,6 +354,7 @@ public class ShapeDrawable extends Drawable { mShapeState.mPaint.setShader(mShapeState.mShaderFactory.resize(w, h)); } } + invalidateSelf(); } @Override diff --git a/graphics/java/android/graphics/drawable/StateListDrawable.java b/graphics/java/android/graphics/drawable/StateListDrawable.java index 239be40..384ca81 100644 --- a/graphics/java/android/graphics/drawable/StateListDrawable.java +++ b/graphics/java/android/graphics/drawable/StateListDrawable.java @@ -20,6 +20,7 @@ import org.xmlpull.v1.XmlPullParser; import org.xmlpull.v1.XmlPullParserException; import java.io.IOException; +import java.util.Arrays; import android.content.res.Resources; import android.content.res.TypedArray; @@ -44,6 +45,7 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_checkable * @attr ref android.R.styleable#DrawableStates_state_checked * @attr ref android.R.styleable#DrawableStates_state_selected + * @attr ref android.R.styleable#DrawableStates_state_activated * @attr ref android.R.styleable#DrawableStates_state_active * @attr ref android.R.styleable#DrawableStates_state_single * @attr ref android.R.styleable#DrawableStates_state_first @@ -52,6 +54,9 @@ import android.util.StateSet; * @attr ref android.R.styleable#DrawableStates_state_pressed */ public class StateListDrawable extends DrawableContainer { + private static final boolean DEBUG = false; + private static final String TAG = "StateListDrawable"; + /** * To be proper, we should have a getter for dither (and alpha, etc.) * so that proxy classes like this can save/restore their delegates' @@ -93,6 +98,8 @@ public class StateListDrawable extends DrawableContainer { @Override protected boolean onStateChange(int[] stateSet) { int idx = mStateListState.indexOfStateSet(stateSet); + if (DEBUG) android.util.Log.i(TAG, "onStateChange " + this + " states " + + Arrays.toString(stateSet) + " found " + idx); if (idx < 0) { idx = mStateListState.indexOfStateSet(StateSet.WILD_CARD); } @@ -117,6 +124,10 @@ public class StateListDrawable extends DrawableContainer { com.android.internal.R.styleable.StateListDrawable_variablePadding, false)); mStateListState.setConstantSize(a.getBoolean( com.android.internal.R.styleable.StateListDrawable_constantSize, false)); + mStateListState.setEnterFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_enterFadeDuration, 0)); + mStateListState.setExitFadeDuration(a.getInt( + com.android.internal.R.styleable.StateListDrawable_exitFadeDuration, 0)); setDither(a.getBoolean(com.android.internal.R.styleable.StateListDrawable_dither, DEFAULT_DITHER)); @@ -251,7 +262,7 @@ public class StateListDrawable extends DrawableContainer { } static final class StateListState extends DrawableContainerState { - private int[][] mStateSets; + int[][] mStateSets; StateListState(StateListState orig, StateListDrawable owner, Resources res) { super(orig, owner, res); diff --git a/graphics/java/android/graphics/drawable/TransitionDrawable.java b/graphics/java/android/graphics/drawable/TransitionDrawable.java index 4470356..9a3ca40 100644 --- a/graphics/java/android/graphics/drawable/TransitionDrawable.java +++ b/graphics/java/android/graphics/drawable/TransitionDrawable.java @@ -137,7 +137,7 @@ public class TransitionDrawable extends LayerDrawable implements Drawable.Callba final long time = SystemClock.uptimeMillis(); // Animation is over if (time - mStartTimeMillis > mDuration) { - if (mAlpha == 0) { + if (mTo == 0) { mFrom = 0; mTo = 255; mAlpha = 0; diff --git a/graphics/java/android/graphics/drawable/package.html b/graphics/java/android/graphics/drawable/package.html index da49df7..60b7a2c 100644 --- a/graphics/java/android/graphics/drawable/package.html +++ b/graphics/java/android/graphics/drawable/package.html @@ -1,9 +1,10 @@ <HTML> <BODY> -Provides classes to manage a variety of visual elements that are intended for +<p>Provides classes to manage a variety of visual elements that are intended for display only, such as bitmaps and gradients. These elements are often used by widgets as background images or simply as indicators (for example, a volume -level indicator). You can create most of these in XML as described in <a -href="{@docRoot}guide/topics/resources/available-resources.html">Availeble Resource Types</a>. +level indicator).</p> +<p>You can create most of these drawables using XML, as described in <a +href="{@docRoot}guide/topics/resources/drawable-resource.html">Drawable Resources</a>.</p> </BODY> </HTML> diff --git a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java index f4cf15c..b469d2a 100644 --- a/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java +++ b/graphics/java/android/graphics/drawable/shapes/RoundRectShape.java @@ -57,13 +57,11 @@ public class RoundRectShape extends RectShape { */ public RoundRectShape(float[] outerRadii, RectF inset, float[] innerRadii) { - if (outerRadii.length < 8) { - throw new ArrayIndexOutOfBoundsException( - "outer radii must have >= 8 values"); + if (outerRadii != null && outerRadii.length < 8) { + throw new ArrayIndexOutOfBoundsException("outer radii must have >= 8 values"); } if (innerRadii != null && innerRadii.length < 8) { - throw new ArrayIndexOutOfBoundsException( - "inner radii must have >= 8 values"); + throw new ArrayIndexOutOfBoundsException("inner radii must have >= 8 values"); } mOuterRadii = outerRadii; mInset = inset; @@ -97,8 +95,7 @@ public class RoundRectShape extends RectShape { r.right - mInset.right, r.bottom - mInset.bottom); if (mInnerRect.width() < w && mInnerRect.height() < h) { if (mInnerRadii != null) { - mPath.addRoundRect(mInnerRect, mInnerRadii, - Path.Direction.CCW); + mPath.addRoundRect(mInnerRect, mInnerRadii, Path.Direction.CCW); } else { mPath.addRect(mInnerRect, Path.Direction.CCW); } @@ -109,8 +106,8 @@ public class RoundRectShape extends RectShape { @Override public RoundRectShape clone() throws CloneNotSupportedException { RoundRectShape shape = (RoundRectShape) super.clone(); - shape.mOuterRadii = mOuterRadii.clone(); - shape.mInnerRadii = mInnerRadii.clone(); + shape.mOuterRadii = mOuterRadii != null ? mOuterRadii.clone() : null; + shape.mInnerRadii = mInnerRadii != null ? mInnerRadii.clone() : null; shape.mInset = new RectF(mInset); shape.mInnerRect = new RectF(mInnerRect); shape.mPath = new Path(mPath); diff --git a/graphics/java/android/graphics/utils/BoundaryPatch.java b/graphics/java/android/graphics/utils/BoundaryPatch.java deleted file mode 100644 index 1cd5e13..0000000 --- a/graphics/java/android/graphics/utils/BoundaryPatch.java +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright (C) 2009 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.graphics.utils; - -import android.graphics.Bitmap; -import android.graphics.BitmapShader; -import android.graphics.Canvas; -import android.graphics.Paint; -import android.graphics.Shader; -import android.graphics.Xfermode; - -/** - * @hide - */ -public class BoundaryPatch { - private Paint mPaint; - private Bitmap mTexture; - private int mRows; - private int mCols; - private float[] mCubicPoints; - private boolean mDirty; - // these are the computed output of the native code - private float[] mVerts; - private short[] mIndices; - - public BoundaryPatch() { - mRows = mCols = 2; // default minimum - mCubicPoints = new float[24]; - mPaint = new Paint(); - mPaint.setDither(true); - mPaint.setFilterBitmap(true); - mDirty = true; - } - - /** - * Set the boundary to be 4 cubics. This takes a single array of floats, - * and picks up the 12 pairs starting at offset, and treats them as - * the x,y coordinates of the cubic control points. The points wrap around - * a patch, as follows. For documentation purposes, pts[i] will mean the - * x,y pair of floats, as if pts[] were an array of "points". - * - * Top: pts[0..3] - * Right: pts[3..6] - * Bottom: pts[6..9] - * Right: pts[9..11], pts[0] - * - * The coordinates are copied from the input array, so subsequent changes - * to pts[] will not be reflected in the boundary. - * - * @param pts The src array of x,y pairs for the boundary cubics - * @param offset The index into pts of the first pair - * @param rows The number of points across to approximate the boundary. - * Must be >= 2, though very large values may slow down drawing - * @param cols The number of points down to approximate the boundary. - * Must be >= 2, though very large values may slow down drawing - */ - public void setCubicBoundary(float[] pts, int offset, int rows, int cols) { - if (rows < 2 || cols < 2) { - throw new RuntimeException("rows and cols must be >= 2"); - } - System.arraycopy(pts, offset, mCubicPoints, 0, 24); - if (mRows != rows || mCols != cols) { - mRows = rows; - mCols = cols; - } - mDirty = true; - } - - /** - * Reference a bitmap texture to be mapped onto the patch. - */ - public void setTexture(Bitmap texture) { - if (mTexture != texture) { - if (mTexture == null || - mTexture.getWidth() != texture.getWidth() || - mTexture.getHeight() != texture.getHeight()) { - // need to recompute texture coordinates - mDirty = true; - } - mTexture = texture; - mPaint.setShader(new BitmapShader(texture, - Shader.TileMode.CLAMP, - Shader.TileMode.CLAMP)); - } - } - - /** - * Return the paint flags for the patch - */ - public int getPaintFlags() { - return mPaint.getFlags(); - } - - /** - * Set the paint flags for the patch - */ - public void setPaintFlags(int flags) { - mPaint.setFlags(flags); - } - - /** - * Set the xfermode for the patch - */ - public void setXfermode(Xfermode mode) { - mPaint.setXfermode(mode); - } - - /** - * Set the alpha for the patch - */ - public void setAlpha(int alpha) { - mPaint.setAlpha(alpha); - } - - /** - * Draw the patch onto the canvas. - * - * setCubicBoundary() and setTexture() must be called before drawing. - */ - public void draw(Canvas canvas) { - if (mDirty) { - buildCache(); - mDirty = false; - } - - // cut the count in half, since mVerts.length is really the length of - // the verts[] and tex[] arrays combined - // (tex[] are stored after verts[]) - int vertCount = mVerts.length >> 1; - canvas.drawVertices(Canvas.VertexMode.TRIANGLES, vertCount, - mVerts, 0, mVerts, vertCount, null, 0, - mIndices, 0, mIndices.length, - mPaint); - } - - private void buildCache() { - // we need mRows * mCols points, for verts and another set for textures - // so *2 for going from points -> floats, and *2 for verts and textures - int vertCount = mRows * mCols * 4; - if (mVerts == null || mVerts.length != vertCount) { - mVerts = new float[vertCount]; - } - - int indexCount = (mRows - 1) * (mCols - 1) * 6; - if (mIndices == null || mIndices.length != indexCount) { - mIndices = new short[indexCount]; - } - - nativeComputeCubicPatch(mCubicPoints, - mTexture.getWidth(), mTexture.getHeight(), - mRows, mCols, mVerts, mIndices); - } - - private static native - void nativeComputeCubicPatch(float[] cubicPoints, - int texW, int texH, int rows, int cols, - float[] verts, short[] indices); -} - diff --git a/graphics/java/android/renderscript/Allocation.java b/graphics/java/android/renderscript/Allocation.java index b27c7f5..4b8c58e 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -18,7 +18,6 @@ package android.renderscript; import java.io.IOException; import java.io.InputStream; - import android.content.res.Resources; import android.content.res.AssetManager; import android.graphics.Bitmap; @@ -27,243 +26,798 @@ import android.util.Log; import android.util.TypedValue; /** - * @hide + * <p> + * Memory allocation class for renderscript. An allocation combines a + * {@link android.renderscript.Type} with the memory to provide storage for user data and objects. + * This implies that all memory in Renderscript is typed. + * </p> + * + * <p>Allocations are the primary way data moves into and out of scripts. Memory is user + * synchronized and it's possible for allocations to exist in multiple memory spaces + * concurrently. Currently those spaces are:</p> + * <ul> + * <li>Script: accessable by RS scripts.</li> + * <li>Graphics Texture: accessable as a graphics texture.</li> + * <li>Graphics Vertex: accessable as graphical vertex data.</li> + * <li>Graphics Constants: Accessable as constants in user shaders</li> + * </ul> + * </p> + * <p> + * For example, when creating a allocation for a texture, the user can + * specify its memory spaces as both script and textures. This means that it can both + * be used as script binding and as a GPU texture for rendering. To maintain + * synchronization if a script modifies an allocation used by other targets it must + * call a synchronizing function to push the updates to the memory, otherwise the results + * are undefined. + * </p> + * <p>By default, Android system side updates are always applied to the script accessable + * memory. If this is not present, they are then applied to the various HW + * memory types. A {@link android.renderscript.Allocation#syncAll syncAll()} + * call is necessary after the script data is updated to + * keep the other memory spaces in sync.</p> + * + * <p>Allocation data is uploaded in one of two primary ways. For simple + * arrays there are copyFrom() functions that take an array from the control code and + * copy it to the slave memory store. Both type checked and unchecked copies are provided. + * The unchecked variants exist to allow apps to copy over arrays of structures from a + * control language that does not support structures.</p> * **/ public class Allocation extends BaseObj { Type mType; Bitmap mBitmap; + int mUsage; + + /** + * The usage of the allocation. These signal to renderscript + * where to place the allocation in memory. + * + * SCRIPT The allocation will be bound to and accessed by + * scripts. + */ + public static final int USAGE_SCRIPT = 0x0001; + + /** + * GRAPHICS_TEXTURE The allcation will be used as a texture + * source by one or more graphcics programs. + * + */ + public static final int USAGE_GRAPHICS_TEXTURE = 0x0002; + + /** + * GRAPHICS_VERTEX The allocation will be used as a graphics + * mesh. + * + */ + public static final int USAGE_GRAPHICS_VERTEX = 0x0004; + + + /** + * GRAPHICS_CONSTANTS The allocation will be used as the source + * of shader constants by one or more programs. + * + */ + public static final int USAGE_GRAPHICS_CONSTANTS = 0x0008; + + + /** + * Controls mipmap behavior when using the bitmap creation and + * update functions. + */ + public enum MipmapControl { + /** + * No mipmaps will be generated and the type generated from the + * incoming bitmap will not contain additional LODs. + */ + MIPMAP_NONE(0), + + /** + * A Full mipmap chain will be created in script memory. The + * type of the allocation will contain a full mipmap chain. On + * upload to graphics the full chain will be transfered. + */ + MIPMAP_FULL(1), + + /** + * The type of the allocation will be the same as MIPMAP_NONE. + * It will not contain mipmaps. On upload to graphics the + * graphics copy of the allocation data will contain a full + * mipmap chain generated from the top level in script memory. + */ + MIPMAP_ON_SYNC_TO_TEXTURE(2); + + int mID; + MipmapControl(int id) { + mID = id; + } + } - Allocation(int id, RenderScript rs, Type t) { - super(rs); - mID = id; + Allocation(int id, RenderScript rs, Type t, int usage) { + super(id, rs); + if ((usage & ~(USAGE_SCRIPT | + USAGE_GRAPHICS_TEXTURE | + USAGE_GRAPHICS_VERTEX | + USAGE_GRAPHICS_CONSTANTS)) != 0) { + throw new RSIllegalArgumentException("Unknown usage specified."); + } mType = t; } + private void validateIsInt32() { + if ((mType.mElement.mType == Element.DataType.SIGNED_32) || + (mType.mElement.mType == Element.DataType.UNSIGNED_32)) { + return; + } + throw new RSIllegalArgumentException( + "32 bit integer source does not match allocation type " + mType.mElement.mType); + } + + private void validateIsInt16() { + if ((mType.mElement.mType == Element.DataType.SIGNED_16) || + (mType.mElement.mType == Element.DataType.UNSIGNED_16)) { + return; + } + throw new RSIllegalArgumentException( + "16 bit integer source does not match allocation type " + mType.mElement.mType); + } + + private void validateIsInt8() { + if ((mType.mElement.mType == Element.DataType.SIGNED_8) || + (mType.mElement.mType == Element.DataType.UNSIGNED_8)) { + return; + } + throw new RSIllegalArgumentException( + "8 bit integer source does not match allocation type " + mType.mElement.mType); + } + + private void validateIsFloat32() { + if (mType.mElement.mType == Element.DataType.FLOAT_32) { + return; + } + throw new RSIllegalArgumentException( + "32 bit float source does not match allocation type " + mType.mElement.mType); + } + + private void validateIsObject() { + if ((mType.mElement.mType == Element.DataType.RS_ELEMENT) || + (mType.mElement.mType == Element.DataType.RS_TYPE) || + (mType.mElement.mType == Element.DataType.RS_ALLOCATION) || + (mType.mElement.mType == Element.DataType.RS_SAMPLER) || + (mType.mElement.mType == Element.DataType.RS_SCRIPT) || + (mType.mElement.mType == Element.DataType.RS_MESH) || + (mType.mElement.mType == Element.DataType.RS_PROGRAM_FRAGMENT) || + (mType.mElement.mType == Element.DataType.RS_PROGRAM_VERTEX) || + (mType.mElement.mType == Element.DataType.RS_PROGRAM_RASTER) || + (mType.mElement.mType == Element.DataType.RS_PROGRAM_STORE)) { + return; + } + throw new RSIllegalArgumentException( + "Object source does not match allocation type " + mType.mElement.mType); + } + + @Override + void updateFromNative() { + super.updateFromNative(); + int typeID = mRS.nAllocationGetType(getID()); + if(typeID != 0) { + mType = new Type(typeID, mRS); + mType.updateFromNative(); + } + } + public Type getType() { return mType; } - public void uploadToTexture(int baseMipLevel) { + public void syncAll(int srcLocation) { + switch (srcLocation) { + case USAGE_SCRIPT: + case USAGE_GRAPHICS_CONSTANTS: + case USAGE_GRAPHICS_TEXTURE: + case USAGE_GRAPHICS_VERTEX: + break; + default: + throw new RSIllegalArgumentException("Source must be exactly one usage type."); + } + mRS.validate(); + mRS.nAllocationSyncAll(getID(), srcLocation); + } + + public void copyFrom(BaseObj[] d) { mRS.validate(); - mRS.nAllocationUploadToTexture(mID, false, baseMipLevel); + validateIsObject(); + if (d.length != mType.getCount()) { + throw new RSIllegalArgumentException("Array size mismatch, allocation sizeX = " + + mType.getCount() + ", array length = " + d.length); + } + int i[] = new int[d.length]; + for (int ct=0; ct < d.length; ct++) { + i[ct] = d[ct].getID(); + } + copy1DRangeFromUnchecked(0, mType.getCount(), i); + } + + private void validateBitmapFormat(Bitmap b) { + Bitmap.Config bc = b.getConfig(); + switch (bc) { + case ALPHA_8: + if (mType.getElement().mKind != Element.DataKind.PIXEL_A) { + throw new RSIllegalArgumentException("Allocation kind is " + + mType.getElement().mKind + ", type " + + mType.getElement().mType + + " of " + mType.getElement().getSizeBytes() + + " bytes, passed bitmap was " + bc); + } + break; + case ARGB_8888: + if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || + (mType.getElement().getSizeBytes() != 4)) { + throw new RSIllegalArgumentException("Allocation kind is " + + mType.getElement().mKind + ", type " + + mType.getElement().mType + + " of " + mType.getElement().getSizeBytes() + + " bytes, passed bitmap was " + bc); + } + break; + case RGB_565: + if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGB) || + (mType.getElement().getSizeBytes() != 2)) { + throw new RSIllegalArgumentException("Allocation kind is " + + mType.getElement().mKind + ", type " + + mType.getElement().mType + + " of " + mType.getElement().getSizeBytes() + + " bytes, passed bitmap was " + bc); + } + break; + case ARGB_4444: + if ((mType.getElement().mKind != Element.DataKind.PIXEL_RGBA) || + (mType.getElement().getSizeBytes() != 2)) { + throw new RSIllegalArgumentException("Allocation kind is " + + mType.getElement().mKind + ", type " + + mType.getElement().mType + + " of " + mType.getElement().getSizeBytes() + + " bytes, passed bitmap was " + bc); + } + break; + + } } - public void uploadToTexture(boolean genMips, int baseMipLevel) { + private void validateBitmapSize(Bitmap b) { + if(mType.getX() != b.getWidth() || + mType.getY() != b.getHeight()) { + throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); + } + } + + /** + * Copy an allocation from an array. This variant is not type + * checked which allows an application to fill in structured + * data from an array. + * + * @param d the source data array + */ + public void copyFromUnchecked(int[] d) { + mRS.validate(); + copy1DRangeFromUnchecked(0, mType.getCount(), d); + } + /** + * Copy an allocation from an array. This variant is not type + * checked which allows an application to fill in structured + * data from an array. + * + * @param d the source data array + */ + public void copyFromUnchecked(short[] d) { + mRS.validate(); + copy1DRangeFromUnchecked(0, mType.getCount(), d); + } + /** + * Copy an allocation from an array. This variant is not type + * checked which allows an application to fill in structured + * data from an array. + * + * @param d the source data array + */ + public void copyFromUnchecked(byte[] d) { + mRS.validate(); + copy1DRangeFromUnchecked(0, mType.getCount(), d); + } + /** + * Copy an allocation from an array. This variant is not type + * checked which allows an application to fill in structured + * data from an array. + * + * @param d the source data array + */ + public void copyFromUnchecked(float[] d) { mRS.validate(); - mRS.nAllocationUploadToTexture(mID, genMips, baseMipLevel); + copy1DRangeFromUnchecked(0, mType.getCount(), d); } - public void uploadToBufferObject() { + /** + * Copy an allocation from an array. This variant is type + * checked and will generate exceptions if the Allocation type + * is not a 32 bit integer type. + * + * @param d the source data array + */ + public void copyFrom(int[] d) { mRS.validate(); - mRS.nAllocationUploadToBufferObject(mID); + copy1DRangeFrom(0, mType.getCount(), d); } - public void data(int[] d) { + /** + * Copy an allocation from an array. This variant is type + * checked and will generate exceptions if the Allocation type + * is not a 16 bit integer type. + * + * @param d the source data array + */ + public void copyFrom(short[] d) { mRS.validate(); - subData1D(0, mType.getElementCount(), d); + copy1DRangeFrom(0, mType.getCount(), d); } - public void data(short[] d) { + + /** + * Copy an allocation from an array. This variant is type + * checked and will generate exceptions if the Allocation type + * is not a 8 bit integer type. + * + * @param d the source data array + */ + public void copyFrom(byte[] d) { mRS.validate(); - subData1D(0, mType.getElementCount(), d); + copy1DRangeFrom(0, mType.getCount(), d); } - public void data(byte[] d) { + + /** + * Copy an allocation from an array. This variant is type + * checked and will generate exceptions if the Allocation type + * is not a 32 bit float type. + * + * @param d the source data array + */ + public void copyFrom(float[] d) { mRS.validate(); - subData1D(0, mType.getElementCount(), d); + copy1DRangeFrom(0, mType.getCount(), d); } - public void data(float[] d) { + + /** + * Copy an allocation from a bitmap. The height, width, and + * format of the bitmap must match the existing allocation. + * + * @param b the source bitmap + */ + public void copyFrom(Bitmap b) { mRS.validate(); - subData1D(0, mType.getElementCount(), d); + validateBitmapSize(b); + validateBitmapFormat(b); + mRS.nAllocationCopyFromBitmap(getID(), b); + } + + /** + * This is only intended to be used by auto-generate code reflected from the + * renderscript script files. + * + * @param xoff + * @param fp + */ + public void setFromFieldPacker(int xoff, FieldPacker fp) { + int eSize = mType.mElement.getSizeBytes(); + final byte[] data = fp.getData(); + + int count = data.length / eSize; + if ((eSize * count) != data.length) { + throw new RSIllegalArgumentException("Field packer length " + data.length + + " not divisible by element size " + eSize + "."); + } + data1DChecks(xoff, count, data.length, data.length); + mRS.nAllocationData1D(getID(), xoff, 0, count, data, data.length); + } + + /** + * This is only intended to be used by auto-generate code reflected from the + * renderscript script files. + * + * @param xoff + * @param component_number + * @param fp + */ + public void setFromFieldPacker(int xoff, int component_number, FieldPacker fp) { + if (component_number >= mType.mElement.mElements.length) { + throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); + } + if(xoff < 0) { + throw new RSIllegalArgumentException("Offset must be >= 0."); + } + + final byte[] data = fp.getData(); + int eSize = mType.mElement.mElements[component_number].getSizeBytes(); + + if (data.length != eSize) { + throw new RSIllegalArgumentException("Field packer sizelength " + data.length + + " does not match component size " + eSize + "."); + } + + mRS.nAllocationElementData1D(getID(), xoff, 0, component_number, data, data.length); } private void data1DChecks(int off, int count, int len, int dataSize) { mRS.validate(); - if((off < 0) || (count < 1) || ((off + count) > mType.getElementCount())) { - throw new IllegalArgumentException("Offset or Count out of bounds."); + if(off < 0) { + throw new RSIllegalArgumentException("Offset must be >= 0."); + } + if(count < 1) { + throw new RSIllegalArgumentException("Count must be >= 1."); + } + if((off + count) > mType.getCount()) { + throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() + + ", got " + count + " at offset " + off + "."); } if((len) < dataSize) { - throw new IllegalArgumentException("Array too small for allocation type."); + throw new RSIllegalArgumentException("Array too small for allocation type."); } } - public void subData1D(int off, int count, int[] d) { + /** + * Generate a mipmap chain. Requires the type of the allocation + * include mipmaps. + * + * This function will generate a complete set of mipmaps from + * the top level lod and place them into the script memoryspace. + * + * If the allocation is also using other memory spaces a + * followup sync will be required. + */ + public void generateMipmaps() { + mRS.nAllocationGenerateMipmaps(getID()); + } + + /** + * Copy part of an allocation from an array. This variant is + * not type checked which allows an application to fill in + * structured data from an array. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFromUnchecked(int off, int count, int[] d) { int dataSize = mType.mElement.getSizeBytes() * count; data1DChecks(off, count, d.length * 4, dataSize); - mRS.nAllocationSubData1D(mID, off, count, d, dataSize); + mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); } - public void subData1D(int off, int count, short[] d) { + /** + * Copy part of an allocation from an array. This variant is + * not type checked which allows an application to fill in + * structured data from an array. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFromUnchecked(int off, int count, short[] d) { int dataSize = mType.mElement.getSizeBytes() * count; data1DChecks(off, count, d.length * 2, dataSize); - mRS.nAllocationSubData1D(mID, off, count, d, dataSize); + mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); } - public void subData1D(int off, int count, byte[] d) { + /** + * Copy part of an allocation from an array. This variant is + * not type checked which allows an application to fill in + * structured data from an array. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFromUnchecked(int off, int count, byte[] d) { int dataSize = mType.mElement.getSizeBytes() * count; data1DChecks(off, count, d.length, dataSize); - mRS.nAllocationSubData1D(mID, off, count, d, dataSize); + mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); } - public void subData1D(int off, int count, float[] d) { + /** + * Copy part of an allocation from an array. This variant is + * not type checked which allows an application to fill in + * structured data from an array. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFromUnchecked(int off, int count, float[] d) { int dataSize = mType.mElement.getSizeBytes() * count; data1DChecks(off, count, d.length * 4, dataSize); - mRS.nAllocationSubData1D(mID, off, count, d, dataSize); + mRS.nAllocationData1D(getID(), off, 0, count, d, dataSize); } + /** + * Copy part of an allocation from an array. This variant is + * type checked and will generate exceptions if the Allocation + * type is not a 32 bit integer type. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFrom(int off, int count, int[] d) { + validateIsInt32(); + copy1DRangeFromUnchecked(off, count, d); + } + /** + * Copy part of an allocation from an array. This variant is + * type checked and will generate exceptions if the Allocation + * type is not a 16 bit integer type. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFrom(int off, int count, short[] d) { + validateIsInt16(); + copy1DRangeFromUnchecked(off, count, d); + } - public void subData2D(int xoff, int yoff, int w, int h, int[] d) { - mRS.validate(); - mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4); + /** + * Copy part of an allocation from an array. This variant is + * type checked and will generate exceptions if the Allocation + * type is not a 8 bit integer type. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFrom(int off, int count, byte[] d) { + validateIsInt8(); + copy1DRangeFromUnchecked(off, count, d); } - public void subData2D(int xoff, int yoff, int w, int h, float[] d) { - mRS.validate(); - mRS.nAllocationSubData2D(mID, xoff, yoff, w, h, d, d.length * 4); + /** + * Copy part of an allocation from an array. This variant is + * type checked and will generate exceptions if the Allocation + * type is not a 32 bit float type. + * + * @param off The offset of the first element to be copied. + * @param count The number of elements to be copied. + * @param d the source data array + */ + public void copy1DRangeFrom(int off, int count, float[] d) { + validateIsFloat32(); + copy1DRangeFromUnchecked(off, count, d); } - public void readData(int[] d) { - mRS.validate(); - mRS.nAllocationRead(mID, d); + private void validate2DRange(int xoff, int yoff, int w, int h) { + if (xoff < 0 || yoff < 0) { + throw new RSIllegalArgumentException("Offset cannot be negative."); + } + if (h < 0 || w < 0) { + throw new RSIllegalArgumentException("Height or width cannot be negative."); + } + if ((xoff + w) > mType.mDimX || + (yoff + h) > mType.mDimY) { + throw new RSIllegalArgumentException("Updated region larger than allocation."); + } } - public void readData(float[] d) { + /** + * Copy a rectanglular region from the array into the + * allocation. The incoming array is assumed to be tightly + * packed. + * + * @param xoff X offset of the region to update + * @param yoff Y offset of the region to update + * @param w Width of the incoming region to update + * @param h Height of the incoming region to update + * @param data to be placed into the allocation + */ + public void copy2DRangeFrom(int xoff, int yoff, int w, int h, byte[] data) { mRS.validate(); - mRS.nAllocationRead(mID, d); + validate2DRange(xoff, yoff, w, h); + mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length); } - public void data(Object o) { + public void copy2DRangeFrom(int xoff, int yoff, int w, int h, short[] data) { mRS.validate(); - mRS.nAllocationSubDataFromObject(mID, mType, 0, o); + validate2DRange(xoff, yoff, w, h); + mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 2); } - public void read(Object o) { + public void copy2DRangeFrom(int xoff, int yoff, int w, int h, int[] data) { mRS.validate(); - mRS.nAllocationSubReadFromObject(mID, mType, 0, o); + validate2DRange(xoff, yoff, w, h); + mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4); } - public void subData(int offset, Object o) { + public void copy2DRangeFrom(int xoff, int yoff, int w, int h, float[] data) { mRS.validate(); - mRS.nAllocationSubDataFromObject(mID, mType, offset, o); + validate2DRange(xoff, yoff, w, h); + mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, w, h, data, data.length * 4); } - public class Adapter1D extends BaseObj { - Adapter1D(int id, RenderScript rs) { - super(rs); - mID = id; - } - - public void setConstraint(Dimension dim, int value) { - mRS.validate(); - mRS.nAdapter1DSetConstraint(mID, dim.mID, value); - } - - public void data(int[] d) { - mRS.validate(); - mRS.nAdapter1DData(mID, d); - } - - public void data(float[] d) { - mRS.validate(); - mRS.nAdapter1DData(mID, d); - } + /** + * Copy a bitmap into an allocation. The height and width of + * the update will use the height and width of the incoming + * bitmap. + * + * @param xoff X offset of the region to update + * @param yoff Y offset of the region to update + * @param data the bitmap to be copied + */ + public void copy2DRangeFrom(int xoff, int yoff, Bitmap data) { + mRS.validate(); + validateBitmapFormat(data); + validate2DRange(xoff, yoff, data.getWidth(), data.getHeight()); + mRS.nAllocationData2D(getID(), xoff, yoff, 0, 0, data); + } - public void subData(int off, int count, int[] d) { - mRS.validate(); - mRS.nAdapter1DSubData(mID, off, count, d); - } - public void subData(int off, int count, float[] d) { - mRS.validate(); - mRS.nAdapter1DSubData(mID, off, count, d); - } + public void copyTo(Bitmap b) { + mRS.validate(); + validateBitmapFormat(b); + validateBitmapSize(b); + mRS.nAllocationCopyToBitmap(getID(), b); } - public Adapter1D createAdapter1D() { + public void copyTo(byte[] d) { + validateIsInt8(); mRS.validate(); - int id = mRS.nAdapter1DCreate(); - if(id == 0) { - throw new IllegalStateException("allocation failed."); - } - mRS.nAdapter1DBindAllocation(id, mID); - return new Adapter1D(id, mRS); + mRS.nAllocationRead(getID(), d); } + public void copyTo(short[] d) { + validateIsInt16(); + mRS.validate(); + mRS.nAllocationRead(getID(), d); + } - public class Adapter2D extends BaseObj { - Adapter2D(int id, RenderScript rs) { - super(rs); - mID = id; - } + public void copyTo(int[] d) { + validateIsInt32(); + mRS.validate(); + mRS.nAllocationRead(getID(), d); + } - public void setConstraint(Dimension dim, int value) { - mRS.validate(); - mRS.nAdapter2DSetConstraint(mID, dim.mID, value); - } + public void copyTo(float[] d) { + validateIsFloat32(); + mRS.validate(); + mRS.nAllocationRead(getID(), d); + } - public void data(int[] d) { - mRS.validate(); - mRS.nAdapter2DData(mID, d); + /** + * Resize a 1D allocation. The contents of the allocation are + * preserved. If new elements are allocated objects are created + * with null contents and the new region is otherwise undefined. + * + * If the new region is smaller the references of any objects + * outside the new region will be released. + * + * A new type will be created with the new dimension. + * + * @param dimX The new size of the allocation. + */ + public synchronized void resize(int dimX) { + if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.hasFaces() || mType.hasMipmaps()) { + throw new RSInvalidStateException("Resize only support for 1D allocations at this time."); } + mRS.nAllocationResize1D(getID(), dimX); + mRS.finish(); // Necessary because resize is fifoed and update is async. - public void data(float[] d) { - mRS.validate(); - mRS.nAdapter2DData(mID, d); - } + int typeID = mRS.nAllocationGetType(getID()); + mType = new Type(typeID, mRS); + mType.updateFromNative(); + } - public void subData(int xoff, int yoff, int w, int h, int[] d) { - mRS.validate(); - mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d); + /* + public void resize(int dimX, int dimY) { + if ((mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) { + throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); } - - public void subData(int xoff, int yoff, int w, int h, float[] d) { - mRS.validate(); - mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d); + if (mType.getY() == 0) { + throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); } + mRS.nAllocationResize2D(getID(), dimX, dimY); } + */ - public Adapter2D createAdapter2D() { - mRS.validate(); - int id = mRS.nAdapter2DCreate(); - if(id == 0) { - throw new IllegalStateException("allocation failed."); - } - mRS.nAdapter2DBindAllocation(id, mID); - return new Adapter2D(id, mRS); - } // creation - private static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); + static BitmapFactory.Options mBitmapOptions = new BitmapFactory.Options(); static { mBitmapOptions.inScaled = false; } - static public Allocation createTyped(RenderScript rs, Type type) - throws IllegalArgumentException { - + /** + * + * @param type renderscript type describing data layout + * @param mips specifies desired mipmap behaviour for the + * allocation + * @param usage bit field specifying how the allocation is + * utilized + */ + static public Allocation createTyped(RenderScript rs, Type type, MipmapControl mips, int usage) { rs.validate(); - if(type.mID == 0) { - throw new IllegalStateException("Bad Type"); + if (type.getID() == 0) { + throw new RSInvalidStateException("Bad Type"); } - int id = rs.nAllocationCreateTyped(type.mID); - return new Allocation(id, rs, type); + int id = rs.nAllocationCreateTyped(type.getID(), mips.mID, usage); + if (id == 0) { + throw new RSRuntimeException("Allocation creation failed."); + } + return new Allocation(id, rs, type, usage); } - static public Allocation createSized(RenderScript rs, Element e, int count) - throws IllegalArgumentException { + /** + * Creates a renderscript allocation with the size specified by + * the type and no mipmaps generated by default + * + * @param rs Context to which the allocation will belong. + * @param type renderscript type describing data layout + * @param usage bit field specifying how the allocation is + * utilized + * + * @return allocation + */ + static public Allocation createTyped(RenderScript rs, Type type, int usage) { + return createTyped(rs, type, MipmapControl.MIPMAP_NONE, usage); + } + /** + * Creates a renderscript allocation for use by the script with + * the size specified by the type and no mipmaps generated by + * default + * + * @param rs Context to which the allocation will belong. + * @param type renderscript type describing data layout + * + * @return allocation + */ + static public Allocation createTyped(RenderScript rs, Type type) { + return createTyped(rs, type, MipmapControl.MIPMAP_NONE, USAGE_SCRIPT); + } + + /** + * Creates a renderscript allocation with a specified number of + * given elements + * + * @param rs Context to which the allocation will belong. + * @param e describes what each element of an allocation is + * @param count specifies the number of element in the allocation + * @param usage bit field specifying how the allocation is + * utilized + * + * @return allocation + */ + static public Allocation createSized(RenderScript rs, Element e, + int count, int usage) { rs.validate(); Type.Builder b = new Type.Builder(rs, e); - b.add(Dimension.X, count); + b.setX(count); Type t = b.create(); - int id = rs.nAllocationCreateTyped(t.mID); - if(id == 0) { - throw new IllegalStateException("Bad element."); + int id = rs.nAllocationCreateTyped(t.getID(), MipmapControl.MIPMAP_NONE.mID, usage); + if (id == 0) { + throw new RSRuntimeException("Allocation creation failed."); } - return new Allocation(id, rs, t); + return new Allocation(id, rs, t, usage); + } + + /** + * Creates a renderscript allocation with a specified number of + * given elements + * + * @param rs Context to which the allocation will belong. + * @param e describes what each element of an allocation is + * @param count specifies the number of element in the allocation + * + * @return allocation + */ + static public Allocation createSized(RenderScript rs, Element e, int count) { + return createSized(rs, e, count, USAGE_SCRIPT); } - static private Element elementFromBitmap(RenderScript rs, Bitmap b) { + static Element elementFromBitmap(RenderScript rs, Bitmap b) { final Bitmap.Config bc = b.getConfig(); if (bc == Bitmap.Config.ALPHA_8) { return Element.A_8(rs); @@ -277,105 +831,294 @@ public class Allocation extends BaseObj { if (bc == Bitmap.Config.RGB_565) { return Element.RGB_565(rs); } - throw new IllegalStateException("Bad bitmap type."); + throw new RSInvalidStateException("Bad bitmap type: " + bc); } - static private Type typeFromBitmap(RenderScript rs, Bitmap b) { + static Type typeFromBitmap(RenderScript rs, Bitmap b, + MipmapControl mip) { Element e = elementFromBitmap(rs, b); Type.Builder tb = new Type.Builder(rs, e); - tb.add(Dimension.X, b.getWidth()); - tb.add(Dimension.Y, b.getHeight()); + tb.setX(b.getWidth()); + tb.setY(b.getHeight()); + tb.setMipmaps(mip == MipmapControl.MIPMAP_FULL); return tb.create(); } - static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) - throws IllegalArgumentException { - + /** + * Creates a renderscript allocation from a bitmap + * + * @param rs Context to which the allocation will belong. + * @param b bitmap source for the allocation data + * @param mips specifies desired mipmap behaviour for the + * allocation + * @param usage bit field specifying how the allocation is + * utilized + * + * @return renderscript allocation containing bitmap data + * + */ + static public Allocation createFromBitmap(RenderScript rs, Bitmap b, + MipmapControl mips, + int usage) { rs.validate(); - Type t = typeFromBitmap(rs, b); + Type t = typeFromBitmap(rs, b, mips); - int id = rs.nAllocationCreateFromBitmap(dstFmt.mID, genMips, b); - if(id == 0) { - throw new IllegalStateException("Load failed."); + int id = rs.nAllocationCreateFromBitmap(t.getID(), mips.mID, b, usage); + if (id == 0) { + throw new RSRuntimeException("Load failed."); } - return new Allocation(id, rs, t); + return new Allocation(id, rs, t, usage); } - static public Allocation createBitmapRef(RenderScript rs, Bitmap b) - throws IllegalArgumentException { + /** + * Creates a non-mipmapped renderscript allocation to use as a + * graphics texture + * + * @param rs Context to which the allocation will belong. + * @param b bitmap source for the allocation data + * + * @return renderscript allocation containing bitmap data + * + */ + static public Allocation createFromBitmap(RenderScript rs, Bitmap b) { + return createFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, + USAGE_GRAPHICS_TEXTURE); + } + /** + * Creates a cubemap allocation from a bitmap containing the + * horizontal list of cube faces. Each individual face must be + * the same size and power of 2 + * + * @param rs Context to which the allocation will belong. + * @param b bitmap with cubemap faces layed out in the following + * format: right, left, top, bottom, front, back + * @param mips specifies desired mipmap behaviour for the cubemap + * @param usage bit field specifying how the cubemap is utilized + * + * @return allocation containing cubemap data + * + */ + static public Allocation createCubemapFromBitmap(RenderScript rs, Bitmap b, + MipmapControl mips, + int usage) { rs.validate(); - Type t = typeFromBitmap(rs, b); - int id = rs.nAllocationCreateBitmapRef(t.getID(), b); - if(id == 0) { - throw new IllegalStateException("Load failed."); - } + int height = b.getHeight(); + int width = b.getWidth(); - Allocation a = new Allocation(id, rs, t); - a.mBitmap = b; - return a; - } + if (width % 6 != 0) { + throw new RSIllegalArgumentException("Cubemap height must be multiple of 6"); + } + if (width / 6 != height) { + throw new RSIllegalArgumentException("Only square cube map faces supported"); + } + boolean isPow2 = (height & (height - 1)) == 0; + if (!isPow2) { + throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); + } - static Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) - throws IllegalArgumentException { + Element e = elementFromBitmap(rs, b); + Type.Builder tb = new Type.Builder(rs, e); + tb.setX(height); + tb.setY(height); + tb.setFaces(true); + tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); + Type t = tb.create(); - rs.validate(); - int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b); + int id = rs.nAllocationCubeCreateFromBitmap(t.getID(), mips.mID, b, usage); if(id == 0) { - throw new IllegalStateException("Load failed."); + throw new RSRuntimeException("Load failed for bitmap " + b + " element " + e); } - return new Allocation(id, rs, null); + return new Allocation(id, rs, t, usage); } - static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) - throws IllegalArgumentException { + /** + * Creates a non-mipmapped cubemap allocation for use as a + * graphics texture from a bitmap containing the horizontal list + * of cube faces. Each individual face must be the same size and + * power of 2 + * + * @param rs Context to which the allocation will belong. + * @param b bitmap with cubemap faces layed out in the following + * format: right, left, top, bottom, front, back + * + * @return allocation containing cubemap data + * + */ + static public Allocation createCubemapFromBitmap(RenderScript rs, + Bitmap b) { + return createCubemapFromBitmap(rs, b, MipmapControl.MIPMAP_NONE, + USAGE_GRAPHICS_TEXTURE); + } - rs.validate(); - InputStream is = null; - try { - final TypedValue value = new TypedValue(); - is = res.openRawResource(id, value); + /** + * Creates a cubemap allocation from 6 bitmaps containing + * the cube faces. All the faces must be the same size and + * power of 2 + * + * @param rs Context to which the allocation will belong. + * @param xpos cubemap face in the positive x direction + * @param xneg cubemap face in the negative x direction + * @param ypos cubemap face in the positive y direction + * @param yneg cubemap face in the negative y direction + * @param zpos cubemap face in the positive z direction + * @param zneg cubemap face in the negative z direction + * @param mips specifies desired mipmap behaviour for the cubemap + * @param usage bit field specifying how the cubemap is utilized + * + * @return allocation containing cubemap data + * + */ + static public Allocation createCubemapFromCubeFaces(RenderScript rs, + Bitmap xpos, + Bitmap xneg, + Bitmap ypos, + Bitmap yneg, + Bitmap zpos, + Bitmap zneg, + MipmapControl mips, + int usage) { + int height = xpos.getHeight(); + if (xpos.getWidth() != height || + xneg.getWidth() != height || xneg.getHeight() != height || + ypos.getWidth() != height || ypos.getHeight() != height || + yneg.getWidth() != height || yneg.getHeight() != height || + zpos.getWidth() != height || zpos.getHeight() != height || + zneg.getWidth() != height || zneg.getHeight() != height) { + throw new RSIllegalArgumentException("Only square cube map faces supported"); + } + boolean isPow2 = (height & (height - 1)) == 0; + if (!isPow2) { + throw new RSIllegalArgumentException("Only power of 2 cube faces supported"); + } - int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); - int allocationId = rs.nAllocationCreateFromAssetStream(dstFmt.mID, genMips, - asset); + Element e = elementFromBitmap(rs, xpos); + Type.Builder tb = new Type.Builder(rs, e); + tb.setX(height); + tb.setY(height); + tb.setFaces(true); + tb.setMipmaps(mips == MipmapControl.MIPMAP_FULL); + Type t = tb.create(); + Allocation cubemap = Allocation.createTyped(rs, t, mips, usage); + + AllocationAdapter adapter = AllocationAdapter.create2D(rs, cubemap); + adapter.setFace(Type.CubemapFace.POSITVE_X); + adapter.copyFrom(xpos); + adapter.setFace(Type.CubemapFace.NEGATIVE_X); + adapter.copyFrom(xneg); + adapter.setFace(Type.CubemapFace.POSITVE_Y); + adapter.copyFrom(ypos); + adapter.setFace(Type.CubemapFace.NEGATIVE_Y); + adapter.copyFrom(yneg); + adapter.setFace(Type.CubemapFace.POSITVE_Z); + adapter.copyFrom(zpos); + adapter.setFace(Type.CubemapFace.NEGATIVE_Z); + adapter.copyFrom(zneg); + + return cubemap; + } - if(allocationId == 0) { - throw new IllegalStateException("Load failed."); - } - return new Allocation(allocationId, rs, null); - } catch (Exception e) { - // Ignore - } finally { - if (is != null) { - try { - is.close(); - } catch (IOException e) { - // Ignore - } - } - } + /** + * Creates a non-mipmapped cubemap allocation for use as a + * graphics texture from 6 bitmaps containing + * the cube faces. All the faces must be the same size and + * power of 2 + * + * @param rs Context to which the allocation will belong. + * @param xpos cubemap face in the positive x direction + * @param xneg cubemap face in the negative x direction + * @param ypos cubemap face in the positive y direction + * @param yneg cubemap face in the negative y direction + * @param zpos cubemap face in the positive z direction + * @param zneg cubemap face in the negative z direction + * + * @return allocation containing cubemap data + * + */ + static public Allocation createCubemapFromCubeFaces(RenderScript rs, + Bitmap xpos, + Bitmap xneg, + Bitmap ypos, + Bitmap yneg, + Bitmap zpos, + Bitmap zneg) { + return createCubemapFromCubeFaces(rs, xpos, xneg, ypos, yneg, + zpos, zneg, MipmapControl.MIPMAP_NONE, + USAGE_GRAPHICS_TEXTURE); + } + + /** + * Creates a renderscript allocation from the bitmap referenced + * by resource id + * + * @param rs Context to which the allocation will belong. + * @param res application resources + * @param id resource id to load the data from + * @param mips specifies desired mipmap behaviour for the + * allocation + * @param usage bit field specifying how the allocation is + * utilized + * + * @return renderscript allocation containing resource data + * + */ + static public Allocation createFromBitmapResource(RenderScript rs, + Resources res, + int id, + MipmapControl mips, + int usage) { - return null; + rs.validate(); + Bitmap b = BitmapFactory.decodeResource(res, id); + Allocation alloc = createFromBitmap(rs, b, mips, usage); + b.recycle(); + return alloc; } - static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) - throws IllegalArgumentException { + /** + * Creates a non-mipmapped renderscript allocation to use as a + * graphics texture from the bitmap referenced by resource id + * + * @param rs Context to which the allocation will belong. + * @param res application resources + * @param id resource id to load the data from + * + * @return renderscript allocation containing resource data + * + */ + static public Allocation createFromBitmapResource(RenderScript rs, + Resources res, + int id) { + return createFromBitmapResource(rs, res, id, + MipmapControl.MIPMAP_NONE, + USAGE_GRAPHICS_TEXTURE); + } - mBitmapOptions.inPreferredConfig = null; - if (dstFmt == rs.mElement_RGBA_8888) { - mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; - } else if (dstFmt == rs.mElement_RGB_888) { - mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_8888; - } else if (dstFmt == rs.mElement_RGBA_4444) { - mBitmapOptions.inPreferredConfig = Bitmap.Config.ARGB_4444; - } else if (dstFmt == rs.mElement_RGB_565) { - mBitmapOptions.inPreferredConfig = Bitmap.Config.RGB_565; + /** + * Creates a renderscript allocation containing string data + * encoded in UTF-8 format + * + * @param rs Context to which the allocation will belong. + * @param str string to create the allocation from + * @param usage bit field specifying how the allocaiton is + * utilized + * + */ + static public Allocation createFromString(RenderScript rs, + String str, + int usage) { + rs.validate(); + byte[] allocArray = null; + try { + allocArray = str.getBytes("UTF-8"); + Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length, usage); + alloc.copyFrom(allocArray); + return alloc; + } + catch (Exception e) { + throw new RSRuntimeException("Could not convert string to utf-8."); } - - Bitmap b = BitmapFactory.decodeResource(res, id, mBitmapOptions); - return createFromBitmapBoxed(rs, b, dstFmt, genMips); } } diff --git a/graphics/java/android/renderscript/AllocationAdapter.java b/graphics/java/android/renderscript/AllocationAdapter.java new file mode 100644 index 0000000..f2fedea --- /dev/null +++ b/graphics/java/android/renderscript/AllocationAdapter.java @@ -0,0 +1,212 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import android.content.res.Resources; +import android.content.res.AssetManager; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; +import android.util.TypedValue; + +/** + * + **/ +public class AllocationAdapter extends Allocation { + private int mSelectedDimX; + private int mSelectedDimY; + private int mSelectedCount; + private Allocation mAlloc; + + private int mSelectedLOD = 0; + private Type.CubemapFace mSelectedFace = Type.CubemapFace.POSITVE_X;; + + AllocationAdapter(int id, RenderScript rs, Allocation alloc) { + super(id, rs, null, alloc.mUsage); + Type t = alloc.getType(); + mSelectedDimX = t.getX(); + mSelectedDimY = t.getY(); + mSelectedCount = t.getCount(); + } + + + public void copyFrom(BaseObj[] d) { + mRS.validate(); + if (d.length != mSelectedCount) { + throw new RSIllegalArgumentException("Array size mismatch, allocation size = " + + mSelectedCount + ", array length = " + d.length); + } + int i[] = new int[d.length]; + for (int ct=0; ct < d.length; ct++) { + i[ct] = d[ct].getID(); + } + subData1D(0, mType.getCount(), i); + } + + void validateBitmap(Bitmap b) { + mRS.validate(); + if(mSelectedDimX != b.getWidth() || + mSelectedDimY != b.getHeight()) { + throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); + } + } + + public void copyFrom(int[] d) { + mRS.validate(); + subData1D(0, mSelectedCount, d); + } + public void copyFrom(short[] d) { + mRS.validate(); + subData1D(0, mSelectedCount, d); + } + public void copyFrom(byte[] d) { + mRS.validate(); + subData1D(0, mSelectedCount, d); + } + public void copyFrom(float[] d) { + mRS.validate(); + subData1D(0, mSelectedCount, d); + } + public void copyFrom(Bitmap b) { + validateBitmap(b); + mRS.nAllocationCopyFromBitmap(getID(), b); + } + + public void copyTo(Bitmap b) { + validateBitmap(b); + mRS.nAllocationCopyToBitmap(getID(), b); + } + + + public void subData(int xoff, FieldPacker fp) { + int eSize = mType.mElement.getSizeBytes(); + final byte[] data = fp.getData(); + + int count = data.length / eSize; + if ((eSize * count) != data.length) { + throw new RSIllegalArgumentException("Field packer length " + data.length + + " not divisible by element size " + eSize + "."); + } + data1DChecks(xoff, count, data.length, data.length); + mRS.nAllocationData1D(getID(), xoff, mSelectedLOD, count, data, data.length); + } + + + public void subElementData(int xoff, int component_number, FieldPacker fp) { + if (component_number >= mType.mElement.mElements.length) { + throw new RSIllegalArgumentException("Component_number " + component_number + " out of range."); + } + if(xoff < 0) { + throw new RSIllegalArgumentException("Offset must be >= 0."); + } + + final byte[] data = fp.getData(); + int eSize = mType.mElement.mElements[component_number].getSizeBytes(); + + if (data.length != eSize) { + throw new RSIllegalArgumentException("Field packer sizelength " + data.length + + " does not match component size " + eSize + "."); + } + + mRS.nAllocationElementData1D(getID(), xoff, mSelectedLOD, component_number, data, data.length); + } + + void data1DChecks(int off, int count, int len, int dataSize) { + mRS.validate(); + if(off < 0) { + throw new RSIllegalArgumentException("Offset must be >= 0."); + } + if(count < 1) { + throw new RSIllegalArgumentException("Count must be >= 1."); + } + if((off + count) > mSelectedDimX * mSelectedDimY) { + throw new RSIllegalArgumentException("Overflow, Available count " + mType.getCount() + + ", got " + count + " at offset " + off + "."); + } + if((len) < dataSize) { + throw new RSIllegalArgumentException("Array too small for allocation type."); + } + } + + public void subData1D(int off, int count, int[] d) { + int dataSize = mAlloc.mType.mElement.getSizeBytes() * count; + data1DChecks(off, count, d.length * 4, dataSize); + mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize); + } + public void subData1D(int off, int count, short[] d) { + int dataSize = mAlloc.mType.mElement.getSizeBytes() * count; + data1DChecks(off, count, d.length * 2, dataSize); + mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize); + } + public void subData1D(int off, int count, byte[] d) { + int dataSize = mAlloc.mType.mElement.getSizeBytes() * count; + data1DChecks(off, count, d.length, dataSize); + mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize); + } + public void subData1D(int off, int count, float[] d) { + int dataSize = mAlloc.mType.mElement.getSizeBytes() * count; + data1DChecks(off, count, d.length * 4, dataSize); + mRS.nAllocationData1D(getID(), off, mSelectedLOD, count, d, dataSize); + } + + + public void subData2D(int xoff, int yoff, int w, int h, int[] d) { + mRS.validate(); + mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h, d, d.length * 4); + } + + public void subData2D(int xoff, int yoff, int w, int h, float[] d) { + mRS.validate(); + mRS.nAllocationData2D(getID(), xoff, yoff, mSelectedLOD, mSelectedFace.mID, w, h, d, d.length * 4); + } + + public void readData(int[] d) { + mRS.validate(); + mRS.nAllocationRead(getID(), d); + } + + public void readData(float[] d) { + mRS.validate(); + mRS.nAllocationRead(getID(), d); + } + + public void setLOD(int lod) { + } + + public void setFace(Type.CubemapFace cf) { + } + + public void setY(int y) { + } + + public void setZ(int z) { + } + + // creation + //static public AllocationAdapter create1D(RenderScript rs, Allocation a) { + //} + + static public AllocationAdapter create2D(RenderScript rs, Allocation a) { + rs.validate(); + AllocationAdapter aa = new AllocationAdapter(0, rs, a); + return aa; + } + + +} + + diff --git a/graphics/java/android/renderscript/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java index 002fc78..8ce1d9a 100644 --- a/graphics/java/android/renderscript/BaseObj.java +++ b/graphics/java/android/renderscript/BaseObj.java @@ -19,50 +19,88 @@ package android.renderscript; import android.util.Log; /** - * @hide + * BaseObj is the base class for interfacing with native renderscript objects. + * It primarly contains code for tracking the native object ID and forcably + * disconecting the object from the native allocation for early cleanup. * **/ class BaseObj { - - BaseObj(RenderScript rs) { + BaseObj(int id, RenderScript rs) { rs.validate(); mRS = rs; - mID = 0; + mID = id; mDestroyed = false; } - public int getID() { + void setID(int id) { + if (mID != 0) { + throw new RSRuntimeException("Internal Error, reset of object ID."); + } + mID = id; + } + + /** + * Lookup the native object ID for this object. Primarily used by the + * generated reflected code. + * + * + * @return int + */ + int getID() { + if (mDestroyed) { + throw new RSInvalidStateException("using a destroyed object."); + } + if (mID == 0) { + throw new RSRuntimeException("Internal error: Object id 0."); + } return mID; } - int mID; - boolean mDestroyed; - String mName; + void checkValid() { + if (mID == 0) { + throw new RSIllegalArgumentException("Invalid object."); + } + } + + private int mID; + private boolean mDestroyed; + private String mName; RenderScript mRS; - public void setName(String s) throws IllegalStateException, IllegalArgumentException - { - if(s.length() < 1) { - throw new IllegalArgumentException("setName does not accept a zero length string."); + /** + * setName assigns a name to an object. This object can later be looked up + * by this name. This name will also be retained if the object is written + * to an A3D file. + * + * @param name The name to assign to the object. + */ + public void setName(String name) { + if (name == null) { + throw new RSIllegalArgumentException( + "setName requires a string of non-zero length."); + } + if(name.length() < 1) { + throw new RSIllegalArgumentException( + "setName does not accept a zero length string."); } if(mName != null) { - throw new IllegalArgumentException("setName object already has a name."); + throw new RSIllegalArgumentException( + "setName object already has a name."); } try { - byte[] bytes = s.getBytes("UTF-8"); + byte[] bytes = name.getBytes("UTF-8"); mRS.nAssignName(mID, bytes); - mName = s; + mName = name; } catch (java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } } - protected void finalize() throws Throwable - { + protected void finalize() throws Throwable { if (!mDestroyed) { if(mID != 0 && mRS.isAlive()) { - mRS.nObjDestroyOOB(mID); + mRS.nObjDestroy(mID); } mRS = null; mID = 0; @@ -73,13 +111,28 @@ class BaseObj { super.finalize(); } - public void destroy() { + /** + * destroy disconnects the object from the native object effectively + * rendering this java object dead. The primary use is to force immediate + * cleanup of resources when it is believed the GC will not respond quickly + * enough. + */ + synchronized public void destroy() { if(mDestroyed) { - throw new IllegalStateException("Object already destroyed."); + throw new RSInvalidStateException("Object already destroyed."); } mDestroyed = true; mRS.nObjDestroy(mID); } + /** + * If an object came from an a3d file, java fields need to be + * created with objects from the native layer + */ + void updateFromNative() { + mRS.validate(); + mName = mRS.nGetName(getID()); + } + } diff --git a/graphics/java/android/renderscript/Vector3f.java b/graphics/java/android/renderscript/Byte2.java index f2842f3..7ec6cb0 100644 --- a/graphics/java/android/renderscript/Vector3f.java +++ b/graphics/java/android/renderscript/Byte2.java @@ -21,16 +21,15 @@ import android.util.Log; /** - * @hide + * Class for exposing the native Renderscript byte2 type back to the Android system. * **/ -public class Vector3f { - public Vector3f() { +public class Byte2 { + public Byte2() { } - public float x; - public float y; - public float z; + public byte x; + public byte y; } diff --git a/graphics/java/android/renderscript/Byte3.java b/graphics/java/android/renderscript/Byte3.java new file mode 100644 index 0000000..7bcd4b4 --- /dev/null +++ b/graphics/java/android/renderscript/Byte3.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript byte3 type back to the Android system. + * + **/ +public class Byte3 { + public Byte3() { + } + + public byte x; + public byte y; + public byte z; +} + + + + diff --git a/graphics/java/android/renderscript/Byte4.java b/graphics/java/android/renderscript/Byte4.java new file mode 100644 index 0000000..c6e7f63 --- /dev/null +++ b/graphics/java/android/renderscript/Byte4.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript byte4 type back to the Android system. + * + **/ +public class Byte4 { + public Byte4() { + } + + public byte x; + public byte y; + public byte z; + public byte w; +} + + + diff --git a/graphics/java/android/renderscript/Element.java b/graphics/java/android/renderscript/Element.java index 10ef05a..fae22f0 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -17,15 +17,35 @@ package android.renderscript; import java.lang.reflect.Field; +import android.util.Log; /** - * @hide + * <p>The most basic data type. An element represents one cell of a memory allocation. + * Element is the basic data type of Renderscript. An element can be of two forms: Basic elements or Complex forms. + * Examples of basic elements are:</p> + * <ul> + * <li>Single float value</li> + * <li>4 element float vector</li> + * <li>single RGB-565 color</li> + * <li>single unsigned int 16</li> + * </ul> + * <p>Complex elements contain a list of sub-elements and names that + * represents a structure of data. The fields can be accessed by name + * from a script or shader. The memory layout is defined and ordered. Data + * alignment is determinied by the most basic primitive type. i.e. a float4 + * vector will be alligned to sizeof(float) and not sizeof(float4). The + * ordering of elements in memory will be the order in which they were added + * with each component aligned as necessary. No re-ordering will be done.</p> * + * <p>The primary source of elements are from scripts. A script that exports a + * bind point for a data structure generates a Renderscript element to represent the + * data exported by the script. The other common source of elements is from bitmap formats.</p> **/ public class Element extends BaseObj { int mSize; Element[] mElements; String[] mElementNames; + int[] mArraySizes; DataType mType; DataKind mKind; @@ -34,33 +54,54 @@ public class Element extends BaseObj { int getSizeBytes() {return mSize;} + + /** + * DataType represents the basic type information for a basic element. The + * naming convention follows. For numeric types its FLOAT, SIGNED, UNSIGNED + * followed by the _BITS where BITS is the size of the data. BOOLEAN is a + * true / false (1,0) represented in an 8 bit container. The UNSIGNED + * variants with multiple bit definitions are for packed graphical data + * formats and represents vectors with per vector member sizes which are + * treated as a single unit for packing and alignment purposes. + * + * MATRIX the three matrix types contain FLOAT_32 elements and are treated + * as 32 bits for alignment purposes. + * + * RS_* objects. 32 bit opaque handles. + */ public enum DataType { //FLOAT_16 (1, 2), FLOAT_32 (2, 4), - //FLOAT_64 (3, 8), + FLOAT_64 (3, 8), SIGNED_8 (4, 1), SIGNED_16 (5, 2), SIGNED_32 (6, 4), - //SIGNED_64 (7, 8), + SIGNED_64 (7, 8), UNSIGNED_8 (8, 1), UNSIGNED_16 (9, 2), UNSIGNED_32 (10, 4), - //UNSIGNED_64 (11, 8), - - UNSIGNED_5_6_5 (12, 2), - UNSIGNED_5_5_5_1 (13, 2), - UNSIGNED_4_4_4_4 (14, 2), - - RS_ELEMENT (15, 4), - RS_TYPE (16, 4), - RS_ALLOCATION (17, 4), - RS_SAMPLER (18, 4), - RS_SCRIPT (19, 4), - RS_MESH (20, 4), - RS_PROGRAM_FRAGMENT (21, 4), - RS_PROGRAM_VERTEX (22, 4), - RS_PROGRAM_RASTER (23, 4), - RS_PROGRAM_STORE (24, 4); + UNSIGNED_64 (11, 8), + + BOOLEAN(12, 1), + + UNSIGNED_5_6_5 (13, 2), + UNSIGNED_5_5_5_1 (14, 2), + UNSIGNED_4_4_4_4 (15, 2), + + MATRIX_4X4 (16, 64), + MATRIX_3X3 (17, 36), + MATRIX_2X2 (18, 16), + + RS_ELEMENT (1000, 4), + RS_TYPE (1001, 4), + RS_ALLOCATION (1002, 4), + RS_SAMPLER (1003, 4), + RS_SCRIPT (1004, 4), + RS_MESH (1005, 4), + RS_PROGRAM_FRAGMENT (1006, 4), + RS_PROGRAM_VERTEX (1007, 4), + RS_PROGRAM_RASTER (1008, 4), + RS_PROGRAM_STORE (1009, 4); int mID; int mSize; @@ -70,14 +111,14 @@ public class Element extends BaseObj { } } + /** + * The special interpretation of the data if required. This is primarly + * useful for graphical data. USER indicates no special interpretation is + * expected. PIXEL is used in conjunction with the standard data types for + * representing texture formats. + */ public enum DataKind { USER (0), - COLOR (1), - POSITION (2), - TEXTURE (3), - NORMAL (4), - INDEX (5), - POINT_SIZE(6), PIXEL_L (7), PIXEL_A (8), @@ -91,41 +132,193 @@ public class Element extends BaseObj { } } - public static Element USER_U8(RenderScript rs) { - if(rs.mElement_USER_U8 == null) { - rs.mElement_USER_U8 = createUser(rs, DataType.UNSIGNED_8); + /** + * Return if a element is too complex for use as a data source for a Mesh or + * a Program. + * + * @return boolean + */ + public boolean isComplex() { + if (mElements == null) { + return false; + } + for (int ct=0; ct < mElements.length; ct++) { + if (mElements[ct].mElements != null) { + return true; + } + } + return false; + } + + /** + * Utility function for returning an Element containing a single Boolean. + * + * @param rs Context to which the element will belong. + * + * @return Element + */ + public static Element BOOLEAN(RenderScript rs) { + if(rs.mElement_BOOLEAN == null) { + rs.mElement_BOOLEAN = createUser(rs, DataType.BOOLEAN); + } + return rs.mElement_BOOLEAN; + } + + /** + * Utility function for returning an Element containing a single UNSIGNED_8. + * + * @param rs Context to which the element will belong. + * + * @return Element + */ + public static Element U8(RenderScript rs) { + if(rs.mElement_U8 == null) { + rs.mElement_U8 = createUser(rs, DataType.UNSIGNED_8); + } + return rs.mElement_U8; + } + + /** + * Utility function for returning an Element containing a single SIGNED_8. + * + * @param rs Context to which the element will belong. + * + * @return Element + */ + public static Element I8(RenderScript rs) { + if(rs.mElement_I8 == null) { + rs.mElement_I8 = createUser(rs, DataType.SIGNED_8); + } + return rs.mElement_I8; + } + + public static Element U16(RenderScript rs) { + if(rs.mElement_U16 == null) { + rs.mElement_U16 = createUser(rs, DataType.UNSIGNED_16); + } + return rs.mElement_U16; + } + + public static Element I16(RenderScript rs) { + if(rs.mElement_I16 == null) { + rs.mElement_I16 = createUser(rs, DataType.SIGNED_16); + } + return rs.mElement_I16; + } + + public static Element U32(RenderScript rs) { + if(rs.mElement_U32 == null) { + rs.mElement_U32 = createUser(rs, DataType.UNSIGNED_32); + } + return rs.mElement_U32; + } + + public static Element I32(RenderScript rs) { + if(rs.mElement_I32 == null) { + rs.mElement_I32 = createUser(rs, DataType.SIGNED_32); + } + return rs.mElement_I32; + } + + public static Element U64(RenderScript rs) { + if(rs.mElement_U64 == null) { + rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64); + } + return rs.mElement_U64; + } + + public static Element I64(RenderScript rs) { + if(rs.mElement_I64 == null) { + rs.mElement_I64 = createUser(rs, DataType.SIGNED_64); + } + return rs.mElement_I64; + } + + public static Element F32(RenderScript rs) { + if(rs.mElement_F32 == null) { + rs.mElement_F32 = createUser(rs, DataType.FLOAT_32); + } + return rs.mElement_F32; + } + + public static Element F64(RenderScript rs) { + if(rs.mElement_F64 == null) { + rs.mElement_F64 = createUser(rs, DataType.FLOAT_64); + } + return rs.mElement_F64; + } + + public static Element ELEMENT(RenderScript rs) { + if(rs.mElement_ELEMENT == null) { + rs.mElement_ELEMENT = createUser(rs, DataType.RS_ELEMENT); + } + return rs.mElement_ELEMENT; + } + + public static Element TYPE(RenderScript rs) { + if(rs.mElement_TYPE == null) { + rs.mElement_TYPE = createUser(rs, DataType.RS_TYPE); + } + return rs.mElement_TYPE; + } + + public static Element ALLOCATION(RenderScript rs) { + if(rs.mElement_ALLOCATION == null) { + rs.mElement_ALLOCATION = createUser(rs, DataType.RS_ALLOCATION); + } + return rs.mElement_ALLOCATION; + } + + public static Element SAMPLER(RenderScript rs) { + if(rs.mElement_SAMPLER == null) { + rs.mElement_SAMPLER = createUser(rs, DataType.RS_SAMPLER); + } + return rs.mElement_SAMPLER; + } + + public static Element SCRIPT(RenderScript rs) { + if(rs.mElement_SCRIPT == null) { + rs.mElement_SCRIPT = createUser(rs, DataType.RS_SCRIPT); + } + return rs.mElement_SCRIPT; + } + + public static Element MESH(RenderScript rs) { + if(rs.mElement_MESH == null) { + rs.mElement_MESH = createUser(rs, DataType.RS_MESH); } - return rs.mElement_USER_U8; + return rs.mElement_MESH; } - public static Element USER_I8(RenderScript rs) { - if(rs.mElement_USER_I8 == null) { - rs.mElement_USER_I8 = createUser(rs, DataType.SIGNED_8); + public static Element PROGRAM_FRAGMENT(RenderScript rs) { + if(rs.mElement_PROGRAM_FRAGMENT == null) { + rs.mElement_PROGRAM_FRAGMENT = createUser(rs, DataType.RS_PROGRAM_FRAGMENT); } - return rs.mElement_USER_I8; + return rs.mElement_PROGRAM_FRAGMENT; } - public static Element USER_U32(RenderScript rs) { - if(rs.mElement_USER_U32 == null) { - rs.mElement_USER_U32 = createUser(rs, DataType.UNSIGNED_32); + public static Element PROGRAM_VERTEX(RenderScript rs) { + if(rs.mElement_PROGRAM_VERTEX == null) { + rs.mElement_PROGRAM_VERTEX = createUser(rs, DataType.RS_PROGRAM_VERTEX); } - return rs.mElement_USER_U32; + return rs.mElement_PROGRAM_VERTEX; } - public static Element USER_I32(RenderScript rs) { - if(rs.mElement_USER_I32 == null) { - rs.mElement_USER_I32 = createUser(rs, DataType.SIGNED_32); + public static Element PROGRAM_RASTER(RenderScript rs) { + if(rs.mElement_PROGRAM_RASTER == null) { + rs.mElement_PROGRAM_RASTER = createUser(rs, DataType.RS_PROGRAM_RASTER); } - return rs.mElement_USER_I32; + return rs.mElement_PROGRAM_RASTER; } - public static Element USER_F32(RenderScript rs) { - if(rs.mElement_USER_F32 == null) { - rs.mElement_USER_F32 = createUser(rs, DataType.FLOAT_32); + public static Element PROGRAM_STORE(RenderScript rs) { + if(rs.mElement_PROGRAM_STORE == null) { + rs.mElement_PROGRAM_STORE = createUser(rs, DataType.RS_PROGRAM_STORE); } - return rs.mElement_USER_F32; + return rs.mElement_PROGRAM_STORE; } + public static Element A_8(RenderScript rs) { if(rs.mElement_A_8 == null) { rs.mElement_A_8 = createPixel(rs, DataType.UNSIGNED_8, DataKind.PIXEL_A); @@ -168,192 +361,198 @@ public class Element extends BaseObj { return rs.mElement_RGBA_8888; } - public static Element INDEX_16(RenderScript rs) { - if(rs.mElement_INDEX_16 == null) { - rs.mElement_INDEX_16 = createIndex(rs); + public static Element F32_2(RenderScript rs) { + if(rs.mElement_FLOAT_2 == null) { + rs.mElement_FLOAT_2 = createVector(rs, DataType.FLOAT_32, 2); } - return rs.mElement_INDEX_16; + return rs.mElement_FLOAT_2; } - public static Element ATTRIB_POSITION_2(RenderScript rs) { - if(rs.mElement_POSITION_2 == null) { - rs.mElement_POSITION_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 2); + public static Element F32_3(RenderScript rs) { + if(rs.mElement_FLOAT_3 == null) { + rs.mElement_FLOAT_3 = createVector(rs, DataType.FLOAT_32, 3); } - return rs.mElement_POSITION_2; + return rs.mElement_FLOAT_3; } - public static Element ATTRIB_POSITION_3(RenderScript rs) { - if(rs.mElement_POSITION_3 == null) { - rs.mElement_POSITION_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.POSITION, 3); + public static Element F32_4(RenderScript rs) { + if(rs.mElement_FLOAT_4 == null) { + rs.mElement_FLOAT_4 = createVector(rs, DataType.FLOAT_32, 4); } - return rs.mElement_POSITION_3; + return rs.mElement_FLOAT_4; } - public static Element ATTRIB_TEXTURE_2(RenderScript rs) { - if(rs.mElement_TEXTURE_2 == null) { - rs.mElement_TEXTURE_2 = createAttrib(rs, DataType.FLOAT_32, DataKind.TEXTURE, 2); + public static Element U8_4(RenderScript rs) { + if(rs.mElement_UCHAR_4 == null) { + rs.mElement_UCHAR_4 = createVector(rs, DataType.UNSIGNED_8, 4); } - return rs.mElement_TEXTURE_2; + return rs.mElement_UCHAR_4; } - public static Element ATTRIB_NORMAL_3(RenderScript rs) { - if(rs.mElement_NORMAL_3 == null) { - rs.mElement_NORMAL_3 = createAttrib(rs, DataType.FLOAT_32, DataKind.NORMAL, 3); + public static Element MATRIX_4X4(RenderScript rs) { + if(rs.mElement_MATRIX_4X4 == null) { + rs.mElement_MATRIX_4X4 = createUser(rs, DataType.MATRIX_4X4); } - return rs.mElement_NORMAL_3; + return rs.mElement_MATRIX_4X4; + } + public static Element MATRIX4X4(RenderScript rs) { + return MATRIX_4X4(rs); } - public static Element ATTRIB_COLOR_U8_4(RenderScript rs) { - if(rs.mElement_COLOR_U8_4 == null) { - rs.mElement_COLOR_U8_4 = createAttrib(rs, DataType.UNSIGNED_8, DataKind.COLOR, 4); + public static Element MATRIX_3X3(RenderScript rs) { + if(rs.mElement_MATRIX_3X3 == null) { + rs.mElement_MATRIX_3X3 = createUser(rs, DataType.MATRIX_3X3); } - return rs.mElement_COLOR_U8_4; + return rs.mElement_MATRIX_3X3; } - public static Element ATTRIB_COLOR_F32_4(RenderScript rs) { - if(rs.mElement_COLOR_F32_4 == null) { - rs.mElement_COLOR_F32_4 = createAttrib(rs, DataType.FLOAT_32, DataKind.COLOR, 4); + public static Element MATRIX_2X2(RenderScript rs) { + if(rs.mElement_MATRIX_2X2 == null) { + rs.mElement_MATRIX_2X2 = createUser(rs, DataType.MATRIX_2X2); } - return rs.mElement_COLOR_F32_4; + return rs.mElement_MATRIX_2X2; } - Element(RenderScript rs, Element[] e, String[] n) { - super(rs); + Element(int id, RenderScript rs, Element[] e, String[] n, int[] as) { + super(id, rs); mSize = 0; mElements = e; mElementNames = n; - int[] ids = new int[mElements.length]; + mArraySizes = as; for (int ct = 0; ct < mElements.length; ct++ ) { - mSize += mElements[ct].mSize; - ids[ct] = mElements[ct].mID; + mSize += mElements[ct].mSize * mArraySizes[ct]; } - mID = rs.nElementCreate2(ids, mElementNames); } - Element(RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) { - super(rs); - mSize = dt.mSize * size; + Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) { + super(id, rs); + if ((dt != DataType.UNSIGNED_5_6_5) && + (dt != DataType.UNSIGNED_4_4_4_4) && + (dt != DataType.UNSIGNED_5_5_5_1)) { + mSize = dt.mSize * size; + } else { + mSize = dt.mSize; + } mType = dt; mKind = dk; mNormalized = norm; mVectorSize = size; - mID = rs.nElementCreate(dt.mID, dk.mID, norm, size); - } - - public void destroy() throws IllegalStateException { - super.destroy(); - } - - public static Element createFromClass(RenderScript rs, Class c) { - rs.validate(); - Field[] fields = c.getFields(); - Builder b = new Builder(rs); - - for(Field f: fields) { - Class fc = f.getType(); - if(fc == int.class) { - b.add(createUser(rs, DataType.SIGNED_32), f.getName()); - } else if(fc == short.class) { - b.add(createUser(rs, DataType.SIGNED_16), f.getName()); - } else if(fc == byte.class) { - b.add(createUser(rs, DataType.SIGNED_8), f.getName()); - } else if(fc == float.class) { - b.add(createUser(rs, DataType.FLOAT_32), f.getName()); - } else { - throw new IllegalArgumentException("Unkown field type"); - } - } - return b.create(); } - - ///////////////////////////////////////// - public static Element createUser(RenderScript rs, DataType dt) { - return new Element(rs, dt, DataKind.USER, false, 1); + Element(int id, RenderScript rs) { + super(id, rs); } - public static Element createVector(RenderScript rs, DataType dt, int size) { - if (size < 2 || size > 4) { - throw new IllegalArgumentException("Bad size"); - } - return new Element(rs, dt, DataKind.USER, false, size); - } + @Override + void updateFromNative() { + super.updateFromNative(); - public static Element createIndex(RenderScript rs) { - return new Element(rs, DataType.UNSIGNED_16, DataKind.INDEX, false, 1); - } + // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements + int[] dataBuffer = new int[5]; + mRS.nElementGetNativeData(getID(), dataBuffer); - public static Element createAttrib(RenderScript rs, DataType dt, DataKind dk, int size) { - if (!(dt == DataType.FLOAT_32 || - dt == DataType.UNSIGNED_8 || - dt == DataType.UNSIGNED_16 || - dt == DataType.UNSIGNED_32 || - dt == DataType.SIGNED_8 || - dt == DataType.SIGNED_16 || - dt == DataType.SIGNED_32)) { - throw new IllegalArgumentException("Unsupported DataType"); + mNormalized = dataBuffer[2] == 1 ? true : false; + mVectorSize = dataBuffer[3]; + mSize = 0; + for (DataType dt: DataType.values()) { + if(dt.mID == dataBuffer[0]){ + mType = dt; + mSize = mType.mSize * mVectorSize; + } } - - if (!(dk == DataKind.COLOR || - dk == DataKind.POSITION || - dk == DataKind.TEXTURE || - dk == DataKind.NORMAL || - dk == DataKind.POINT_SIZE || - dk == DataKind.USER)) { - throw new IllegalArgumentException("Unsupported DataKind"); + for (DataKind dk: DataKind.values()) { + if(dk.mID == dataBuffer[1]){ + mKind = dk; + } } - if (dk == DataKind.COLOR && - ((dt != DataType.FLOAT_32 && dt != DataType.UNSIGNED_8) || - size < 3 || size > 4)) { - throw new IllegalArgumentException("Bad combo"); - } - if (dk == DataKind.POSITION && (size < 1 || size > 4)) { - throw new IllegalArgumentException("Bad combo"); - } - if (dk == DataKind.TEXTURE && - (dt != DataType.FLOAT_32 || size < 1 || size > 4)) { - throw new IllegalArgumentException("Bad combo"); - } - if (dk == DataKind.NORMAL && - (dt != DataType.FLOAT_32 || size != 3)) { - throw new IllegalArgumentException("Bad combo"); - } - if (dk == DataKind.POINT_SIZE && - (dt != DataType.FLOAT_32 || size != 1)) { - throw new IllegalArgumentException("Bad combo"); + int numSubElements = dataBuffer[4]; + if(numSubElements > 0) { + mElements = new Element[numSubElements]; + mElementNames = new String[numSubElements]; + + int[] subElementIds = new int[numSubElements]; + mRS.nElementGetSubElements(getID(), subElementIds, mElementNames); + for(int i = 0; i < numSubElements; i ++) { + mElements[i] = new Element(subElementIds[i], mRS); + mElements[i].updateFromNative(); + mSize += mElements[i].mSize; + } } + } + + /** + * Create a custom Element of the specified DataType. The DataKind will be + * set to USER and the vector size to 1 indicating non-vector. + * + * @param rs The context associated with the new Element. + * @param dt The DataType for the new element. + * @return Element + */ + static Element createUser(RenderScript rs, DataType dt) { + DataKind dk = DataKind.USER; boolean norm = false; - if (dk == DataKind.COLOR && dt == DataType.UNSIGNED_8) { - norm = true; - } + int vecSize = 1; + int id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize); + return new Element(id, rs, dt, dk, norm, vecSize); + } - return new Element(rs, dt, dk, norm, size); + /** + * Create a custom vector element of the specified DataType and vector size. + * DataKind will be set to USER. + * + * @param rs The context associated with the new Element. + * @param dt The DataType for the new element. + * @param size Vector size for the new Element. Range 2-4 inclusive + * supported. + * + * @return Element + */ + public static Element createVector(RenderScript rs, DataType dt, int size) { + if (size < 2 || size > 4) { + throw new RSIllegalArgumentException("Vector size out of range 2-4."); + } + DataKind dk = DataKind.USER; + boolean norm = false; + int id = rs.nElementCreate(dt.mID, dk.mID, norm, size); + return new Element(id, rs, dt, dk, norm, size); } + /** + * Create a new pixel Element type. A matching DataType and DataKind must + * be provided. The DataType and DataKind must contain the same number of + * components. Vector size will be set to 1. + * + * @param rs The context associated with the new Element. + * @param dt The DataType for the new element. + * @param dk The DataKind to specify the mapping of each component in the + * DataType. + * + * @return Element + */ public static Element createPixel(RenderScript rs, DataType dt, DataKind dk) { if (!(dk == DataKind.PIXEL_L || dk == DataKind.PIXEL_A || dk == DataKind.PIXEL_LA || dk == DataKind.PIXEL_RGB || dk == DataKind.PIXEL_RGBA)) { - throw new IllegalArgumentException("Unsupported DataKind"); + throw new RSIllegalArgumentException("Unsupported DataKind"); } if (!(dt == DataType.UNSIGNED_8 || dt == DataType.UNSIGNED_5_6_5 || dt == DataType.UNSIGNED_4_4_4_4 || dt == DataType.UNSIGNED_5_5_5_1)) { - throw new IllegalArgumentException("Unsupported DataType"); + throw new RSIllegalArgumentException("Unsupported DataType"); } if (dt == DataType.UNSIGNED_5_6_5 && dk != DataKind.PIXEL_RGB) { - throw new IllegalArgumentException("Bad kind and type combo"); + throw new RSIllegalArgumentException("Bad kind and type combo"); } if (dt == DataType.UNSIGNED_5_5_5_1 && dk != DataKind.PIXEL_RGBA) { - throw new IllegalArgumentException("Bad kind and type combo"); + throw new RSIllegalArgumentException("Bad kind and type combo"); } if (dt == DataType.UNSIGNED_4_4_4_4 && dk != DataKind.PIXEL_RGBA) { - throw new IllegalArgumentException("Bad kind and type combo"); + throw new RSIllegalArgumentException("Bad kind and type combo"); } int size = 1; @@ -367,56 +566,98 @@ public class Element extends BaseObj { size = 4; } - return new Element(rs, dt, dk, true, size); + boolean norm = true; + int id = rs.nElementCreate(dt.mID, dk.mID, norm, size); + return new Element(id, rs, dt, dk, norm, size); } + /** + * Builder class for producing complex elements with matching field and name + * pairs. The builder starts empty. The order in which elements are added + * is retained for the layout in memory. + * + */ public static class Builder { RenderScript mRS; Element[] mElements; String[] mElementNames; + int[] mArraySizes; int mCount; + /** + * Create a builder object. + * + * @param rs + */ public Builder(RenderScript rs) { mRS = rs; mCount = 0; mElements = new Element[8]; mElementNames = new String[8]; - } - - public void add(Element element, String name) { + mArraySizes = new int[8]; + } + + /** + * Add an array of elements to this element. + * + * @param element + * @param name + * @param arraySize + */ + public Builder add(Element element, String name, int arraySize) { + if (arraySize < 1) { + throw new RSIllegalArgumentException("Array size cannot be less than 1."); + } if(mCount == mElements.length) { Element[] e = new Element[mCount + 8]; String[] s = new String[mCount + 8]; + int[] as = new int[mCount + 8]; System.arraycopy(mElements, 0, e, 0, mCount); System.arraycopy(mElementNames, 0, s, 0, mCount); + System.arraycopy(mArraySizes, 0, as, 0, mCount); mElements = e; mElementNames = s; + mArraySizes = as; } mElements[mCount] = element; mElementNames[mCount] = name; + mArraySizes[mCount] = arraySize; mCount++; + return this; } + /** + * Add a single element to this Element. + * + * @param element + * @param name + */ + public Builder add(Element element, String name) { + return add(element, name, 1); + } + + /** + * Create the element from this builder. + * + * + * @return Element + */ public Element create() { mRS.validate(); Element[] ein = new Element[mCount]; String[] sin = new String[mCount]; + int[] asin = new int[mCount]; java.lang.System.arraycopy(mElements, 0, ein, 0, mCount); java.lang.System.arraycopy(mElementNames, 0, sin, 0, mCount); - return new Element(mRS, ein, sin); - } - } + java.lang.System.arraycopy(mArraySizes, 0, asin, 0, mCount); - static void initPredefined(RenderScript rs) { - int a8 = rs.nElementCreate(DataType.UNSIGNED_8.mID, - DataKind.PIXEL_A.mID, true, 1); - int rgba4444 = rs.nElementCreate(DataType.UNSIGNED_4_4_4_4.mID, - DataKind.PIXEL_RGBA.mID, true, 4); - int rgba8888 = rs.nElementCreate(DataType.UNSIGNED_8.mID, - DataKind.PIXEL_RGBA.mID, true, 4); - int rgb565 = rs.nElementCreate(DataType.UNSIGNED_5_6_5.mID, - DataKind.PIXEL_RGB.mID, true, 3); - rs.nInitElements(a8, rgba4444, rgba8888, rgb565); + int[] ids = new int[ein.length]; + for (int ct = 0; ct < ein.length; ct++ ) { + ids[ct] = ein[ct].getID(); + } + int id = mRS.nElementCreate2(ids, sin, asin); + return new Element(id, mRS, ein, sin, asin); + } } } diff --git a/graphics/java/android/renderscript/FieldPacker.java b/graphics/java/android/renderscript/FieldPacker.java index b26e47d..bdda830 100644 --- a/graphics/java/android/renderscript/FieldPacker.java +++ b/graphics/java/android/renderscript/FieldPacker.java @@ -18,7 +18,8 @@ package android.renderscript; /** - * @hide + * Utility class for packing arguments and structures from Android system objects to + * Renderscript objects. * **/ public class FieldPacker { @@ -33,21 +34,28 @@ public class FieldPacker { } } - void reset() { + public void reset() { mPos = 0; } + public void reset(int i) { + mPos = i; + } + + public void skip(int i) { + mPos += i; + } - void addI8(byte v) { + public void addI8(byte v) { mData[mPos++] = v; } - void addI16(short v) { + public void addI16(short v) { align(2); mData[mPos++] = (byte)(v & 0xff); mData[mPos++] = (byte)(v >> 8); } - void addI32(int v) { + public void addI32(int v) { align(4); mData[mPos++] = (byte)(v & 0xff); mData[mPos++] = (byte)((v >> 8) & 0xff); @@ -55,7 +63,7 @@ public class FieldPacker { mData[mPos++] = (byte)((v >> 24) & 0xff); } - void addI64(long v) { + public void addI64(long v) { align(8); mData[mPos++] = (byte)(v & 0xff); mData[mPos++] = (byte)((v >> 8) & 0xff); @@ -67,15 +75,17 @@ public class FieldPacker { mData[mPos++] = (byte)((v >> 56) & 0xff); } - void addU8(short v) { + public void addU8(short v) { if ((v < 0) || (v > 0xff)) { + android.util.Log.e("rs", "FieldPacker.addU8( " + v + " )"); throw new IllegalArgumentException("Saving value out of range for type"); } mData[mPos++] = (byte)v; } - void addU16(int v) { + public void addU16(int v) { if ((v < 0) || (v > 0xffff)) { + android.util.Log.e("rs", "FieldPacker.addU16( " + v + " )"); throw new IllegalArgumentException("Saving value out of range for type"); } align(2); @@ -83,8 +93,9 @@ public class FieldPacker { mData[mPos++] = (byte)(v >> 8); } - void addU32(long v) { - if ((v < 0) || (v > 0xffffffff)) { + public void addU32(long v) { + if ((v < 0) || (v > 0xffffffffL)) { + android.util.Log.e("rs", "FieldPacker.addU32( " + v + " )"); throw new IllegalArgumentException("Saving value out of range for type"); } align(4); @@ -94,8 +105,9 @@ public class FieldPacker { mData[mPos++] = (byte)((v >> 24) & 0xff); } - void addU64(long v) { + public void addU64(long v) { if (v < 0) { + android.util.Log.e("rs", "FieldPacker.addU64( " + v + " )"); throw new IllegalArgumentException("Saving value out of range for type"); } align(8); @@ -109,15 +121,157 @@ public class FieldPacker { mData[mPos++] = (byte)((v >> 56) & 0xff); } - void addF32(float v) { + public void addF32(float v) { addI32(Float.floatToRawIntBits(v)); } - void addF64(float v) { + public void addF64(double v) { addI64(Double.doubleToRawLongBits(v)); } - final byte[] getData() { + public void addObj(BaseObj obj) { + if (obj != null) { + addI32(obj.getID()); + } else { + addI32(0); + } + } + + public void addF32(Float2 v) { + addF32(v.x); + addF32(v.y); + } + public void addF32(Float3 v) { + addF32(v.x); + addF32(v.y); + addF32(v.z); + } + public void addF32(Float4 v) { + addF32(v.x); + addF32(v.y); + addF32(v.z); + addF32(v.w); + } + + public void addI8(Byte2 v) { + addI8(v.x); + addI8(v.y); + } + public void addI8(Byte3 v) { + addI8(v.x); + addI8(v.y); + addI8(v.z); + } + public void addI8(Byte4 v) { + addI8(v.x); + addI8(v.y); + addI8(v.z); + addI8(v.w); + } + + public void addU8(Short2 v) { + addU8(v.x); + addU8(v.y); + } + public void addU8(Short3 v) { + addU8(v.x); + addU8(v.y); + addU8(v.z); + } + public void addU8(Short4 v) { + addU8(v.x); + addU8(v.y); + addU8(v.z); + addU8(v.w); + } + + public void addI16(Short2 v) { + addI16(v.x); + addI16(v.y); + } + public void addI16(Short3 v) { + addI16(v.x); + addI16(v.y); + addI16(v.z); + } + public void addI16(Short4 v) { + addI16(v.x); + addI16(v.y); + addI16(v.z); + addI16(v.w); + } + + public void addU16(Int2 v) { + addU16(v.x); + addU16(v.y); + } + public void addU16(Int3 v) { + addU16(v.x); + addU16(v.y); + addU16(v.z); + } + public void addU16(Int4 v) { + addU16(v.x); + addU16(v.y); + addU16(v.z); + addU16(v.w); + } + + public void addI32(Int2 v) { + addI32(v.x); + addI32(v.y); + } + public void addI32(Int3 v) { + addI32(v.x); + addI32(v.y); + addI32(v.z); + } + public void addI32(Int4 v) { + addI32(v.x); + addI32(v.y); + addI32(v.z); + addI32(v.w); + } + + public void addU32(Long2 v) { + addU32(v.x); + addU32(v.y); + } + public void addU32(Long3 v) { + addU32(v.x); + addU32(v.y); + addU32(v.z); + } + public void addU32(Long4 v) { + addU32(v.x); + addU32(v.y); + addU32(v.z); + addU32(v.w); + } + + public void addMatrix(Matrix4f v) { + for (int i=0; i < v.mMat.length; i++) { + addF32(v.mMat[i]); + } + } + + public void addMatrix(Matrix3f v) { + for (int i=0; i < v.mMat.length; i++) { + addF32(v.mMat[i]); + } + } + + public void addMatrix(Matrix2f v) { + for (int i=0; i < v.mMat.length; i++) { + addF32(v.mMat[i]); + } + } + + public void addBoolean(boolean v) { + addI8((byte)(v ? 1 : 0)); + } + + public final byte[] getData() { return mData; } diff --git a/graphics/java/android/renderscript/FileA3D.java b/graphics/java/android/renderscript/FileA3D.java new file mode 100644 index 0000000..b5419a7 --- /dev/null +++ b/graphics/java/android/renderscript/FileA3D.java @@ -0,0 +1,298 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; + +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.graphics.Bitmap; +import android.graphics.BitmapFactory; +import android.util.Log; +import android.util.TypedValue; + +/** + * FileA3D allows users to load Renderscript objects from files + * or resources stored on disk. It could be used to load items + * such as 3D geometry data converted to a Renderscript format from + * content creation tools. Currently only meshes are supported + * in FileA3D. + * + * When successfully loaded, FileA3D will contain a list of + * index entries for all the objects stored inside it. + * + **/ +public class FileA3D extends BaseObj { + + /** + * Specifies what renderscript object type is contained within + * the FileA3D IndexEntry + **/ + public enum EntryType { + + /** + * Unknown or or invalid object, nothing will be loaded + **/ + UNKNOWN (0), + /** + * Renderscript Mesh object + **/ + MESH (1); + + int mID; + EntryType(int id) { + mID = id; + } + + static EntryType toEntryType(int intID) { + return EntryType.values()[intID]; + } + } + + /** + * IndexEntry contains information about one of the Renderscript + * objects inside the file's index. It could be used to query the + * object's type and also name and load the object itself if + * necessary. + */ + public static class IndexEntry { + RenderScript mRS; + int mIndex; + int mID; + String mName; + EntryType mEntryType; + BaseObj mLoadedObj; + + /** + * Returns the name of a renderscript object the index entry + * describes + * + * @return name of a renderscript object the index entry + * describes + * + */ + public String getName() { + return mName; + } + + /** + * Returns the type of a renderscript object the index entry + * describes + * @return type of a renderscript object the index entry + * describes + */ + public EntryType getEntryType() { + return mEntryType; + } + + /** + * Used to load the object described by the index entry + * @return base renderscript object described by the entry + */ + public BaseObj getObject() { + mRS.validate(); + BaseObj obj = internalCreate(mRS, this); + return obj; + } + + /** + * Used to load the mesh described by the index entry, object + * described by the index entry must be a renderscript mesh + * + * @return renderscript mesh object described by the entry + */ + public Mesh getMesh() { + return (Mesh)getObject(); + } + + static synchronized BaseObj internalCreate(RenderScript rs, IndexEntry entry) { + if(entry.mLoadedObj != null) { + return entry.mLoadedObj; + } + + // to be purged on cleanup + if(entry.mEntryType == EntryType.UNKNOWN) { + return null; + } + + int objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex); + if(objectID == 0) { + return null; + } + + switch (entry.mEntryType) { + case MESH: + entry.mLoadedObj = new Mesh(objectID, rs); + break; + } + + entry.mLoadedObj.updateFromNative(); + return entry.mLoadedObj; + } + + IndexEntry(RenderScript rs, int index, int id, String name, EntryType type) { + mRS = rs; + mIndex = index; + mID = id; + mName = name; + mEntryType = type; + mLoadedObj = null; + } + } + + IndexEntry[] mFileEntries; + InputStream mInputStream; + + FileA3D(int id, RenderScript rs, InputStream stream) { + super(id, rs); + mInputStream = stream; + } + + private void initEntries() { + int numFileEntries = mRS.nFileA3DGetNumIndexEntries(getID()); + if(numFileEntries <= 0) { + return; + } + + mFileEntries = new IndexEntry[numFileEntries]; + int[] ids = new int[numFileEntries]; + String[] names = new String[numFileEntries]; + + mRS.nFileA3DGetIndexEntries(getID(), numFileEntries, ids, names); + + for(int i = 0; i < numFileEntries; i ++) { + mFileEntries[i] = new IndexEntry(mRS, i, getID(), names[i], EntryType.toEntryType(ids[i])); + } + } + + /** + * Returns the number of objects stored inside the a3d file + * + * @return the number of objects stored inside the a3d file + */ + public int getIndexEntryCount() { + if(mFileEntries == null) { + return 0; + } + return mFileEntries.length; + } + + /** + * Returns an index entry from the list of all objects inside + * FileA3D + * + * @param index number of the entry from the list to return + * + * @return entry in the a3d file described by the index + */ + public IndexEntry getIndexEntry(int index) { + if(getIndexEntryCount() == 0 || index < 0 || index >= mFileEntries.length) { + return null; + } + return mFileEntries[index]; + } + + /** + * Creates a FileA3D object from an asset stored on disk + * + * @param rs Context to which the object will belong. + * @param mgr asset manager used to load asset + * @param path location of the file to load + * + * @return a3d file containing renderscript objects + */ + static public FileA3D createFromAsset(RenderScript rs, AssetManager mgr, String path) { + rs.validate(); + int fileId = rs.nFileA3DCreateFromAsset(mgr, path); + + if(fileId == 0) { + throw new RSRuntimeException("Unable to create a3d file from asset " + path); + } + FileA3D fa3d = new FileA3D(fileId, rs, null); + fa3d.initEntries(); + return fa3d; + } + + /** + * Creates a FileA3D object from a file stored on disk + * + * @param rs Context to which the object will belong. + * @param path location of the file to load + * + * @return a3d file containing renderscript objects + */ + static public FileA3D createFromFile(RenderScript rs, String path) { + int fileId = rs.nFileA3DCreateFromFile(path); + + if(fileId == 0) { + throw new RSRuntimeException("Unable to create a3d file from " + path); + } + FileA3D fa3d = new FileA3D(fileId, rs, null); + fa3d.initEntries(); + return fa3d; + } + + /** + * Creates a FileA3D object from a file stored on disk + * + * @param rs Context to which the object will belong. + * @param path location of the file to load + * + * @return a3d file containing renderscript objects + */ + static public FileA3D createFromFile(RenderScript rs, File path) { + return createFromFile(rs, path.getAbsolutePath()); + } + + /** + * Creates a FileA3D object from an application resource + * + * @param rs Context to which the object will belong. + * @param res resource manager used for loading + * @param id resource to create FileA3D from + * + * @return a3d file containing renderscript objects + */ + static public FileA3D createFromResource(RenderScript rs, Resources res, int id) { + + rs.validate(); + InputStream is = null; + try { + is = res.openRawResource(id); + } catch (Exception e) { + throw new RSRuntimeException("Unable to open resource " + id); + } + + int fileId = 0; + if (is instanceof AssetManager.AssetInputStream) { + int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); + fileId = rs.nFileA3DCreateFromAssetStream(asset); + } else { + throw new RSRuntimeException("Unsupported asset stream"); + } + + if(fileId == 0) { + throw new RSRuntimeException("Unable to create a3d file from resource " + id); + } + FileA3D fa3d = new FileA3D(fileId, rs, is); + fa3d.initEntries(); + return fa3d; + + } +} diff --git a/graphics/java/android/renderscript/Float2.java b/graphics/java/android/renderscript/Float2.java new file mode 100644 index 0000000..1d4ce36 --- /dev/null +++ b/graphics/java/android/renderscript/Float2.java @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript float2 type back to the Android system. + * + **/ +public class Float2 { + public Float2() { + } + + public Float2(float initX, float initY) { + x = initX; + y = initY; + } + + public float x; + public float y; +} + + + + diff --git a/graphics/java/android/renderscript/Float3.java b/graphics/java/android/renderscript/Float3.java new file mode 100644 index 0000000..ffd1135 --- /dev/null +++ b/graphics/java/android/renderscript/Float3.java @@ -0,0 +1,43 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript float2 type back to the Android system. + * + **/ +public class Float3 { + public Float3() { + } + public Float3(float initX, float initY, float initZ) { + x = initX; + y = initY; + z = initZ; + } + + public float x; + public float y; + public float z; +} + + + + diff --git a/graphics/java/android/renderscript/Float4.java b/graphics/java/android/renderscript/Float4.java new file mode 100644 index 0000000..c7cc3ae --- /dev/null +++ b/graphics/java/android/renderscript/Float4.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript float2 type back to the Android system. + * + **/ +public class Float4 { + public Float4() { + } + + public Float4(float initX, float initY, float initZ, float initW) { + x = initX; + y = initY; + z = initZ; + w = initW; + } + + public float x; + public float y; + public float z; + public float w; +} + + + diff --git a/graphics/java/android/renderscript/Font.java b/graphics/java/android/renderscript/Font.java new file mode 100644 index 0000000..fa27590 --- /dev/null +++ b/graphics/java/android/renderscript/Font.java @@ -0,0 +1,218 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.util.HashMap; +import java.util.Map; + +import android.os.Environment; + +import android.content.res.AssetManager; +import android.content.res.Resources; +import android.util.Log; +import android.util.TypedValue; + +/** + * <p>This class gives users a simple way to draw hardware accelerated text. + * Internally, the glyphs are rendered using the Freetype library and an internal cache of + * rendered glyph bitmaps is maintained. Each font object represents a combination of a typeface, + * and point size. You can create multiple font objects to represent styles such as bold or italic text, + * faces, and different font sizes. During creation, the Android system quieries device's screen DPI to + * ensure proper sizing across multiple device configurations.</p> + * <p>Fonts are rendered using screen-space positions and no state setup beyond binding a + * font to the Renderscript is required. A note of caution on performance, though the state changes + * are transparent to the user, they do happen internally, and it is more efficient to + * render large batches of text in sequence. It is also more efficient to render multiple + * characters at once instead of one by one to improve draw call batching.</p> + * <p>Font color and transparency are not part of the font object and you can freely modify + * them in the script to suit the user's rendering needs. Font colors work as a state machine. + * Every new call to draw text uses the last color set in the script.</p> + **/ +public class Font extends BaseObj { + + //These help us create a font by family name + private static final String[] sSansNames = { + "sans-serif", "arial", "helvetica", "tahoma", "verdana" + }; + + private static final String[] sSerifNames = { + "serif", "times", "times new roman", "palatino", "georgia", "baskerville", + "goudy", "fantasy", "cursive", "ITC Stone Serif" + }; + + private static final String[] sMonoNames = { + "monospace", "courier", "courier new", "monaco" + }; + + private static class FontFamily { + String[] mNames; + String mNormalFileName; + String mBoldFileName; + String mItalicFileName; + String mBoldItalicFileName; + } + + private static Map<String, FontFamily> sFontFamilyMap; + + public enum Style { + NORMAL, + BOLD, + ITALIC, + BOLD_ITALIC; + } + + private static void addFamilyToMap(FontFamily family) { + for(int i = 0; i < family.mNames.length; i ++) { + sFontFamilyMap.put(family.mNames[i], family); + } + } + + private static void initFontFamilyMap() { + sFontFamilyMap = new HashMap<String, FontFamily>(); + + FontFamily sansFamily = new FontFamily(); + sansFamily.mNames = sSansNames; + sansFamily.mNormalFileName = "DroidSans.ttf"; + sansFamily.mBoldFileName = "DroidSans-Bold.ttf"; + sansFamily.mItalicFileName = "DroidSans.ttf"; + sansFamily.mBoldItalicFileName = "DroidSans-Bold.ttf"; + addFamilyToMap(sansFamily); + + FontFamily serifFamily = new FontFamily(); + serifFamily.mNames = sSerifNames; + serifFamily.mNormalFileName = "DroidSerif-Regular.ttf"; + serifFamily.mBoldFileName = "DroidSerif-Bold.ttf"; + serifFamily.mItalicFileName = "DroidSerif-Italic.ttf"; + serifFamily.mBoldItalicFileName = "DroidSerif-BoldItalic.ttf"; + addFamilyToMap(serifFamily); + + FontFamily monoFamily = new FontFamily(); + monoFamily.mNames = sMonoNames; + monoFamily.mNormalFileName = "DroidSansMono.ttf"; + monoFamily.mBoldFileName = "DroidSansMono.ttf"; + monoFamily.mItalicFileName = "DroidSansMono.ttf"; + monoFamily.mBoldItalicFileName = "DroidSansMono.ttf"; + addFamilyToMap(monoFamily); + } + + static { + initFontFamilyMap(); + } + + static String getFontFileName(String familyName, Style style) { + FontFamily family = sFontFamilyMap.get(familyName); + if(family != null) { + switch(style) { + case NORMAL: + return family.mNormalFileName; + case BOLD: + return family.mBoldFileName; + case ITALIC: + return family.mItalicFileName; + case BOLD_ITALIC: + return family.mBoldItalicFileName; + } + } + // Fallback if we could not find the desired family + return "DroidSans.ttf"; + } + + Font(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Takes a specific file name as an argument + */ + static public Font createFromFile(RenderScript rs, Resources res, String path, float pointSize) { + rs.validate(); + int dpi = res.getDisplayMetrics().densityDpi; + int fontId = rs.nFontCreateFromFile(path, pointSize, dpi); + + if(fontId == 0) { + throw new RSRuntimeException("Unable to create font from file " + path); + } + Font rsFont = new Font(fontId, rs); + + return rsFont; + } + + static public Font createFromFile(RenderScript rs, Resources res, File path, float pointSize) { + return createFromFile(rs, res, path.getAbsolutePath(), pointSize); + } + + static public Font createFromAsset(RenderScript rs, Resources res, String path, float pointSize) { + rs.validate(); + AssetManager mgr = res.getAssets(); + int dpi = res.getDisplayMetrics().densityDpi; + + int fontId = rs.nFontCreateFromAsset(mgr, path, pointSize, dpi); + if(fontId == 0) { + throw new RSRuntimeException("Unable to create font from asset " + path); + } + Font rsFont = new Font(fontId, rs); + return rsFont; + } + + static public Font createFromResource(RenderScript rs, Resources res, int id, float pointSize) { + String name = "R." + Integer.toString(id); + + rs.validate(); + InputStream is = null; + try { + is = res.openRawResource(id); + } catch (Exception e) { + throw new RSRuntimeException("Unable to open resource " + id); + } + + int dpi = res.getDisplayMetrics().densityDpi; + + int fontId = 0; + if (is instanceof AssetManager.AssetInputStream) { + int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); + fontId = rs.nFontCreateFromAssetStream(name, pointSize, dpi, asset); + } else { + throw new RSRuntimeException("Unsupported asset stream created"); + } + + if(fontId == 0) { + throw new RSRuntimeException("Unable to create font from resource " + id); + } + Font rsFont = new Font(fontId, rs); + return rsFont; + } + + /** + * Accepts one of the following family names as an argument + * and will attemp to produce the best match with a system font + * "sans-serif" "arial" "helvetica" "tahoma" "verdana" + * "serif" "times" "times new roman" "palatino" "georgia" "baskerville" + * "goudy" "fantasy" "cursive" "ITC Stone Serif" + * "monospace" "courier" "courier new" "monaco" + * Returns default font if no match could be found + */ + static public Font create(RenderScript rs, Resources res, String familyName, Style fontStyle, float pointSize) { + String fileName = getFontFileName(familyName, fontStyle); + String fontPath = Environment.getRootDirectory().getAbsolutePath(); + fontPath += "/fonts/" + fileName; + return createFromFile(rs, res, fontPath, pointSize); + } + +} diff --git a/graphics/java/android/renderscript/Vector2f.java b/graphics/java/android/renderscript/Int2.java index 567d57f..7aaa4e8 100644 --- a/graphics/java/android/renderscript/Vector2f.java +++ b/graphics/java/android/renderscript/Int2.java @@ -21,15 +21,15 @@ import android.util.Log; /** - * @hide + * Class for exposing the native Renderscript int2 type back to the Android system. * **/ -public class Vector2f { - public Vector2f() { +public class Int2 { + public Int2() { } - public float x; - public float y; + public int x; + public int y; } diff --git a/graphics/java/android/renderscript/Int3.java b/graphics/java/android/renderscript/Int3.java new file mode 100644 index 0000000..e5c1cdf --- /dev/null +++ b/graphics/java/android/renderscript/Int3.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript int3 type back to the Android system. + * + **/ +public class Int3 { + public Int3() { + } + + public int x; + public int y; + public int z; +} + + + + diff --git a/graphics/java/android/renderscript/Int4.java b/graphics/java/android/renderscript/Int4.java new file mode 100644 index 0000000..5289a89 --- /dev/null +++ b/graphics/java/android/renderscript/Int4.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript int4 type back to the Android system. + * + **/ +public class Int4 { + public Int4() { + } + + public int x; + public int y; + public int z; + public int w; +} + + + diff --git a/graphics/java/android/renderscript/Light.java b/graphics/java/android/renderscript/Light.java deleted file mode 100644 index aab656f..0000000 --- a/graphics/java/android/renderscript/Light.java +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.renderscript; - -import android.util.Config; -import android.util.Log; - -/** - * @hide - * - **/ -public class Light extends BaseObj { - Light(int id, RenderScript rs) { - super(rs); - mID = id; - } - - public void setColor(float r, float g, float b) { - mRS.validate(); - mRS.nLightSetColor(mID, r, g, b); - } - - public void setPosition(float x, float y, float z) { - mRS.validate(); - mRS.nLightSetPosition(mID, x, y, z); - } - - public static class Builder { - RenderScript mRS; - boolean mIsMono; - boolean mIsLocal; - - public Builder(RenderScript rs) { - mRS = rs; - mIsMono = false; - mIsLocal = false; - } - - public void lightSetIsMono(boolean isMono) { - mIsMono = isMono; - } - - public void lightSetIsLocal(boolean isLocal) { - mIsLocal = isLocal; - } - - static synchronized Light internalCreate(RenderScript rs, Builder b) { - rs.nSamplerBegin(); - rs.nLightSetIsMono(b.mIsMono); - rs.nLightSetIsLocal(b.mIsLocal); - int id = rs.nLightCreate(); - return new Light(id, rs); - } - - public Light create() { - mRS.validate(); - return internalCreate(mRS, this); - } - } - -} - diff --git a/graphics/java/android/renderscript/Vector4f.java b/graphics/java/android/renderscript/Long2.java index fabd959..8590b96 100644 --- a/graphics/java/android/renderscript/Vector4f.java +++ b/graphics/java/android/renderscript/Long2.java @@ -21,18 +21,16 @@ import android.util.Log; /** - * @hide - * + * Class for exposing the native Renderscript long2 type back to the Android system. **/ -public class Vector4f { - public Vector4f() { +public class Long2 { + public Long2() { } - public float x; - public float y; - public float z; - public float w; + public long x; + public long y; } + diff --git a/graphics/java/android/renderscript/Long3.java b/graphics/java/android/renderscript/Long3.java new file mode 100644 index 0000000..6ae837a --- /dev/null +++ b/graphics/java/android/renderscript/Long3.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript long3 type back to the Android system. + **/ +public class Long3 { + public Long3() { + } + + public long x; + public long y; + public long z; +} + + + + diff --git a/graphics/java/android/renderscript/Long4.java b/graphics/java/android/renderscript/Long4.java new file mode 100644 index 0000000..04c12f2 --- /dev/null +++ b/graphics/java/android/renderscript/Long4.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript long4 type back to the Android system. + **/ +public class Long4 { + public Long4() { + } + + public long x; + public long y; + public long z; + public long w; +} + + + diff --git a/graphics/java/android/renderscript/Matrix2f.java b/graphics/java/android/renderscript/Matrix2f.java index 4b5e61b..acc5bd8 100644 --- a/graphics/java/android/renderscript/Matrix2f.java +++ b/graphics/java/android/renderscript/Matrix2f.java @@ -21,24 +21,66 @@ import android.util.Log; /** - * @hide + * Class for exposing the native Renderscript rs_matrix2x2 type back to the Android system. * **/ public class Matrix2f { + /** + * Creates a new identity 2x2 matrix + */ public Matrix2f() { mMat = new float[4]; loadIdentity(); } + /** + * Creates a new matrix and sets its values from the given + * parameter + * + * @param dataArray values to set the matrix to, must be 4 + * floats long + */ + public Matrix2f(float[] dataArray) { + mMat = new float[4]; + System.arraycopy(dataArray, 0, mMat, 0, mMat.length); + } + + /** + * Return a reference to the internal array representing matrix + * values. Modifying this array will also change the matrix + * + * @return internal array representing the matrix + */ + public float[] getArray() { + return mMat; + } + + /** + * Returns the value for a given row and column + * + * @param i row of the value to return + * @param j column of the value to return + * + * @return value in the ith row and jth column + */ public float get(int i, int j) { return mMat[i*2 + j]; } + /** + * Sets the value for a given row and column + * + * @param i row of the value to set + * @param j column of the value to set + */ public void set(int i, int j, float v) { mMat[i*2 + j] = v; } + /** + * Sets the matrix values to identity + */ public void loadIdentity() { mMat[0] = 1; mMat[1] = 0; @@ -47,8 +89,104 @@ public class Matrix2f { mMat[3] = 1; } + /** + * Sets the values of the matrix to those of the parameter + * + * @param src matrix to load the values from + */ public void load(Matrix2f src) { - System.arraycopy(mMat, 0, src, 0, 4); + System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length); + } + + /** + * Sets current values to be a rotation matrix of given angle + * + * @param rot rotation angle + */ + public void loadRotate(float rot) { + float c, s; + rot *= (float)(java.lang.Math.PI / 180.0f); + c = (float)java.lang.Math.cos(rot); + s = (float)java.lang.Math.sin(rot); + mMat[0] = c; + mMat[1] = -s; + mMat[2] = s; + mMat[3] = c; + } + + /** + * Sets current values to be a scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + */ + public void loadScale(float x, float y) { + loadIdentity(); + mMat[0] = x; + mMat[3] = y; + } + + /** + * Sets current values to be the result of multiplying two given + * matrices + * + * @param lhs left hand side matrix + * @param rhs right hand side matrix + */ + public void loadMultiply(Matrix2f lhs, Matrix2f rhs) { + for (int i=0 ; i<2 ; i++) { + float ri0 = 0; + float ri1 = 0; + for (int j=0 ; j<2 ; j++) { + float rhs_ij = rhs.get(i,j); + ri0 += lhs.get(j,0) * rhs_ij; + ri1 += lhs.get(j,1) * rhs_ij; + } + set(i,0, ri0); + set(i,1, ri1); + } + } + + /** + * Post-multiplies the current matrix by a given parameter + * + * @param rhs right hand side to multiply by + */ + public void multiply(Matrix2f rhs) { + Matrix2f tmp = new Matrix2f(); + tmp.loadMultiply(this, rhs); + load(tmp); + } + /** + * Modifies the current matrix by post-multiplying it with a + * rotation matrix of given angle + * + * @param rot angle of rotation + */ + public void rotate(float rot) { + Matrix2f tmp = new Matrix2f(); + tmp.loadRotate(rot); + multiply(tmp); + } + /** + * Modifies the current matrix by post-multiplying it with a + * scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + */ + public void scale(float x, float y) { + Matrix2f tmp = new Matrix2f(); + tmp.loadScale(x, y); + multiply(tmp); + } + /** + * Sets the current matrix to its transpose + */ + public void transpose() { + float temp = mMat[1]; + mMat[1] = mMat[2]; + mMat[2] = temp; } final float[] mMat; diff --git a/graphics/java/android/renderscript/Matrix3f.java b/graphics/java/android/renderscript/Matrix3f.java index 19d7b43..253506d 100644 --- a/graphics/java/android/renderscript/Matrix3f.java +++ b/graphics/java/android/renderscript/Matrix3f.java @@ -21,24 +21,66 @@ import android.util.Log; /** - * @hide + * Class for exposing the native Renderscript rs_matrix3x3 type back to the Android system. * **/ public class Matrix3f { + /** + * Creates a new identity 3x3 matrix + */ public Matrix3f() { mMat = new float[9]; loadIdentity(); } + /** + * Creates a new matrix and sets its values from the given + * parameter + * + * @param dataArray values to set the matrix to, must be 9 + * floats long + */ + public Matrix3f(float[] dataArray) { + mMat = new float[9]; + System.arraycopy(dataArray, 0, mMat, 0, mMat.length); + } + + /** + * Return a reference to the internal array representing matrix + * values. Modifying this array will also change the matrix + * + * @return internal array representing the matrix + */ + public float[] getArray() { + return mMat; + } + + /** + * Returns the value for a given row and column + * + * @param i row of the value to return + * @param j column of the value to return + * + * @return value in the ith row and jth column + */ public float get(int i, int j) { return mMat[i*3 + j]; } + /** + * Sets the value for a given row and column + * + * @param i row of the value to set + * @param j column of the value to set + */ public void set(int i, int j, float v) { mMat[i*3 + j] = v; } + /** + * Sets the matrix values to identity + */ public void loadIdentity() { mMat[0] = 1; mMat[1] = 0; @@ -53,8 +95,224 @@ public class Matrix3f { mMat[8] = 1; } + /** + * Sets the values of the matrix to those of the parameter + * + * @param src matrix to load the values from + */ public void load(Matrix3f src) { - System.arraycopy(mMat, 0, src, 0, 9); + System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length); + } + + /** + * Sets current values to be a rotation matrix of certain angle + * about a given axis + * + * @param rot angle of rotation + * @param x rotation axis x + * @param y rotation axis y + * @param z rotation axis z + */ + public void loadRotate(float rot, float x, float y, float z) { + float c, s; + rot *= (float)(java.lang.Math.PI / 180.0f); + c = (float)java.lang.Math.cos(rot); + s = (float)java.lang.Math.sin(rot); + + float len = (float)java.lang.Math.sqrt(x*x + y*y + z*z); + if (!(len != 1)) { + float recipLen = 1.f / len; + x *= recipLen; + y *= recipLen; + z *= recipLen; + } + float nc = 1.0f - c; + float xy = x * y; + float yz = y * z; + float zx = z * x; + float xs = x * s; + float ys = y * s; + float zs = z * s; + mMat[0] = x*x*nc + c; + mMat[3] = xy*nc - zs; + mMat[6] = zx*nc + ys; + mMat[1] = xy*nc + zs; + mMat[4] = y*y*nc + c; + mMat[9] = yz*nc - xs; + mMat[2] = zx*nc - ys; + mMat[6] = yz*nc + xs; + mMat[8] = z*z*nc + c; + } + + /** + * Makes the upper 2x2 a rotation matrix of the given angle + * + * @param rot rotation angle + */ + public void loadRotate(float rot) { + loadIdentity(); + float c, s; + rot *= (float)(java.lang.Math.PI / 180.0f); + c = (float)java.lang.Math.cos(rot); + s = (float)java.lang.Math.sin(rot); + mMat[0] = c; + mMat[1] = -s; + mMat[3] = s; + mMat[4] = c; + } + + /** + * Makes the upper 2x2 a scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + */ + public void loadScale(float x, float y) { + loadIdentity(); + mMat[0] = x; + mMat[4] = y; + } + + /** + * Sets current values to be a scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + * @param z scale component z + */ + public void loadScale(float x, float y, float z) { + loadIdentity(); + mMat[0] = x; + mMat[4] = y; + mMat[8] = z; + } + + /** + * Sets current values to be a translation matrix of given + * dimensions + * + * @param x translation component x + * @param y translation component y + */ + public void loadTranslate(float x, float y) { + loadIdentity(); + mMat[6] = x; + mMat[7] = y; + } + + /** + * Sets current values to be the result of multiplying two given + * matrices + * + * @param lhs left hand side matrix + * @param rhs right hand side matrix + */ + public void loadMultiply(Matrix3f lhs, Matrix3f rhs) { + for (int i=0 ; i<3 ; i++) { + float ri0 = 0; + float ri1 = 0; + float ri2 = 0; + for (int j=0 ; j<3 ; j++) { + float rhs_ij = rhs.get(i,j); + ri0 += lhs.get(j,0) * rhs_ij; + ri1 += lhs.get(j,1) * rhs_ij; + ri2 += lhs.get(j,2) * rhs_ij; + } + set(i,0, ri0); + set(i,1, ri1); + set(i,2, ri2); + } + } + + /** + * Post-multiplies the current matrix by a given parameter + * + * @param rhs right hand side to multiply by + */ + public void multiply(Matrix3f rhs) { + Matrix3f tmp = new Matrix3f(); + tmp.loadMultiply(this, rhs); + load(tmp); + } + + /** + * Modifies the current matrix by post-multiplying it with a + * rotation matrix of certain angle about a given axis + * + * @param rot angle of rotation + * @param x rotation axis x + * @param y rotation axis y + * @param z rotation axis z + */ + public void rotate(float rot, float x, float y, float z) { + Matrix3f tmp = new Matrix3f(); + tmp.loadRotate(rot, x, y, z); + multiply(tmp); + } + + /** + * Modifies the upper 2x2 of the current matrix by + * post-multiplying it with a rotation matrix of given angle + * + * @param rot angle of rotation + */ + public void rotate(float rot) { + Matrix3f tmp = new Matrix3f(); + tmp.loadRotate(rot); + multiply(tmp); + } + + /** + * Modifies the upper 2x2 of the current matrix by + * post-multiplying it with a scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + */ + public void scale(float x, float y) { + Matrix3f tmp = new Matrix3f(); + tmp.loadScale(x, y); + multiply(tmp); + } + + /** + * Modifies the current matrix by post-multiplying it with a + * scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + * @param z scale component z + */ + public void scale(float x, float y, float z) { + Matrix3f tmp = new Matrix3f(); + tmp.loadScale(x, y, z); + multiply(tmp); + } + + /** + * Modifies the current matrix by post-multiplying it with a + * translation matrix of given dimensions + * + * @param x translation component x + * @param y translation component y + */ + public void translate(float x, float y) { + Matrix3f tmp = new Matrix3f(); + tmp.loadTranslate(x, y); + multiply(tmp); + } + + /** + * Sets the current matrix to its transpose + */ + public void transpose() { + for(int i = 0; i < 2; ++i) { + for(int j = i + 1; j < 3; ++j) { + float temp = mMat[i*3 + j]; + mMat[i*3 + j] = mMat[j*3 + i]; + mMat[j*3 + i] = temp; + } + } } final float[] mMat; diff --git a/graphics/java/android/renderscript/Matrix4f.java b/graphics/java/android/renderscript/Matrix4f.java index ebd5bde..adc1806 100644 --- a/graphics/java/android/renderscript/Matrix4f.java +++ b/graphics/java/android/renderscript/Matrix4f.java @@ -21,24 +21,66 @@ import android.util.Log; /** - * @hide + * Class for exposing the native Renderscript rs_matrix4x4 type back to the Android system. * **/ public class Matrix4f { + /** + * Creates a new identity 4x4 matrix + */ public Matrix4f() { mMat = new float[16]; loadIdentity(); } + /** + * Creates a new matrix and sets its values from the given + * parameter + * + * @param dataArray values to set the matrix to, must be 16 + * floats long + */ + public Matrix4f(float[] dataArray) { + mMat = new float[16]; + System.arraycopy(dataArray, 0, mMat, 0, mMat.length); + } + + /** + * Return a reference to the internal array representing matrix + * values. Modifying this array will also change the matrix + * + * @return internal array representing the matrix + */ + public float[] getArray() { + return mMat; + } + + /** + * Returns the value for a given row and column + * + * @param i row of the value to return + * @param j column of the value to return + * + * @return value in the ith row and jth column + */ public float get(int i, int j) { return mMat[i*4 + j]; } + /** + * Sets the value for a given row and column + * + * @param i row of the value to set + * @param j column of the value to set + */ public void set(int i, int j, float v) { mMat[i*4 + j] = v; } + /** + * Sets the matrix values to identity + */ public void loadIdentity() { mMat[0] = 1; mMat[1] = 0; @@ -61,10 +103,24 @@ public class Matrix4f { mMat[15] = 1; } + /** + * Sets the values of the matrix to those of the parameter + * + * @param src matrix to load the values from + */ public void load(Matrix4f src) { - System.arraycopy(mMat, 0, src, 0, 16); + System.arraycopy(src.getArray(), 0, mMat, 0, mMat.length); } + /** + * Sets current values to be a rotation matrix of certain angle + * about a given axis + * + * @param rot angle of rotation + * @param x rotation axis x + * @param y rotation axis y + * @param z rotation axis z + */ public void loadRotate(float rot, float x, float y, float z) { float c, s; mMat[3] = 0; @@ -103,6 +159,13 @@ public class Matrix4f { mMat[10] = z*z*nc + c; } + /** + * Sets current values to be a scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + * @param z scale component z + */ public void loadScale(float x, float y, float z) { loadIdentity(); mMat[0] = x; @@ -110,6 +173,14 @@ public class Matrix4f { mMat[10] = z; } + /** + * Sets current values to be a translation matrix of given + * dimensions + * + * @param x translation component x + * @param y translation component y + * @param z translation component z + */ public void loadTranslate(float x, float y, float z) { loadIdentity(); mMat[12] = x; @@ -117,6 +188,13 @@ public class Matrix4f { mMat[14] = z; } + /** + * Sets current values to be the result of multiplying two given + * matrices + * + * @param lhs left hand side matrix + * @param rhs right hand side matrix + */ public void loadMultiply(Matrix4f lhs, Matrix4f rhs) { for (int i=0 ; i<4 ; i++) { float ri0 = 0; @@ -137,6 +215,16 @@ public class Matrix4f { } } + /** + * Set current values to be an orthographic projection matrix + * + * @param l location of the left vertical clipping plane + * @param r location of the right vertical clipping plane + * @param b location of the bottom horizontal clipping plane + * @param t location of the top horizontal clipping plane + * @param n location of the near clipping plane + * @param f location of the far clipping plane + */ public void loadOrtho(float l, float r, float b, float t, float n, float f) { loadIdentity(); mMat[0] = 2 / (r - l); @@ -147,6 +235,31 @@ public class Matrix4f { mMat[14]= -(f + n) / (f - n); } + /** + * Set current values to be an orthographic projection matrix + * with the right and bottom clipping planes set to the given + * values. Left and top clipping planes are set to 0. Near and + * far are set to -1, 1 respectively + * + * @param w location of the right vertical clipping plane + * @param h location of the bottom horizontal clipping plane + * + */ + public void loadOrthoWindow(int w, int h) { + loadOrtho(0,w, h,0, -1,1); + } + + /** + * Sets current values to be a perspective projection matrix + * + * @param l location of the left vertical clipping plane + * @param r location of the right vertical clipping plane + * @param b location of the bottom horizontal clipping plane + * @param t location of the top horizontal clipping plane + * @param n location of the near clipping plane, must be positive + * @param f location of the far clipping plane, must be positive + * + */ public void loadFrustum(float l, float r, float b, float t, float n, float f) { loadIdentity(); mMat[0] = 2 * n / (r - l); @@ -159,31 +272,195 @@ public class Matrix4f { mMat[15]= 0; } + /** + * Sets current values to be a perspective projection matrix + * + * @param fovy vertical field of view angle in degrees + * @param aspect aspect ratio of the screen + * @param near near cliping plane, must be positive + * @param far far clipping plane, must be positive + */ + public void loadPerspective(float fovy, float aspect, float near, float far) { + float top = near * (float)Math.tan((float) (fovy * Math.PI / 360.0f)); + float bottom = -top; + float left = bottom * aspect; + float right = top * aspect; + loadFrustum(left, right, bottom, top, near, far); + } + + /** + * Helper function to set the current values to a perspective + * projection matrix with aspect ratio defined by the parameters + * and (near, far), (bottom, top) mapping to (-1, 1) at z = 0 + * + * @param w screen width + * @param h screen height + */ + public void loadProjectionNormalized(int w, int h) { + // range -1,1 in the narrow axis at z = 0. + Matrix4f m1 = new Matrix4f(); + Matrix4f m2 = new Matrix4f(); + + if(w > h) { + float aspect = ((float)w) / h; + m1.loadFrustum(-aspect,aspect, -1,1, 1,100); + } else { + float aspect = ((float)h) / w; + m1.loadFrustum(-1,1, -aspect,aspect, 1,100); + } + + m2.loadRotate(180, 0, 1, 0); + m1.loadMultiply(m1, m2); + + m2.loadScale(-2, 2, 1); + m1.loadMultiply(m1, m2); + + m2.loadTranslate(0, 0, 2); + m1.loadMultiply(m1, m2); + + load(m1); + } + + /** + * Post-multiplies the current matrix by a given parameter + * + * @param rhs right hand side to multiply by + */ public void multiply(Matrix4f rhs) { Matrix4f tmp = new Matrix4f(); tmp.loadMultiply(this, rhs); load(tmp); } + /** + * Modifies the current matrix by post-multiplying it with a + * rotation matrix of certain angle about a given axis + * + * @param rot angle of rotation + * @param x rotation axis x + * @param y rotation axis y + * @param z rotation axis z + */ public void rotate(float rot, float x, float y, float z) { Matrix4f tmp = new Matrix4f(); tmp.loadRotate(rot, x, y, z); multiply(tmp); } + + /** + * Modifies the current matrix by post-multiplying it with a + * scale matrix of given dimensions + * + * @param x scale component x + * @param y scale component y + * @param z scale component z + */ public void scale(float x, float y, float z) { Matrix4f tmp = new Matrix4f(); tmp.loadScale(x, y, z); multiply(tmp); } + + /** + * Modifies the current matrix by post-multiplying it with a + * translation matrix of given dimensions + * + * @param x translation component x + * @param y translation component y + * @param z translation component z + */ public void translate(float x, float y, float z) { Matrix4f tmp = new Matrix4f(); tmp.loadTranslate(x, y, z); multiply(tmp); } + private float computeCofactor(int i, int j) { + int c0 = (i+1) % 4; + int c1 = (i+2) % 4; + int c2 = (i+3) % 4; + int r0 = (j+1) % 4; + int r1 = (j+2) % 4; + int r2 = (j+3) % 4; - final float[] mMat; -} + float minor = (mMat[c0 + 4*r0] * (mMat[c1 + 4*r1] * mMat[c2 + 4*r2] - + mMat[c1 + 4*r2] * mMat[c2 + 4*r1])) + - (mMat[c0 + 4*r1] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r2] - + mMat[c1 + 4*r2] * mMat[c2 + 4*r0])) + + (mMat[c0 + 4*r2] * (mMat[c1 + 4*r0] * mMat[c2 + 4*r1] - + mMat[c1 + 4*r1] * mMat[c2 + 4*r0])); + + float cofactor = ((i+j) & 1) != 0 ? -minor : minor; + return cofactor; + } + /** + * Sets the current matrix to its inverse + */ + public boolean inverse() { + Matrix4f result = new Matrix4f(); + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + result.mMat[4*i + j] = computeCofactor(i, j); + } + } + // Dot product of 0th column of source and 0th row of result + float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[1] + + mMat[8]*result.mMat[2] + mMat[12]*result.mMat[3]; + if (Math.abs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (int i = 0; i < 16; ++i) { + mMat[i] = result.mMat[i] * det; + } + + return true; + } + + /** + * Sets the current matrix to its inverse transpose + */ + public boolean inverseTranspose() { + + Matrix4f result = new Matrix4f(); + + for (int i = 0; i < 4; ++i) { + for (int j = 0; j < 4; ++j) { + result.mMat[4*j + i] = computeCofactor(i, j); + } + } + + float det = mMat[0]*result.mMat[0] + mMat[4]*result.mMat[4] + + mMat[8]*result.mMat[8] + mMat[12]*result.mMat[12]; + + if (Math.abs(det) < 1e-6) { + return false; + } + + det = 1.0f / det; + for (int i = 0; i < 16; ++i) { + mMat[i] = result.mMat[i] * det; + } + + return true; + } + + /** + * Sets the current matrix to its transpose + */ + public void transpose() { + for(int i = 0; i < 3; ++i) { + for(int j = i + 1; j < 4; ++j) { + float temp = mMat[i*4 + j]; + mMat[i*4 + j] = mMat[j*4 + i]; + mMat[j*4 + i] = temp; + } + } + } + + final float[] mMat; +} diff --git a/graphics/java/android/renderscript/Mesh.java b/graphics/java/android/renderscript/Mesh.java new file mode 100644 index 0000000..bb910cc --- /dev/null +++ b/graphics/java/android/renderscript/Mesh.java @@ -0,0 +1,772 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.util.Vector; + +import android.util.Config; +import android.util.Log; + +/** + * <p>This class is a container for geometric data displayed with + * Renderscript. Internally, a mesh is a collection of allocations that + * represent vertex data (positions, normals, texture + * coordinates) and index data such as triangles and lines. </p> + * <p> + * Vertex data could either be interleaved within one + * allocation that is provided separately, as multiple allocation + * objects, or done as a combination of both. When a + * vertex channel name matches an input in the vertex program, + * Renderscript automatically connects the two together. + * </p> + * <p> + * Parts of the mesh can be rendered with either explicit + * index sets or primitive types. + * </p> + **/ +public class Mesh extends BaseObj { + + /** + * Describes the way mesh vertex data is interpreted when rendering + * + **/ + public enum Primitive { + /** + * Vertex data will be rendered as a series of points + */ + POINT (0), + /** + * Vertex pairs will be rendered as lines + */ + LINE (1), + /** + * Vertex data will be rendered as a connected line strip + */ + LINE_STRIP (2), + /** + * Vertices will be rendered as individual triangles + */ + TRIANGLE (3), + /** + * Vertices will be rendered as a connected triangle strip + * defined by the first three vertices with each additional + * triangle defined by a new vertex + */ + TRIANGLE_STRIP (4), + /** + * Vertices will be rendered as a sequence of triangles that all + * share first vertex as the origin + */ + TRIANGLE_FAN (5); + + int mID; + Primitive(int id) { + mID = id; + } + } + + Allocation[] mVertexBuffers; + Allocation[] mIndexBuffers; + Primitive[] mPrimitives; + + Mesh(int id, RenderScript rs) { + super(id, rs); + } + + /** + * @return number of allocations containing vertex data + * + **/ + public int getVertexAllocationCount() { + if(mVertexBuffers == null) { + return 0; + } + return mVertexBuffers.length; + } + /** + * @param slot index in the list of allocations to return + * @return vertex data allocation at the given index + * + **/ + public Allocation getVertexAllocation(int slot) { + return mVertexBuffers[slot]; + } + + /** + * @return number of primitives or index sets in the mesh + * + **/ + public int getPrimitiveCount() { + if(mIndexBuffers == null) { + return 0; + } + return mIndexBuffers.length; + } + + /** + * @param slot locaton within the list of index set allocation + * @return allocation containing primtive index data or null if + * the index data is not specified explicitly + * + **/ + public Allocation getIndexSetAllocation(int slot) { + return mIndexBuffers[slot]; + } + /** + * @param slot locaiton within the list of index set primitives + * @return index set primitive type + * + **/ + public Primitive getPrimitive(int slot) { + return mPrimitives[slot]; + } + + @Override + void updateFromNative() { + super.updateFromNative(); + int vtxCount = mRS.nMeshGetVertexBufferCount(getID()); + int idxCount = mRS.nMeshGetIndexCount(getID()); + + int[] vtxIDs = new int[vtxCount]; + int[] idxIDs = new int[idxCount]; + int[] primitives = new int[idxCount]; + + mRS.nMeshGetVertices(getID(), vtxIDs, vtxCount); + mRS.nMeshGetIndices(getID(), idxIDs, primitives, idxCount); + + mVertexBuffers = new Allocation[vtxCount]; + mIndexBuffers = new Allocation[idxCount]; + mPrimitives = new Primitive[idxCount]; + + for(int i = 0; i < vtxCount; i ++) { + if(vtxIDs[i] != 0) { + mVertexBuffers[i] = new Allocation(vtxIDs[i], mRS, null, Allocation.USAGE_SCRIPT); + mVertexBuffers[i].updateFromNative(); + } + } + + for(int i = 0; i < idxCount; i ++) { + if(idxIDs[i] != 0) { + mIndexBuffers[i] = new Allocation(idxIDs[i], mRS, null, Allocation.USAGE_SCRIPT); + mIndexBuffers[i].updateFromNative(); + } + mPrimitives[i] = Primitive.values()[primitives[i]]; + } + } + + /** + * Mesh builder object. It starts empty and requires you to + * add the types necessary to create vertex and index + * allocations. + * + */ + public static class Builder { + RenderScript mRS; + int mUsage; + + class Entry { + Type t; + Element e; + int size; + Primitive prim; + int usage; + } + + int mVertexTypeCount; + Entry[] mVertexTypes; + Vector mIndexTypes; + + /** + * Creates builder object + * @param rs Context to which the mesh will belong. + * @param usage specifies how the mesh allocations are to be + * handled, whether they need to be uploaded to a + * buffer on the gpu, maintain a cpu copy, etc + */ + public Builder(RenderScript rs, int usage) { + mRS = rs; + mUsage = usage; + mVertexTypeCount = 0; + mVertexTypes = new Entry[16]; + mIndexTypes = new Vector(); + } + + /** + * @return internal index of the last vertex buffer type added to + * builder + **/ + public int getCurrentVertexTypeIndex() { + return mVertexTypeCount - 1; + } + + /** + * @return internal index of the last index set added to the + * builder + **/ + public int getCurrentIndexSetIndex() { + return mIndexTypes.size() - 1; + } + + /** + * Adds a vertex data type to the builder object + * + * @param t type of the vertex data allocation to be created + * + * @return this + **/ + public Builder addVertexType(Type t) throws IllegalStateException { + if (mVertexTypeCount >= mVertexTypes.length) { + throw new IllegalStateException("Max vertex types exceeded."); + } + + mVertexTypes[mVertexTypeCount] = new Entry(); + mVertexTypes[mVertexTypeCount].t = t; + mVertexTypes[mVertexTypeCount].e = null; + mVertexTypeCount++; + return this; + } + + /** + * Adds a vertex data type to the builder object + * + * @param e element describing the vertex data layout + * @param size number of elements in the buffer + * + * @return this + **/ + public Builder addVertexType(Element e, int size) throws IllegalStateException { + if (mVertexTypeCount >= mVertexTypes.length) { + throw new IllegalStateException("Max vertex types exceeded."); + } + + mVertexTypes[mVertexTypeCount] = new Entry(); + mVertexTypes[mVertexTypeCount].t = null; + mVertexTypes[mVertexTypeCount].e = e; + mVertexTypes[mVertexTypeCount].size = size; + mVertexTypeCount++; + return this; + } + + /** + * Adds an index set data type to the builder object + * + * @param t type of the index set data, could be null + * @param p primitive type + * + * @return this + **/ + public Builder addIndexSetType(Type t, Primitive p) { + Entry indexType = new Entry(); + indexType.t = t; + indexType.e = null; + indexType.size = 0; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return this; + } + + /** + * Adds an index set primitive type to the builder object + * + * @param p primitive type + * + * @return this + **/ + public Builder addIndexSetType(Primitive p) { + Entry indexType = new Entry(); + indexType.t = null; + indexType.e = null; + indexType.size = 0; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return this; + } + + /** + * Adds an index set data type to the builder object + * + * @param e element describing the index set data layout + * @param size number of elements in the buffer + * @param p primitive type + * + * @return this + **/ + public Builder addIndexSetType(Element e, int size, Primitive p) { + Entry indexType = new Entry(); + indexType.t = null; + indexType.e = e; + indexType.size = size; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return this; + } + + Type newType(Element e, int size) { + Type.Builder tb = new Type.Builder(mRS, e); + tb.setX(size); + return tb.create(); + } + + static synchronized Mesh internalCreate(RenderScript rs, Builder b) { + + int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size()); + Mesh newMesh = new Mesh(id, rs); + newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()]; + newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()]; + newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount]; + + for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) { + Allocation alloc = null; + Entry entry = (Entry)b.mIndexTypes.elementAt(ct); + if (entry.t != null) { + alloc = Allocation.createTyped(rs, entry.t, b.mUsage); + } + else if(entry.e != null) { + alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage); + } + int allocID = (alloc == null) ? 0 : alloc.getID(); + rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct); + newMesh.mIndexBuffers[ct] = alloc; + newMesh.mPrimitives[ct] = entry.prim; + } + + for(int ct = 0; ct < b.mVertexTypeCount; ct ++) { + Allocation alloc = null; + Entry entry = b.mVertexTypes[ct]; + if (entry.t != null) { + alloc = Allocation.createTyped(rs, entry.t, b.mUsage); + } else if(entry.e != null) { + alloc = Allocation.createSized(rs, entry.e, entry.size, b.mUsage); + } + rs.nMeshBindVertex(id, alloc.getID(), ct); + newMesh.mVertexBuffers[ct] = alloc; + } + rs.nMeshInitVertexAttribs(id); + + return newMesh; + } + + /** + * Create a Mesh object from the current state of the builder + * + **/ + public Mesh create() { + mRS.validate(); + Mesh sm = internalCreate(mRS, this); + return sm; + } + } + + /** + * Mesh builder object. It starts empty and requires the user to + * add all the vertex and index allocations that comprise the + * mesh + * + */ + public static class AllocationBuilder { + RenderScript mRS; + + class Entry { + Allocation a; + Primitive prim; + } + + int mVertexTypeCount; + Entry[] mVertexTypes; + + Vector mIndexTypes; + + public AllocationBuilder(RenderScript rs) { + mRS = rs; + mVertexTypeCount = 0; + mVertexTypes = new Entry[16]; + mIndexTypes = new Vector(); + } + + /** + * @return internal index of the last vertex buffer type added to + * builder + **/ + public int getCurrentVertexTypeIndex() { + return mVertexTypeCount - 1; + } + + /** + * @return internal index of the last index set added to the + * builder + **/ + public int getCurrentIndexSetIndex() { + return mIndexTypes.size() - 1; + } + + /** + * Adds an allocation containing vertex buffer data to the + * builder + * + * @param a vertex data allocation + * + * @return this + **/ + public AllocationBuilder addVertexAllocation(Allocation a) throws IllegalStateException { + if (mVertexTypeCount >= mVertexTypes.length) { + throw new IllegalStateException("Max vertex types exceeded."); + } + + mVertexTypes[mVertexTypeCount] = new Entry(); + mVertexTypes[mVertexTypeCount].a = a; + mVertexTypeCount++; + return this; + } + + /** + * Adds an allocation containing index buffer data and index type + * to the builder + * + * @param a index set data allocation, could be null + * @param p index set primitive type + * + * @return this + **/ + public AllocationBuilder addIndexSetAllocation(Allocation a, Primitive p) { + Entry indexType = new Entry(); + indexType.a = a; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return this; + } + + /** + * Adds an index set type to the builder + * + * @param p index set primitive type + * + * @return this + **/ + public AllocationBuilder addIndexSetType(Primitive p) { + Entry indexType = new Entry(); + indexType.a = null; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return this; + } + + static synchronized Mesh internalCreate(RenderScript rs, AllocationBuilder b) { + + int id = rs.nMeshCreate(b.mVertexTypeCount, b.mIndexTypes.size()); + Mesh newMesh = new Mesh(id, rs); + newMesh.mIndexBuffers = new Allocation[b.mIndexTypes.size()]; + newMesh.mPrimitives = new Primitive[b.mIndexTypes.size()]; + newMesh.mVertexBuffers = new Allocation[b.mVertexTypeCount]; + + for(int ct = 0; ct < b.mIndexTypes.size(); ct ++) { + Entry entry = (Entry)b.mIndexTypes.elementAt(ct); + int allocID = (entry.a == null) ? 0 : entry.a.getID(); + rs.nMeshBindIndex(id, allocID, entry.prim.mID, ct); + newMesh.mIndexBuffers[ct] = entry.a; + newMesh.mPrimitives[ct] = entry.prim; + } + + for(int ct = 0; ct < b.mVertexTypeCount; ct ++) { + Entry entry = b.mVertexTypes[ct]; + rs.nMeshBindVertex(id, entry.a.getID(), ct); + newMesh.mVertexBuffers[ct] = entry.a; + } + rs.nMeshInitVertexAttribs(id); + + return newMesh; + } + + /** + * Create a Mesh object from the current state of the builder + * + **/ + public Mesh create() { + mRS.validate(); + Mesh sm = internalCreate(mRS, this); + return sm; + } + } + + /** + * Builder that allows creation of a mesh object point by point + * and triangle by triangle + * + **/ + public static class TriangleMeshBuilder { + float mVtxData[]; + int mVtxCount; + short mIndexData[]; + int mIndexCount; + RenderScript mRS; + Element mElement; + + float mNX = 0; + float mNY = 0; + float mNZ = -1; + float mS0 = 0; + float mT0 = 0; + float mR = 1; + float mG = 1; + float mB = 1; + float mA = 1; + + int mVtxSize; + int mFlags; + + public static final int COLOR = 0x0001; + public static final int NORMAL = 0x0002; + public static final int TEXTURE_0 = 0x0100; + + /** + * @param rs Context to which the mesh will belong. + * @param vtxSize specifies whether the vertex is a float2 or + * float3 + * @param flags bitfield that is a combination of COLOR, NORMAL, + * and TEXTURE_0 that specifies what vertex data + * channels are present in the mesh + * + **/ + public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) { + mRS = rs; + mVtxCount = 0; + mIndexCount = 0; + mVtxData = new float[128]; + mIndexData = new short[128]; + mVtxSize = vtxSize; + mFlags = flags; + + if (vtxSize < 2 || vtxSize > 3) { + throw new IllegalArgumentException("Vertex size out of range."); + } + } + + private void makeSpace(int count) { + if ((mVtxCount + count) >= mVtxData.length) { + float t[] = new float[mVtxData.length * 2]; + System.arraycopy(mVtxData, 0, t, 0, mVtxData.length); + mVtxData = t; + } + } + + private void latch() { + if ((mFlags & COLOR) != 0) { + makeSpace(4); + mVtxData[mVtxCount++] = mR; + mVtxData[mVtxCount++] = mG; + mVtxData[mVtxCount++] = mB; + mVtxData[mVtxCount++] = mA; + } + if ((mFlags & TEXTURE_0) != 0) { + makeSpace(2); + mVtxData[mVtxCount++] = mS0; + mVtxData[mVtxCount++] = mT0; + } + if ((mFlags & NORMAL) != 0) { + makeSpace(3); + mVtxData[mVtxCount++] = mNX; + mVtxData[mVtxCount++] = mNY; + mVtxData[mVtxCount++] = mNZ; + } + } + + /** + * Adds a float2 vertex to the mesh + * + * @param x position x + * @param y position y + * + * @return this + * + **/ + public TriangleMeshBuilder addVertex(float x, float y) { + if (mVtxSize != 2) { + throw new IllegalStateException("add mistmatch with declared components."); + } + makeSpace(2); + mVtxData[mVtxCount++] = x; + mVtxData[mVtxCount++] = y; + latch(); + return this; + } + + /** + * Adds a float3 vertex to the mesh + * + * @param x position x + * @param y position y + * @param z position z + * + * @return this + * + **/ + public TriangleMeshBuilder addVertex(float x, float y, float z) { + if (mVtxSize != 3) { + throw new IllegalStateException("add mistmatch with declared components."); + } + makeSpace(3); + mVtxData[mVtxCount++] = x; + mVtxData[mVtxCount++] = y; + mVtxData[mVtxCount++] = z; + latch(); + return this; + } + + /** + * Sets the texture coordinate for the last added vertex + * + * @param s texture coordinate s + * @param t texture coordinate t + * + * @return this + **/ + public TriangleMeshBuilder setTexture(float s, float t) { + if ((mFlags & TEXTURE_0) == 0) { + throw new IllegalStateException("add mistmatch with declared components."); + } + mS0 = s; + mT0 = t; + return this; + } + + /** + * Sets the normal vector for the last added vertex + * + * @param x normal vector x + * @param y normal vector y + * @param z normal vector z + * + * @return this + **/ + public TriangleMeshBuilder setNormal(float x, float y, float z) { + if ((mFlags & NORMAL) == 0) { + throw new IllegalStateException("add mistmatch with declared components."); + } + mNX = x; + mNY = y; + mNZ = z; + return this; + } + + /** + * Sets the color for the last added vertex + * + * @param r red component + * @param g green component + * @param b blue component + * @param a alpha component + * + * @return this + **/ + public TriangleMeshBuilder setColor(float r, float g, float b, float a) { + if ((mFlags & COLOR) == 0) { + throw new IllegalStateException("add mistmatch with declared components."); + } + mR = r; + mG = g; + mB = b; + mA = a; + return this; + } + + /** + * Adds a new triangle to the mesh builder + * + * @param idx1 index of the first vertex in the triangle + * @param idx2 index of the second vertex in the triangle + * @param idx3 index of the third vertex in the triangle + * + * @return this + **/ + public TriangleMeshBuilder addTriangle(int idx1, int idx2, int idx3) { + if((idx1 >= mVtxCount) || (idx1 < 0) || + (idx2 >= mVtxCount) || (idx2 < 0) || + (idx3 >= mVtxCount) || (idx3 < 0)) { + throw new IllegalStateException("Index provided greater than vertex count."); + } + if ((mIndexCount + 3) >= mIndexData.length) { + short t[] = new short[mIndexData.length * 2]; + System.arraycopy(mIndexData, 0, t, 0, mIndexData.length); + mIndexData = t; + } + mIndexData[mIndexCount++] = (short)idx1; + mIndexData[mIndexCount++] = (short)idx2; + mIndexData[mIndexCount++] = (short)idx3; + return this; + } + + /** + * Creates the mesh object from the current state of the builder + * + * @param uploadToBufferObject specifies whether the vertex data + * is to be uploaded into the buffer + * object indicating that it's likely + * not going to be modified and + * rendered many times. + * Alternatively, it indicates the + * mesh data will be updated + * frequently and remain in script + * accessible memory + * + **/ + public Mesh create(boolean uploadToBufferObject) { + Element.Builder b = new Element.Builder(mRS); + int floatCount = mVtxSize; + b.add(Element.createVector(mRS, + Element.DataType.FLOAT_32, + mVtxSize), "position"); + if ((mFlags & COLOR) != 0) { + floatCount += 4; + b.add(Element.F32_4(mRS), "color"); + } + if ((mFlags & TEXTURE_0) != 0) { + floatCount += 2; + b.add(Element.F32_2(mRS), "texture0"); + } + if ((mFlags & NORMAL) != 0) { + floatCount += 3; + b.add(Element.F32_3(mRS), "normal"); + } + mElement = b.create(); + + int usage = Allocation.USAGE_SCRIPT; + if (uploadToBufferObject) { + usage |= Allocation.USAGE_GRAPHICS_VERTEX; + } + + Builder smb = new Builder(mRS, usage); + smb.addVertexType(mElement, mVtxCount / floatCount); + smb.addIndexSetType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE); + + Mesh sm = smb.create(); + + sm.getVertexAllocation(0).copy1DRangeFromUnchecked(0, mVtxCount / floatCount, mVtxData); + if(uploadToBufferObject) { + if (uploadToBufferObject) { + sm.getVertexAllocation(0).syncAll(Allocation.USAGE_SCRIPT); + } + } + + sm.getIndexSetAllocation(0).copy1DRangeFromUnchecked(0, mIndexCount, mIndexData); + if (uploadToBufferObject) { + sm.getIndexSetAllocation(0).syncAll(Allocation.USAGE_SCRIPT); + } + + return sm; + } + } +} + diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java index 1614ec5..323225f 100644 --- a/graphics/java/android/renderscript/Program.java +++ b/graphics/java/android/renderscript/Program.java @@ -17,53 +17,126 @@ package android.renderscript; +import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; + +import android.content.res.Resources; import android.util.Config; import android.util.Log; /** - * @hide + * + * Program is a base class for all the objects that modify + * various stages of the graphics pipeline * **/ public class Program extends BaseObj { - public static final int MAX_INPUT = 8; - public static final int MAX_OUTPUT = 8; - public static final int MAX_CONSTANT = 8; - public static final int MAX_TEXTURE = 8; + static final int MAX_INPUT = 8; + static final int MAX_OUTPUT = 8; + static final int MAX_CONSTANT = 8; + static final int MAX_TEXTURE = 8; + + /** + * + * TextureType specifies what textures are attached to Program + * objects + * + **/ + public enum TextureType { + TEXTURE_2D (0), + TEXTURE_CUBE (1); + + int mID; + TextureType(int id) { + mID = id; + } + } + + enum ProgramParam { + INPUT (0), + OUTPUT (1), + CONSTANT (2), + TEXTURE_TYPE (3); + + int mID; + ProgramParam(int id) { + mID = id; + } + }; Element mInputs[]; Element mOutputs[]; Type mConstants[]; + TextureType mTextures[]; int mTextureCount; String mShader; Program(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } + /** + * Binds a constant buffer to be used as uniform inputs to the + * program + * + * @param a allocation containing uniform data + * @param slot index within the program's list of constant + * buffer allocations + */ public void bindConstants(Allocation a, int slot) { - mRS.nProgramBindConstants(mID, slot, a.mID); + if (slot < 0 || slot >= mConstants.length) { + throw new IllegalArgumentException("Slot ID out of range."); + } + if (a != null && + a.getType().getID() != mConstants[slot].getID()) { + throw new IllegalArgumentException("Allocation type does not match slot type."); + } + int id = a != null ? a.getID() : 0; + mRS.nProgramBindConstants(getID(), slot, id); } + /** + * Binds a texture to be used in the program + * + * @param va allocation containing texture data + * @param slot index within the program's list of textures + * + */ public void bindTexture(Allocation va, int slot) throws IllegalArgumentException { mRS.validate(); - if((slot < 0) || (slot >= mTextureCount)) { + if ((slot < 0) || (slot >= mTextureCount)) { throw new IllegalArgumentException("Slot ID out of range."); } + if (va != null && va.getType().hasFaces() && + mTextures[slot] != TextureType.TEXTURE_CUBE) { + throw new IllegalArgumentException("Cannot bind cubemap to 2d texture slot"); + } - mRS.nProgramBindTexture(mID, slot, va.mID); + int id = va != null ? va.getID() : 0; + mRS.nProgramBindTexture(getID(), slot, id); } + /** + * Binds an object that describes how a texture at the + * corresponding location is sampled + * + * @param vs sampler for a corresponding texture + * @param slot index within the program's list of textures to + * use the sampler on + * + */ public void bindSampler(Sampler vs, int slot) throws IllegalArgumentException { mRS.validate(); - if((slot < 0) || (slot >= mTextureCount)) { + if ((slot < 0) || (slot >= mTextureCount)) { throw new IllegalArgumentException("Slot ID out of range."); } - mRS.nProgramBindSampler(mID, slot, vs.mID); + int id = vs != null ? vs.getID() : 0; + mRS.nProgramBindSampler(getID(), slot, id); } @@ -73,6 +146,7 @@ public class Program extends BaseObj { Element mOutputs[]; Type mConstants[]; Type mTextures[]; + TextureType mTextureTypes[]; int mInputCount; int mOutputCount; int mConstantCount; @@ -89,43 +163,115 @@ public class Program extends BaseObj { mOutputCount = 0; mConstantCount = 0; mTextureCount = 0; + mTextureTypes = new TextureType[MAX_TEXTURE]; } - public void setShader(String s) { + /** + * Sets the GLSL shader code to be used in the program + * + * @param s GLSL shader string + * @return self + */ + public BaseProgramBuilder setShader(String s) { mShader = s; + return this; } - public void addInput(Element e) throws IllegalStateException { - // Should check for consistant and non-conflicting names... - if(mInputCount >= MAX_INPUT) { - throw new IllegalArgumentException("Max input count exceeded."); + /** + * Sets the GLSL shader code to be used in the program + * + * @param resources application resources + * @param resourceID id of the file containing GLSL shader code + * + * @return self + */ + public BaseProgramBuilder setShader(Resources resources, int resourceID) { + byte[] str; + int strLength; + InputStream is = resources.openRawResource(resourceID); + try { + try { + str = new byte[1024]; + strLength = 0; + while(true) { + int bytesLeft = str.length - strLength; + if (bytesLeft == 0) { + byte[] buf2 = new byte[str.length * 2]; + System.arraycopy(str, 0, buf2, 0, str.length); + str = buf2; + bytesLeft = str.length - strLength; + } + int bytesRead = is.read(str, strLength, bytesLeft); + if (bytesRead <= 0) { + break; + } + strLength += bytesRead; + } + } finally { + is.close(); + } + } catch(IOException e) { + throw new Resources.NotFoundException(); } - mInputs[mInputCount++] = e; - } - public void addOutput(Element e) throws IllegalStateException { - // Should check for consistant and non-conflicting names... - if(mOutputCount >= MAX_OUTPUT) { - throw new IllegalArgumentException("Max output count exceeded."); + try { + mShader = new String(str, 0, strLength, "UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.e("Renderscript shader creation", "Could not decode shader string"); } - mOutputs[mOutputCount++] = e; + + return this; } - public int addConstant(Type t) throws IllegalStateException { + /** + * Queries the index of the last added constant buffer type + * + */ + public int getCurrentConstantIndex() { + return mConstantCount - 1; + } + + /** + * Queries the index of the last added texture type + * + */ + public int getCurrentTextureIndex() { + return mTextureCount - 1; + } + + /** + * Adds constant (uniform) inputs to the program + * + * @param t Type that describes the layout of the Allocation + * object to be used as constant inputs to the Program + * @return self + */ + public BaseProgramBuilder addConstant(Type t) throws IllegalStateException { // Should check for consistant and non-conflicting names... if(mConstantCount >= MAX_CONSTANT) { - throw new IllegalArgumentException("Max input count exceeded."); + throw new RSIllegalArgumentException("Max input count exceeded."); + } + if (t.getElement().isComplex()) { + throw new RSIllegalArgumentException("Complex elements not allowed."); } mConstants[mConstantCount] = t; - return mConstantCount++; + mConstantCount++; + return this; } - public void setTextureCount(int count) throws IllegalArgumentException { - // Should check for consistant and non-conflicting names... - if(count >= MAX_CONSTANT) { + /** + * Adds a texture input to the Program + * + * @param texType describes that the texture to append it (2D, + * Cubemap, etc.) + * @return self + */ + public BaseProgramBuilder addTexture(TextureType texType) throws IllegalArgumentException { + if(mTextureCount >= MAX_TEXTURE) { throw new IllegalArgumentException("Max texture count exceeded."); } - mTextureCount = count; + mTextureTypes[mTextureCount ++] = texType; + return this; } protected void initProgram(Program p) { @@ -136,6 +282,8 @@ public class Program extends BaseObj { p.mConstants = new Type[mConstantCount]; System.arraycopy(mConstants, 0, p.mConstants, 0, mConstantCount); p.mTextureCount = mTextureCount; + p.mTextures = new TextureType[mTextureCount]; + System.arraycopy(mTextureTypes, 0, p.mTextures, 0, mTextureCount); } } diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java index 5e04f0c..a48c2e3 100644 --- a/graphics/java/android/renderscript/ProgramFragment.java +++ b/graphics/java/android/renderscript/ProgramFragment.java @@ -22,7 +22,19 @@ import android.util.Log; /** - * @hide + * <p>The Renderscript fragment program, also known as fragment shader is responsible + * for manipulating pixel data in a user defined way. It's constructed from a GLSL + * shader string containing the program body, textures inputs, and a Type object + * that describes the constants used by the program. Similar to the vertex programs, + * when an allocation with constant input values is bound to the shader, its values + * are sent to the graphics program automatically.</p> + * <p> The values inside the allocation are not explicitly tracked. If they change between two draw + * calls using the same program object, the runtime needs to be notified of that + * change by calling rsgAllocationSyncAll so it could send the new values to hardware. + * Communication between the vertex and fragment programs is handled internally in the + * GLSL code. For example, if the fragment program is expecting a varying input called + * varTex0, the GLSL code inside the program vertex must provide it. + * </p> * **/ public class ProgramFragment extends Program { @@ -30,109 +42,46 @@ public class ProgramFragment extends Program { super(id, rs); } - public static class ShaderBuilder extends BaseProgramBuilder { - public ShaderBuilder(RenderScript rs) { + public static class Builder extends BaseProgramBuilder { + /** + * Create a builder object. + * + * @param rs Context to which the program will belong. + */ + public Builder(RenderScript rs) { super(rs); } + /** + * Creates ProgramFragment from the current state of the builder + * + * @return ProgramFragment + */ public ProgramFragment create() { mRS.validate(); - int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + 1) * 2]; + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; int idx = 0; for (int i=0; i < mInputCount; i++) { - tmp[idx++] = 0; - tmp[idx++] = mInputs[i].mID; + tmp[idx++] = ProgramParam.INPUT.mID; + tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { - tmp[idx++] = 1; - tmp[idx++] = mOutputs[i].mID; + tmp[idx++] = ProgramParam.OUTPUT.mID; + tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { - tmp[idx++] = 2; - tmp[idx++] = mConstants[i].mID; - } - tmp[idx++] = 3; - tmp[idx++] = mTextureCount; - - int id = mRS.nProgramFragmentCreate2(mShader, tmp); - ProgramFragment pf = new ProgramFragment(id, mRS); - initProgram(pf); - return pf; - } - } - - public static class Builder { - public static final int MAX_TEXTURE = 2; - RenderScript mRS; - boolean mPointSpriteEnable; - - public enum EnvMode { - REPLACE (1), - MODULATE (2), - DECAL (3); - - int mID; - EnvMode(int id) { - mID = id; + tmp[idx++] = ProgramParam.CONSTANT.mID; + tmp[idx++] = mConstants[i].getID(); } - } - - public enum Format { - ALPHA (1), - LUMINANCE_ALPHA (2), - RGB (3), - RGBA (4); - - int mID; - Format(int id) { - mID = id; + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; } - } - private class Slot { - EnvMode env; - Format format; - Slot(EnvMode _env, Format _fmt) { - env = _env; - format = _fmt; - } - } - Slot[] mSlots; - - public Builder(RenderScript rs) { - mRS = rs; - mSlots = new Slot[MAX_TEXTURE]; - mPointSpriteEnable = false; - } - - public void setTexture(EnvMode env, Format fmt, int slot) - throws IllegalArgumentException { - if((slot < 0) || (slot >= MAX_TEXTURE)) { - throw new IllegalArgumentException("MAX_TEXTURE exceeded."); - } - mSlots[slot] = new Slot(env, fmt); - } - - public void setPointSpriteTexCoordinateReplacement(boolean enable) { - mPointSpriteEnable = enable; - } - - public ProgramFragment create() { - mRS.validate(); - int[] tmp = new int[MAX_TEXTURE * 2 + 1]; - if (mSlots[0] != null) { - tmp[0] = mSlots[0].env.mID; - tmp[1] = mSlots[0].format.mID; - } - if (mSlots[1] != null) { - tmp[2] = mSlots[1].env.mID; - tmp[3] = mSlots[1].format.mID; - } - tmp[4] = mPointSpriteEnable ? 1 : 0; - int id = mRS.nProgramFragmentCreate(tmp); + int id = mRS.nProgramFragmentCreate(mShader, tmp); ProgramFragment pf = new ProgramFragment(id, mRS); - pf.mTextureCount = MAX_TEXTURE; + initProgram(pf); return pf; } } diff --git a/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java new file mode 100644 index 0000000..f99cd7b --- /dev/null +++ b/graphics/java/android/renderscript/ProgramFragmentFixedFunction.java @@ -0,0 +1,294 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +import android.util.Config; +import android.util.Log; + + +/** + * <p>ProgramFragmentFixedFunction is a helper class that provides + * a way to make a simple fragment shader without writing any + * GLSL code. This class allows for display of constant color, interpolated + * color from the vertex shader, or combinations of the both + * blended with results of up to two texture lookups.</p + * + **/ +public class ProgramFragmentFixedFunction extends ProgramFragment { + ProgramFragmentFixedFunction(int id, RenderScript rs) { + super(id, rs); + } + + static class InternalBuilder extends BaseProgramBuilder { + public InternalBuilder(RenderScript rs) { + super(rs); + } + + /** + * Creates ProgramFragmentFixedFunction from the current state + * of the builder + * + * @return ProgramFragmentFixedFunction + */ + public ProgramFragmentFixedFunction create() { + mRS.validate(); + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + int idx = 0; + + for (int i=0; i < mInputCount; i++) { + tmp[idx++] = ProgramParam.INPUT.mID; + tmp[idx++] = mInputs[i].getID(); + } + for (int i=0; i < mOutputCount; i++) { + tmp[idx++] = ProgramParam.OUTPUT.mID; + tmp[idx++] = mOutputs[i].getID(); + } + for (int i=0; i < mConstantCount; i++) { + tmp[idx++] = ProgramParam.CONSTANT.mID; + tmp[idx++] = mConstants[i].getID(); + } + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; + } + + int id = mRS.nProgramFragmentCreate(mShader, tmp); + ProgramFragmentFixedFunction pf = new ProgramFragmentFixedFunction(id, mRS); + initProgram(pf); + return pf; + } + } + + public static class Builder { + public static final int MAX_TEXTURE = 2; + int mNumTextures; + boolean mPointSpriteEnable; + boolean mVaryingColorEnable; + String mShader; + RenderScript mRS; + + /** + * EnvMode describes how textures are combined with the existing + * color in the fixed function fragment shader + * + **/ + public enum EnvMode { + REPLACE (1), + MODULATE (2), + DECAL (3); + + int mID; + EnvMode(int id) { + mID = id; + } + } + + /** + * Format describes the pixel format of textures in the fixed + * function fragment shader and how they are sampled + * + **/ + public enum Format { + ALPHA (1), + LUMINANCE_ALPHA (2), + RGB (3), + RGBA (4); + + int mID; + Format(int id) { + mID = id; + } + } + + private class Slot { + EnvMode env; + Format format; + Slot(EnvMode _env, Format _fmt) { + env = _env; + format = _fmt; + } + } + Slot[] mSlots; + + private void buildShaderString() { + mShader = "//rs_shader_internal\n"; + mShader += "varying lowp vec4 varColor;\n"; + mShader += "varying vec2 varTex0;\n"; + + mShader += "void main() {\n"; + if (mVaryingColorEnable) { + mShader += " lowp vec4 col = varColor;\n"; + } else { + mShader += " lowp vec4 col = UNI_Color;\n"; + } + + if (mNumTextures != 0) { + if (mPointSpriteEnable) { + mShader += " vec2 t0 = gl_PointCoord;\n"; + } else { + mShader += " vec2 t0 = varTex0.xy;\n"; + } + } + + for(int i = 0; i < mNumTextures; i ++) { + switch(mSlots[i].env) { + case REPLACE: + switch (mSlots[i].format) { + case ALPHA: + mShader += " col.a = texture2D(UNI_Tex0, t0).a;\n"; + break; + case LUMINANCE_ALPHA: + mShader += " col.rgba = texture2D(UNI_Tex0, t0).rgba;\n"; + break; + case RGB: + mShader += " col.rgb = texture2D(UNI_Tex0, t0).rgb;\n"; + break; + case RGBA: + mShader += " col.rgba = texture2D(UNI_Tex0, t0).rgba;\n"; + break; + } + break; + case MODULATE: + switch (mSlots[i].format) { + case ALPHA: + mShader += " col.a *= texture2D(UNI_Tex0, t0).a;\n"; + break; + case LUMINANCE_ALPHA: + mShader += " col.rgba *= texture2D(UNI_Tex0, t0).rgba;\n"; + break; + case RGB: + mShader += " col.rgb *= texture2D(UNI_Tex0, t0).rgb;\n"; + break; + case RGBA: + mShader += " col.rgba *= texture2D(UNI_Tex0, t0).rgba;\n"; + break; + } + break; + case DECAL: + mShader += " col = texture2D(UNI_Tex0, t0);\n"; + break; + } + } + + mShader += " gl_FragColor = col;\n"; + mShader += "}\n"; + } + + /** + * Creates a builder for fixed function fragment program + * + * @param rs Context to which the program will belong. + */ + public Builder(RenderScript rs) { + mRS = rs; + mSlots = new Slot[MAX_TEXTURE]; + mPointSpriteEnable = false; + } + + /** + * Adds a texture to be fetched as part of the fixed function + * fragment program + * + * @param env specifies how the texture is combined with the + * current color + * @param fmt specifies the format of the texture and how its + * components will be used to combine with the + * current color + * @param slot index of the texture to apply the operations on + * + * @return this + */ + public Builder setTexture(EnvMode env, Format fmt, int slot) + throws IllegalArgumentException { + if((slot < 0) || (slot >= MAX_TEXTURE)) { + throw new IllegalArgumentException("MAX_TEXTURE exceeded."); + } + mSlots[slot] = new Slot(env, fmt); + return this; + } + + /** + * Specifies whether the texture coordinate passed from the + * vertex program is replaced with an openGL internal point + * sprite texture coordinate + * + **/ + public Builder setPointSpriteTexCoordinateReplacement(boolean enable) { + mPointSpriteEnable = enable; + return this; + } + + /** + * Specifies whether the varying color passed from the vertex + * program or the constant color set on the fragment program is + * used in the final color calculation in the fixed function + * fragment shader + * + **/ + public Builder setVaryingColor(boolean enable) { + mVaryingColorEnable = enable; + return this; + } + + /** + * Creates the fixed function fragment program from the current + * state of the builder. + * + */ + public ProgramFragmentFixedFunction create() { + InternalBuilder sb = new InternalBuilder(mRS); + mNumTextures = 0; + for(int i = 0; i < MAX_TEXTURE; i ++) { + if(mSlots[i] != null) { + mNumTextures ++; + } + } + buildShaderString(); + sb.setShader(mShader); + + Type constType = null; + if (!mVaryingColorEnable) { + Element.Builder b = new Element.Builder(mRS); + b.add(Element.F32_4(mRS), "Color"); + Type.Builder typeBuilder = new Type.Builder(mRS, b.create()); + typeBuilder.setX(1); + constType = typeBuilder.create(); + sb.addConstant(constType); + } + for (int i = 0; i < mNumTextures; i ++) { + sb.addTexture(TextureType.TEXTURE_2D); + } + + ProgramFragmentFixedFunction pf = sb.create(); + pf.mTextureCount = MAX_TEXTURE; + if (!mVaryingColorEnable) { + Allocation constantData = Allocation.createTyped(mRS,constType); + FieldPacker fp = new FieldPacker(16); + Float4 f4 = new Float4(1.f, 1.f, 1.f, 1.f); + fp.addF32(f4); + constantData.setFromFieldPacker(0, fp); + pf.bindConstants(constantData, 0); + } + return pf; + } + } +} + + + + diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java index 56f9bf4..b89d36d 100644 --- a/graphics/java/android/renderscript/ProgramRaster.java +++ b/graphics/java/android/renderscript/ProgramRaster.java @@ -22,80 +22,107 @@ import android.util.Log; /** - * @hide - * + * Program raster is primarily used to specify whether point sprites are enabled and to control + * the culling mode. By default, back faces are culled. **/ public class ProgramRaster extends BaseObj { + + public enum CullMode { + BACK (0), + FRONT (1), + NONE (2); + + int mID; + CullMode(int id) { + mID = id; + } + } + boolean mPointSmooth; boolean mLineSmooth; boolean mPointSprite; - float mPointSize; float mLineWidth; - Element mIn; - Element mOut; + CullMode mCullMode; ProgramRaster(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); - mPointSize = 1.0f; mLineWidth = 1.0f; mPointSmooth = false; mLineSmooth = false; mPointSprite = false; + + mCullMode = CullMode.BACK; } - public void setLineWidth(float w) { + void setLineWidth(float w) { mRS.validate(); mLineWidth = w; - mRS.nProgramRasterSetLineWidth(mID, w); + mRS.nProgramRasterSetLineWidth(getID(), w); } - public void setPointSize(float s) { + void setCullMode(CullMode m) { mRS.validate(); - mPointSize = s; - mRS.nProgramRasterSetPointSize(mID, s); + mCullMode = m; + mRS.nProgramRasterSetCullMode(getID(), m.mID); } - void internalInit() { - int inID = 0; - int outID = 0; - if (mIn != null) { - inID = mIn.mID; + public static ProgramRaster CULL_BACK(RenderScript rs) { + if(rs.mProgramRaster_CULL_BACK == null) { + ProgramRaster.Builder builder = new ProgramRaster.Builder(rs); + builder.setCullMode(CullMode.BACK); + rs.mProgramRaster_CULL_BACK = builder.create(); } - if (mOut != null) { - outID = mOut.mID; + return rs.mProgramRaster_CULL_BACK; + } + + public static ProgramRaster CULL_FRONT(RenderScript rs) { + if(rs.mProgramRaster_CULL_FRONT == null) { + ProgramRaster.Builder builder = new ProgramRaster.Builder(rs); + builder.setCullMode(CullMode.FRONT); + rs.mProgramRaster_CULL_FRONT = builder.create(); } - mID = mRS.nProgramRasterCreate(inID, outID, mPointSmooth, mLineSmooth, mPointSprite); + return rs.mProgramRaster_CULL_FRONT; } + public static ProgramRaster CULL_NONE(RenderScript rs) { + if(rs.mProgramRaster_CULL_NONE == null) { + ProgramRaster.Builder builder = new ProgramRaster.Builder(rs); + builder.setCullMode(CullMode.NONE); + rs.mProgramRaster_CULL_NONE = builder.create(); + } + return rs.mProgramRaster_CULL_NONE; + } public static class Builder { RenderScript mRS; - ProgramRaster mPR; + boolean mPointSprite; + boolean mPointSmooth; + boolean mLineSmooth; + CullMode mCullMode; - public Builder(RenderScript rs, Element in, Element out) { + public Builder(RenderScript rs) { mRS = rs; - mPR = new ProgramRaster(0, rs); + mPointSmooth = false; + mLineSmooth = false; + mPointSprite = false; + mCullMode = CullMode.BACK; } - public void setPointSpriteEnable(boolean enable) { - mPR.mPointSprite = enable; + public Builder setPointSpriteEnabled(boolean enable) { + mPointSprite = enable; + return this; } - public void setPointSmoothEnable(boolean enable) { - mPR.mPointSmooth = enable; + public Builder setCullMode(CullMode m) { + mCullMode = m; + return this; } - public void setLineSmoothEnable(boolean enable) { - mPR.mLineSmooth = enable; - } - - static synchronized ProgramRaster internalCreate(RenderScript rs, Builder b) { - b.mPR.internalInit(); - ProgramRaster pr = b.mPR; - b.mPR = new ProgramRaster(0, b.mRS); + int id = rs.nProgramRasterCreate(b.mPointSmooth, b.mLineSmooth, b.mPointSprite); + ProgramRaster pr = new ProgramRaster(id, rs); + pr.setCullMode(b.mCullMode); return pr; } @@ -111,3 +138,4 @@ public class ProgramRaster extends BaseObj { + diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java index 69be245..c46e6b9 100644 --- a/graphics/java/android/renderscript/ProgramStore.java +++ b/graphics/java/android/renderscript/ProgramStore.java @@ -22,18 +22,63 @@ import android.util.Log; /** - * @hide + * <p>ProgramStore contains a set of parameters that control how + * the graphics hardware handles writes to the framebuffer. + * It could be used to:</p> + * <ul> + * <li>enable/disable depth testing</li> + * <li>specify wheather depth writes are performed</li> + * <li>setup various blending modes for use in effects like + * transparency</li> + * <li>define write masks for color components written into the + * framebuffer</li> + * </ul> * **/ public class ProgramStore extends BaseObj { - public enum DepthFunc { + /** + * Specifies the function used to determine whether a fragment + * will be drawn during the depth testing stage in the rendering + * pipeline by comparing its value with that already in the depth + * buffer. DepthFunc is only valid when depth buffer is present + * and depth testing is enabled + */ + public enum DepthFunc { + + /** + * Always drawn + */ ALWAYS (0), + /** + * Drawn if the incoming depth value is less than that in the + * depth buffer + */ LESS (1), - LEQUAL (2), + /** + * Drawn if the incoming depth value is less or equal to that in + * the depth buffer + */ + LESS_OR_EQUAL (2), + /** + * Drawn if the incoming depth value is greater than that in the + * depth buffer + */ GREATER (3), - GEQUAL (4), + /** + * Drawn if the incoming depth value is greater or equal to that + * in the depth buffer + */ + GREATER_OR_EQUAL (4), + /** + * Drawn if the incoming depth value is equal to that in the + * depth buffer + */ EQUAL (5), - NOTEQUAL (6); + /** + * Drawn if the incoming depth value is not equal to that in the + * depth buffer + */ + NOT_EQUAL (6); int mID; DepthFunc(int id) { @@ -41,6 +86,14 @@ public class ProgramStore extends BaseObj { } } + /** + * Specifies the functions used to combine incoming pixels with + * those already in the frame buffer. + * + * BlendSrcFunc describes how the coefficient used to scale the + * source pixels during the blending operation is computed + * + */ public enum BlendSrcFunc { ZERO (0), ONE (1), @@ -58,6 +111,15 @@ public class ProgramStore extends BaseObj { } } + /** + * Specifies the functions used to combine incoming pixels with + * those already in the frame buffer. + * + * BlendDstFunc describes how the coefficient used to scale the + * pixels already in the framebuffer is computed during the + * blending operation + * + */ public enum BlendDstFunc { ZERO (0), ONE (1), @@ -76,16 +138,106 @@ public class ProgramStore extends BaseObj { ProgramStore(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } + /** + * Returns a pre-defined program store object with the following + * characteristics: + * - incoming pixels are drawn if their depth value is less than + * the stored value in the depth buffer. If the pixel is + * drawn, its value is also stored in the depth buffer + * - incoming pixels override the value stored in the color + * buffer if it passes the depth test + * + * @param rs Context to which the program will belong. + **/ + public static ProgramStore BLEND_NONE_DEPTH_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_NONE_DEPTH_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.LESS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(true); + rs.mProgramStore_BLEND_NONE_DEPTH_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_TEST; + } + /** + * Returns a pre-defined program store object with the following + * characteristics: + * - incoming pixels always pass the depth test and their value + * is not stored in the depth buffer + * - incoming pixels override the value stored in the color + * buffer + * + * @param rs Context to which the program will belong. + **/ + public static ProgramStore BLEND_NONE_DEPTH_NONE(RenderScript rs) { + if(rs.mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + rs.mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH; + } + /** + * Returns a pre-defined program store object with the following + * characteristics: + * - incoming pixels are drawn if their depth value is less than + * the stored value in the depth buffer. If the pixel is + * drawn, its value is also stored in the depth buffer + * - if the incoming (Source) pixel passes depth test, its value + * is combined with the stored color (Dest) using the + * following formula + * Final.RGB = Source.RGB * Source.A + Dest.RGB * (1 - Source.A) + * + * @param rs Context to which the program will belong. + **/ + public static ProgramStore BLEND_ALPHA_DEPTH_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_ALPHA_DEPTH_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.LESS); + builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(true); + rs.mProgramStore_BLEND_ALPHA_DEPTH_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_TEST; + } + /** + * Returns a pre-defined program store object with the following + * characteristics: + * - incoming pixels always pass the depth test and their value + * is not stored in the depth buffer + * - incoming pixel's value is combined with the stored color + * (Dest) using the following formula + * Final.RGB = Source.RGB * Source.A + Dest.RGB * (1 - Source.A) + * + * @param rs Context to which the program will belong. + **/ + public static ProgramStore BLEND_ALPHA_DEPTH_NONE(RenderScript rs) { + if(rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnabled(false); + builder.setDepthMaskEnabled(false); + rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH; + } - + /** + * Builder class for ProgramStore object. If the builder is left + * empty, the equivalent of BLEND_NONE_DEPTH_NONE would be + * returned + */ public static class Builder { RenderScript mRS; - Element mIn; - Element mOut; DepthFunc mDepthFunc; boolean mDepthMask; boolean mColorMaskR; @@ -96,12 +248,8 @@ public class ProgramStore extends BaseObj { BlendDstFunc mBlendDst; boolean mDither; - - - public Builder(RenderScript rs, Element in, Element out) { + public Builder(RenderScript rs) { mRS = rs; - mIn = in; - mOut = out; mDepthFunc = DepthFunc.ALWAYS; mDepthMask = false; mColorMaskR = true; @@ -110,57 +258,99 @@ public class ProgramStore extends BaseObj { mColorMaskA = true; mBlendSrc = BlendSrcFunc.ONE; mBlendDst = BlendDstFunc.ZERO; - - } - public void setDepthFunc(DepthFunc func) { + /** + * Specifies the depth testing behavior + * + * @param func function used for depth testing + * + * @return this + */ + public Builder setDepthFunc(DepthFunc func) { mDepthFunc = func; + return this; } - public void setDepthMask(boolean enable) { + /** + * Enables writes into the depth buffer + * + * @param enable specifies whether depth writes are + * enabled or disabled + * + * @return this + */ + public Builder setDepthMaskEnabled(boolean enable) { mDepthMask = enable; + return this; } - public void setColorMask(boolean r, boolean g, boolean b, boolean a) { + /** + * Enables writes into the color buffer + * + * @param r specifies whether red channel is written + * @param g specifies whether green channel is written + * @param b specifies whether blue channel is written + * @param a specifies whether alpha channel is written + * + * @return this + */ + public Builder setColorMaskEnabled(boolean r, boolean g, boolean b, boolean a) { mColorMaskR = r; mColorMaskG = g; mColorMaskB = b; mColorMaskA = a; + return this; } - public void setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) { + /** + * Specifies how incoming pixels are combined with the pixels + * stored in the framebuffer + * + * @param src specifies how the source blending factor is + * computed + * @param dst specifies how the destination blending factor is + * computed + * + * @return this + */ + public Builder setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) { mBlendSrc = src; mBlendDst = dst; + return this; } - public void setDitherEnable(boolean enable) { + /** + * Enables dithering + * + * @param enable specifies whether dithering is enabled or + * disabled + * + * @return this + */ + public Builder setDitherEnabled(boolean enable) { mDither = enable; + return this; } static synchronized ProgramStore internalCreate(RenderScript rs, Builder b) { - int inID = 0; - int outID = 0; - if (b.mIn != null) { - inID = b.mIn.mID; - } - if (b.mOut != null) { - outID = b.mOut.mID; - } - rs.nProgramFragmentStoreBegin(inID, outID); - rs.nProgramFragmentStoreDepthFunc(b.mDepthFunc.mID); - rs.nProgramFragmentStoreDepthMask(b.mDepthMask); - rs.nProgramFragmentStoreColorMask(b.mColorMaskR, + rs.nProgramStoreBegin(0, 0); + rs.nProgramStoreDepthFunc(b.mDepthFunc.mID); + rs.nProgramStoreDepthMask(b.mDepthMask); + rs.nProgramStoreColorMask(b.mColorMaskR, b.mColorMaskG, b.mColorMaskB, b.mColorMaskA); - rs.nProgramFragmentStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID); - rs.nProgramFragmentStoreDither(b.mDither); + rs.nProgramStoreBlendFunc(b.mBlendSrc.mID, b.mBlendDst.mID); + rs.nProgramStoreDither(b.mDither); - int id = rs.nProgramFragmentStoreCreate(); + int id = rs.nProgramStoreCreate(); return new ProgramStore(id, rs); } + /** + * Creates a program store from the current state of the builder + */ public ProgramStore create() { mRS.validate(); return internalCreate(mRS, this); diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index 1b155d7..55653f7 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -14,169 +14,116 @@ * limitations under the License. */ + /** + * <p>The Renderscript vertex program, also known as a vertex shader, describes a stage in + * the graphics pipeline responsible for manipulating geometric data in a user-defined way. + * The object is constructed by providing the Renderscript system with the following data:</p> + * <ul> + * <li>Element describing its varying inputs or attributes</li> + * <li>GLSL shader string that defines the body of the program</li> + * <li>a Type that describes the layout of an Allocation containing constant or uniform inputs</li> + * </ul> + * + * <p>Once the program is created, you bind it to the graphics context, RenderScriptGL, and it will be used for + * all subsequent draw calls until you bind a new program. If the program has constant inputs, + * the user needs to bind an allocation containing those inputs. The allocation's type must match + * the one provided during creation. The Renderscript library then does all the necessary plumbing + * to send those constants to the graphics hardware. Varying inputs to the shader, such as position, normal, + * and texture coordinates are matched by name between the input Element and the Mesh object being drawn. + * The signatures don't have to be exact or in any strict order. As long as the input name in the shader + * matches a channel name and size available on the mesh, the runtime takes care of connecting the + * two. Unlike OpenGL, there is no need to link the vertex and fragment programs.</p> + * + **/ package android.renderscript; +import android.graphics.Matrix; import android.util.Config; import android.util.Log; /** - * @hide + * ProgramVertex, also know as a vertex shader, describes a + * stage in the graphics pipeline responsible for manipulating + * geometric data in a user-defined way. * **/ public class ProgramVertex extends Program { - public static final int MAX_LIGHT = 8; - ProgramVertex(int id, RenderScript rs) { super(id, rs); } - public void bindAllocation(MatrixAllocation va) { - mRS.validate(); - bindConstants(va.mAlloc, 0); - } - - - public static class Builder { - RenderScript mRS; - boolean mTextureMatrixEnable; - - public Builder(RenderScript rs, Element in, Element out) { - mRS = rs; - } - - public void setTextureMatrixEnable(boolean enable) { - mTextureMatrixEnable = enable; - } - - public ProgramVertex create() { - int id = mRS.nProgramVertexCreate(mTextureMatrixEnable); - return new ProgramVertex(id, mRS); + /** + * Builder class for creating ProgramVertex objects. + * The builder starts empty and the user must minimally provide + * the GLSL shader code, and the varying inputs. Constant, or + * uniform parameters to the shader may optionally be provided as + * well. + * + **/ + public static class Builder extends BaseProgramBuilder { + /** + * Create a builder object. + * + * @param rs Context to which the program will belong. + */ + public Builder(RenderScript rs) { + super(rs); } - } - public static class ShaderBuilder extends BaseProgramBuilder { - public ShaderBuilder(RenderScript rs) { - super(rs); + /** + * Add varying inputs to the program + * + * @param e element describing the layout of the varying input + * structure + * @return self + */ + public Builder addInput(Element e) throws IllegalStateException { + // Should check for consistant and non-conflicting names... + if(mInputCount >= MAX_INPUT) { + throw new RSIllegalArgumentException("Max input count exceeded."); + } + if (e.isComplex()) { + throw new RSIllegalArgumentException("Complex elements not allowed."); + } + mInputs[mInputCount++] = e; + return this; } + /** + * Creates ProgramVertex from the current state of the builder + * + * @return ProgramVertex + */ public ProgramVertex create() { mRS.validate(); - int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount +1) * 2]; + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; int idx = 0; for (int i=0; i < mInputCount; i++) { - tmp[idx++] = 0; - tmp[idx++] = mInputs[i].mID; + tmp[idx++] = ProgramParam.INPUT.mID; + tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { - tmp[idx++] = 1; - tmp[idx++] = mOutputs[i].mID; + tmp[idx++] = ProgramParam.OUTPUT.mID; + tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { - tmp[idx++] = 2; - tmp[idx++] = mConstants[i].mID; + tmp[idx++] = ProgramParam.CONSTANT.mID; + tmp[idx++] = mConstants[i].getID(); + } + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; } - tmp[idx++] = 3; - tmp[idx++] = mTextureCount; - int id = mRS.nProgramVertexCreate2(mShader, tmp); + int id = mRS.nProgramVertexCreate(mShader, tmp); ProgramVertex pv = new ProgramVertex(id, mRS); initProgram(pv); return pv; } } - - - public static class MatrixAllocation { - static final int MODELVIEW_OFFSET = 0; - static final int PROJECTION_OFFSET = 16; - static final int TEXTURE_OFFSET = 32; - - Matrix4f mModel; - Matrix4f mProjection; - Matrix4f mTexture; - - public Allocation mAlloc; - - public MatrixAllocation(RenderScript rs) { - mModel = new Matrix4f(); - mProjection = new Matrix4f(); - mTexture = new Matrix4f(); - - mAlloc = Allocation.createSized(rs, Element.createUser(rs, Element.DataType.FLOAT_32), 48); - mAlloc.subData1D(MODELVIEW_OFFSET, 16, mModel.mMat); - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); - mAlloc.subData1D(TEXTURE_OFFSET, 16, mTexture.mMat); - } - - public void destroy() { - mAlloc.destroy(); - mAlloc = null; - } - - public void loadModelview(Matrix4f m) { - mModel = m; - mAlloc.subData1D(MODELVIEW_OFFSET, 16, m.mMat); - } - - public void loadProjection(Matrix4f m) { - mProjection = m; - mAlloc.subData1D(PROJECTION_OFFSET, 16, m.mMat); - } - - public void loadTexture(Matrix4f m) { - mTexture = m; - mAlloc.subData1D(TEXTURE_OFFSET, 16, m.mMat); - } - - public void setupOrthoWindow(int w, int h) { - mProjection.loadOrtho(0,w, h,0, -1,1); - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); - } - - public void setupOrthoNormalized(int w, int h) { - // range -1,1 in the narrow axis. - if(w > h) { - float aspect = ((float)w) / h; - mProjection.loadOrtho(-aspect,aspect, -1,1, -1,1); - } else { - float aspect = ((float)h) / w; - mProjection.loadOrtho(-1,1, -aspect,aspect, -1,1); - } - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); - } - - public void setupProjectionNormalized(int w, int h) { - // range -1,1 in the narrow axis at z = 0. - Matrix4f m1 = new Matrix4f(); - Matrix4f m2 = new Matrix4f(); - - if(w > h) { - float aspect = ((float)w) / h; - m1.loadFrustum(-aspect,aspect, -1,1, 1,100); - } else { - float aspect = ((float)h) / w; - m1.loadFrustum(-1,1, -aspect,aspect, 1,100); - } - - m2.loadRotate(180, 0, 1, 0); - m1.loadMultiply(m1, m2); - - m2.loadScale(-2, 2, 1); - m1.loadMultiply(m1, m2); - - m2.loadTranslate(0, 0, 2); - m1.loadMultiply(m1, m2); - - mProjection = m1; - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); - } - - } - } - diff --git a/graphics/java/android/renderscript/ProgramVertexFixedFunction.java b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java new file mode 100644 index 0000000..556964a --- /dev/null +++ b/graphics/java/android/renderscript/ProgramVertexFixedFunction.java @@ -0,0 +1,268 @@ +/* + * Copyright (C) 2008 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +import android.graphics.Matrix; +import android.util.Config; +import android.util.Log; + + +/** + * ProgramVertexFixedFunction is a helper class that provides a + * simple way to create a fixed function emulation vertex shader + * without writing any GLSL code. + * + **/ +public class ProgramVertexFixedFunction extends ProgramVertex { + + ProgramVertexFixedFunction(int id, RenderScript rs) { + super(id, rs); + } + + /** + * Binds the constant buffer containing fixed function emulation + * matrices + * + * @param va allocation containing fixed function matrices + */ + public void bindConstants(Constants va) { + mRS.validate(); + bindConstants(va.getAllocation(), 0); + } + + static class InternalBuilder extends BaseProgramBuilder { + public InternalBuilder(RenderScript rs) { + super(rs); + } + + public InternalBuilder addInput(Element e) throws IllegalStateException { + // Should check for consistant and non-conflicting names... + if(mInputCount >= MAX_INPUT) { + throw new RSIllegalArgumentException("Max input count exceeded."); + } + if (e.isComplex()) { + throw new RSIllegalArgumentException("Complex elements not allowed."); + } + mInputs[mInputCount++] = e; + return this; + } + + /** + * Creates ProgramVertexFixedFunction from the current state of + * the builder + * + * @return ProgramVertexFixedFunction + */ + public ProgramVertexFixedFunction create() { + mRS.validate(); + int[] tmp = new int[(mInputCount + mOutputCount + mConstantCount + mTextureCount) * 2]; + int idx = 0; + + for (int i=0; i < mInputCount; i++) { + tmp[idx++] = ProgramParam.INPUT.mID; + tmp[idx++] = mInputs[i].getID(); + } + for (int i=0; i < mOutputCount; i++) { + tmp[idx++] = ProgramParam.OUTPUT.mID; + tmp[idx++] = mOutputs[i].getID(); + } + for (int i=0; i < mConstantCount; i++) { + tmp[idx++] = ProgramParam.CONSTANT.mID; + tmp[idx++] = mConstants[i].getID(); + } + for (int i=0; i < mTextureCount; i++) { + tmp[idx++] = ProgramParam.TEXTURE_TYPE.mID; + tmp[idx++] = mTextureTypes[i].mID; + } + + int id = mRS.nProgramVertexCreate(mShader, tmp); + ProgramVertexFixedFunction pv = new ProgramVertexFixedFunction(id, mRS); + initProgram(pv); + return pv; + } + } + + public static class Builder { + boolean mTextureMatrixEnable; + String mShader; + RenderScript mRS; + + /** + * Creates a builder for fixed function vertex program + * + * @param rs Context to which the program will belong. + */ + public Builder(RenderScript rs) { + mRS = rs; + } + + /** + * Specifies whether texture matrix calculations are to be added + * to the shader + * + */ + public Builder setTextureMatrixEnable(boolean enable) { + mTextureMatrixEnable = enable; + return this; + } + static Type getConstantInputType(RenderScript rs) { + Element.Builder b = new Element.Builder(rs); + b.add(Element.MATRIX4X4(rs), "MV"); + b.add(Element.MATRIX4X4(rs), "P"); + b.add(Element.MATRIX4X4(rs), "TexMatrix"); + b.add(Element.MATRIX4X4(rs), "MVP"); + + Type.Builder typeBuilder = new Type.Builder(rs, b.create()); + typeBuilder.setX(1); + return typeBuilder.create(); + } + + private void buildShaderString() { + + mShader = "//rs_shader_internal\n"; + mShader += "varying vec4 varColor;\n"; + mShader += "varying vec2 varTex0;\n"; + + mShader += "void main() {\n"; + mShader += " gl_Position = UNI_MVP * ATTRIB_position;\n"; + mShader += " gl_PointSize = 1.0;\n"; + + mShader += " varColor = ATTRIB_color;\n"; + if (mTextureMatrixEnable) { + mShader += " varTex0 = (UNI_TexMatrix * vec4(ATTRIB_texture0, 0.0, 1.0)).xy;\n"; + } else { + mShader += " varTex0 = ATTRIB_texture0;\n"; + } + mShader += "}\n"; + } + + /** + * Creates ProgramVertexFixedFunction from the current state of + * the builder + * + * @return Fixed function emulation ProgramVertex + */ + public ProgramVertexFixedFunction create() { + buildShaderString(); + + InternalBuilder sb = new InternalBuilder(mRS); + sb.setShader(mShader); + sb.addConstant(getConstantInputType(mRS)); + + Element.Builder b = new Element.Builder(mRS); + b.add(Element.F32_4(mRS), "position"); + b.add(Element.F32_4(mRS), "color"); + b.add(Element.F32_3(mRS), "normal"); + b.add(Element.F32_2(mRS), "texture0"); + sb.addInput(b.create()); + + return sb.create(); + } + } + + /** + * Helper class to store modelview, projection and texture + * matrices for ProgramVertexFixedFunction + * + */ + public static class Constants { + static final int MODELVIEW_OFFSET = 0; + static final int PROJECTION_OFFSET = 16; + static final int TEXTURE_OFFSET = 32; + + Matrix4f mModel; + Matrix4f mProjection; + Matrix4f mTexture; + + Allocation mAlloc; + Allocation getAllocation() { + return mAlloc; + } + private FieldPacker mIOBuffer; + + /** + * Creates a buffer to store fixed function emulation matrices + * + * @param rs Context to which the allocation will belong. + **/ + public Constants(RenderScript rs) { + Type constInputType = ProgramVertexFixedFunction.Builder.getConstantInputType(rs); + mAlloc = Allocation.createTyped(rs, constInputType); + int bufferSize = constInputType.getElement().getSizeBytes()* + constInputType.getCount(); + mIOBuffer = new FieldPacker(bufferSize); + mModel = new Matrix4f(); + mProjection = new Matrix4f(); + mTexture = new Matrix4f(); + setModelview(new Matrix4f()); + setProjection(new Matrix4f()); + setTexture(new Matrix4f()); + } + + /** + * Forces deallocation of memory backing the contant matrices. + * Normally, this is unnecessary and will be garbage collected + * + */ + public void destroy() { + mAlloc.destroy(); + mAlloc = null; + } + + private void addToBuffer(int offset, Matrix4f m) { + mIOBuffer.reset(offset); + for(int i = 0; i < 16; i ++) { + mIOBuffer.addF32(m.mMat[i]); + } + mAlloc.setFromFieldPacker(0, mIOBuffer); + } + + /** + * Sets the modelview matrix in the fixed function matrix buffer + * + * @param m modelview matrix + */ + public void setModelview(Matrix4f m) { + mModel.load(m); + addToBuffer(MODELVIEW_OFFSET*4, m); + } + + /** + * Sets the projection matrix in the fixed function matrix buffer + * + * @param m projection matrix + */ + public void setProjection(Matrix4f m) { + mProjection.load(m); + addToBuffer(PROJECTION_OFFSET*4, m); + } + + /** + * Sets the texture matrix in the fixed function matrix buffer. + * Texture matrix must be enabled in the + * ProgramVertexFixedFunction builder for the shader to utilize + * it. + * + * @param m modelview matrix + */ + public void setTexture(Matrix4f m) { + mTexture.load(m); + addToBuffer(TEXTURE_OFFSET*4, m); + } + } +} diff --git a/graphics/java/android/renderscript/Primitive.java b/graphics/java/android/renderscript/RSDriverException.java index 7925cac..ce85b53 100644 --- a/graphics/java/android/renderscript/Primitive.java +++ b/graphics/java/android/renderscript/RSDriverException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,14 @@ package android.renderscript; -/** - * @hide - **/ -public enum Primitive { - POINT (0), - LINE (1), - LINE_STRIP (2), - TRIANGLE (3), - TRIANGLE_STRIP (4), - TRIANGLE_FAN (5); - int mID; - Primitive(int id) { - mID = id; +/** + * Base class for all exceptions thrown by the Android + * Renderscript + */ +public class RSDriverException extends RSRuntimeException { + public RSDriverException(String string) { + super(string); } } diff --git a/graphics/java/android/renderscript/RSIllegalArgumentException.java b/graphics/java/android/renderscript/RSIllegalArgumentException.java new file mode 100644 index 0000000..954c0e8 --- /dev/null +++ b/graphics/java/android/renderscript/RSIllegalArgumentException.java @@ -0,0 +1,30 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +/** + * Base class for all exceptions thrown by the Android + * Renderscript + */ +public class RSIllegalArgumentException extends RSRuntimeException { + public RSIllegalArgumentException(String string) { + super(string); + } +} + + diff --git a/graphics/java/android/renderscript/RSInvalidStateException.java b/graphics/java/android/renderscript/RSInvalidStateException.java new file mode 100644 index 0000000..691aeba --- /dev/null +++ b/graphics/java/android/renderscript/RSInvalidStateException.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + + +/** + * Base class for all exceptions thrown by the Android + * Renderscript + */ +public class RSInvalidStateException extends RSRuntimeException { + public RSInvalidStateException(String string) { + super(string); + } +} + + + diff --git a/graphics/java/android/renderscript/Dimension.java b/graphics/java/android/renderscript/RSRuntimeException.java index f29057d..5a16478 100644 --- a/graphics/java/android/renderscript/Dimension.java +++ b/graphics/java/android/renderscript/RSRuntimeException.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 The Android Open Source Project + * Copyright (C) 2010 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,20 +16,15 @@ package android.renderscript; -/** - * @hide - **/ -public enum Dimension { - X (0), - Y (1), - Z (2), - LOD (3), - FACE (4), - ARRAY_0 (100); - int mID; - Dimension(int id) { - mID = id; +/** + * Base class for all exceptions thrown by the Android + * Renderscript + */ +public class RSRuntimeException + extends java.lang.RuntimeException { + public RSRuntimeException(String string) { + super(string); } } diff --git a/graphics/java/android/renderscript/RSSurfaceView.java b/graphics/java/android/renderscript/RSSurfaceView.java index f05e84c..199952c 100644 --- a/graphics/java/android/renderscript/RSSurfaceView.java +++ b/graphics/java/android/renderscript/RSSurfaceView.java @@ -25,22 +25,21 @@ import android.os.Handler; import android.os.Message; import android.util.AttributeSet; import android.util.Log; -import android.util.Log; import android.view.Surface; import android.view.SurfaceHolder; import android.view.SurfaceView; /** - * @hide - * - **/ + * The Surface View for a graphics renderscript (RenderScriptGL) to draw on. + */ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder mSurfaceHolder; private RenderScriptGL mRS; /** * Standard View constructor. In order to render something, you - * must call {@link #setRenderer} to register a renderer. + * must call {@link android.opengl.GLSurfaceView#setRenderer} to + * register a renderer. */ public RSSurfaceView(Context context) { super(context); @@ -50,7 +49,8 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback /** * Standard View constructor. In order to render something, you - * must call {@link #setRenderer} to register a renderer. + * must call {@link android.opengl.GLSurfaceView#setRenderer} to + * register a renderer. */ public RSSurfaceView(Context context, AttributeSet attrs) { super(context, attrs); @@ -70,7 +70,6 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback * not normally called or subclassed by clients of RSSurfaceView. */ public void surfaceCreated(SurfaceHolder holder) { - Log.v(RenderScript.LOG_TAG, "surfaceCreated"); mSurfaceHolder = holder; } @@ -80,9 +79,8 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback */ public void surfaceDestroyed(SurfaceHolder holder) { // Surface will be destroyed when we return - Log.v(RenderScript.LOG_TAG, "surfaceDestroyed"); if (mRS != null) { - mRS.contextSetSurface(0, 0, null); + mRS.setSurface(null, 0, 0); } } @@ -91,23 +89,21 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback * not normally called or subclassed by clients of RSSurfaceView. */ public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) { - Log.v(RenderScript.LOG_TAG, "surfaceChanged"); if (mRS != null) { - mRS.contextSetSurface(w, h, holder.getSurface()); + mRS.setSurface(holder, w, h); } } - /** + /** * Inform the view that the activity is paused. The owner of this view must * call this method when the activity is paused. Calling this method will * pause the rendering thread. * Must not be called before a renderer has been set. */ - public void onPause() { + public void pause() { if(mRS != null) { mRS.pause(); } - //Log.v(RenderScript.LOG_TAG, "onPause"); } /** @@ -117,53 +113,28 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback * thread. * Must not be called before a renderer has been set. */ - public void onResume() { + public void resume() { if(mRS != null) { mRS.resume(); } - //Log.v(RenderScript.LOG_TAG, "onResume"); - } - - /** - * Queue a runnable to be run on the GL rendering thread. This can be used - * to communicate with the Renderer on the rendering thread. - * Must not be called before a renderer has been set. - * @param r the runnable to be run on the GL rendering thread. - */ - public void queueEvent(Runnable r) { - //Log.v(RenderScript.LOG_TAG, "queueEvent"); } - /** - * This method is used as part of the View class and is not normally - * called or subclassed by clients of RSSurfaceView. - * Must not be called before a renderer has been set. - */ - @Override - protected void onDetachedFromWindow() { - super.onDetachedFromWindow(); + public RenderScriptGL createRenderScriptGL(RenderScriptGL.SurfaceConfig sc) { + RenderScriptGL rs = new RenderScriptGL(this.getContext(), sc); + setRenderScriptGL(rs); + return rs; } - // ---------------------------------------------------------------------- - - public RenderScriptGL createRenderScript(boolean useDepth, boolean forceSW) { - Log.v(RenderScript.LOG_TAG, "createRenderScript"); - mRS = new RenderScriptGL(useDepth, forceSW); - return mRS; - } - - public RenderScriptGL createRenderScript(boolean useDepth) { - return createRenderScript(useDepth, false); - } - - public void destroyRenderScript() { - Log.v(RenderScript.LOG_TAG, "destroyRenderScript"); + public void destroyRenderScriptGL() { mRS.destroy(); mRS = null; } - - public void createRenderScript(RenderScriptGL rs) { + + public void setRenderScriptGL(RenderScriptGL rs) { mRS = rs; } -} + public RenderScriptGL getRenderScriptGL() { + return mRS; + } +} diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index a935243..b51279a 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -18,6 +18,8 @@ package android.renderscript; import java.lang.reflect.Field; +import android.content.Context; +import android.content.res.AssetManager; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Config; @@ -26,24 +28,29 @@ import android.view.Surface; /** - * @hide + * RenderScript base master class. An instance of this class creates native + * worker threads for processing commands from this object. This base class + * does not provide any extended capabilities beyond simple data processing. + * For extended capabilities use derived classes such as RenderScriptGL. + * + * * **/ public class RenderScript { static final String LOG_TAG = "RenderScript_jni"; - protected static final boolean DEBUG = false; + static final boolean DEBUG = false; @SuppressWarnings({"UnusedDeclaration", "deprecation"}) - protected static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; - + static final boolean LOG_ENABLED = DEBUG ? Config.LOGD : Config.LOGV; + private Context mApplicationContext; - /* + /* * We use a class initializer to allow the native code to cache some * field offsets. */ @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) - protected static boolean sInitialized; - native protected static void _nInit(); + static boolean sInitialized; + native static void _nInit(); static { @@ -53,155 +60,587 @@ public class RenderScript { _nInit(); sInitialized = true; } catch (UnsatisfiedLinkError e) { - Log.d(LOG_TAG, "RenderScript JNI library not found!"); + Log.e(LOG_TAG, "Error loading RS jni library: " + e); + throw new RSRuntimeException("Error loading RS jni library: " + e); } } - native void nInitElements(int a8, int rgba4444, int rgba8888, int rgb565); - + // Non-threadsafe functions. native int nDeviceCreate(); native void nDeviceDestroy(int dev); native void nDeviceSetConfig(int dev, int param, int value); - native int nContextCreateGL(int dev, int ver, boolean useDepth); - native int nContextCreate(int dev, int ver); - native void nContextDestroy(int con); - native void nContextSetSurface(int w, int h, Surface sur); - native void nContextSetPriority(int p); - native void nContextDump(int bits); - - native void nContextBindRootScript(int script); - native void nContextBindSampler(int sampler, int slot); - native void nContextBindProgramFragmentStore(int pfs); - native void nContextBindProgramFragment(int pf); - native void nContextBindProgramVertex(int pf); - native void nContextBindProgramRaster(int pr); - native void nContextPause(); - native void nContextResume(); - native int nContextGetMessage(int[] data, boolean wait); - native void nContextInitToClient(); - native void nContextDeinitToClient(); - - native void nAssignName(int obj, byte[] name); - native void nObjDestroy(int id); - native void nObjDestroyOOB(int id); - native int nFileOpen(byte[] name); - - - native int nElementCreate(int type, int kind, boolean norm, int vecSize); - native int nElementCreate2(int[] elements, String[] names); - - native void nTypeBegin(int elementID); - native void nTypeAdd(int dim, int val); - native int nTypeCreate(); - native void nTypeFinalDestroy(Type t); - native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs); - - native int nAllocationCreateTyped(int type); - native int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp); - native int nAllocationCreateBitmapRef(int type, Bitmap bmp); - native int nAllocationCreateFromBitmapBoxed(int dstFmt, boolean genMips, Bitmap bmp); - native int nAllocationCreateFromAssetStream(int dstFmt, boolean genMips, int assetStream); - - native void nAllocationUploadToTexture(int alloc, boolean genMips, int baseMioLevel); - native void nAllocationUploadToBufferObject(int alloc); - - native void nAllocationSubData1D(int id, int off, int count, int[] d, int sizeBytes); - native void nAllocationSubData1D(int id, int off, int count, short[] d, int sizeBytes); - native void nAllocationSubData1D(int id, int off, int count, byte[] d, int sizeBytes); - native void nAllocationSubData1D(int id, int off, int count, float[] d, int sizeBytes); - - native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d, int sizeBytes); - native void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes); - native void nAllocationRead(int id, int[] d); - native void nAllocationRead(int id, float[] d); - native void nAllocationSubDataFromObject(int id, Type t, int offset, Object o); - native void nAllocationSubReadFromObject(int id, Type t, int offset, Object o); - - native void nAdapter1DBindAllocation(int ad, int alloc); - native void nAdapter1DSetConstraint(int ad, int dim, int value); - native void nAdapter1DData(int ad, int[] d); - native void nAdapter1DData(int ad, float[] d); - native void nAdapter1DSubData(int ad, int off, int count, int[] d); - native void nAdapter1DSubData(int ad, int off, int count, float[] d); - native int nAdapter1DCreate(); - - native void nAdapter2DBindAllocation(int ad, int alloc); - native void nAdapter2DSetConstraint(int ad, int dim, int value); - native void nAdapter2DData(int ad, int[] d); - native void nAdapter2DData(int ad, float[] d); - native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, int[] d); - native void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, float[] d); - native int nAdapter2DCreate(); - - native void nScriptBindAllocation(int script, int alloc, int slot); - native void nScriptSetClearColor(int script, float r, float g, float b, float a); - native void nScriptSetClearDepth(int script, float depth); - native void nScriptSetClearStencil(int script, int stencil); - native void nScriptSetTimeZone(int script, byte[] timeZone); - native void nScriptSetType(int type, boolean writable, String name, int slot); - native void nScriptSetRoot(boolean isRoot); - native void nScriptSetInvokable(String name, int slot); - native void nScriptInvoke(int id, int slot); - - native void nScriptCBegin(); - native void nScriptCSetScript(byte[] script, int offset, int length); - native int nScriptCCreate(); - native void nScriptCAddDefineI32(String name, int value); - native void nScriptCAddDefineF(String name, float value); - - native void nSamplerBegin(); - native void nSamplerSet(int param, int value); - native int nSamplerCreate(); - - native void nProgramFragmentStoreBegin(int in, int out); - native void nProgramFragmentStoreDepthFunc(int func); - native void nProgramFragmentStoreDepthMask(boolean enable); - native void nProgramFragmentStoreColorMask(boolean r, boolean g, boolean b, boolean a); - native void nProgramFragmentStoreBlendFunc(int src, int dst); - native void nProgramFragmentStoreDither(boolean enable); - native int nProgramFragmentStoreCreate(); - - native int nProgramRasterCreate(int in, int out, boolean pointSmooth, boolean lineSmooth, boolean pointSprite); - native void nProgramRasterSetLineWidth(int pr, float v); - native void nProgramRasterSetPointSize(int pr, float v); - - native void nProgramBindConstants(int pv, int slot, int mID); - native void nProgramBindTexture(int vpf, int slot, int a); - native void nProgramBindSampler(int vpf, int slot, int s); - - native int nProgramFragmentCreate(int[] params); - native int nProgramFragmentCreate2(String shader, int[] params); - - native int nProgramVertexCreate(boolean texMat); - native int nProgramVertexCreate2(String shader, int[] params); - - native void nLightBegin(); - native void nLightSetIsMono(boolean isMono); - native void nLightSetIsLocal(boolean isLocal); - native int nLightCreate(); - native void nLightSetColor(int l, float r, float g, float b); - native void nLightSetPosition(int l, float x, float y, float z); - - native int nSimpleMeshCreate(int batchID, int idxID, int[] vtxID, int prim); - native void nSimpleMeshBindVertex(int id, int alloc, int slot); - native void nSimpleMeshBindIndex(int id, int alloc); - - native void nAnimationBegin(int attribCount, int keyframeCount); - native void nAnimationAdd(float time, float[] attribs); - native int nAnimationCreate(); - - protected int mDev; - protected int mContext; - @SuppressWarnings({"FieldCanBeLocal"}) - protected MessageThread mMessageThread; + native void nContextGetUserMessage(int con, int[] data); + native String nContextGetErrorMessage(int con); + native int nContextPeekMessage(int con, int[] subID, boolean wait); + native void nContextInitToClient(int con); + native void nContextDeinitToClient(int con); + + + // Methods below are wrapped to protect the non-threadsafe + // lockless fifo. + native int rsnContextCreateGL(int dev, int ver, + int colorMin, int colorPref, + int alphaMin, int alphaPref, + int depthMin, int depthPref, + int stencilMin, int stencilPref, + int samplesMin, int samplesPref, float samplesQ, int dpi); + synchronized int nContextCreateGL(int dev, int ver, + int colorMin, int colorPref, + int alphaMin, int alphaPref, + int depthMin, int depthPref, + int stencilMin, int stencilPref, + int samplesMin, int samplesPref, float samplesQ, int dpi) { + return rsnContextCreateGL(dev, ver, colorMin, colorPref, + alphaMin, alphaPref, depthMin, depthPref, + stencilMin, stencilPref, + samplesMin, samplesPref, samplesQ, dpi); + } + native int rsnContextCreate(int dev, int ver); + synchronized int nContextCreate(int dev, int ver) { + return rsnContextCreate(dev, ver); + } + native void rsnContextDestroy(int con); + synchronized void nContextDestroy() { + validate(); + rsnContextDestroy(mContext); + } + native void rsnContextSetSurface(int con, int w, int h, Surface sur); + synchronized void nContextSetSurface(int w, int h, Surface sur) { + validate(); + rsnContextSetSurface(mContext, w, h, sur); + } + native void rsnContextSetPriority(int con, int p); + synchronized void nContextSetPriority(int p) { + validate(); + rsnContextSetPriority(mContext, p); + } + native void rsnContextDump(int con, int bits); + synchronized void nContextDump(int bits) { + validate(); + rsnContextDump(mContext, bits); + } + native void rsnContextFinish(int con); + synchronized void nContextFinish() { + validate(); + rsnContextFinish(mContext); + } + + native void rsnContextBindRootScript(int con, int script); + synchronized void nContextBindRootScript(int script) { + validate(); + rsnContextBindRootScript(mContext, script); + } + native void rsnContextBindSampler(int con, int sampler, int slot); + synchronized void nContextBindSampler(int sampler, int slot) { + validate(); + rsnContextBindSampler(mContext, sampler, slot); + } + native void rsnContextBindProgramStore(int con, int pfs); + synchronized void nContextBindProgramStore(int pfs) { + validate(); + rsnContextBindProgramStore(mContext, pfs); + } + native void rsnContextBindProgramFragment(int con, int pf); + synchronized void nContextBindProgramFragment(int pf) { + validate(); + rsnContextBindProgramFragment(mContext, pf); + } + native void rsnContextBindProgramVertex(int con, int pv); + synchronized void nContextBindProgramVertex(int pv) { + validate(); + rsnContextBindProgramVertex(mContext, pv); + } + native void rsnContextBindProgramRaster(int con, int pr); + synchronized void nContextBindProgramRaster(int pr) { + validate(); + rsnContextBindProgramRaster(mContext, pr); + } + native void rsnContextPause(int con); + synchronized void nContextPause() { + validate(); + rsnContextPause(mContext); + } + native void rsnContextResume(int con); + synchronized void nContextResume() { + validate(); + rsnContextResume(mContext); + } + + native void rsnAssignName(int con, int obj, byte[] name); + synchronized void nAssignName(int obj, byte[] name) { + validate(); + rsnAssignName(mContext, obj, name); + } + native String rsnGetName(int con, int obj); + synchronized String nGetName(int obj) { + validate(); + return rsnGetName(mContext, obj); + } + native void rsnObjDestroy(int con, int id); + synchronized void nObjDestroy(int id) { + // There is a race condition here. The calling code may be run + // by the gc while teardown is occuring. This protects againts + // deleting dead objects. + if (mContext != 0) { + rsnObjDestroy(mContext, id); + } + } + + native int rsnElementCreate(int con, int type, int kind, boolean norm, int vecSize); + synchronized int nElementCreate(int type, int kind, boolean norm, int vecSize) { + validate(); + return rsnElementCreate(mContext, type, kind, norm, vecSize); + } + native int rsnElementCreate2(int con, int[] elements, String[] names, int[] arraySizes); + synchronized int nElementCreate2(int[] elements, String[] names, int[] arraySizes) { + validate(); + return rsnElementCreate2(mContext, elements, names, arraySizes); + } + native void rsnElementGetNativeData(int con, int id, int[] elementData); + synchronized void nElementGetNativeData(int id, int[] elementData) { + validate(); + rsnElementGetNativeData(mContext, id, elementData); + } + native void rsnElementGetSubElements(int con, int id, int[] IDs, String[] names); + synchronized void nElementGetSubElements(int id, int[] IDs, String[] names) { + validate(); + rsnElementGetSubElements(mContext, id, IDs, names); + } + + native int rsnTypeCreate(int con, int eid, int x, int y, int z, boolean mips, boolean faces); + synchronized int nTypeCreate(int eid, int x, int y, int z, boolean mips, boolean faces) { + validate(); + return rsnTypeCreate(mContext, eid, x, y, z, mips, faces); + } + native void rsnTypeGetNativeData(int con, int id, int[] typeData); + synchronized void nTypeGetNativeData(int id, int[] typeData) { + validate(); + rsnTypeGetNativeData(mContext, id, typeData); + } + + native int rsnAllocationCreateTyped(int con, int type, int mip, int usage); + synchronized int nAllocationCreateTyped(int type, int mip, int usage) { + validate(); + return rsnAllocationCreateTyped(mContext, type, mip, usage); + } + native int rsnAllocationCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage); + synchronized int nAllocationCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) { + validate(); + return rsnAllocationCreateFromBitmap(mContext, type, mip, bmp, usage); + } + native int rsnAllocationCubeCreateFromBitmap(int con, int type, int mip, Bitmap bmp, int usage); + synchronized int nAllocationCubeCreateFromBitmap(int type, int mip, Bitmap bmp, int usage) { + validate(); + return rsnAllocationCubeCreateFromBitmap(mContext, type, mip, bmp, usage); + } + native int rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp); + synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) { + validate(); + return rsnAllocationCreateBitmapRef(mContext, type, bmp); + } + native int rsnAllocationCreateFromAssetStream(int con, int mips, int assetStream, int usage); + synchronized int nAllocationCreateFromAssetStream(int mips, int assetStream, int usage) { + validate(); + return rsnAllocationCreateFromAssetStream(mContext, mips, assetStream, usage); + } + + native void rsnAllocationCopyToBitmap(int con, int alloc, Bitmap bmp); + synchronized void nAllocationCopyToBitmap(int alloc, Bitmap bmp) { + validate(); + rsnAllocationCopyToBitmap(mContext, alloc, bmp); + } + + + native void rsnAllocationSyncAll(int con, int alloc, int src); + synchronized void nAllocationSyncAll(int alloc, int src) { + validate(); + rsnAllocationSyncAll(mContext, alloc, src); + } + native void rsnAllocationGenerateMipmaps(int con, int alloc); + synchronized void nAllocationGenerateMipmaps(int alloc) { + validate(); + rsnAllocationGenerateMipmaps(mContext, alloc); + } + native void rsnAllocationCopyFromBitmap(int con, int alloc, Bitmap bmp); + synchronized void nAllocationCopyFromBitmap(int alloc, Bitmap bmp) { + validate(); + rsnAllocationCopyFromBitmap(mContext, alloc, bmp); + } + + + native void rsnAllocationData1D(int con, int id, int off, int mip, int count, int[] d, int sizeBytes); + synchronized void nAllocationData1D(int id, int off, int mip, int count, int[] d, int sizeBytes) { + validate(); + rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes); + } + native void rsnAllocationData1D(int con, int id, int off, int mip, int count, short[] d, int sizeBytes); + synchronized void nAllocationData1D(int id, int off, int mip, int count, short[] d, int sizeBytes) { + validate(); + rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes); + } + native void rsnAllocationData1D(int con, int id, int off, int mip, int count, byte[] d, int sizeBytes); + synchronized void nAllocationData1D(int id, int off, int mip, int count, byte[] d, int sizeBytes) { + validate(); + rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes); + } + native void rsnAllocationData1D(int con, int id, int off, int mip, int count, float[] d, int sizeBytes); + synchronized void nAllocationData1D(int id, int off, int mip, int count, float[] d, int sizeBytes) { + validate(); + rsnAllocationData1D(mContext, id, off, mip, count, d, sizeBytes); + } + + native void rsnAllocationElementData1D(int con, int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes); + synchronized void nAllocationElementData1D(int id, int xoff, int mip, int compIdx, byte[] d, int sizeBytes) { + validate(); + rsnAllocationElementData1D(mContext, id, xoff, mip, compIdx, d, sizeBytes); + } + + native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes); + synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, byte[] d, int sizeBytes) { + validate(); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes); + } + native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes); + synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, short[] d, int sizeBytes) { + validate(); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes); + } + native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes); + synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, int[] d, int sizeBytes) { + validate(); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes); + } + native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes); + synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, int w, int h, float[] d, int sizeBytes) { + validate(); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, w, h, d, sizeBytes); + } + native void rsnAllocationData2D(int con, int id, int xoff, int yoff, int mip, int face, Bitmap b); + synchronized void nAllocationData2D(int id, int xoff, int yoff, int mip, int face, Bitmap b) { + validate(); + rsnAllocationData2D(mContext, id, xoff, yoff, mip, face, b); + } + + native void rsnAllocationRead(int con, int id, byte[] d); + synchronized void nAllocationRead(int id, byte[] d) { + validate(); + rsnAllocationRead(mContext, id, d); + } + native void rsnAllocationRead(int con, int id, short[] d); + synchronized void nAllocationRead(int id, short[] d) { + validate(); + rsnAllocationRead(mContext, id, d); + } + native void rsnAllocationRead(int con, int id, int[] d); + synchronized void nAllocationRead(int id, int[] d) { + validate(); + rsnAllocationRead(mContext, id, d); + } + native void rsnAllocationRead(int con, int id, float[] d); + synchronized void nAllocationRead(int id, float[] d) { + validate(); + rsnAllocationRead(mContext, id, d); + } + native int rsnAllocationGetType(int con, int id); + synchronized int nAllocationGetType(int id) { + validate(); + return rsnAllocationGetType(mContext, id); + } + + native void rsnAllocationResize1D(int con, int id, int dimX); + synchronized void nAllocationResize1D(int id, int dimX) { + validate(); + rsnAllocationResize1D(mContext, id, dimX); + } + native void rsnAllocationResize2D(int con, int id, int dimX, int dimY); + synchronized void nAllocationResize2D(int id, int dimX, int dimY) { + validate(); + rsnAllocationResize2D(mContext, id, dimX, dimY); + } + + native int rsnFileA3DCreateFromAssetStream(int con, int assetStream); + synchronized int nFileA3DCreateFromAssetStream(int assetStream) { + validate(); + return rsnFileA3DCreateFromAssetStream(mContext, assetStream); + } + native int rsnFileA3DCreateFromFile(int con, String path); + synchronized int nFileA3DCreateFromFile(String path) { + validate(); + return rsnFileA3DCreateFromFile(mContext, path); + } + native int rsnFileA3DCreateFromAsset(int con, AssetManager mgr, String path); + synchronized int nFileA3DCreateFromAsset(AssetManager mgr, String path) { + validate(); + return rsnFileA3DCreateFromAsset(mContext, mgr, path); + } + native int rsnFileA3DGetNumIndexEntries(int con, int fileA3D); + synchronized int nFileA3DGetNumIndexEntries(int fileA3D) { + validate(); + return rsnFileA3DGetNumIndexEntries(mContext, fileA3D); + } + native void rsnFileA3DGetIndexEntries(int con, int fileA3D, int numEntries, int[] IDs, String[] names); + synchronized void nFileA3DGetIndexEntries(int fileA3D, int numEntries, int[] IDs, String[] names) { + validate(); + rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names); + } + native int rsnFileA3DGetEntryByIndex(int con, int fileA3D, int index); + synchronized int nFileA3DGetEntryByIndex(int fileA3D, int index) { + validate(); + return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index); + } + + native int rsnFontCreateFromFile(int con, String fileName, float size, int dpi); + synchronized int nFontCreateFromFile(String fileName, float size, int dpi) { + validate(); + return rsnFontCreateFromFile(mContext, fileName, size, dpi); + } + native int rsnFontCreateFromAssetStream(int con, String name, float size, int dpi, int assetStream); + synchronized int nFontCreateFromAssetStream(String name, float size, int dpi, int assetStream) { + validate(); + return rsnFontCreateFromAssetStream(mContext, name, size, dpi, assetStream); + } + native int rsnFontCreateFromAsset(int con, AssetManager mgr, String path, float size, int dpi); + synchronized int nFontCreateFromAsset(AssetManager mgr, String path, float size, int dpi) { + validate(); + return rsnFontCreateFromAsset(mContext, mgr, path, size, dpi); + } - Element mElement_USER_U8; - Element mElement_USER_I8; - Element mElement_USER_U16; - Element mElement_USER_I16; - Element mElement_USER_U32; - Element mElement_USER_I32; - Element mElement_USER_F32; + + native void rsnScriptBindAllocation(int con, int script, int alloc, int slot); + synchronized void nScriptBindAllocation(int script, int alloc, int slot) { + validate(); + rsnScriptBindAllocation(mContext, script, alloc, slot); + } + native void rsnScriptSetTimeZone(int con, int script, byte[] timeZone); + synchronized void nScriptSetTimeZone(int script, byte[] timeZone) { + validate(); + rsnScriptSetTimeZone(mContext, script, timeZone); + } + native void rsnScriptInvoke(int con, int id, int slot); + synchronized void nScriptInvoke(int id, int slot) { + validate(); + rsnScriptInvoke(mContext, id, slot); + } + native void rsnScriptInvokeV(int con, int id, int slot, byte[] params); + synchronized void nScriptInvokeV(int id, int slot, byte[] params) { + validate(); + rsnScriptInvokeV(mContext, id, slot, params); + } + native void rsnScriptSetVarI(int con, int id, int slot, int val); + synchronized void nScriptSetVarI(int id, int slot, int val) { + validate(); + rsnScriptSetVarI(mContext, id, slot, val); + } + native void rsnScriptSetVarJ(int con, int id, int slot, long val); + synchronized void nScriptSetVarJ(int id, int slot, long val) { + validate(); + rsnScriptSetVarJ(mContext, id, slot, val); + } + native void rsnScriptSetVarF(int con, int id, int slot, float val); + synchronized void nScriptSetVarF(int id, int slot, float val) { + validate(); + rsnScriptSetVarF(mContext, id, slot, val); + } + native void rsnScriptSetVarD(int con, int id, int slot, double val); + synchronized void nScriptSetVarD(int id, int slot, double val) { + validate(); + rsnScriptSetVarD(mContext, id, slot, val); + } + native void rsnScriptSetVarV(int con, int id, int slot, byte[] val); + synchronized void nScriptSetVarV(int id, int slot, byte[] val) { + validate(); + rsnScriptSetVarV(mContext, id, slot, val); + } + native void rsnScriptSetVarObj(int con, int id, int slot, int val); + synchronized void nScriptSetVarObj(int id, int slot, int val) { + validate(); + rsnScriptSetVarObj(mContext, id, slot, val); + } + + native void rsnScriptCBegin(int con); + synchronized void nScriptCBegin() { + validate(); + rsnScriptCBegin(mContext); + } + native void rsnScriptCSetScript(int con, byte[] script, int offset, int length); + synchronized void nScriptCSetScript(byte[] script, int offset, int length) { + validate(); + rsnScriptCSetScript(mContext, script, offset, length); + } + native int rsnScriptCCreate(int con, String packageName, String resName, String cacheDir); + synchronized int nScriptCCreate(String packageName, String resName, String cacheDir) { + validate(); + return rsnScriptCCreate(mContext, packageName, resName, cacheDir); + } + + native void rsnSamplerBegin(int con); + synchronized void nSamplerBegin() { + validate(); + rsnSamplerBegin(mContext); + } + native void rsnSamplerSet(int con, int param, int value); + synchronized void nSamplerSet(int param, int value) { + validate(); + rsnSamplerSet(mContext, param, value); + } + native void rsnSamplerSet2(int con, int param, float value); + synchronized void nSamplerSet2(int param, float value) { + validate(); + rsnSamplerSet2(mContext, param, value); + } + native int rsnSamplerCreate(int con); + synchronized int nSamplerCreate() { + validate(); + return rsnSamplerCreate(mContext); + } + + native void rsnProgramStoreBegin(int con, int in, int out); + synchronized void nProgramStoreBegin(int in, int out) { + validate(); + rsnProgramStoreBegin(mContext, in, out); + } + native void rsnProgramStoreDepthFunc(int con, int func); + synchronized void nProgramStoreDepthFunc(int func) { + validate(); + rsnProgramStoreDepthFunc(mContext, func); + } + native void rsnProgramStoreDepthMask(int con, boolean enable); + synchronized void nProgramStoreDepthMask(boolean enable) { + validate(); + rsnProgramStoreDepthMask(mContext, enable); + } + native void rsnProgramStoreColorMask(int con, boolean r, boolean g, boolean b, boolean a); + synchronized void nProgramStoreColorMask(boolean r, boolean g, boolean b, boolean a) { + validate(); + rsnProgramStoreColorMask(mContext, r, g, b, a); + } + native void rsnProgramStoreBlendFunc(int con, int src, int dst); + synchronized void nProgramStoreBlendFunc(int src, int dst) { + validate(); + rsnProgramStoreBlendFunc(mContext, src, dst); + } + native void rsnProgramStoreDither(int con, boolean enable); + synchronized void nProgramStoreDither(boolean enable) { + validate(); + rsnProgramStoreDither(mContext, enable); + } + native int rsnProgramStoreCreate(int con); + synchronized int nProgramStoreCreate() { + validate(); + return rsnProgramStoreCreate(mContext); + } + + native int rsnProgramRasterCreate(int con, boolean pointSmooth, boolean lineSmooth, boolean pointSprite); + synchronized int nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite) { + validate(); + return rsnProgramRasterCreate(mContext, pointSmooth, lineSmooth, pointSprite); + } + native void rsnProgramRasterSetLineWidth(int con, int pr, float v); + synchronized void nProgramRasterSetLineWidth(int pr, float v) { + validate(); + rsnProgramRasterSetLineWidth(mContext, pr, v); + } + native void rsnProgramRasterSetCullMode(int con, int pr, int mode); + synchronized void nProgramRasterSetCullMode(int pr, int mode) { + validate(); + rsnProgramRasterSetCullMode(mContext, pr, mode); + } + + native void rsnProgramBindConstants(int con, int pv, int slot, int mID); + synchronized void nProgramBindConstants(int pv, int slot, int mID) { + validate(); + rsnProgramBindConstants(mContext, pv, slot, mID); + } + native void rsnProgramBindTexture(int con, int vpf, int slot, int a); + synchronized void nProgramBindTexture(int vpf, int slot, int a) { + validate(); + rsnProgramBindTexture(mContext, vpf, slot, a); + } + native void rsnProgramBindSampler(int con, int vpf, int slot, int s); + synchronized void nProgramBindSampler(int vpf, int slot, int s) { + validate(); + rsnProgramBindSampler(mContext, vpf, slot, s); + } + native int rsnProgramFragmentCreate(int con, String shader, int[] params); + synchronized int nProgramFragmentCreate(String shader, int[] params) { + validate(); + return rsnProgramFragmentCreate(mContext, shader, params); + } + native int rsnProgramVertexCreate(int con, String shader, int[] params); + synchronized int nProgramVertexCreate(String shader, int[] params) { + validate(); + return rsnProgramVertexCreate(mContext, shader, params); + } + + native int rsnMeshCreate(int con, int vtxCount, int indexCount); + synchronized int nMeshCreate(int vtxCount, int indexCount) { + validate(); + return rsnMeshCreate(mContext, vtxCount, indexCount); + } + native void rsnMeshBindVertex(int con, int id, int alloc, int slot); + synchronized void nMeshBindVertex(int id, int alloc, int slot) { + validate(); + rsnMeshBindVertex(mContext, id, alloc, slot); + } + native void rsnMeshBindIndex(int con, int id, int alloc, int prim, int slot); + synchronized void nMeshBindIndex(int id, int alloc, int prim, int slot) { + validate(); + rsnMeshBindIndex(mContext, id, alloc, prim, slot); + } + native void rsnMeshInitVertexAttribs(int con, int id); + synchronized void nMeshInitVertexAttribs(int id) { + validate(); + rsnMeshInitVertexAttribs(mContext, id); + } + native int rsnMeshGetVertexBufferCount(int con, int id); + synchronized int nMeshGetVertexBufferCount(int id) { + validate(); + return rsnMeshGetVertexBufferCount(mContext, id); + } + native int rsnMeshGetIndexCount(int con, int id); + synchronized int nMeshGetIndexCount(int id) { + validate(); + return rsnMeshGetIndexCount(mContext, id); + } + native void rsnMeshGetVertices(int con, int id, int[] vtxIds, int vtxIdCount); + synchronized void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount) { + validate(); + rsnMeshGetVertices(mContext, id, vtxIds, vtxIdCount); + } + native void rsnMeshGetIndices(int con, int id, int[] idxIds, int[] primitives, int vtxIdCount); + synchronized void nMeshGetIndices(int id, int[] idxIds, int[] primitives, int vtxIdCount) { + validate(); + rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount); + } + + + int mDev; + int mContext; + @SuppressWarnings({"FieldCanBeLocal"}) + MessageThread mMessageThread; + + Element mElement_U8; + Element mElement_I8; + Element mElement_U16; + Element mElement_I16; + Element mElement_U32; + Element mElement_I32; + Element mElement_U64; + Element mElement_I64; + Element mElement_F32; + Element mElement_F64; + Element mElement_BOOLEAN; + + Element mElement_ELEMENT; + Element mElement_TYPE; + Element mElement_ALLOCATION; + Element mElement_SAMPLER; + Element mElement_SCRIPT; + Element mElement_MESH; + Element mElement_PROGRAM_FRAGMENT; + Element mElement_PROGRAM_VERTEX; + Element mElement_PROGRAM_RASTER; + Element mElement_PROGRAM_STORE; Element mElement_A_8; Element mElement_RGB_565; @@ -210,26 +649,101 @@ public class RenderScript { Element mElement_RGBA_4444; Element mElement_RGBA_8888; - Element mElement_INDEX_16; - Element mElement_POSITION_2; - Element mElement_POSITION_3; - Element mElement_TEXTURE_2; - Element mElement_NORMAL_3; - Element mElement_COLOR_U8_4; - Element mElement_COLOR_F32_4; + Element mElement_FLOAT_2; + Element mElement_FLOAT_3; + Element mElement_FLOAT_4; + Element mElement_UCHAR_4; + + Element mElement_MATRIX_4X4; + Element mElement_MATRIX_3X3; + Element mElement_MATRIX_2X2; + + Sampler mSampler_CLAMP_NEAREST; + Sampler mSampler_CLAMP_LINEAR; + Sampler mSampler_CLAMP_LINEAR_MIP_LINEAR; + Sampler mSampler_WRAP_NEAREST; + Sampler mSampler_WRAP_LINEAR; + Sampler mSampler_WRAP_LINEAR_MIP_LINEAR; + + ProgramStore mProgramStore_BLEND_NONE_DEPTH_TEST; + ProgramStore mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_TEST; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH; + + ProgramRaster mProgramRaster_CULL_BACK; + ProgramRaster mProgramRaster_CULL_FRONT; + ProgramRaster mProgramRaster_CULL_NONE; /////////////////////////////////////////////////////////////////////////////////// // - public static class RSMessage implements Runnable { + /** + * Base class application should derive from for handling RS messages + * coming from their scripts. When a script calls sendToClient the data + * fields will be filled in and then the run method called by a message + * handling thread. This will occur some time after sendToClient completes + * in the script. + * + */ + public static class RSMessageHandler implements Runnable { protected int[] mData; protected int mID; + protected int mLength; + public void run() { + } + } + /** + * If an application is expecting messages it should set this field to an + * instance of RSMessage. This instance will receive all the user messages + * sent from sendToClient by scripts from this context. + * + */ + RSMessageHandler mMessageCallback = null; + + public void setMessageHandler(RSMessageHandler msg) { + mMessageCallback = msg; + } + public RSMessageHandler getMessageHandler() { + return mMessageCallback; + } + + /** + * Runtime error base class. An application should derive from this class + * if it wishes to install an error handler. When errors occur at runtime + * the fields in this class will be filled and the run method called. + * + */ + public static class RSErrorHandler implements Runnable { + protected String mErrorMessage; + protected int mErrorNum; public void run() { } } - public RSMessage mMessageCallback = null; + /** + * Application Error handler. All runtime errors will be dispatched to the + * instance of RSAsyncError set here. If this field is null a + * RSRuntimeException will instead be thrown with details about the error. + * This will cause program termaination. + * + */ + RSErrorHandler mErrorCallback = null; + + public void setErrorHandler(RSErrorHandler msg) { + mErrorCallback = msg; + } + public RSErrorHandler getErrorHandler() { + return mErrorCallback; + } + + /** + * RenderScript worker threads priority enumeration. The default value is + * NORMAL. Applications wishing to do background processing such as + * wallpapers should set their priority to LOW to avoid starving forground + * processes. + */ public enum Priority { + // Remap these numbers to opaque... LOW (5), //ANDROID_PRIORITY_BACKGROUND + 5 NORMAL (-4); //ANDROID_PRIORITY_DISPLAY @@ -241,18 +755,33 @@ public class RenderScript { void validate() { if (mContext == 0) { - throw new IllegalStateException("Calling RS with no Context active."); + throw new RSInvalidStateException("Calling RS with no Context active."); } } - public void contextSetPriority(Priority p) { + + /** + * Change the priority of the worker threads for this context. + * + * @param p New priority to be set. + */ + public void setPriority(Priority p) { validate(); nContextSetPriority(p.mID); } - protected static class MessageThread extends Thread { + static class MessageThread extends Thread { RenderScript mRS; boolean mRun = true; + int[] mAuxData = new int[2]; + + static final int RS_MESSAGE_TO_CLIENT_NONE = 0; + static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1; + static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2; + static final int RS_MESSAGE_TO_CLIENT_ERROR = 3; + static final int RS_MESSAGE_TO_CLIENT_USER = 4; + + static final int RS_ERROR_FATAL_UNKNOWN = 0x1000; MessageThread(RenderScript rs) { super("RSMessageThread"); @@ -264,55 +793,123 @@ public class RenderScript { // This function is a temporary solution. The final solution will // used typed allocations where the message id is the type indicator. int[] rbuf = new int[16]; - mRS.nContextInitToClient(); + mRS.nContextInitToClient(mRS.mContext); while(mRun) { - int msg = mRS.nContextGetMessage(rbuf, true); - if (msg == 0) { - // Should only happen during teardown. - // But we want to avoid starving other threads during - // teardown by yielding until the next line in the destructor - // can execute to set mRun = false - try { - sleep(1, 0); - } catch(InterruptedException e) { + rbuf[0] = 0; + int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData, true); + int size = mAuxData[1]; + int subID = mAuxData[0]; + + if (msg == RS_MESSAGE_TO_CLIENT_USER) { + if ((size>>2) >= rbuf.length) { + rbuf = new int[(size + 3) >> 2]; + } + mRS.nContextGetUserMessage(mRS.mContext, rbuf); + + if(mRS.mMessageCallback != null) { + mRS.mMessageCallback.mData = rbuf; + mRS.mMessageCallback.mID = subID; + mRS.mMessageCallback.mLength = size; + mRS.mMessageCallback.run(); + } else { + throw new RSInvalidStateException("Received a message from the script with no message handler installed."); + } + continue; + } + + if (msg == RS_MESSAGE_TO_CLIENT_ERROR) { + String e = mRS.nContextGetErrorMessage(mRS.mContext); + + if (subID >= RS_ERROR_FATAL_UNKNOWN) { + throw new RSRuntimeException("Fatal error " + subID + ", details: " + e); + } + + if(mRS.mErrorCallback != null) { + mRS.mErrorCallback.mErrorMessage = e; + mRS.mErrorCallback.mErrorNum = subID; + mRS.mErrorCallback.run(); + } else { + //throw new RSRuntimeException("Received error num " + subID + ", details: " + e); } + continue; } - if(mRS.mMessageCallback != null) { - mRS.mMessageCallback.mData = rbuf; - mRS.mMessageCallback.mID = msg; - mRS.mMessageCallback.run(); + + // 2: teardown. + // But we want to avoid starving other threads during + // teardown by yielding until the next line in the destructor + // can execute to set mRun = false + try { + sleep(1, 0); + } catch(InterruptedException e) { } - //Log.d(LOG_TAG, "MessageThread msg " + msg + " v1 " + rbuf[0] + " v2 " + rbuf[1] + " v3 " +rbuf[2]); } Log.d(LOG_TAG, "MessageThread exiting."); } } - protected RenderScript() { + RenderScript(Context ctx) { + mApplicationContext = ctx.getApplicationContext(); } - public static RenderScript create() { - RenderScript rs = new RenderScript(); + /** + * Gets the application context associated with the RenderScript context. + * + * @return The application context. + */ + public final Context getApplicationContext() { + return mApplicationContext; + } + + /** + * Create a basic RenderScript context. + * + * @param ctx The context. + * @return RenderScript + */ + public static RenderScript create(Context ctx) { + RenderScript rs = new RenderScript(ctx); rs.mDev = rs.nDeviceCreate(); rs.mContext = rs.nContextCreate(rs.mDev, 0); rs.mMessageThread = new MessageThread(rs); rs.mMessageThread.start(); - Element.initPredefined(rs); return rs; } - public void contextDump(int bits) { + /** + * Print the currently available debugging information about the state of + * the RS context to the log. + * + */ + public void contextDump() { validate(); - nContextDump(bits); + nContextDump(0); } + /** + * Wait for any commands in the fifo between the java bindings and native to + * be processed. + * + */ + public void finish() { + nContextFinish(); + } + + /** + * Destroy this renderscript context. Once this function is called its no + * longer legal to use this or any objects created by this context. + * + */ public void destroy() { validate(); - nContextDeinitToClient(); + nContextDeinitToClient(mContext); mMessageThread.mRun = false; + try { + mMessageThread.join(); + } catch(InterruptedException e) { + } - nContextDestroy(mContext); + nContextDestroy(); mContext = 0; nDeviceDestroy(mDev); @@ -323,15 +920,10 @@ public class RenderScript { return mContext != 0; } - /////////////////////////////////////////////////////////////////////////////////// - // Root state - - protected int safeID(BaseObj o) { + int safeID(BaseObj o) { if(o != null) { - return o.mID; + return o.getID(); } return 0; } } - - diff --git a/graphics/java/android/renderscript/RenderScriptGL.java b/graphics/java/android/renderscript/RenderScriptGL.java index d1df23d..d4b5434 100644 --- a/graphics/java/android/renderscript/RenderScriptGL.java +++ b/graphics/java/android/renderscript/RenderScriptGL.java @@ -18,110 +18,277 @@ package android.renderscript; import java.lang.reflect.Field; +import android.content.Context; +import android.graphics.PixelFormat; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.util.Config; import android.util.Log; import android.view.Surface; - +import android.view.SurfaceHolder; +import android.view.SurfaceView; /** - * @hide - * + * The Graphics derivitive of RenderScript. Extends the basic context to add a + * root script which is the display window for graphical output. When the + * system needs to update the display the currently bound root script will be + * called. This script is expected to issue the rendering commands to repaint + * the screen. **/ public class RenderScriptGL extends RenderScript { private Surface mSurface; int mWidth; int mHeight; + /** + * Class which is used to describe a pixel format for a graphical buffer. + * This is used to describe the intended format of the display surface. + * + * The configuration is described by pairs of minimum and preferred bit + * depths for each component within the config and additional structural + * information. + */ + public static class SurfaceConfig { + int mDepthMin = 0; + int mDepthPref = 0; + int mStencilMin = 0; + int mStencilPref = 0; + int mColorMin = 8; + int mColorPref = 8; + int mAlphaMin = 0; + int mAlphaPref = 0; + int mSamplesMin = 1; + int mSamplesPref = 1; + float mSamplesQ = 1.f; + + public SurfaceConfig() { + } + + public SurfaceConfig(SurfaceConfig sc) { + mDepthMin = sc.mDepthMin; + mDepthPref = sc.mDepthPref; + mStencilMin = sc.mStencilMin; + mStencilPref = sc.mStencilPref; + mColorMin = sc.mColorMin; + mColorPref = sc.mColorPref; + mAlphaMin = sc.mAlphaMin; + mAlphaPref = sc.mAlphaPref; + mSamplesMin = sc.mSamplesMin; + mSamplesPref = sc.mSamplesPref; + mSamplesQ = sc.mSamplesQ; + } + + private void validateRange(int umin, int upref, int rmin, int rmax) { + if (umin < rmin || umin > rmax) { + throw new RSIllegalArgumentException("Minimum value provided out of range."); + } + if (upref < umin) { + throw new RSIllegalArgumentException("preferred must be >= Minimum."); + } + } + + /** + * Set the per-component bit depth for color (red, green, blue). This + * configures the surface for an unsigned integer buffer type. + * + * @param minimum + * @param preferred + */ + public void setColor(int minimum, int preferred) { + validateRange(minimum, preferred, 5, 8); + mColorMin = minimum; + mColorPref = preferred; + } + + /** + * Set the bit depth for alpha. This configures the surface for + * an unsigned integer buffer type. + * + * @param minimum + * @param preferred + */ + public void setAlpha(int minimum, int preferred) { + validateRange(minimum, preferred, 0, 8); + mAlphaMin = minimum; + mAlphaPref = preferred; + } + + /** + * Set the bit depth for the depth buffer. This configures the + * surface for an unsigned integer buffer type. If a minimum of 0 + * is specified then its possible no depth buffer will be + * allocated. + * + * @param minimum + * @param preferred + */ + public void setDepth(int minimum, int preferred) { + validateRange(minimum, preferred, 0, 24); + mDepthMin = minimum; + mDepthPref = preferred; + } + + /** + * Configure the multisample rendering. + * + * @param minimum The required number of samples, must be at least 1. + * @param preferred The targe number of samples, must be at least + * minimum + * @param Q The quality of samples, range 0-1. Used to decide between + * different formats which have the same number of samples but + * different rendering quality. + */ + public void setSamples(int minimum, int preferred, float Q) { + validateRange(minimum, preferred, 1, 32); + if (Q < 0.0f || Q > 1.0f) { + throw new RSIllegalArgumentException("Quality out of 0-1 range."); + } + mSamplesMin = minimum; + mSamplesPref = preferred; + mSamplesQ = Q; + } + }; + + SurfaceConfig mSurfaceConfig; + + /** + * Construct a new RenderScriptGL context. + * + * @param ctx The context. + * @param sc The desired format of the primary rendering surface. + */ + public RenderScriptGL(Context ctx, SurfaceConfig sc) { + super(ctx); + mSurfaceConfig = new SurfaceConfig(sc); - public RenderScriptGL(boolean useDepth, boolean forceSW) { mSurface = null; mWidth = 0; mHeight = 0; mDev = nDeviceCreate(); - if(forceSW) { - nDeviceSetConfig(mDev, 0, 1); + int dpi = ctx.getResources().getDisplayMetrics().densityDpi; + mContext = nContextCreateGL(mDev, 0, + mSurfaceConfig.mColorMin, mSurfaceConfig.mColorPref, + mSurfaceConfig.mAlphaMin, mSurfaceConfig.mAlphaPref, + mSurfaceConfig.mDepthMin, mSurfaceConfig.mDepthPref, + mSurfaceConfig.mStencilMin, mSurfaceConfig.mStencilPref, + mSurfaceConfig.mSamplesMin, mSurfaceConfig.mSamplesPref, + mSurfaceConfig.mSamplesQ, dpi); + if (mContext == 0) { + throw new RSDriverException("Failed to create RS context."); } - mContext = nContextCreateGL(mDev, 0, useDepth); mMessageThread = new MessageThread(this); mMessageThread.start(); - Element.initPredefined(this); } - public void contextSetSurface(int w, int h, Surface sur) { - mSurface = sur; + /** + * Bind an os surface + * + * + * @param w + * @param h + * @param sur + */ + public void setSurface(SurfaceHolder sur, int w, int h) { + validate(); + if (sur != null) { + mSurface = sur.getSurface(); + } else { + mSurface = null; + } mWidth = w; mHeight = h; - validate(); nContextSetSurface(w, h, mSurface); } + /** + * return the height of the last set surface. + * + * @return int + */ + public int getHeight() { + return mHeight; + } + + /** + * return the width of the last set surface. + * + * @return int + */ + public int getWidth() { + return mWidth; + } - void pause() { + /** + * Temporarly halt calls to the root rendering script. + * + */ + public void pause() { validate(); nContextPause(); } - void resume() { + /** + * Resume calls to the root rendering script. + * + */ + public void resume() { validate(); nContextResume(); } - public void contextBindRootScript(Script s) { + /** + * Set the script to handle calls to render the primary surface. + * + * @param s Graphics script to process rendering requests. + */ + public void bindRootScript(Script s) { validate(); nContextBindRootScript(safeID(s)); } - public void contextBindProgramFragmentStore(ProgramStore p) { + /** + * Set the default ProgramStore object seen as the parent state by the root + * rendering script. + * + * @param p + */ + public void bindProgramStore(ProgramStore p) { validate(); - nContextBindProgramFragmentStore(safeID(p)); + nContextBindProgramStore(safeID(p)); } - public void contextBindProgramFragment(ProgramFragment p) { + /** + * Set the default ProgramFragment object seen as the parent state by the + * root rendering script. + * + * @param p + */ + public void bindProgramFragment(ProgramFragment p) { validate(); nContextBindProgramFragment(safeID(p)); } - public void contextBindProgramRaster(ProgramRaster p) { + /** + * Set the default ProgramRaster object seen as the parent state by the + * root rendering script. + * + * @param p + */ + public void bindProgramRaster(ProgramRaster p) { validate(); nContextBindProgramRaster(safeID(p)); } - public void contextBindProgramVertex(ProgramVertex p) { + /** + * Set the default ProgramVertex object seen as the parent state by the + * root rendering script. + * + * @param p + */ + public void bindProgramVertex(ProgramVertex p) { validate(); nContextBindProgramVertex(safeID(p)); } - - - - ////////////////////////////////////////////////////////////////////////////////// - // File - - public class File extends BaseObj { - File(int id) { - super(RenderScriptGL.this); - mID = id; - } - } - - public File fileOpen(String s) throws IllegalStateException, IllegalArgumentException - { - if(s.length() < 1) { - throw new IllegalArgumentException("fileOpen does not accept a zero length string."); - } - - try { - byte[] bytes = s.getBytes("UTF-8"); - int id = nFileOpen(bytes); - return new File(id); - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - } - - diff --git a/graphics/java/android/renderscript/Sampler.java b/graphics/java/android/renderscript/Sampler.java index 40ba722..8ee4d72 100644 --- a/graphics/java/android/renderscript/Sampler.java +++ b/graphics/java/android/renderscript/Sampler.java @@ -29,14 +29,16 @@ import android.graphics.Bitmap; import android.graphics.BitmapFactory; /** - * @hide - * + * Sampler object which defines how data is extracted from textures. Samplers + * are attached to Program objects (currently only ProgramFragment) when those objects + * need to access texture data. **/ public class Sampler extends BaseObj { public enum Value { NEAREST (0), LINEAR (1), LINEAR_MIP_LINEAR (2), + LINEAR_MIP_NEAREST (5), WRAP (3), CLAMP (4); @@ -47,10 +49,135 @@ public class Sampler extends BaseObj { } Sampler(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); + } + + /** + * Retrieve a sampler with min and mag set to nearest and wrap modes set to + * clamp. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler CLAMP_NEAREST(RenderScript rs) { + if(rs.mSampler_CLAMP_NEAREST == null) { + Builder b = new Builder(rs); + b.setMinification(Value.NEAREST); + b.setMagnification(Value.NEAREST); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + rs.mSampler_CLAMP_NEAREST = b.create(); + } + return rs.mSampler_CLAMP_NEAREST; } + /** + * Retrieve a sampler with min and mag set to linear and wrap modes set to + * clamp. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler CLAMP_LINEAR(RenderScript rs) { + if(rs.mSampler_CLAMP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMinification(Value.LINEAR); + b.setMagnification(Value.LINEAR); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + rs.mSampler_CLAMP_LINEAR = b.create(); + } + return rs.mSampler_CLAMP_LINEAR; + } + + /** + * Retrieve a sampler with ag set to linear, min linear mipmap linear, and + * to and wrap modes set to clamp. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) { + if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMinification(Value.LINEAR_MIP_LINEAR); + b.setMagnification(Value.LINEAR); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + rs.mSampler_CLAMP_LINEAR_MIP_LINEAR = b.create(); + } + return rs.mSampler_CLAMP_LINEAR_MIP_LINEAR; + } + + /** + * Retrieve a sampler with min and mag set to nearest and wrap modes set to + * wrap. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler WRAP_NEAREST(RenderScript rs) { + if(rs.mSampler_WRAP_NEAREST == null) { + Builder b = new Builder(rs); + b.setMinification(Value.NEAREST); + b.setMagnification(Value.NEAREST); + b.setWrapS(Value.WRAP); + b.setWrapT(Value.WRAP); + rs.mSampler_WRAP_NEAREST = b.create(); + } + return rs.mSampler_WRAP_NEAREST; + } + + /** + * Retrieve a sampler with min and mag set to nearest and wrap modes set to + * wrap. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler WRAP_LINEAR(RenderScript rs) { + if(rs.mSampler_WRAP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMinification(Value.LINEAR); + b.setMagnification(Value.LINEAR); + b.setWrapS(Value.WRAP); + b.setWrapT(Value.WRAP); + rs.mSampler_WRAP_LINEAR = b.create(); + } + return rs.mSampler_WRAP_LINEAR; + } + + /** + * Retrieve a sampler with ag set to linear, min linear mipmap linear, and + * to and wrap modes set to wrap. + * + * @param rs Context to which the sampler will belong. + * + * @return Sampler + */ + public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) { + if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMinification(Value.LINEAR_MIP_LINEAR); + b.setMagnification(Value.LINEAR); + b.setWrapS(Value.WRAP); + b.setWrapT(Value.WRAP); + rs.mSampler_WRAP_LINEAR_MIP_LINEAR = b.create(); + } + return rs.mSampler_WRAP_LINEAR_MIP_LINEAR; + } + + + /** + * Builder for creating non-standard samplers. Usefull if mix and match of + * wrap modes is necesary or if anisotropic filtering is desired. + * + */ public static class Builder { RenderScript mRS; Value mMin; @@ -58,6 +185,7 @@ public class Sampler extends BaseObj { Value mWrapS; Value mWrapT; Value mWrapR; + float mAniso; public Builder(RenderScript rs) { mRS = rs; @@ -66,19 +194,21 @@ public class Sampler extends BaseObj { mWrapS = Value.WRAP; mWrapT = Value.WRAP; mWrapR = Value.WRAP; + mAniso = 1.0f; } - public void setMin(Value v) { + public void setMinification(Value v) { if (v == Value.NEAREST || v == Value.LINEAR || - v == Value.LINEAR_MIP_LINEAR) { + v == Value.LINEAR_MIP_LINEAR || + v == Value.LINEAR_MIP_NEAREST) { mMin = v; } else { throw new IllegalArgumentException("Invalid value"); } } - public void setMag(Value v) { + public void setMagnification(Value v) { if (v == Value.NEAREST || v == Value.LINEAR) { mMag = v; } else { @@ -102,9 +232,9 @@ public class Sampler extends BaseObj { } } - public void setWrapR(Value v) { - if (v == Value.WRAP || v == Value.CLAMP) { - mWrapR = v; + public void setAnisotropy(float v) { + if(v >= 0.0f) { + mAniso = v; } else { throw new IllegalArgumentException("Invalid value"); } @@ -117,6 +247,7 @@ public class Sampler extends BaseObj { rs.nSamplerSet(2, b.mWrapS.mID); rs.nSamplerSet(3, b.mWrapT.mID); rs.nSamplerSet(4, b.mWrapR.mID); + rs.nSamplerSet2(5, b.mAniso); int id = rs.nSamplerCreate(); return new Sampler(id, rs); } diff --git a/graphics/java/android/renderscript/Script.java b/graphics/java/android/renderscript/Script.java index 57ccfa3..56abba5 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -17,60 +17,127 @@ package android.renderscript; /** - * @hide + * **/ public class Script extends BaseObj { - public static final int MAX_SLOT = 16; - - boolean mIsRoot; - Type[] mTypes; - boolean[] mWritable; - Invokable[] mInvokables; - - public static class Invokable { - RenderScript mRS; - Script mScript; - int mSlot; - String mName; - - Invokable() { - mSlot = -1; - } + /** + * Only intended for use by generated reflected code. + * + * @param slot + */ + protected void invoke(int slot) { + mRS.nScriptInvoke(getID(), slot); + } - public void execute() { - mRS.nScriptInvoke(mScript.mID, mSlot); + /** + * Only intended for use by generated reflected code. + * + * @param slot + * @param v + */ + protected void invoke(int slot, FieldPacker v) { + if (v != null) { + mRS.nScriptInvokeV(getID(), slot, v.getData()); + } else { + mRS.nScriptInvoke(getID(), slot); } } + Script(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } + + /** + * Only intended for use by generated reflected code. + * + * @param va + * @param slot + */ public void bindAllocation(Allocation va, int slot) { mRS.validate(); - mRS.nScriptBindAllocation(mID, va.mID, slot); + if (va != null) { + mRS.nScriptBindAllocation(getID(), va.getID(), slot); + } else { + mRS.nScriptBindAllocation(getID(), 0, slot); + } } - public void setClearColor(float r, float g, float b, float a) { - mRS.validate(); - mRS.nScriptSetClearColor(mID, r, g, b, a); + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, float v) { + mRS.nScriptSetVarF(getID(), index, v); } - public void setClearDepth(float d) { - mRS.validate(); - mRS.nScriptSetClearDepth(mID, d); + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, double v) { + mRS.nScriptSetVarD(getID(), index, v); } - public void setClearStencil(int stencil) { - mRS.validate(); - mRS.nScriptSetClearStencil(mID, stencil); + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, int v) { + mRS.nScriptSetVarI(getID(), index, v); + } + + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, long v) { + mRS.nScriptSetVarJ(getID(), index, v); + } + + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, boolean v) { + mRS.nScriptSetVarI(getID(), index, v ? 1 : 0); + } + + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param o + */ + public void setVar(int index, BaseObj o) { + mRS.nScriptSetVarObj(getID(), index, (o == null) ? 0 : o.getID()); + } + + /** + * Only intended for use by generated reflected code. + * + * @param index + * @param v + */ + public void setVar(int index, FieldPacker v) { + mRS.nScriptSetVarV(getID(), index, v.getData()); } public void setTimeZone(String timeZone) { mRS.validate(); try { - mRS.nScriptSetTimeZone(mID, timeZone.getBytes("UTF-8")); + mRS.nScriptSetTimeZone(getID(), timeZone.getBytes("UTF-8")); } catch (java.io.UnsupportedEncodingException e) { throw new RuntimeException(e); } @@ -78,72 +145,43 @@ public class Script extends BaseObj { public static class Builder { RenderScript mRS; - boolean mIsRoot = false; - Type[] mTypes; - String[] mNames; - boolean[] mWritable; - int mInvokableCount = 0; - Invokable[] mInvokables; Builder(RenderScript rs) { mRS = rs; - mTypes = new Type[MAX_SLOT]; - mNames = new String[MAX_SLOT]; - mWritable = new boolean[MAX_SLOT]; - mInvokables = new Invokable[MAX_SLOT]; } + } - public void setType(Type t, int slot) { - mTypes[slot] = t; - mNames[slot] = null; - } - public void setType(Type t, String name, int slot) { - mTypes[slot] = t; - mNames[slot] = name; + public static class FieldBase { + protected Element mElement; + protected Allocation mAllocation; + + protected void init(RenderScript rs, int dimx) { + mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT); } - public Invokable addInvokable(String func) { - Invokable i = new Invokable(); - i.mName = func; - i.mRS = mRS; - i.mSlot = mInvokableCount; - mInvokables[mInvokableCount++] = i; - return i; + protected void init(RenderScript rs, int dimx, int usages) { + mAllocation = Allocation.createSized(rs, mElement, dimx, Allocation.USAGE_SCRIPT | usages); } - public void setType(boolean writable, int slot) { - mWritable[slot] = writable; + protected FieldBase() { } - void transferCreate() { - mRS.nScriptSetRoot(mIsRoot); - for(int ct=0; ct < mTypes.length; ct++) { - if(mTypes[ct] != null) { - mRS.nScriptSetType(mTypes[ct].mID, mWritable[ct], mNames[ct], ct); - } - } - for(int ct=0; ct < mInvokableCount; ct++) { - mRS.nScriptSetInvokable(mInvokables[ct].mName, ct); - } + public Element getElement() { + return mElement; } - void transferObject(Script s) { - s.mIsRoot = mIsRoot; - s.mTypes = mTypes; - s.mInvokables = new Invokable[mInvokableCount]; - for(int ct=0; ct < mInvokableCount; ct++) { - s.mInvokables[ct] = mInvokables[ct]; - s.mInvokables[ct].mScript = s; - } - s.mInvokables = null; + public Type getType() { + return mAllocation.getType(); } - public void setRoot(boolean r) { - mIsRoot = r; + public Allocation getAllocation() { + return mAllocation; } + //@Override + public void updateAllocation() { + } } - } diff --git a/graphics/java/android/renderscript/ScriptC.java b/graphics/java/android/renderscript/ScriptC.java index bb99e23..9445283 100644 --- a/graphics/java/android/renderscript/ScriptC.java +++ b/graphics/java/android/renderscript/ScriptC.java @@ -16,9 +16,11 @@ package android.renderscript; +import android.content.Context; import android.content.res.Resources; import android.util.Log; +import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Map.Entry; @@ -28,134 +30,78 @@ import java.lang.reflect.Field; import java.lang.reflect.Modifier; /** - * @hide + * **/ public class ScriptC extends Script { private static final String TAG = "ScriptC"; - ScriptC(int id, RenderScript rs) { + /** + * Only intended for use by the generated derived classes. + * + * @param id + * @param rs + */ + protected ScriptC(int id, RenderScript rs) { super(id, rs); } - public static class Builder extends Script.Builder { - byte[] mProgram; - int mProgramLength; - HashMap<String,Integer> mIntDefines = new HashMap(); - HashMap<String,Float> mFloatDefines = new HashMap(); - - public Builder(RenderScript rs) { - super(rs); + /** + * Only intended for use by the generated derived classes. + * + * + * @param rs + * @param resources + * @param resourceID + */ + protected ScriptC(RenderScript rs, Resources resources, int resourceID) { + super(0, rs); + int id = internalCreate(rs, resources, resourceID); + if (id == 0) { + throw new RSRuntimeException("Loading of ScriptC script failed."); } + setID(id); + } - public void setScript(String s) { - try { - mProgram = s.getBytes("UTF-8"); - mProgramLength = mProgram.length; - } catch (java.io.UnsupportedEncodingException e) { - throw new RuntimeException(e); - } - } - public void setScript(Resources resources, int id) { - InputStream is = resources.openRawResource(id); + private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) { + byte[] pgm; + int pgmLength; + InputStream is = resources.openRawResource(resourceID); + try { try { - try { - setScript(is); - } finally { - is.close(); - } - } catch(IOException e) { - throw new Resources.NotFoundException(); - } - } - - public void setScript(InputStream is) throws IOException { - byte[] buf = new byte[1024]; - int currentPos = 0; - while(true) { - int bytesLeft = buf.length - currentPos; - if (bytesLeft == 0) { - byte[] buf2 = new byte[buf.length * 2]; - System.arraycopy(buf, 0, buf2, 0, buf.length); - buf = buf2; - bytesLeft = buf.length - currentPos; - } - int bytesRead = is.read(buf, currentPos, bytesLeft); - if (bytesRead <= 0) { - break; + pgm = new byte[1024]; + pgmLength = 0; + while(true) { + int bytesLeft = pgm.length - pgmLength; + if (bytesLeft == 0) { + byte[] buf2 = new byte[pgm.length * 2]; + System.arraycopy(pgm, 0, buf2, 0, pgm.length); + pgm = buf2; + bytesLeft = pgm.length - pgmLength; + } + int bytesRead = is.read(pgm, pgmLength, bytesLeft); + if (bytesRead <= 0) { + break; + } + pgmLength += bytesRead; } - currentPos += bytesRead; - } - mProgram = buf; - mProgramLength = currentPos; - } - - static synchronized ScriptC internalCreate(Builder b) { - b.mRS.nScriptCBegin(); - b.transferCreate(); - - for (Entry<String,Integer> e: b.mIntDefines.entrySet()) { - b.mRS.nScriptCAddDefineI32(e.getKey(), e.getValue().intValue()); + } finally { + is.close(); } - for (Entry<String,Float> e: b.mFloatDefines.entrySet()) { - b.mRS.nScriptCAddDefineF(e.getKey(), e.getValue().floatValue()); - } - - b.mRS.nScriptCSetScript(b.mProgram, 0, b.mProgramLength); - - int id = b.mRS.nScriptCCreate(); - ScriptC obj = new ScriptC(id, b.mRS); - b.transferObject(obj); - - return obj; + } catch(IOException e) { + throw new Resources.NotFoundException(); } - public void addDefine(String name, int value) { - mIntDefines.put(name, value); - } + rs.nScriptCBegin(); + rs.nScriptCSetScript(pgm, 0, pgmLength); - public void addDefine(String name, float value) { - mFloatDefines.put(name, value); - } - - /** - * Takes the all public static final fields for a class, and adds defines - * for them, using the name of the field as the name of the define. - */ - public void addDefines(Class cl) { - addDefines(cl.getFields(), (Modifier.STATIC | Modifier.FINAL | Modifier.PUBLIC), null); - } + // E.g, /system/apps/Fountain.apk + String packageName = rs.getApplicationContext().getPackageResourcePath(); + // For res/raw/fountain.bc, it wil be /com.android.fountain:raw/fountain + String resName = resources.getResourceName(resourceID); + String cacheDir = rs.getApplicationContext().getCacheDir().toString(); - /** - * Takes the all public fields for an object, and adds defines - * for them, using the name of the field as the name of the define. - */ - public void addDefines(Object o) { - addDefines(o.getClass().getFields(), Modifier.PUBLIC, o); - } - - void addDefines(Field[] fields, int mask, Object o) { - for (Field f: fields) { - try { - if ((f.getModifiers() & mask) == mask) { - Class t = f.getType(); - if (t == int.class) { - mIntDefines.put(f.getName(), f.getInt(o)); - } - else if (t == float.class) { - mFloatDefines.put(f.getName(), f.getFloat(o)); - } - } - } catch (IllegalAccessException ex) { - // TODO: Do we want this log? - Log.d(TAG, "addDefines skipping field " + f.getName()); - } - } - } - - public ScriptC create() { - return internalCreate(this); - } + Log.v(TAG, "Create script for resource = " + resName); + return rs.nScriptCCreate(packageName, resName, cacheDir); } } - diff --git a/graphics/java/android/renderscript/Short2.java b/graphics/java/android/renderscript/Short2.java new file mode 100644 index 0000000..7094edd --- /dev/null +++ b/graphics/java/android/renderscript/Short2.java @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript Short2 type back to the Android system. + * + **/ +public class Short2 { + public Short2() { + } + + public short x; + public short y; +} + + + + diff --git a/graphics/java/android/renderscript/Short3.java b/graphics/java/android/renderscript/Short3.java new file mode 100644 index 0000000..f34500c --- /dev/null +++ b/graphics/java/android/renderscript/Short3.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript short3 type back to the Android system. + * + **/ +public class Short3 { + public Short3() { + } + + public short x; + public short y; + public short z; +} + + + + diff --git a/graphics/java/android/renderscript/Short4.java b/graphics/java/android/renderscript/Short4.java new file mode 100644 index 0000000..5698fee --- /dev/null +++ b/graphics/java/android/renderscript/Short4.java @@ -0,0 +1,38 @@ +/* + * Copyright (C) 2009 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.renderscript; + +import java.lang.Math; +import android.util.Log; + + +/** + * Class for exposing the native Renderscript short4 type back to the Android system. + * + **/ +public class Short4 { + public Short4() { + } + + public short x; + public short y; + public short z; + public short w; +} + + + diff --git a/graphics/java/android/renderscript/SimpleMesh.java b/graphics/java/android/renderscript/SimpleMesh.java deleted file mode 100644 index 4a217a9..0000000 --- a/graphics/java/android/renderscript/SimpleMesh.java +++ /dev/null @@ -1,364 +0,0 @@ -/* - * Copyright (C) 2008 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package android.renderscript; - -import android.util.Config; -import android.util.Log; - -/** - * @hide - * - **/ -public class SimpleMesh extends BaseObj { - Type[] mVertexTypes; - Type mIndexType; - //Type mBatcheType; - Primitive mPrimitive; - - SimpleMesh(int id, RenderScript rs) { - super(rs); - mID = id; - } - - public void bindVertexAllocation(Allocation a, int slot) { - mRS.validate(); - mRS.nSimpleMeshBindVertex(mID, a.mID, slot); - } - - public void bindIndexAllocation(Allocation a) { - mRS.validate(); - mRS.nSimpleMeshBindIndex(mID, a.mID); - } - - public Allocation createVertexAllocation(int slot) { - mRS.validate(); - return Allocation.createTyped(mRS, mVertexTypes[slot]); - } - - public Allocation createIndexAllocation() { - mRS.validate(); - return Allocation.createTyped(mRS, mIndexType); - } - - public Type getVertexType(int slot) { - return mVertexTypes[slot]; - } - - public Type getIndexType() { - return mIndexType; - } - - public static class Builder { - RenderScript mRS; - - class Entry { - Type t; - Element e; - int size; - } - - int mVertexTypeCount; - Entry[] mVertexTypes; - Entry mIndexType; - //Entry mBatchType; - Primitive mPrimitive; - - - public Builder(RenderScript rs) { - mRS = rs; - mVertexTypeCount = 0; - mVertexTypes = new Entry[16]; - mIndexType = new Entry(); - } - - public int addVertexType(Type t) throws IllegalStateException { - if (mVertexTypeCount >= mVertexTypes.length) { - throw new IllegalStateException("Max vertex types exceeded."); - } - - int addedIndex = mVertexTypeCount; - mVertexTypes[mVertexTypeCount] = new Entry(); - mVertexTypes[mVertexTypeCount].t = t; - mVertexTypeCount++; - return addedIndex; - } - - public int addVertexType(Element e, int size) throws IllegalStateException { - if (mVertexTypeCount >= mVertexTypes.length) { - throw new IllegalStateException("Max vertex types exceeded."); - } - - int addedIndex = mVertexTypeCount; - mVertexTypes[mVertexTypeCount] = new Entry(); - mVertexTypes[mVertexTypeCount].e = e; - mVertexTypes[mVertexTypeCount].size = size; - mVertexTypeCount++; - return addedIndex; - } - - public void setIndexType(Type t) { - mIndexType.t = t; - mIndexType.e = null; - mIndexType.size = 0; - } - - public void setIndexType(Element e, int size) { - mIndexType.t = null; - mIndexType.e = e; - mIndexType.size = size; - } - - public void setPrimitive(Primitive p) { - mPrimitive = p; - } - - - Type newType(Element e, int size) { - Type.Builder tb = new Type.Builder(mRS, e); - tb.add(Dimension.X, size); - return tb.create(); - } - - static synchronized SimpleMesh internalCreate(RenderScript rs, Builder b) { - Type[] toDestroy = new Type[18]; - int toDestroyCount = 0; - - int indexID = 0; - if (b.mIndexType.t != null) { - indexID = b.mIndexType.t.mID; - } else if (b.mIndexType.size != 0) { - b.mIndexType.t = b.newType(b.mIndexType.e, b.mIndexType.size); - indexID = b.mIndexType.t.mID; - toDestroy[toDestroyCount++] = b.mIndexType.t; - } - - int[] IDs = new int[b.mVertexTypeCount]; - for(int ct=0; ct < b.mVertexTypeCount; ct++) { - if (b.mVertexTypes[ct].t != null) { - IDs[ct] = b.mVertexTypes[ct].t.mID; - } else { - b.mVertexTypes[ct].t = b.newType(b.mVertexTypes[ct].e, b.mVertexTypes[ct].size); - IDs[ct] = b.mVertexTypes[ct].t.mID; - toDestroy[toDestroyCount++] = b.mVertexTypes[ct].t; - } - } - - int id = rs.nSimpleMeshCreate(0, indexID, IDs, b.mPrimitive.mID); - for(int ct=0; ct < toDestroyCount; ct++) { - toDestroy[ct].destroy(); - } - - return new SimpleMesh(id, rs); - } - - public SimpleMesh create() { - mRS.validate(); - SimpleMesh sm = internalCreate(mRS, this); - sm.mVertexTypes = new Type[mVertexTypeCount]; - for(int ct=0; ct < mVertexTypeCount; ct++) { - sm.mVertexTypes[ct] = mVertexTypes[ct].t; - } - sm.mIndexType = mIndexType.t; - sm.mPrimitive = mPrimitive; - return sm; - } - } - - public static class TriangleMeshBuilder { - float mVtxData[]; - int mVtxCount; - short mIndexData[]; - int mIndexCount; - RenderScript mRS; - Element mElement; - - float mNX = 0; - float mNY = 0; - float mNZ = -1; - float mS0 = 0; - float mT0 = 0; - float mR = 1; - float mG = 1; - float mB = 1; - float mA = 1; - - int mVtxSize; - int mFlags; - - public static final int COLOR = 0x0001; - public static final int NORMAL = 0x0002; - public static final int TEXTURE_0 = 0x0100; - - public TriangleMeshBuilder(RenderScript rs, int vtxSize, int flags) { - mRS = rs; - mVtxCount = 0; - mIndexCount = 0; - mVtxData = new float[128]; - mIndexData = new short[128]; - mVtxSize = vtxSize; - mFlags = flags; - - if (vtxSize < 2 || vtxSize > 3) { - throw new IllegalArgumentException("Vertex size out of range."); - } - } - - private void makeSpace(int count) { - if ((mVtxCount + count) >= mVtxData.length) { - float t[] = new float[mVtxData.length * 2]; - System.arraycopy(mVtxData, 0, t, 0, mVtxData.length); - mVtxData = t; - } - } - - private void latch() { - if ((mFlags & COLOR) != 0) { - makeSpace(4); - mVtxData[mVtxCount++] = mR; - mVtxData[mVtxCount++] = mG; - mVtxData[mVtxCount++] = mB; - mVtxData[mVtxCount++] = mA; - } - if ((mFlags & TEXTURE_0) != 0) { - makeSpace(2); - mVtxData[mVtxCount++] = mS0; - mVtxData[mVtxCount++] = mT0; - } - if ((mFlags & NORMAL) != 0) { - makeSpace(3); - mVtxData[mVtxCount++] = mNX; - mVtxData[mVtxCount++] = mNY; - mVtxData[mVtxCount++] = mNZ; - } - } - - public void addVertex(float x, float y) { - if (mVtxSize != 2) { - throw new IllegalStateException("add mistmatch with declared components."); - } - makeSpace(2); - mVtxData[mVtxCount++] = x; - mVtxData[mVtxCount++] = y; - latch(); - } - - public void addVertex(float x, float y, float z) { - if (mVtxSize != 3) { - throw new IllegalStateException("add mistmatch with declared components."); - } - makeSpace(3); - mVtxData[mVtxCount++] = x; - mVtxData[mVtxCount++] = y; - mVtxData[mVtxCount++] = z; - latch(); - } - - public void setTexture(float s, float t) { - if ((mFlags & TEXTURE_0) == 0) { - throw new IllegalStateException("add mistmatch with declared components."); - } - mS0 = s; - mT0 = t; - } - - public void setNormal(float x, float y, float z) { - if ((mFlags & NORMAL) == 0) { - throw new IllegalStateException("add mistmatch with declared components."); - } - mNX = x; - mNY = y; - mNZ = z; - } - - public void setColor(float r, float g, float b, float a) { - if ((mFlags & COLOR) == 0) { - throw new IllegalStateException("add mistmatch with declared components."); - } - mR = r; - mG = g; - mB = b; - mA = a; - } - - public void addTriangle(int idx1, int idx2, int idx3) { - if((idx1 >= mVtxCount) || (idx1 < 0) || - (idx2 >= mVtxCount) || (idx2 < 0) || - (idx3 >= mVtxCount) || (idx3 < 0)) { - throw new IllegalStateException("Index provided greater than vertex count."); - } - if ((mIndexCount + 3) >= mIndexData.length) { - short t[] = new short[mIndexData.length * 2]; - System.arraycopy(mIndexData, 0, t, 0, mIndexData.length); - mIndexData = t; - } - mIndexData[mIndexCount++] = (short)idx1; - mIndexData[mIndexCount++] = (short)idx2; - mIndexData[mIndexCount++] = (short)idx3; - } - - public SimpleMesh create() { - Element.Builder b = new Element.Builder(mRS); - int floatCount = mVtxSize; - b.add(Element.createAttrib(mRS, - Element.DataType.FLOAT_32, - Element.DataKind.POSITION, - mVtxSize), "position"); - if ((mFlags & COLOR) != 0) { - floatCount += 4; - b.add(Element.createAttrib(mRS, - Element.DataType.FLOAT_32, - Element.DataKind.COLOR, - 4), "color"); - } - if ((mFlags & TEXTURE_0) != 0) { - floatCount += 2; - b.add(Element.createAttrib(mRS, - Element.DataType.FLOAT_32, - Element.DataKind.TEXTURE, - 2), "texture"); - } - if ((mFlags & NORMAL) != 0) { - floatCount += 3; - b.add(Element.createAttrib(mRS, - Element.DataType.FLOAT_32, - Element.DataKind.NORMAL, - 3), "normal"); - } - mElement = b.create(); - - Builder smb = new Builder(mRS); - smb.addVertexType(mElement, mVtxCount / floatCount); - smb.setIndexType(Element.createIndex(mRS), mIndexCount); - smb.setPrimitive(Primitive.TRIANGLE); - SimpleMesh sm = smb.create(); - - Allocation vertexAlloc = sm.createVertexAllocation(0); - Allocation indexAlloc = sm.createIndexAllocation(); - sm.bindVertexAllocation(vertexAlloc, 0); - sm.bindIndexAllocation(indexAlloc); - - vertexAlloc.data(mVtxData); - vertexAlloc.uploadToBufferObject(); - - indexAlloc.data(mIndexData); - indexAlloc.uploadToBufferObject(); - - return sm; - } - } -} - diff --git a/graphics/java/android/renderscript/Type.java b/graphics/java/android/renderscript/Type.java index 62d3867..b39d2e4 100644 --- a/graphics/java/android/renderscript/Type.java +++ b/graphics/java/android/renderscript/Type.java @@ -16,68 +16,134 @@ package android.renderscript; + import java.lang.reflect.Field; +import android.util.Log; /** - * @hide + * <p>Type is an allocation template. It consists of an Element and one or more + * dimensions. It describes only the layout of memory but does not allocate any + * storage for the data that is described.</p> + * + * <p>A Type consists of several dimensions. Those are X, Y, Z, LOD (level of + * detail), Faces (faces of a cube map). The X,Y,Z dimensions can be assigned + * any positive integral value within the constraints of available memory. A + * single dimension allocation would have an X dimension of greater than zero + * while the Y and Z dimensions would be zero to indicate not present. In this + * regard an allocation of x=10, y=1 would be considered 2 dimensionsal while + * x=10, y=0 would be considered 1 dimensional.</p> + * + * <p>The LOD and Faces dimensions are booleans to indicate present or not present.</p> * **/ public class Type extends BaseObj { int mDimX; int mDimY; int mDimZ; - boolean mDimLOD; + boolean mDimMipmaps; boolean mDimFaces; int mElementCount; Element mElement; - private int mNativeCache; - Class mJavaClass; + public enum CubemapFace { + POSITVE_X (0), + NEGATIVE_X (1), + POSITVE_Y (2), + NEGATIVE_Y (3), + POSITVE_Z (4), + NEGATIVE_Z (5); + + int mID; + CubemapFace(int id) { + mID = id; + } + } + /** + * Return the element associated with this Type. + * + * @return Element + */ public Element getElement() { return mElement; } + /** + * Return the value of the X dimension. + * + * @return int + */ public int getX() { return mDimX; } + + /** + * Return the value of the Y dimension or 0 for a 1D allocation. + * + * @return int + */ public int getY() { return mDimY; } + + /** + * Return the value of the Z dimension or 0 for a 1D or 2D allocation. + * + * @return int + */ public int getZ() { return mDimZ; } - public boolean getLOD() { - return mDimLOD; + + /** + * Return if the Type has a mipmap chain. + * + * @return boolean + */ + public boolean hasMipmaps() { + return mDimMipmaps; } - public boolean getFaces() { + + /** + * Return if the Type is a cube map. + * + * @return boolean + */ + public boolean hasFaces() { return mDimFaces; } - public int getElementCount() { + + /** + * Return the total number of accessable cells in the Type. + * + * @return int + */ + public int getCount() { return mElementCount; } void calcElementCount() { - boolean hasLod = getLOD(); + boolean hasLod = hasMipmaps(); int x = getX(); int y = getY(); int z = getZ(); int faces = 1; - if(getFaces()) { + if (hasFaces()) { faces = 6; } - if(x == 0) { + if (x == 0) { x = 1; } - if(y == 0) { + if (y == 0) { y = 1; } - if(z == 0) { + if (z == 0) { z = 1; } int count = x * y * z * faces; - if(hasLod && (x > 1) && (y > 1) && (z > 1)) { + + while (hasLod && ((x > 1) || (y > 1) || (z > 1))) { if(x > 1) { x >>= 1; } @@ -95,131 +161,123 @@ public class Type extends BaseObj { Type(int id, RenderScript rs) { - super(rs); - mID = id; - mNativeCache = 0; + super(id, rs); } - protected void finalize() throws Throwable { - if(mNativeCache != 0) { - mRS.nTypeFinalDestroy(this); - mNativeCache = 0; - } - super.finalize(); - } + @Override + void updateFromNative() { + // We have 6 integer to obtain mDimX; mDimY; mDimZ; + // mDimLOD; mDimFaces; mElement; + int[] dataBuffer = new int[6]; + mRS.nTypeGetNativeData(getID(), dataBuffer); - public static Type createFromClass(RenderScript rs, Class c, int size) { - Element e = Element.createFromClass(rs, c); - Builder b = new Builder(rs, e); - b.add(Dimension.X, size); - Type t = b.create(); - e.destroy(); - - // native fields - { - Field[] fields = c.getFields(); - int[] arTypes = new int[fields.length]; - int[] arBits = new int[fields.length]; - - for(int ct=0; ct < fields.length; ct++) { - Field f = fields[ct]; - Class fc = f.getType(); - if(fc == int.class) { - arTypes[ct] = Element.DataType.SIGNED_32.mID; - arBits[ct] = 32; - } else if(fc == short.class) { - arTypes[ct] = Element.DataType.SIGNED_16.mID; - arBits[ct] = 16; - } else if(fc == byte.class) { - arTypes[ct] = Element.DataType.SIGNED_8.mID; - arBits[ct] = 8; - } else if(fc == float.class) { - arTypes[ct] = Element.DataType.FLOAT_32.mID; - arBits[ct] = 32; - } else { - throw new IllegalArgumentException("Unkown field type"); - } - } - rs.nTypeSetupFields(t, arTypes, arBits, fields); - } - t.mJavaClass = c; - return t; - } + mDimX = dataBuffer[0]; + mDimY = dataBuffer[1]; + mDimZ = dataBuffer[2]; + mDimMipmaps = dataBuffer[3] == 1 ? true : false; + mDimFaces = dataBuffer[4] == 1 ? true : false; - public static Type createFromClass(RenderScript rs, Class c, int size, String scriptName) { - Type t = createFromClass(rs, c, size); - t.setName(scriptName); - return t; + int elementID = dataBuffer[5]; + if(elementID != 0) { + mElement = new Element(elementID, mRS); + mElement.updateFromNative(); + } + calcElementCount(); } - + /** + * Builder class for Type. + * + */ public static class Builder { RenderScript mRS; - Entry[] mEntries; - int mEntryCount; - Element mElement; + int mDimX = 1; + int mDimY; + int mDimZ; + boolean mDimMipmaps; + boolean mDimFaces; - class Entry { - Dimension mDim; - int mValue; - } + Element mElement; + /** + * Create a new builder object. + * + * @param rs + * @param e The element for the type to be created. + */ public Builder(RenderScript rs, Element e) { - if(e.mID == 0) { - throw new IllegalArgumentException("Invalid element."); - } - + e.checkValid(); mRS = rs; - mEntries = new Entry[4]; mElement = e; } - public void add(Dimension d, int value) { + /** + * Add a dimension to the Type. + * + * + * @param value + */ + public Builder setX(int value) { if(value < 1) { - throw new IllegalArgumentException("Values of less than 1 for Dimensions are not valid."); + throw new RSIllegalArgumentException("Values of less than 1 for Dimension X are not valid."); } - if(mEntries.length >= mEntryCount) { - Entry[] en = new Entry[mEntryCount + 8]; - System.arraycopy(mEntries, 0, en, 0, mEntries.length); - mEntries = en; - } - mEntries[mEntryCount] = new Entry(); - mEntries[mEntryCount].mDim = d; - mEntries[mEntryCount].mValue = value; - mEntryCount++; + mDimX = value; + return this; } - static synchronized Type internalCreate(RenderScript rs, Builder b) { - rs.nTypeBegin(b.mElement.mID); - for (int ct=0; ct < b.mEntryCount; ct++) { - Entry en = b.mEntries[ct]; - rs.nTypeAdd(en.mDim.mID, en.mValue); + public Builder setY(int value) { + if(value < 1) { + throw new RSIllegalArgumentException("Values of less than 1 for Dimension Y are not valid."); } - int id = rs.nTypeCreate(); - return new Type(id, rs); + mDimY = value; + return this; } - public Type create() { - Type t = internalCreate(mRS, this); - t.mElement = mElement; + public Builder setMipmaps(boolean value) { + mDimMipmaps = value; + return this; + } - for(int ct=0; ct < mEntryCount; ct++) { - if(mEntries[ct].mDim == Dimension.X) { - t.mDimX = mEntries[ct].mValue; - } - if(mEntries[ct].mDim == Dimension.Y) { - t.mDimY = mEntries[ct].mValue; + public Builder setFaces(boolean value) { + mDimFaces = value; + return this; + } + + + /** + * Validate structure and create a new type. + * + * @return Type + */ + public Type create() { + if (mDimZ > 0) { + if ((mDimX < 1) || (mDimY < 1)) { + throw new RSInvalidStateException("Both X and Y dimension required when Z is present."); } - if(mEntries[ct].mDim == Dimension.Z) { - t.mDimZ = mEntries[ct].mValue; + if (mDimFaces) { + throw new RSInvalidStateException("Cube maps not supported with 3D types."); } - if(mEntries[ct].mDim == Dimension.LOD) { - t.mDimLOD = mEntries[ct].mValue != 0; + } + if (mDimY > 0) { + if (mDimX < 1) { + throw new RSInvalidStateException("X dimension required when Y is present."); } - if(mEntries[ct].mDim == Dimension.FACE) { - t.mDimFaces = mEntries[ct].mValue != 0; + } + if (mDimFaces) { + if (mDimY < 1) { + throw new RSInvalidStateException("Cube maps require 2D Types."); } } + + int id = mRS.nTypeCreate(mElement.getID(), mDimX, mDimY, mDimZ, mDimMipmaps, mDimFaces); + Type t = new Type(id, mRS); + t.mElement = mElement; + t.mDimX = mDimX; + t.mDimY = mDimY; + t.mDimZ = mDimZ; + t.mDimMipmaps = mDimMipmaps; + t.mDimFaces = mDimFaces; + t.calcElementCount(); return t; } diff --git a/graphics/java/android/renderscript/package.html b/graphics/java/android/renderscript/package.html new file mode 100644 index 0000000..36a24ff --- /dev/null +++ b/graphics/java/android/renderscript/package.html @@ -0,0 +1,85 @@ +<HTML> +<BODY> +<p>The Renderscript rendering and computational APIs offer a low-level, high performance means of +carrying out mathematical calculations and 3D graphics rendering. An example of Renderscript in +applications include the 3D carousel view that is present in Android 3.0 applications such as the +Books and YouTube applications. This API is intended for developers who are comfortable working with +native code and want to maximize their performance critical applications.</p> + +<p>Renderscript adopts a control and slave architecture where the low-level native code is controlled by the +higher level Android system that runs in the virtual machine (VM). The VM code handles resource +allocation and lifecycle management of the Renderscript enabled application and calls the Renderscript +code through high level entry points. The Android build tools generate these entry points through reflection on +the native Renderscript code, which you write in C (C99 standard). The Renderscript code +does the intensive computation and returns the result back to the Android VM.</p> + +<p>You can find the Renderscript native +APIs in the <code><sdk_root>/platforms/android-3.0/renderscript</code> directory. +The Android system APIs are broken into a few main groups:</p> + +<h4>Core</h4> +<p>These classes are used internally by the system for memory allocation. They are used by the classes that +are generated by the build tools:</p> +<ul> + <li>Allocation</li> + <li>Element</li> + <li>Type</li> + <li>Script</li> +</ul> + + +<h4>Data Types</h4> +<p>These data types are used by the classes that are generated +by the build tools. They are the reflected counterparts of the native data types that +are defined by the native Renderscript APIs and used by your Renderscript code. The +classes include:</p> +<ul> + <li>Byte2, Byte3, and Byte4</li> + <li>Float2, Float3, Float4</li> + <li>Int2, Int3, Int4</li> + <li>Long2, Long3, Long4</li> + <li>Matrix2f, Matrix3f, Matrix4f</li> + <li>Short2, Short3, Short4</li> +</ul> + +<p>For example, if you declared the following struct in your .rs Renderscript file:</p> + +<pre>struct Hello { float3 position; rs_matrix4x4 transform; }</pre> + +<p>The build tools generate a class through reflection that looks like the following:</p> +<pre> +class Hello { + static public class Item { + Float4 position; + Matrix4f transform; + } +Element createElement(RenderScript rs) { + Element.Builder eb = new Element.Builder(rs); + eb.add(Element.F32_3(rs), "position"); + eb.add(Element.MATRIX_4X4(rs), "transform"); + return eb.create(); + } +} +</pre> + +<h4>Graphics</h4> +<p>These classes are specific to graphics Renderscripts and support a typical rendering +pipeline.</p> +<ul> +<li>Mesh</li> +<li>ProgramFragment</li> +<li>ProgramRaster</li> +<li>ProgramStore</li> +<li>ProgramVertex</li> +<li>RSSurfaceView</li> +<li>Sampler</li> +</ul> + +</p> +<p> +For information on how to create an application that uses Renderscript, and also the +see <a href="../../../guide/topics/graphics/renderscript.html">3D with +Renderscript</a> dev guide. +</p> +</BODY> +</HTML> diff --git a/graphics/jni/Android.mk b/graphics/jni/Android.mk index 8476be1..4c4a128 100644 --- a/graphics/jni/Android.mk +++ b/graphics/jni/Android.mk @@ -13,14 +13,13 @@ LOCAL_SRC_FILES:= \ LOCAL_SHARED_LIBRARIES := \ libandroid_runtime \ - libacc \ libnativehelper \ libRS \ libcutils \ libskia \ libutils \ libui \ - libsurfaceflinger_client + libsurfaceflinger_client LOCAL_STATIC_LIBRARIES := diff --git a/graphics/jni/android_renderscript_RenderScript.cpp b/graphics/jni/android_renderscript_RenderScript.cpp index 45cc72e..2afd74c 100644 --- a/graphics/jni/android_renderscript_RenderScript.cpp +++ b/graphics/jni/android_renderscript_RenderScript.cpp @@ -32,11 +32,14 @@ #include <images/SkImageDecoder.h> #include <utils/Asset.h> +#include <utils/AssetManager.h> #include <utils/ResourceTypes.h> #include "jni.h" #include "JNIHelp.h" #include "android_runtime/AndroidRuntime.h" +#include "android_runtime/android_view_Surface.h" +#include "android_runtime/android_util_AssetManager.h" #include <RenderScript.h> #include <RenderScriptEnv.h> @@ -46,6 +49,27 @@ using namespace android; +class AutoJavaStringToUTF8 { +public: + AutoJavaStringToUTF8(JNIEnv* env, jstring str) : fEnv(env), fJStr(str) + { + fCStr = env->GetStringUTFChars(str, NULL); + fLength = env->GetStringUTFLength(str); + } + ~AutoJavaStringToUTF8() + { + fEnv->ReleaseStringUTFChars(fJStr, fCStr); + } + const char* c_str() const { return fCStr; } + jsize length() const { return fLength; } + +private: + JNIEnv* fEnv; + jstring fJStr; + const char* fCStr; + jsize fLength; +}; + // --------------------------------------------------------------------------- static void doThrow(JNIEnv* env, const char* exc, const char* msg = NULL) @@ -58,73 +82,50 @@ static jfieldID gContextId = 0; static jfieldID gNativeBitmapID = 0; static jfieldID gTypeNativeCache = 0; -static RsElement g_A_8 = NULL; -static RsElement g_RGBA_4444 = NULL; -static RsElement g_RGBA_8888 = NULL; -static RsElement g_RGB_565 = NULL; - static void _nInit(JNIEnv *_env, jclass _this) { gContextId = _env->GetFieldID(_this, "mContext", "I"); jclass bitmapClass = _env->FindClass("android/graphics/Bitmap"); gNativeBitmapID = _env->GetFieldID(bitmapClass, "mNativeBitmap", "I"); - - jclass typeClass = _env->FindClass("android/renderscript/Type"); - gTypeNativeCache = _env->GetFieldID(typeClass, "mNativeCache", "I"); } -static void nInitElements(JNIEnv *_env, jobject _this, jint a8, jint rgba4444, jint rgba8888, jint rgb565) +// --------------------------------------------------------------------------- + +static void +nContextFinish(JNIEnv *_env, jobject _this, RsContext con) { - g_A_8 = reinterpret_cast<RsElement>(a8); - g_RGBA_4444 = reinterpret_cast<RsElement>(rgba4444); - g_RGBA_8888 = reinterpret_cast<RsElement>(rgba8888); - g_RGB_565 = reinterpret_cast<RsElement>(rgb565); + LOG_API("nContextFinish, con(%p)", con); + rsContextFinish(con); } -// --------------------------------------------------------------------------- - static void -nAssignName(JNIEnv *_env, jobject _this, jint obj, jbyteArray str) +nAssignName(JNIEnv *_env, jobject _this, RsContext con, jint obj, jbyteArray str) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nAssignName, con(%p), obj(%p)", con, (void *)obj); - jint len = _env->GetArrayLength(str); jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0); rsAssignName(con, (void *)obj, (const char *)cptr, len); _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT); } -static void -nObjDestroy(JNIEnv *_env, jobject _this, jint obj) +static jstring +nGetName(JNIEnv *_env, jobject _this, RsContext con, jint obj) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nObjDestroy, con(%p) obj(%p)", con, (void *)obj); - rsObjDestroy(con, (void *)obj); + LOG_API("nGetName, con(%p), obj(%p)", con, (void *)obj); + const char *name = NULL; + rsaGetName(con, (void *)obj, &name); + if(name == NULL || strlen(name) == 0) { + return NULL; + } + return _env->NewStringUTF(name); } static void -nObjDestroyOOB(JNIEnv *_env, jobject _this, jint obj) -{ - // This function only differs from nObjDestroy in that it calls the - // special Out Of Band version of ObjDestroy which is thread safe. - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nObjDestroyOOB, con(%p) obj(%p)", con, (void *)obj); - rsObjDestroyOOB(con, (void *)obj); -} - -static jint -nFileOpen(JNIEnv *_env, jobject _this, jbyteArray str) +nObjDestroy(JNIEnv *_env, jobject _this, RsContext con, jint obj) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nFileOpen, con(%p)", con); - - jint len = _env->GetArrayLength(str); - jbyte * cptr = (jbyte *) _env->GetPrimitiveArrayCritical(str, 0); - jint ret = (jint)rsFileOpen(con, (const char *)cptr, len); - _env->ReleasePrimitiveArrayCritical(str, cptr, JNI_ABORT); - return ret; + LOG_API("nObjDestroy, con(%p) obj(%p)", con, (void *)obj); + rsObjDestroy(con, (void *)obj); } // --------------------------------------------------------------------------- @@ -158,16 +159,32 @@ nContextCreate(JNIEnv *_env, jobject _this, jint dev, jint ver) } static jint -nContextCreateGL(JNIEnv *_env, jobject _this, jint dev, jint ver, jboolean useDepth) -{ +nContextCreateGL(JNIEnv *_env, jobject _this, jint dev, jint ver, + int colorMin, int colorPref, + int alphaMin, int alphaPref, + int depthMin, int depthPref, + int stencilMin, int stencilPref, + int samplesMin, int samplesPref, float samplesQ, + int dpi) +{ + RsSurfaceConfig sc; + sc.alphaMin = alphaMin; + sc.alphaPref = alphaPref; + sc.colorMin = colorMin; + sc.colorPref = colorPref; + sc.depthMin = depthMin; + sc.depthPref = depthPref; + sc.samplesMin = samplesMin; + sc.samplesPref = samplesPref; + sc.samplesQ = samplesQ; + LOG_API("nContextCreateGL"); - return (jint)rsContextCreateGL((RsDevice)dev, ver, useDepth); + return (jint)rsContextCreateGL((RsDevice)dev, ver, sc, dpi); } static void -nContextSetPriority(JNIEnv *_env, jobject _this, jint p) +nContextSetPriority(JNIEnv *_env, jobject _this, RsContext con, jint p) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("ContextSetPriority, con(%p), priority(%i)", con, p); rsContextSetPriority(con, p); } @@ -175,101 +192,121 @@ nContextSetPriority(JNIEnv *_env, jobject _this, jint p) static void -nContextSetSurface(JNIEnv *_env, jobject _this, jint width, jint height, jobject wnd) +nContextSetSurface(JNIEnv *_env, jobject _this, RsContext con, jint width, jint height, jobject wnd) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextSetSurface, con(%p), width(%i), height(%i), surface(%p)", con, width, height, (Surface *)wnd); Surface * window = NULL; if (wnd == NULL) { } else { - jclass surface_class = _env->FindClass("android/view/Surface"); - jfieldID surfaceFieldID = _env->GetFieldID(surface_class, ANDROID_VIEW_SURFACE_JNI_ID, "I"); - window = (Surface*)_env->GetIntField(wnd, surfaceFieldID); + window = (Surface*) android_Surface_getNativeWindow(_env, wnd).get(); } rsContextSetSurface(con, width, height, window); } static void -nContextDestroy(JNIEnv *_env, jobject _this, jint con) +nContextDestroy(JNIEnv *_env, jobject _this, RsContext con) { - LOG_API("nContextDestroy, con(%p)", (RsContext)con); - rsContextDestroy((RsContext)con); + LOG_API("nContextDestroy, con(%p)", con); + rsContextDestroy(con); } static void -nContextDump(JNIEnv *_env, jobject _this, jint bits) +nContextDump(JNIEnv *_env, jobject _this, RsContext con, jint bits) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextDump, con(%p) bits(%i)", (RsContext)con, bits); rsContextDump((RsContext)con, bits); } static void -nContextPause(JNIEnv *_env, jobject _this) +nContextPause(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextPause, con(%p)", con); rsContextPause(con); } static void -nContextResume(JNIEnv *_env, jobject _this) +nContextResume(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextResume, con(%p)", con); rsContextResume(con); } -static jint -nContextGetMessage(JNIEnv *_env, jobject _this, jintArray data, jboolean wait) + +static jstring +nContextGetErrorMessage(JNIEnv *_env, jobject _this, RsContext con) +{ + LOG_API("nContextGetErrorMessage, con(%p)", con); + char buf[1024]; + + size_t receiveLen; + uint32_t subID; + int id = rsContextGetMessage(con, buf, &receiveLen, &subID, sizeof(buf), true); + if (!id && receiveLen) { + LOGV("message receive buffer too small. %i", receiveLen); + } + return _env->NewStringUTF(buf); +} + +static void +nContextGetUserMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray data) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); LOG_API("nContextGetMessage, con(%p), len(%i)", con, len); jint *ptr = _env->GetIntArrayElements(data, NULL); size_t receiveLen; - int id = rsContextGetMessage(con, ptr, &receiveLen, len * 4, wait); + uint32_t subID; + int id = rsContextGetMessage(con, ptr, &receiveLen, &subID, len * 4, true); if (!id && receiveLen) { - LOGE("message receive buffer too small. %i", receiveLen); + LOGV("message receive buffer too small. %i", receiveLen); } _env->ReleaseIntArrayElements(data, ptr, 0); +} + +static jint +nContextPeekMessage(JNIEnv *_env, jobject _this, RsContext con, jintArray auxData, jboolean wait) +{ + LOG_API("nContextPeekMessage, con(%p)", con); + jint *auxDataPtr = _env->GetIntArrayElements(auxData, NULL); + size_t receiveLen; + uint32_t subID; + int id = rsContextPeekMessage(con, &receiveLen, &subID, wait); + auxDataPtr[0] = (jint)subID; + auxDataPtr[1] = (jint)receiveLen; + _env->ReleaseIntArrayElements(auxData, auxDataPtr, 0); return id; } -static void nContextInitToClient(JNIEnv *_env, jobject _this) +static void nContextInitToClient(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextInitToClient, con(%p)", con); rsContextInitToClient(con); } -static void nContextDeinitToClient(JNIEnv *_env, jobject _this) +static void nContextDeinitToClient(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextDeinitToClient, con(%p)", con); rsContextDeinitToClient(con); } static jint -nElementCreate(JNIEnv *_env, jobject _this, jint type, jint kind, jboolean norm, jint size) +nElementCreate(JNIEnv *_env, jobject _this, RsContext con, jint type, jint kind, jboolean norm, jint size) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nElementCreate, con(%p), type(%i), kind(%i), norm(%i), size(%i)", con, type, kind, norm, size); return (jint)rsElementCreate(con, (RsDataType)type, (RsDataKind)kind, norm, size); } static jint -nElementCreate2(JNIEnv *_env, jobject _this, jintArray _ids, jobjectArray _names) +nElementCreate2(JNIEnv *_env, jobject _this, RsContext con, jintArray _ids, jobjectArray _names, jintArray _arraySizes) { int fieldCount = _env->GetArrayLength(_ids); - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nElementCreate2, con(%p)", con); jint *ids = _env->GetIntArrayElements(_ids, NULL); + jint *arraySizes = _env->GetIntArrayElements(_arraySizes, NULL); const char ** nameArray = (const char **)calloc(fieldCount, sizeof(char *)); size_t* sizeArray = (size_t*)calloc(fieldCount, sizeof(size_t)); @@ -278,369 +315,273 @@ nElementCreate2(JNIEnv *_env, jobject _this, jintArray _ids, jobjectArray _names nameArray[ct] = _env->GetStringUTFChars(s, NULL); sizeArray[ct] = _env->GetStringUTFLength(s); } - jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray); + jint id = (jint)rsElementCreate2(con, fieldCount, (RsElement *)ids, nameArray, sizeArray, (const uint32_t *)arraySizes); for (int ct=0; ct < fieldCount; ct++) { jstring s = (jstring)_env->GetObjectArrayElement(_names, ct); _env->ReleaseStringUTFChars(s, nameArray[ct]); } _env->ReleaseIntArrayElements(_ids, ids, JNI_ABORT); + _env->ReleaseIntArrayElements(_arraySizes, arraySizes, JNI_ABORT); free(nameArray); free(sizeArray); return (jint)id; } -// ----------------------------------- - static void -nTypeBegin(JNIEnv *_env, jobject _this, jint eID) +nElementGetNativeData(JNIEnv *_env, jobject _this, RsContext con, jint id, jintArray _elementData) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nTypeBegin, con(%p) e(%p)", con, (RsElement)eID); - rsTypeBegin(con, (RsElement)eID); -} + int dataSize = _env->GetArrayLength(_elementData); + LOG_API("nElementGetNativeData, con(%p)", con); -static void -nTypeAdd(JNIEnv *_env, jobject _this, jint dim, jint val) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nTypeAdd, con(%p) dim(%i), val(%i)", con, dim, val); - rsTypeAdd(con, (RsDimension)dim, val); -} + // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements + assert(dataSize == 5); -static jint -nTypeCreate(JNIEnv *_env, jobject _this) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nTypeCreate, con(%p)", con); - return (jint)rsTypeCreate(con); -} + uint32_t elementData[5]; + rsaElementGetNativeData(con, (RsElement)id, elementData, dataSize); -static void * SF_LoadInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - ((int32_t *)buffer)[0] = _env->GetIntField(_obj, _field); - return ((uint8_t *)buffer) + 4; -} - -static void * SF_LoadShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - ((int16_t *)buffer)[0] = _env->GetShortField(_obj, _field); - return ((uint8_t *)buffer) + 2; + for(jint i = 0; i < dataSize; i ++) { + _env->SetIntArrayRegion(_elementData, i, 1, (const jint*)&elementData[i]); + } } -static void * SF_LoadByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - ((int8_t *)buffer)[0] = _env->GetByteField(_obj, _field); - return ((uint8_t *)buffer) + 1; -} -static void * SF_LoadFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) +static void +nElementGetSubElements(JNIEnv *_env, jobject _this, RsContext con, jint id, jintArray _IDs, jobjectArray _names) { - ((float *)buffer)[0] = _env->GetFloatField(_obj, _field); - return ((uint8_t *)buffer) + 4; -} + int dataSize = _env->GetArrayLength(_IDs); + LOG_API("nElementGetSubElements, con(%p)", con); -static void * SF_SaveInt(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - _env->SetIntField(_obj, _field, ((int32_t *)buffer)[0]); - return ((uint8_t *)buffer) + 4; -} + uint32_t *ids = (uint32_t *)malloc((uint32_t)dataSize * sizeof(uint32_t)); + const char **names = (const char **)malloc((uint32_t)dataSize * sizeof(const char *)); -static void * SF_SaveShort(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - _env->SetShortField(_obj, _field, ((int16_t *)buffer)[0]); - return ((uint8_t *)buffer) + 2; -} + rsaElementGetSubElements(con, (RsElement)id, ids, names, (uint32_t)dataSize); -static void * SF_SaveByte(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - _env->SetByteField(_obj, _field, ((int8_t *)buffer)[0]); - return ((uint8_t *)buffer) + 1; -} + for(jint i = 0; i < dataSize; i++) { + _env->SetObjectArrayElement(_names, i, _env->NewStringUTF(names[i])); + _env->SetIntArrayRegion(_IDs, i, 1, (const jint*)&ids[i]); + } -static void * SF_SaveFloat(JNIEnv *_env, jobject _obj, jfieldID _field, void *buffer) -{ - _env->SetFloatField(_obj, _field, ((float *)buffer)[0]); - return ((uint8_t *)buffer) + 4; + free(ids); + free(names); } -struct TypeFieldCache { - jfieldID field; - int bits; - void * (*ptr)(JNIEnv *, jobject, jfieldID, void *buffer); - void * (*readPtr)(JNIEnv *, jobject, jfieldID, void *buffer); -}; - -struct TypeCache { - int fieldCount; - int size; - TypeFieldCache fields[1]; -}; +// ----------------------------------- -//{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy }, -static void -nTypeFinalDestroy(JNIEnv *_env, jobject _this, jobject _type) +static int +nTypeCreate(JNIEnv *_env, jobject _this, RsContext con, RsElement eid, + jint dimx, jint dimy, jint dimz, jboolean mips, jboolean faces) { - TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache); - free(tc); + LOG_API("nTypeCreate, con(%p) eid(%p), x(%i), y(%i), z(%i), mips(%i), faces(%i)", + con, eid, dimx, dimy, dimz, mips, faces); + + jint id = (jint)rsaTypeCreate(con, (RsElement)eid, dimx, dimy, dimz, mips, faces); + return (jint)id; } -// native void nTypeSetupFields(Type t, int[] types, int[] bits, Field[] IDs); static void -nTypeSetupFields(JNIEnv *_env, jobject _this, jobject _type, jintArray _types, jintArray _bits, jobjectArray _IDs) +nTypeGetNativeData(JNIEnv *_env, jobject _this, RsContext con, jint id, jintArray _typeData) { - int fieldCount = _env->GetArrayLength(_types); - size_t structSize = sizeof(TypeCache) + (sizeof(TypeFieldCache) * (fieldCount-1)); - TypeCache *tc = (TypeCache *)malloc(structSize); - memset(tc, 0, structSize); + // We are packing 6 items: mDimX; mDimY; mDimZ; + // mDimLOD; mDimFaces; mElement; into typeData + int elementCount = _env->GetArrayLength(_typeData); - TypeFieldCache *tfc = &tc->fields[0]; - tc->fieldCount = fieldCount; - _env->SetIntField(_type, gTypeNativeCache, (jint)tc); + assert(elementCount == 6); + LOG_API("nTypeCreate, con(%p)", con); - jint *fType = _env->GetIntArrayElements(_types, NULL); - jint *fBits = _env->GetIntArrayElements(_bits, NULL); - for (int ct=0; ct < fieldCount; ct++) { - jobject field = _env->GetObjectArrayElement(_IDs, ct); - tfc[ct].field = _env->FromReflectedField(field); - tfc[ct].bits = fBits[ct]; - - switch(fType[ct]) { - case RS_TYPE_FLOAT_32: - tfc[ct].ptr = SF_LoadFloat; - tfc[ct].readPtr = SF_SaveFloat; - break; - case RS_TYPE_UNSIGNED_32: - case RS_TYPE_SIGNED_32: - tfc[ct].ptr = SF_LoadInt; - tfc[ct].readPtr = SF_SaveInt; - break; - case RS_TYPE_UNSIGNED_16: - case RS_TYPE_SIGNED_16: - tfc[ct].ptr = SF_LoadShort; - tfc[ct].readPtr = SF_SaveShort; - break; - case RS_TYPE_UNSIGNED_8: - case RS_TYPE_SIGNED_8: - tfc[ct].ptr = SF_LoadByte; - tfc[ct].readPtr = SF_SaveByte; - break; - } - tc->size += 4; - } + uint32_t typeData[6]; + rsaTypeGetNativeData(con, (RsType)id, typeData, 6); - _env->ReleaseIntArrayElements(_types, fType, JNI_ABORT); - _env->ReleaseIntArrayElements(_bits, fBits, JNI_ABORT); + for(jint i = 0; i < elementCount; i ++) { + _env->SetIntArrayRegion(_typeData, i, 1, (const jint*)&typeData[i]); + } } - // ----------------------------------- static jint -nAllocationCreateTyped(JNIEnv *_env, jobject _this, jint e) +nAllocationCreateTyped(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mips, jint usage) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAllocationCreateTyped, con(%p), e(%p)", con, (RsElement)e); - return (jint) rsAllocationCreateTyped(con, (RsElement)e); + LOG_API("nAllocationCreateTyped, con(%p), type(%p), mip(%i), usage(%i)", con, (RsElement)type, mips, usage); + return (jint) rsaAllocationCreateTyped(con, (RsType)type, (RsAllocationMipmapControl)mips, (uint32_t)usage); } static void -nAllocationUploadToTexture(JNIEnv *_env, jobject _this, jint a, jboolean genMip, jint mip) +nAllocationSyncAll(JNIEnv *_env, jobject _this, RsContext con, jint a, jint bits) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAllocationUploadToTexture, con(%p), a(%p), genMip(%i), mip(%i)", con, (RsAllocation)a, genMip, mip); - rsAllocationUploadToTexture(con, (RsAllocation)a, genMip, mip); + LOG_API("nAllocationSyncAll, con(%p), a(%p), bits(0x%08x)", con, (RsAllocation)a, bits); + rsAllocationSyncAll(con, (RsAllocation)a, (RsAllocationUsageType)bits); } static void -nAllocationUploadToBufferObject(JNIEnv *_env, jobject _this, jint a) +nAllocationGenerateMipmaps(JNIEnv *_env, jobject _this, RsContext con, jint alloc) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAllocationUploadToBufferObject, con(%p), a(%p)", con, (RsAllocation)a); - rsAllocationUploadToBufferObject(con, (RsAllocation)a); -} - -static RsElement SkBitmapToPredefined(SkBitmap::Config cfg) -{ - switch (cfg) { - case SkBitmap::kA8_Config: - return g_A_8; - case SkBitmap::kARGB_4444_Config: - return g_RGBA_4444; - case SkBitmap::kARGB_8888_Config: - return g_RGBA_8888; - case SkBitmap::kRGB_565_Config: - return g_RGB_565; - - default: - break; - } - // If we don't have a conversion mark it as a user type. - LOGE("Unsupported bitmap type"); - return NULL; + LOG_API("nAllocationGenerateMipmaps, con(%p), a(%p)", con, (RsAllocation)alloc); + rsAllocationGenerateMipmaps(con, (RsAllocation)alloc); } static int -nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap) +nAllocationCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mip, jobject jbitmap, jint usage) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); SkBitmap const * nativeBitmap = (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); - - RsElement e = SkBitmapToPredefined(config); - if (e) { - bitmap.lockPixels(); - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* ptr = bitmap.getPixels(); - jint id = (jint)rsAllocationCreateFromBitmap(con, w, h, (RsElement)dstFmt, e, genMips, ptr); - bitmap.unlockPixels(); - return id; - } - return 0; -} -static void ReleaseBitmapCallback(void *bmp) -{ - SkBitmap const * nativeBitmap = (SkBitmap const *)bmp; - nativeBitmap->unlockPixels(); + bitmap.lockPixels(); + const void* ptr = bitmap.getPixels(); + jint id = (jint)rsaAllocationCreateFromBitmap(con, (RsType)type, (RsAllocationMipmapControl)mip, ptr, usage); + bitmap.unlockPixels(); + return id; } static int -nAllocationCreateBitmapRef(JNIEnv *_env, jobject _this, jint type, jobject jbitmap) +nAllocationCubeCreateFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint type, jint mip, jobject jbitmap, jint usage) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - SkBitmap * nativeBitmap = - (SkBitmap *)_env->GetIntField(jbitmap, gNativeBitmapID); - + SkBitmap const * nativeBitmap = + (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID); + const SkBitmap& bitmap(*nativeBitmap); - nativeBitmap->lockPixels(); - void* ptr = nativeBitmap->getPixels(); - jint id = (jint)rsAllocationCreateBitmapRef(con, (RsType)type, ptr, nativeBitmap, ReleaseBitmapCallback); + bitmap.lockPixels(); + const void* ptr = bitmap.getPixels(); + jint id = (jint)rsaAllocationCubeCreateFromBitmap(con, (RsType)type, (RsAllocationMipmapControl)mip, ptr, usage); + bitmap.unlockPixels(); return id; } -static int -nAllocationCreateFromAssetStream(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jint native_asset) +static void +nAllocationCopyFromBitmap(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jobject jbitmap) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); + SkBitmap const * nativeBitmap = + (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID); + const SkBitmap& bitmap(*nativeBitmap); + int w = bitmap.width(); + int h = bitmap.height(); - Asset* asset = reinterpret_cast<Asset*>(native_asset); - SkBitmap bitmap; - SkImageDecoder::DecodeMemory(asset->getBuffer(false), asset->getLength(), - &bitmap, SkBitmap::kNo_Config, SkImageDecoder::kDecodePixels_Mode); - - SkBitmap::Config config = bitmap.getConfig(); - - RsElement e = SkBitmapToPredefined(config); - - if (e) { - bitmap.lockPixels(); - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* ptr = bitmap.getPixels(); - jint id = (jint)rsAllocationCreateFromBitmap(con, w, h, (RsElement)dstFmt, e, genMips, ptr); - bitmap.unlockPixels(); - return id; - } - return 0; + bitmap.lockPixels(); + const void* ptr = bitmap.getPixels(); + rsAllocation2DData(con, (RsAllocation)alloc, 0, 0, + 0, RS_ALLOCATION_CUBMAP_FACE_POSITVE_X, + w, h, ptr, bitmap.getSize()); + bitmap.unlockPixels(); } -static int -nAllocationCreateFromBitmapBoxed(JNIEnv *_env, jobject _this, jint dstFmt, jboolean genMips, jobject jbitmap) +static void +nAllocationCopyToBitmap(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jobject jbitmap) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); SkBitmap const * nativeBitmap = (SkBitmap const *)_env->GetIntField(jbitmap, gNativeBitmapID); const SkBitmap& bitmap(*nativeBitmap); - SkBitmap::Config config = bitmap.getConfig(); - - RsElement e = SkBitmapToPredefined(config); - - if (e) { - bitmap.lockPixels(); - const int w = bitmap.width(); - const int h = bitmap.height(); - const void* ptr = bitmap.getPixels(); - jint id = (jint)rsAllocationCreateFromBitmapBoxed(con, w, h, (RsElement)dstFmt, e, genMips, ptr); - bitmap.unlockPixels(); - return id; - } - return 0; + + bitmap.lockPixels(); + void* ptr = bitmap.getPixels(); + rsAllocationCopyToBitmap(con, (RsAllocation)alloc, ptr, bitmap.getSize()); + bitmap.unlockPixels(); +} + +static void ReleaseBitmapCallback(void *bmp) +{ + SkBitmap const * nativeBitmap = (SkBitmap const *)bmp; + nativeBitmap->unlockPixels(); } static void -nAllocationSubData1D_i(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jintArray data, int sizeBytes) +nAllocationData1D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jintArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); + LOG_API("nAllocation1DData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes); + rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes); _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationSubData1D_s(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jshortArray data, int sizeBytes) +nAllocationData1D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jshortArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation1DSubData_s, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); + LOG_API("nAllocation1DData_s, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); jshort *ptr = _env->GetShortArrayElements(data, NULL); - rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes); + rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes); _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationSubData1D_b(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jbyteArray data, int sizeBytes) +nAllocationData1D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jbyteArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation1DSubData_b, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); + LOG_API("nAllocation1DData_b, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); jbyte *ptr = _env->GetByteArrayElements(data, NULL); - rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes); + rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes); _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationSubData1D_f(JNIEnv *_env, jobject _this, jint alloc, jint offset, jint count, jfloatArray data, int sizeBytes) +nAllocationData1D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint count, jfloatArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); + LOG_API("nAllocation1DData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, count, len, sizeBytes); jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAllocation1DSubData(con, (RsAllocation)alloc, offset, count, ptr, sizeBytes); + rsAllocation1DData(con, (RsAllocation)alloc, offset, lod, count, ptr, sizeBytes); _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationSubData2D_i(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jintArray data, int sizeBytes) +// native void rsnAllocationElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes); +nAllocationElementData1D(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint offset, jint lod, jint compIdx, jbyteArray data, int sizeBytes) +{ + jint len = _env->GetArrayLength(data); + LOG_API("nAllocationElementData1D, con(%p), alloc(%p), offset(%i), comp(%i), len(%i), sizeBytes(%i)", con, (RsAllocation)alloc, offset, compIdx, len, sizeBytes); + jbyte *ptr = _env->GetByteArrayElements(data, NULL); + rsAllocation1DElementData(con, (RsAllocation)alloc, offset, lod, ptr, compIdx, sizeBytes); + _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); +} + +static void +nAllocationData2D_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face, + jint w, jint h, jshortArray data, int sizeBytes) +{ + jint len = _env->GetArrayLength(data); + LOG_API("nAllocation2DData_s, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); + jshort *ptr = _env->GetShortArrayElements(data, NULL); + rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes); + _env->ReleaseShortArrayElements(data, ptr, JNI_ABORT); +} + +static void +nAllocationData2D_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face, + jint w, jint h, jbyteArray data, int sizeBytes) +{ + jint len = _env->GetArrayLength(data); + LOG_API("nAllocation2DData_b, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); + jbyte *ptr = _env->GetByteArrayElements(data, NULL); + rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes); + _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); +} + +static void +nAllocationData2D_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face, + jint w, jint h, jintArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); + LOG_API("nAllocation2DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAllocation2DSubData(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr, sizeBytes); + rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes); _env->ReleaseIntArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationSubData2D_f(JNIEnv *_env, jobject _this, jint alloc, jint xoff, jint yoff, jint w, jint h, jfloatArray data, int sizeBytes) +nAllocationData2D_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint xoff, jint yoff, jint lod, jint face, + jint w, jint h, jfloatArray data, int sizeBytes) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); - LOG_API("nAllocation2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); + LOG_API("nAllocation2DData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", con, (RsAllocation)alloc, xoff, yoff, w, h, len); jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAllocation2DSubData(con, (RsAllocation)alloc, xoff, yoff, w, h, ptr, sizeBytes); + rsAllocation2DData(con, (RsAllocation)alloc, xoff, yoff, lod, (RsAllocationCubemapFace)face, w, h, ptr, sizeBytes); _env->ReleaseFloatArrayElements(data, ptr, JNI_ABORT); } static void -nAllocationRead_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data) +nAllocationRead_i(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jintArray data) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len); jint *ptr = _env->GetIntArrayElements(data, NULL); @@ -649,9 +590,28 @@ nAllocationRead_i(JNIEnv *_env, jobject _this, jint alloc, jintArray data) } static void -nAllocationRead_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data) +nAllocationRead_s(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jshortArray data) +{ + jint len = _env->GetArrayLength(data); + LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len); + jshort *ptr = _env->GetShortArrayElements(data, NULL); + rsAllocationRead(con, (RsAllocation)alloc, ptr); + _env->ReleaseShortArrayElements(data, ptr, 0); +} + +static void +nAllocationRead_b(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jbyteArray data) +{ + jint len = _env->GetArrayLength(data); + LOG_API("nAllocationRead_i, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len); + jbyte *ptr = _env->GetByteArrayElements(data, NULL); + rsAllocationRead(con, (RsAllocation)alloc, ptr); + _env->ReleaseByteArrayElements(data, ptr, 0); +} + +static void +nAllocationRead_f(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jfloatArray data) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); jint len = _env->GetArrayLength(data); LOG_API("nAllocationRead_f, con(%p), alloc(%p), len(%i)", con, (RsAllocation)alloc, len); jfloat *ptr = _env->GetFloatArrayElements(data, NULL); @@ -659,228 +619,202 @@ nAllocationRead_f(JNIEnv *_env, jobject _this, jint alloc, jfloatArray data) _env->ReleaseFloatArrayElements(data, ptr, 0); } +static jint +nAllocationGetType(JNIEnv *_env, jobject _this, RsContext con, jint a) +{ + LOG_API("nAllocationGetType, con(%p), a(%p)", con, (RsAllocation)a); + return (jint) rsaAllocationGetType(con, (RsAllocation)a); +} -//{"nAllocationDataFromObject", "(ILandroid/renderscript/Type;Ljava/lang/Object;)V", (void*)nAllocationDataFromObject }, static void -nAllocationSubDataFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jint offset, jobject _o) +nAllocationResize1D(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint dimX) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAllocationDataFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc); - - const TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache); - - void * bufAlloc = malloc(tc->size); - void * buf = bufAlloc; - for (int ct=0; ct < tc->fieldCount; ct++) { - const TypeFieldCache *tfc = &tc->fields[ct]; - buf = tfc->ptr(_env, _o, tfc->field, buf); - } - rsAllocation1DSubData(con, (RsAllocation)alloc, offset, 1, bufAlloc, tc->size); - free(bufAlloc); + LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i)", con, (RsAllocation)alloc, dimX); + rsAllocationResize1D(con, (RsAllocation)alloc, dimX); } static void -nAllocationSubReadFromObject(JNIEnv *_env, jobject _this, jint alloc, jobject _type, jint offset, jobject _o) +nAllocationResize2D(JNIEnv *_env, jobject _this, RsContext con, jint alloc, jint dimX, jint dimY) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAllocationReadFromObject con(%p), alloc(%p)", con, (RsAllocation)alloc); + LOG_API("nAllocationResize1D, con(%p), alloc(%p), sizeX(%i), sizeY(%i)", con, (RsAllocation)alloc, dimX, dimY); + rsAllocationResize2D(con, (RsAllocation)alloc, dimX, dimY); +} - assert(offset == 0); +// ----------------------------------- - const TypeCache *tc = (TypeCache *)_env->GetIntField(_type, gTypeNativeCache); +static int +nFileA3DCreateFromAssetStream(JNIEnv *_env, jobject _this, RsContext con, jint native_asset) +{ + LOGV("______nFileA3D %u", (uint32_t) native_asset); - void * bufAlloc = malloc(tc->size); - void * buf = bufAlloc; - rsAllocationRead(con, (RsAllocation)alloc, bufAlloc); + Asset* asset = reinterpret_cast<Asset*>(native_asset); - for (int ct=0; ct < tc->fieldCount; ct++) { - const TypeFieldCache *tfc = &tc->fields[ct]; - buf = tfc->readPtr(_env, _o, tfc->field, buf); - } - free(bufAlloc); + jint id = (jint)rsaFileA3DCreateFromMemory(con, asset->getBuffer(false), asset->getLength()); + return id; } +static int +nFileA3DCreateFromAsset(JNIEnv *_env, jobject _this, RsContext con, jobject _assetMgr, jstring _path) +{ + AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr); + if (mgr == NULL) { + return 0; + } -// ----------------------------------- + AutoJavaStringToUTF8 str(_env, _path); + Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + if (asset == NULL) { + return 0; + } -static void -nAdapter1DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter1DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter1D)adapter, (RsAllocation)alloc); - rsAdapter1DBindAllocation(con, (RsAdapter1D)adapter, (RsAllocation)alloc); + jint id = (jint)rsaFileA3DCreateFromAsset(con, asset); + return id; } -static void -nAdapter1DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value) +static int +nFileA3DCreateFromFile(JNIEnv *_env, jobject _this, RsContext con, jstring fileName) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter1DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter1D)adapter, dim, value); - rsAdapter1DSetConstraint(con, (RsAdapter1D)adapter, (RsDimension)dim, value); -} + AutoJavaStringToUTF8 fileNameUTF(_env, fileName); + jint id = (jint)rsaFileA3DCreateFromFile(con, fileNameUTF.c_str()); -static void -nAdapter1DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter1DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len); - jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAdapter1DData(con, (RsAdapter1D)adapter, ptr); - _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/); + return id; } -static void -nAdapter1DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jintArray data) +static int +nFileA3DGetNumIndexEntries(JNIEnv *_env, jobject _this, RsContext con, jint fileA3D) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter1DSubData_i, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len); - jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAdapter1DSubData(con, (RsAdapter1D)adapter, offset, count, ptr); - _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/); + int32_t numEntries = 0; + rsaFileA3DGetNumIndexEntries(con, &numEntries, (RsFile)fileA3D); + return numEntries; } static void -nAdapter1DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data) +nFileA3DGetIndexEntries(JNIEnv *_env, jobject _this, RsContext con, jint fileA3D, jint numEntries, jintArray _ids, jobjectArray _entries) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter1DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter1D)adapter, len); - jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAdapter1DData(con, (RsAdapter1D)adapter, ptr); - _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/); -} + LOGV("______nFileA3D %u", (uint32_t) fileA3D); + RsFileIndexEntry *fileEntries = (RsFileIndexEntry*)malloc((uint32_t)numEntries * sizeof(RsFileIndexEntry)); -static void -nAdapter1DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint offset, jint count, jfloatArray data) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter1DSubData_f, con(%p), adapter(%p), offset(%i), count(%i), len(%i)", con, (RsAdapter1D)adapter, offset, count, len); - jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAdapter1DSubData(con, (RsAdapter1D)adapter, offset, count, ptr); - _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/); + rsaFileA3DGetIndexEntries(con, fileEntries, (uint32_t)numEntries, (RsFile)fileA3D); + + for(jint i = 0; i < numEntries; i ++) { + _env->SetObjectArrayElement(_entries, i, _env->NewStringUTF(fileEntries[i].objectName)); + _env->SetIntArrayRegion(_ids, i, 1, (const jint*)&fileEntries[i].classID); + } + + free(fileEntries); } -static jint -nAdapter1DCreate(JNIEnv *_env, jobject _this) +static int +nFileA3DGetEntryByIndex(JNIEnv *_env, jobject _this, RsContext con, jint fileA3D, jint index) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter1DCreate, con(%p)", con); - return (jint)rsAdapter1DCreate(con); + LOGV("______nFileA3D %u", (uint32_t) fileA3D); + jint id = (jint)rsaFileA3DGetEntryByIndex(con, (uint32_t)index, (RsFile)fileA3D); + return id; } // ----------------------------------- -static void -nAdapter2DBindAllocation(JNIEnv *_env, jobject _this, jint adapter, jint alloc) +static int +nFontCreateFromFile(JNIEnv *_env, jobject _this, RsContext con, + jstring fileName, jfloat fontSize, jint dpi) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter2DBindAllocation, con(%p), adapter(%p), alloc(%p)", con, (RsAdapter2D)adapter, (RsAllocation)alloc); - rsAdapter2DBindAllocation(con, (RsAdapter2D)adapter, (RsAllocation)alloc); -} + AutoJavaStringToUTF8 fileNameUTF(_env, fileName); + jint id = (jint)rsFontCreateFromFile(con, fileNameUTF.c_str(), fontSize, dpi); -static void -nAdapter2DSetConstraint(JNIEnv *_env, jobject _this, jint adapter, jint dim, jint value) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter2DSetConstraint, con(%p), adapter(%p), dim(%i), value(%i)", con, (RsAdapter2D)adapter, dim, value); - rsAdapter2DSetConstraint(con, (RsAdapter2D)adapter, (RsDimension)dim, value); + return id; } -static void -nAdapter2DData_i(JNIEnv *_env, jobject _this, jint adapter, jintArray data) +static int +nFontCreateFromAssetStream(JNIEnv *_env, jobject _this, RsContext con, + jstring name, jfloat fontSize, jint dpi, jint native_asset) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter2DData_i, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len); - jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAdapter2DData(con, (RsAdapter2D)adapter, ptr); - _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/); + Asset* asset = reinterpret_cast<Asset*>(native_asset); + AutoJavaStringToUTF8 nameUTF(_env, name); + + jint id = (jint)rsFontCreateFromMemory(con, nameUTF.c_str(), fontSize, dpi, + asset->getBuffer(false), asset->getLength()); + return id; } -static void -nAdapter2DData_f(JNIEnv *_env, jobject _this, jint adapter, jfloatArray data) +static int +nFontCreateFromAsset(JNIEnv *_env, jobject _this, RsContext con, jobject _assetMgr, jstring _path, + jfloat fontSize, jint dpi) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter2DData_f, con(%p), adapter(%p), len(%i)", con, (RsAdapter2D)adapter, len); - jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAdapter2DData(con, (RsAdapter2D)adapter, ptr); - _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/); + AssetManager* mgr = assetManagerForJavaObject(_env, _assetMgr); + if (mgr == NULL) { + return 0; + } + + AutoJavaStringToUTF8 str(_env, _path); + Asset* asset = mgr->open(str.c_str(), Asset::ACCESS_BUFFER); + if (asset == NULL) { + return 0; + } + + jint id = (jint)rsFontCreateFromMemory(con, str.c_str(), fontSize, dpi, + asset->getBuffer(false), asset->getLength()); + delete asset; + return id; } +// ----------------------------------- + static void -nAdapter2DSubData_i(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jintArray data) +nScriptBindAllocation(JNIEnv *_env, jobject _this, RsContext con, jint script, jint alloc, jint slot) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter2DSubData_i, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", - con, (RsAdapter2D)adapter, xoff, yoff, w, h, len); - jint *ptr = _env->GetIntArrayElements(data, NULL); - rsAdapter2DSubData(con, (RsAdapter2D)adapter, xoff, yoff, w, h, ptr); - _env->ReleaseIntArrayElements(data, ptr, 0/*JNI_ABORT*/); + LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", con, (RsScript)script, (RsAllocation)alloc, slot); + rsScriptBindAllocation(con, (RsScript)script, (RsAllocation)alloc, slot); } static void -nAdapter2DSubData_f(JNIEnv *_env, jobject _this, jint adapter, jint xoff, jint yoff, jint w, jint h, jfloatArray data) +nScriptSetVarI(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jint val) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(data); - LOG_API("nAdapter2DSubData_f, con(%p), adapter(%p), xoff(%i), yoff(%i), w(%i), h(%i), len(%i)", - con, (RsAdapter2D)adapter, xoff, yoff, w, h, len); - jfloat *ptr = _env->GetFloatArrayElements(data, NULL); - rsAdapter2DSubData(con, (RsAdapter1D)adapter, xoff, yoff, w, h, ptr); - _env->ReleaseFloatArrayElements(data, ptr, 0/*JNI_ABORT*/); + LOG_API("nScriptSetVarI, con(%p), s(%p), slot(%i), val(%i)", con, (void *)script, slot, val); + rsScriptSetVarI(con, (RsScript)script, slot, val); } -static jint -nAdapter2DCreate(JNIEnv *_env, jobject _this) +static void +nScriptSetVarObj(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jint val) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nAdapter2DCreate, con(%p)", con); - return (jint)rsAdapter2DCreate(con); + LOG_API("nScriptSetVarObj, con(%p), s(%p), slot(%i), val(%i)", con, (void *)script, slot, val); + rsScriptSetVarObj(con, (RsScript)script, slot, (RsObjectBase)val); } -// ----------------------------------- - static void -nScriptBindAllocation(JNIEnv *_env, jobject _this, jint script, jint alloc, jint slot) +nScriptSetVarJ(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jlong val) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptBindAllocation, con(%p), script(%p), alloc(%p), slot(%i)", con, (RsScript)script, (RsAllocation)alloc, slot); - rsScriptBindAllocation(con, (RsScript)script, (RsAllocation)alloc, slot); + LOG_API("nScriptSetVarJ, con(%p), s(%p), slot(%i), val(%lli)", con, (void *)script, slot, val); + rsScriptSetVarJ(con, (RsScript)script, slot, val); } static void -nScriptSetClearColor(JNIEnv *_env, jobject _this, jint script, jfloat r, jfloat g, jfloat b, jfloat a) +nScriptSetVarF(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, float val) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptSetClearColor, con(%p), s(%p), r(%f), g(%f), b(%f), a(%f)", con, (void *)script, r, g, b, a); - rsScriptSetClearColor(con, (RsScript)script, r, g, b, a); + LOG_API("nScriptSetVarF, con(%p), s(%p), slot(%i), val(%f)", con, (void *)script, slot, val); + rsScriptSetVarF(con, (RsScript)script, slot, val); } static void -nScriptSetClearDepth(JNIEnv *_env, jobject _this, jint script, jfloat d) +nScriptSetVarD(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, double val) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCSetClearDepth, con(%p), s(%p), depth(%f)", con, (void *)script, d); - rsScriptSetClearDepth(con, (RsScript)script, d); + LOG_API("nScriptSetVarD, con(%p), s(%p), slot(%i), val(%lf)", con, (void *)script, slot, val); + rsScriptSetVarD(con, (RsScript)script, slot, val); } static void -nScriptSetClearStencil(JNIEnv *_env, jobject _this, jint script, jint stencil) +nScriptSetVarV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCSetClearStencil, con(%p), s(%p), stencil(%i)", con, (void *)script, stencil); - rsScriptSetClearStencil(con, (RsScript)script, stencil); + LOG_API("nScriptSetVarV, con(%p), s(%p), slot(%i)", con, (void *)script, slot); + jint len = _env->GetArrayLength(data); + jbyte *ptr = _env->GetByteArrayElements(data, NULL); + rsScriptSetVarV(con, (RsScript)script, slot, ptr, len); + _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); } + static void -nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone) +nScriptSetTimeZone(JNIEnv *_env, jobject _this, RsContext con, jint script, jbyteArray timeZone) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nScriptCSetTimeZone, con(%p), s(%p), timeZone(%s)", con, (void *)script, (const char *)timeZone); jint length = _env->GetArrayLength(timeZone); @@ -895,66 +829,36 @@ nScriptSetTimeZone(JNIEnv *_env, jobject _this, jint script, jbyteArray timeZone } static void -nScriptSetType(JNIEnv *_env, jobject _this, jint type, jboolean writable, jstring _str, jint slot) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCAddType, con(%p), type(%p), writable(%i), slot(%i)", con, (RsType)type, writable, slot); - const char* n = NULL; - if (_str) { - n = _env->GetStringUTFChars(_str, NULL); - } - rsScriptSetType(con, (RsType)type, slot, writable, n); - if (n) { - _env->ReleaseStringUTFChars(_str, n); - } -} - -static void -nScriptSetInvoke(JNIEnv *_env, jobject _this, jstring _str, jint slot) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptSetInvoke, con(%p)", con); - const char* n = NULL; - if (_str) { - n = _env->GetStringUTFChars(_str, NULL); - } - rsScriptSetInvoke(con, n, slot); - if (n) { - _env->ReleaseStringUTFChars(_str, n); - } -} - -static void -nScriptInvoke(JNIEnv *_env, jobject _this, jint obj, jint slot) +nScriptInvoke(JNIEnv *_env, jobject _this, RsContext con, jint obj, jint slot) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nScriptInvoke, con(%p), script(%p)", con, (void *)obj); rsScriptInvoke(con, (RsScript)obj, slot); } static void -nScriptSetRoot(JNIEnv *_env, jobject _this, jboolean isRoot) +nScriptInvokeV(JNIEnv *_env, jobject _this, RsContext con, jint script, jint slot, jbyteArray data) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nScriptCSetRoot, con(%p), isRoot(%i)", con, isRoot); - rsScriptSetRoot(con, isRoot); + LOG_API("nScriptInvokeV, con(%p), s(%p), slot(%i)", con, (void *)script, slot); + jint len = _env->GetArrayLength(data); + jbyte *ptr = _env->GetByteArrayElements(data, NULL); + rsScriptInvokeV(con, (RsScript)script, slot, ptr, len); + _env->ReleaseByteArrayElements(data, ptr, JNI_ABORT); } + // ----------------------------------- static void -nScriptCBegin(JNIEnv *_env, jobject _this) +nScriptCBegin(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nScriptCBegin, con(%p)", con); rsScriptCBegin(con); } static void -nScriptCSetScript(JNIEnv *_env, jobject _this, jbyteArray scriptRef, +nScriptCSetScript(JNIEnv *_env, jobject _this, RsContext con, jbyteArray scriptRef, jint offset, jint length) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("!!! nScriptCSetScript, con(%p)", con); jint _exception = 0; jint remaining; @@ -995,114 +899,86 @@ exit: } static jint -nScriptCCreate(JNIEnv *_env, jobject _this) +nScriptCCreate(JNIEnv *_env, jobject _this, RsContext con, jstring packageName, jstring resName, jstring cacheDir) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nScriptCCreate, con(%p)", con); - return (jint)rsScriptCCreate(con); -} - -static void -nScriptCAddDefineI32(JNIEnv *_env, jobject _this, jstring name, jint value) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - const char* n = _env->GetStringUTFChars(name, NULL); - LOG_API("nScriptCAddDefineI32, con(%p) name(%s) value(%d)", con, n, value); - rsScriptCSetDefineI32(con, n, value); - _env->ReleaseStringUTFChars(name, n); -} - -static void -nScriptCAddDefineF(JNIEnv *_env, jobject _this, jstring name, jfloat value) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - const char* n = _env->GetStringUTFChars(name, NULL); - LOG_API("nScriptCAddDefineF, con(%p) name(%s) value(%f)", con, n, value); - rsScriptCSetDefineF(con, n, value); - _env->ReleaseStringUTFChars(name, n); + AutoJavaStringToUTF8 packageNameUTF(_env, packageName); + AutoJavaStringToUTF8 resNameUTF(_env, resName); + AutoJavaStringToUTF8 cacheDirUTF(_env, cacheDir); + jint i = (jint)rsScriptCCreate(con, packageNameUTF.c_str(), resNameUTF.c_str(), cacheDirUTF.c_str()); + return i; } // --------------------------------------------------------------------------- static void -nProgramFragmentStoreBegin(JNIEnv *_env, jobject _this, jint in, jint out) +nProgramStoreBegin(JNIEnv *_env, jobject _this, RsContext con, jint in, jint out) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out); - rsProgramFragmentStoreBegin(con, (RsElement)in, (RsElement)out); + LOG_API("nProgramStoreBegin, con(%p), in(%p), out(%p)", con, (RsElement)in, (RsElement)out); + rsProgramStoreBegin(con, (RsElement)in, (RsElement)out); } static void -nProgramFragmentStoreDepthFunc(JNIEnv *_env, jobject _this, jint func) +nProgramStoreDepthFunc(JNIEnv *_env, jobject _this, RsContext con, jint func) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreDepthFunc, con(%p), func(%i)", con, func); - rsProgramFragmentStoreDepthFunc(con, (RsDepthFunc)func); + LOG_API("nProgramStoreDepthFunc, con(%p), func(%i)", con, func); + rsProgramStoreDepthFunc(con, (RsDepthFunc)func); } static void -nProgramFragmentStoreDepthMask(JNIEnv *_env, jobject _this, jboolean enable) +nProgramStoreDepthMask(JNIEnv *_env, jobject _this, RsContext con, jboolean enable) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreDepthMask, con(%p), enable(%i)", con, enable); - rsProgramFragmentStoreDepthMask(con, enable); + LOG_API("nProgramStoreDepthMask, con(%p), enable(%i)", con, enable); + rsProgramStoreDepthMask(con, enable); } static void -nProgramFragmentStoreColorMask(JNIEnv *_env, jobject _this, jboolean r, jboolean g, jboolean b, jboolean a) +nProgramStoreColorMask(JNIEnv *_env, jobject _this, RsContext con, jboolean r, jboolean g, jboolean b, jboolean a) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a); - rsProgramFragmentStoreColorMask(con, r, g, b, a); + LOG_API("nProgramStoreColorMask, con(%p), r(%i), g(%i), b(%i), a(%i)", con, r, g, b, a); + rsProgramStoreColorMask(con, r, g, b, a); } static void -nProgramFragmentStoreBlendFunc(JNIEnv *_env, jobject _this, int src, int dst) +nProgramStoreBlendFunc(JNIEnv *_env, jobject _this, RsContext con, int src, int dst) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst); - rsProgramFragmentStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst); + LOG_API("nProgramStoreBlendFunc, con(%p), src(%i), dst(%i)", con, src, dst); + rsProgramStoreBlendFunc(con, (RsBlendSrcFunc)src, (RsBlendDstFunc)dst); } static void -nProgramFragmentStoreDither(JNIEnv *_env, jobject _this, jboolean enable) +nProgramStoreDither(JNIEnv *_env, jobject _this, RsContext con, jboolean enable) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreDither, con(%p), enable(%i)", con, enable); - rsProgramFragmentStoreDither(con, enable); + LOG_API("nProgramStoreDither, con(%p), enable(%i)", con, enable); + rsProgramStoreDither(con, enable); } static jint -nProgramFragmentStoreCreate(JNIEnv *_env, jobject _this) +nProgramStoreCreate(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramFragmentStoreCreate, con(%p)", con); - - return (jint)rsProgramFragmentStoreCreate(con); + LOG_API("nProgramStoreCreate, con(%p)", con); + return (jint)rsProgramStoreCreate(con); } // --------------------------------------------------------------------------- static void -nProgramBindConstants(JNIEnv *_env, jobject _this, jint vpv, jint slot, jint a) +nProgramBindConstants(JNIEnv *_env, jobject _this, RsContext con, jint vpv, jint slot, jint a) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nProgramBindConstants, con(%p), vpf(%p), sloat(%i), a(%p)", con, (RsProgramVertex)vpv, slot, (RsAllocation)a); rsProgramBindConstants(con, (RsProgram)vpv, slot, (RsAllocation)a); } static void -nProgramBindTexture(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a) +nProgramBindTexture(JNIEnv *_env, jobject _this, RsContext con, jint vpf, jint slot, jint a) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nProgramBindTexture, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsAllocation)a); rsProgramBindTexture(con, (RsProgramFragment)vpf, slot, (RsAllocation)a); } static void -nProgramBindSampler(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a) +nProgramBindSampler(JNIEnv *_env, jobject _this, RsContext con, jint vpf, jint slot, jint a) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nProgramBindSampler, con(%p), vpf(%p), slot(%i), a(%p)", con, (RsProgramFragment)vpf, slot, (RsSampler)a); rsProgramBindSampler(con, (RsProgramFragment)vpf, slot, (RsSampler)a); } @@ -1110,32 +986,15 @@ nProgramBindSampler(JNIEnv *_env, jobject _this, jint vpf, jint slot, jint a) // --------------------------------------------------------------------------- static jint -nProgramFragmentCreate(JNIEnv *_env, jobject _this, jintArray params) +nProgramFragmentCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); + AutoJavaStringToUTF8 shaderUTF(_env, shader); jint *paramPtr = _env->GetIntArrayElements(params, NULL); jint paramLen = _env->GetArrayLength(params); LOG_API("nProgramFragmentCreate, con(%p), paramLen(%i)", con, paramLen); - jint ret = (jint)rsProgramFragmentCreate(con, (uint32_t *)paramPtr, paramLen); - _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT); - return ret; -} - -static jint -nProgramFragmentCreate2(JNIEnv *_env, jobject _this, jstring shader, jintArray params) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - const char* shaderUTF = _env->GetStringUTFChars(shader, NULL); - jint shaderLen = _env->GetStringUTFLength(shader); - jint *paramPtr = _env->GetIntArrayElements(params, NULL); - jint paramLen = _env->GetArrayLength(params); - - LOG_API("nProgramFragmentCreate2, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen); - - jint ret = (jint)rsProgramFragmentCreate2(con, shaderUTF, shaderLen, (uint32_t *)paramPtr, paramLen); - _env->ReleaseStringUTFChars(shader, shaderUTF); + jint ret = (jint)rsProgramFragmentCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen); _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT); return ret; } @@ -1144,26 +1003,15 @@ nProgramFragmentCreate2(JNIEnv *_env, jobject _this, jstring shader, jintArray p // --------------------------------------------------------------------------- static jint -nProgramVertexCreate(JNIEnv *_env, jobject _this, jboolean texMat) +nProgramVertexCreate(JNIEnv *_env, jobject _this, RsContext con, jstring shader, jintArray params) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramVertexCreate, con(%p), texMat(%i)", con, texMat); - return (jint)rsProgramVertexCreate(con, texMat); -} - -static jint -nProgramVertexCreate2(JNIEnv *_env, jobject _this, jstring shader, jintArray params) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - const char* shaderUTF = _env->GetStringUTFChars(shader, NULL); - jint shaderLen = _env->GetStringUTFLength(shader); + AutoJavaStringToUTF8 shaderUTF(_env, shader); jint *paramPtr = _env->GetIntArrayElements(params, NULL); jint paramLen = _env->GetArrayLength(params); - LOG_API("nProgramVertexCreate2, con(%p), shaderLen(%i), paramLen(%i)", con, shaderLen, paramLen); + LOG_API("nProgramVertexCreate, con(%p), paramLen(%i)", con, paramLen); - jint ret = (jint)rsProgramVertexCreate2(con, shaderUTF, shaderLen, (uint32_t *)paramPtr, paramLen); - _env->ReleaseStringUTFChars(shader, shaderUTF); + jint ret = (jint)rsProgramVertexCreate(con, shaderUTF.c_str(), shaderUTF.length(), (uint32_t *)paramPtr, paramLen); _env->ReleaseIntArrayElements(params, paramPtr, JNI_ABORT); return ret; } @@ -1171,70 +1019,61 @@ nProgramVertexCreate2(JNIEnv *_env, jobject _this, jstring shader, jintArray par // --------------------------------------------------------------------------- static jint -nProgramRasterCreate(JNIEnv *_env, jobject _this, jint in, jint out, - jboolean pointSmooth, jboolean lineSmooth, jboolean pointSprite) +nProgramRasterCreate(JNIEnv *_env, jobject _this, RsContext con, jboolean pointSmooth, jboolean lineSmooth, jboolean pointSprite) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramRasterCreate, con(%p), in(%p), out(%p), pointSmooth(%i), lineSmooth(%i), pointSprite(%i)", - con, (RsElement)in, (RsElement)out, pointSmooth, lineSmooth, pointSprite); - return (jint)rsProgramRasterCreate(con, (RsElement)in, (RsElement)out, pointSmooth, lineSmooth, pointSprite); + LOG_API("nProgramRasterCreate, con(%p), pointSmooth(%i), lineSmooth(%i), pointSprite(%i)", + con, pointSmooth, lineSmooth, pointSprite); + return (jint)rsProgramRasterCreate(con, pointSmooth, lineSmooth, pointSprite); } static void -nProgramRasterSetPointSize(JNIEnv *_env, jobject _this, jint vpr, jfloat v) +nProgramRasterSetLineWidth(JNIEnv *_env, jobject _this, RsContext con, jint vpr, jfloat v) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramRasterSetPointSize, con(%p), vpf(%p), value(%f)", con, (RsProgramRaster)vpr, v); - rsProgramRasterSetPointSize(con, (RsProgramFragment)vpr, v); + LOG_API("nProgramRasterSetLineWidth, con(%p), vpf(%p), value(%f)", con, (RsProgramRaster)vpr, v); + rsProgramRasterSetLineWidth(con, (RsProgramRaster)vpr, v); } static void -nProgramRasterSetLineWidth(JNIEnv *_env, jobject _this, jint vpr, jfloat v) +nProgramRasterSetCullMode(JNIEnv *_env, jobject _this, RsContext con, jint vpr, jint v) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nProgramRasterSetLineWidth, con(%p), vpf(%p), value(%f)", con, (RsProgramRaster)vpr, v); - rsProgramRasterSetLineWidth(con, (RsProgramFragment)vpr, v); + LOG_API("nProgramRasterSetCullMode, con(%p), vpf(%p), value(%i)", con, (RsProgramRaster)vpr, v); + rsProgramRasterSetCullMode(con, (RsProgramRaster)vpr, (RsCullMode)v); } // --------------------------------------------------------------------------- static void -nContextBindRootScript(JNIEnv *_env, jobject _this, jint script) +nContextBindRootScript(JNIEnv *_env, jobject _this, RsContext con, jint script) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextBindRootScript, con(%p), script(%p)", con, (RsScript)script); rsContextBindRootScript(con, (RsScript)script); } static void -nContextBindProgramFragmentStore(JNIEnv *_env, jobject _this, jint pfs) +nContextBindProgramStore(JNIEnv *_env, jobject _this, RsContext con, jint pfs) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nContextBindProgramFragmentStore, con(%p), pfs(%p)", con, (RsProgramFragmentStore)pfs); - rsContextBindProgramFragmentStore(con, (RsProgramFragmentStore)pfs); + LOG_API("nContextBindProgramStore, con(%p), pfs(%p)", con, (RsProgramStore)pfs); + rsContextBindProgramStore(con, (RsProgramStore)pfs); } static void -nContextBindProgramFragment(JNIEnv *_env, jobject _this, jint pf) +nContextBindProgramFragment(JNIEnv *_env, jobject _this, RsContext con, jint pf) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextBindProgramFragment, con(%p), pf(%p)", con, (RsProgramFragment)pf); rsContextBindProgramFragment(con, (RsProgramFragment)pf); } static void -nContextBindProgramVertex(JNIEnv *_env, jobject _this, jint pf) +nContextBindProgramVertex(JNIEnv *_env, jobject _this, RsContext con, jint pf) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextBindProgramVertex, con(%p), pf(%p)", con, (RsProgramVertex)pf); rsContextBindProgramVertex(con, (RsProgramVertex)pf); } static void -nContextBindProgramRaster(JNIEnv *_env, jobject _this, jint pf) +nContextBindProgramRaster(JNIEnv *_env, jobject _this, RsContext con, jint pf) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nContextBindProgramRaster, con(%p), pf(%p)", con, (RsProgramRaster)pf); rsContextBindProgramRaster(con, (RsProgramRaster)pf); } @@ -1243,108 +1082,115 @@ nContextBindProgramRaster(JNIEnv *_env, jobject _this, jint pf) // --------------------------------------------------------------------------- static void -nSamplerBegin(JNIEnv *_env, jobject _this) +nSamplerBegin(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nSamplerBegin, con(%p)", con); rsSamplerBegin(con); } static void -nSamplerSet(JNIEnv *_env, jobject _this, jint p, jint v) +nSamplerSet(JNIEnv *_env, jobject _this, RsContext con, jint p, jint v) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nSamplerSet, con(%p), param(%i), value(%i)", con, p, v); rsSamplerSet(con, (RsSamplerParam)p, (RsSamplerValue)v); } +static void +nSamplerSet2(JNIEnv *_env, jobject _this, RsContext con, jint p, jfloat v) +{ + LOG_API("nSamplerSet2, con(%p), param(%i), value(%f)", con, p, v); + rsSamplerSet2(con, (RsSamplerParam)p, v); +} + static jint -nSamplerCreate(JNIEnv *_env, jobject _this) +nSamplerCreate(JNIEnv *_env, jobject _this, RsContext con) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); LOG_API("nSamplerCreate, con(%p)", con); return (jint)rsSamplerCreate(con); } // --------------------------------------------------------------------------- +static jint +nMeshCreate(JNIEnv *_env, jobject _this, RsContext con, jint vtxCount, jint idxCount) +{ + LOG_API("nMeshCreate, con(%p), vtxCount(%i), idxCount(%i)", con, vtxCount, idxCount); + int id = (int)rsMeshCreate(con, vtxCount, idxCount); + return id; +} + static void -nLightBegin(JNIEnv *_env, jobject _this) +nMeshBindVertex(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jint alloc, jint slot) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightBegin, con(%p)", con); - rsLightBegin(con); + LOG_API("nMeshBindVertex, con(%p), Mesh(%p), Alloc(%p), slot(%i)", con, (RsMesh)mesh, (RsAllocation)alloc, slot); + rsMeshBindVertex(con, (RsMesh)mesh, (RsAllocation)alloc, slot); } static void -nLightSetIsMono(JNIEnv *_env, jobject _this, jboolean isMono) +nMeshBindIndex(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jint alloc, jint primID, jint slot) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightSetIsMono, con(%p), isMono(%i)", con, isMono); - rsLightSetMonochromatic(con, isMono); + LOG_API("nMeshBindIndex, con(%p), Mesh(%p), Alloc(%p)", con, (RsMesh)mesh, (RsAllocation)alloc); + rsMeshBindIndex(con, (RsMesh)mesh, (RsAllocation)alloc, primID, slot); } static void -nLightSetIsLocal(JNIEnv *_env, jobject _this, jboolean isLocal) +nMeshInitVertexAttribs(JNIEnv *_env, jobject _this, RsContext con, jint mesh) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightSetIsLocal, con(%p), isLocal(%i)", con, isLocal); - rsLightSetLocal(con, isLocal); + LOG_API("nMeshInitVertexAttribs, con(%p), Mesh(%p)", con, (RsMesh)mesh); + rsMeshInitVertexAttribs(con, (RsMesh)mesh); } + static jint -nLightCreate(JNIEnv *_env, jobject _this) +nMeshGetVertexBufferCount(JNIEnv *_env, jobject _this, RsContext con, jint mesh) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightCreate, con(%p)", con); - return (jint)rsLightCreate(con); + LOG_API("nMeshGetVertexBufferCount, con(%p), Mesh(%p)", con, (RsMesh)mesh); + jint vtxCount = 0; + rsaMeshGetVertexBufferCount(con, (RsMesh)mesh, &vtxCount); + return vtxCount; } -static void -nLightSetColor(JNIEnv *_env, jobject _this, jint light, float r, float g, float b) +static jint +nMeshGetIndexCount(JNIEnv *_env, jobject _this, RsContext con, jint mesh) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightSetColor, con(%p), light(%p), r(%f), g(%f), b(%f)", con, (RsLight)light, r, g, b); - rsLightSetColor(con, (RsLight)light, r, g, b); + LOG_API("nMeshGetIndexCount, con(%p), Mesh(%p)", con, (RsMesh)mesh); + jint idxCount = 0; + rsaMeshGetIndexCount(con, (RsMesh)mesh, &idxCount); + return idxCount; } static void -nLightSetPosition(JNIEnv *_env, jobject _this, jint light, float x, float y, float z) +nMeshGetVertices(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jintArray _ids, int numVtxIDs) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nLightSetPosition, con(%p), light(%p), x(%f), y(%f), z(%f)", con, (RsLight)light, x, y, z); - rsLightSetPosition(con, (RsLight)light, x, y, z); -} + LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", con, (RsMesh)mesh); -// --------------------------------------------------------------------------- + RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numVtxIDs * sizeof(RsAllocation)); + rsaMeshGetVertices(con, (RsMesh)mesh, allocs, (uint32_t)numVtxIDs); -static jint -nSimpleMeshCreate(JNIEnv *_env, jobject _this, jint batchID, jint indexID, jintArray vtxIDs, jint primID) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - jint len = _env->GetArrayLength(vtxIDs); - LOG_API("nSimpleMeshCreate, con(%p), batchID(%i), indexID(%i), vtxIDs.len(%i), primID(%i)", - con, batchID, indexID, len, primID); - jint *ptr = _env->GetIntArrayElements(vtxIDs, NULL); - int id = (int)rsSimpleMeshCreate(con, (void *)batchID, (void *)indexID, (void **)ptr, len, primID); - _env->ReleaseIntArrayElements(vtxIDs, ptr, 0/*JNI_ABORT*/); - return id; -} + for(jint i = 0; i < numVtxIDs; i ++) { + _env->SetIntArrayRegion(_ids, i, 1, (const jint*)&allocs[i]); + } -static void -nSimpleMeshBindVertex(JNIEnv *_env, jobject _this, jint s, jint alloc, jint slot) -{ - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nSimpleMeshBindVertex, con(%p), SimpleMesh(%p), Alloc(%p), slot(%i)", con, (RsSimpleMesh)s, (RsAllocation)alloc, slot); - rsSimpleMeshBindVertex(con, (RsSimpleMesh)s, (RsAllocation)alloc, slot); + free(allocs); } static void -nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc) +nMeshGetIndices(JNIEnv *_env, jobject _this, RsContext con, jint mesh, jintArray _idxIds, jintArray _primitives, int numIndices) { - RsContext con = (RsContext)(_env->GetIntField(_this, gContextId)); - LOG_API("nSimpleMeshBindIndex, con(%p), SimpleMesh(%p), Alloc(%p)", con, (RsSimpleMesh)s, (RsAllocation)alloc); - rsSimpleMeshBindIndex(con, (RsSimpleMesh)s, (RsAllocation)alloc); + LOG_API("nMeshGetVertices, con(%p), Mesh(%p)", con, (RsMesh)mesh); + + RsAllocation *allocs = (RsAllocation*)malloc((uint32_t)numIndices * sizeof(RsAllocation)); + uint32_t *prims= (uint32_t*)malloc((uint32_t)numIndices * sizeof(uint32_t)); + + rsaMeshGetIndices(con, (RsMesh)mesh, allocs, prims, (uint32_t)numIndices); + + for(jint i = 0; i < numIndices; i ++) { + _env->SetIntArrayRegion(_idxIds, i, 1, (const jint*)&allocs[i]); + _env->SetIntArrayRegion(_primitives, i, 1, (const jint*)&prims[i]); + } + + free(allocs); + free(prims); } // --------------------------------------------------------------------------- @@ -1353,130 +1199,133 @@ nSimpleMeshBindIndex(JNIEnv *_env, jobject _this, jint s, jint alloc) static const char *classPathName = "android/renderscript/RenderScript"; static JNINativeMethod methods[] = { -{"_nInit", "()V", (void*)_nInit }, -{"nInitElements", "(IIII)V", (void*)nInitElements }, - -{"nDeviceCreate", "()I", (void*)nDeviceCreate }, -{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy }, -{"nDeviceSetConfig", "(III)V", (void*)nDeviceSetConfig }, -{"nContextCreate", "(II)I", (void*)nContextCreate }, -{"nContextCreateGL", "(IIZ)I", (void*)nContextCreateGL }, -{"nContextSetPriority", "(I)V", (void*)nContextSetPriority }, -{"nContextSetSurface", "(IILandroid/view/Surface;)V", (void*)nContextSetSurface }, -{"nContextDestroy", "(I)V", (void*)nContextDestroy }, -{"nContextDump", "(I)V", (void*)nContextDump }, -{"nContextPause", "()V", (void*)nContextPause }, -{"nContextResume", "()V", (void*)nContextResume }, -{"nAssignName", "(I[B)V", (void*)nAssignName }, -{"nObjDestroy", "(I)V", (void*)nObjDestroy }, -{"nObjDestroyOOB", "(I)V", (void*)nObjDestroyOOB }, -{"nContextGetMessage", "([IZ)I", (void*)nContextGetMessage }, -{"nContextInitToClient", "()V", (void*)nContextInitToClient }, -{"nContextDeinitToClient", "()V", (void*)nContextDeinitToClient }, - -{"nFileOpen", "([B)I", (void*)nFileOpen }, - -{"nElementCreate", "(IIZI)I", (void*)nElementCreate }, -{"nElementCreate2", "([I[Ljava/lang/String;)I", (void*)nElementCreate2 }, - -{"nTypeBegin", "(I)V", (void*)nTypeBegin }, -{"nTypeAdd", "(II)V", (void*)nTypeAdd }, -{"nTypeCreate", "()I", (void*)nTypeCreate }, -{"nTypeFinalDestroy", "(Landroid/renderscript/Type;)V", (void*)nTypeFinalDestroy }, -{"nTypeSetupFields", "(Landroid/renderscript/Type;[I[I[Ljava/lang/reflect/Field;)V", (void*)nTypeSetupFields }, - -{"nAllocationCreateTyped", "(I)I", (void*)nAllocationCreateTyped }, -{"nAllocationCreateFromBitmap", "(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmap }, -{"nAllocationCreateBitmapRef", "(ILandroid/graphics/Bitmap;)I", (void*)nAllocationCreateBitmapRef }, -{"nAllocationCreateFromBitmapBoxed","(IZLandroid/graphics/Bitmap;)I", (void*)nAllocationCreateFromBitmapBoxed }, -{"nAllocationCreateFromAssetStream","(IZI)I", (void*)nAllocationCreateFromAssetStream }, -{"nAllocationUploadToTexture", "(IZI)V", (void*)nAllocationUploadToTexture }, -{"nAllocationUploadToBufferObject","(I)V", (void*)nAllocationUploadToBufferObject }, -{"nAllocationSubData1D", "(III[II)V", (void*)nAllocationSubData1D_i }, -{"nAllocationSubData1D", "(III[SI)V", (void*)nAllocationSubData1D_s }, -{"nAllocationSubData1D", "(III[BI)V", (void*)nAllocationSubData1D_b }, -{"nAllocationSubData1D", "(III[FI)V", (void*)nAllocationSubData1D_f }, -{"nAllocationSubData2D", "(IIIII[II)V", (void*)nAllocationSubData2D_i }, -{"nAllocationSubData2D", "(IIIII[FI)V", (void*)nAllocationSubData2D_f }, -{"nAllocationRead", "(I[I)V", (void*)nAllocationRead_i }, -{"nAllocationRead", "(I[F)V", (void*)nAllocationRead_f }, -{"nAllocationSubDataFromObject", "(ILandroid/renderscript/Type;ILjava/lang/Object;)V", (void*)nAllocationSubDataFromObject }, -{"nAllocationSubReadFromObject", "(ILandroid/renderscript/Type;ILjava/lang/Object;)V", (void*)nAllocationSubReadFromObject }, - -{"nAdapter1DBindAllocation", "(II)V", (void*)nAdapter1DBindAllocation }, -{"nAdapter1DSetConstraint", "(III)V", (void*)nAdapter1DSetConstraint }, -{"nAdapter1DData", "(I[I)V", (void*)nAdapter1DData_i }, -{"nAdapter1DData", "(I[F)V", (void*)nAdapter1DData_f }, -{"nAdapter1DSubData", "(III[I)V", (void*)nAdapter1DSubData_i }, -{"nAdapter1DSubData", "(III[F)V", (void*)nAdapter1DSubData_f }, -{"nAdapter1DCreate", "()I", (void*)nAdapter1DCreate }, - -{"nAdapter2DBindAllocation", "(II)V", (void*)nAdapter2DBindAllocation }, -{"nAdapter2DSetConstraint", "(III)V", (void*)nAdapter2DSetConstraint }, -{"nAdapter2DData", "(I[I)V", (void*)nAdapter2DData_i }, -{"nAdapter2DData", "(I[F)V", (void*)nAdapter2DData_f }, -{"nAdapter2DSubData", "(IIIII[I)V", (void*)nAdapter2DSubData_i }, -{"nAdapter2DSubData", "(IIIII[F)V", (void*)nAdapter2DSubData_f }, -{"nAdapter2DCreate", "()I", (void*)nAdapter2DCreate }, - -{"nScriptBindAllocation", "(III)V", (void*)nScriptBindAllocation }, -{"nScriptSetClearColor", "(IFFFF)V", (void*)nScriptSetClearColor }, -{"nScriptSetClearDepth", "(IF)V", (void*)nScriptSetClearDepth }, -{"nScriptSetClearStencil", "(II)V", (void*)nScriptSetClearStencil }, -{"nScriptSetTimeZone", "(I[B)V", (void*)nScriptSetTimeZone }, -{"nScriptSetType", "(IZLjava/lang/String;I)V", (void*)nScriptSetType }, -{"nScriptSetRoot", "(Z)V", (void*)nScriptSetRoot }, -{"nScriptSetInvokable", "(Ljava/lang/String;I)V", (void*)nScriptSetInvoke }, -{"nScriptInvoke", "(II)V", (void*)nScriptInvoke }, - -{"nScriptCBegin", "()V", (void*)nScriptCBegin }, -{"nScriptCSetScript", "([BII)V", (void*)nScriptCSetScript }, -{"nScriptCCreate", "()I", (void*)nScriptCCreate }, -{"nScriptCAddDefineI32", "(Ljava/lang/String;I)V", (void*)nScriptCAddDefineI32 }, -{"nScriptCAddDefineF", "(Ljava/lang/String;F)V", (void*)nScriptCAddDefineF }, - -{"nProgramFragmentStoreBegin", "(II)V", (void*)nProgramFragmentStoreBegin }, -{"nProgramFragmentStoreDepthFunc", "(I)V", (void*)nProgramFragmentStoreDepthFunc }, -{"nProgramFragmentStoreDepthMask", "(Z)V", (void*)nProgramFragmentStoreDepthMask }, -{"nProgramFragmentStoreColorMask", "(ZZZZ)V", (void*)nProgramFragmentStoreColorMask }, -{"nProgramFragmentStoreBlendFunc", "(II)V", (void*)nProgramFragmentStoreBlendFunc }, -{"nProgramFragmentStoreDither", "(Z)V", (void*)nProgramFragmentStoreDither }, -{"nProgramFragmentStoreCreate", "()I", (void*)nProgramFragmentStoreCreate }, - -{"nProgramBindConstants", "(III)V", (void*)nProgramBindConstants }, -{"nProgramBindTexture", "(III)V", (void*)nProgramBindTexture }, -{"nProgramBindSampler", "(III)V", (void*)nProgramBindSampler }, - -{"nProgramFragmentCreate", "([I)I", (void*)nProgramFragmentCreate }, -{"nProgramFragmentCreate2", "(Ljava/lang/String;[I)I", (void*)nProgramFragmentCreate2 }, - -{"nProgramRasterCreate", "(IIZZZ)I", (void*)nProgramRasterCreate }, -{"nProgramRasterSetPointSize", "(IF)V", (void*)nProgramRasterSetPointSize }, -{"nProgramRasterSetLineWidth", "(IF)V", (void*)nProgramRasterSetLineWidth }, - -{"nProgramVertexCreate", "(Z)I", (void*)nProgramVertexCreate }, -{"nProgramVertexCreate2", "(Ljava/lang/String;[I)I", (void*)nProgramVertexCreate2 }, - -{"nLightBegin", "()V", (void*)nLightBegin }, -{"nLightSetIsMono", "(Z)V", (void*)nLightSetIsMono }, -{"nLightSetIsLocal", "(Z)V", (void*)nLightSetIsLocal }, -{"nLightCreate", "()I", (void*)nLightCreate }, -{"nLightSetColor", "(IFFF)V", (void*)nLightSetColor }, -{"nLightSetPosition", "(IFFF)V", (void*)nLightSetPosition }, - -{"nContextBindRootScript", "(I)V", (void*)nContextBindRootScript }, -{"nContextBindProgramFragmentStore","(I)V", (void*)nContextBindProgramFragmentStore }, -{"nContextBindProgramFragment", "(I)V", (void*)nContextBindProgramFragment }, -{"nContextBindProgramVertex", "(I)V", (void*)nContextBindProgramVertex }, -{"nContextBindProgramRaster", "(I)V", (void*)nContextBindProgramRaster }, - -{"nSamplerBegin", "()V", (void*)nSamplerBegin }, -{"nSamplerSet", "(II)V", (void*)nSamplerSet }, -{"nSamplerCreate", "()I", (void*)nSamplerCreate }, - -{"nSimpleMeshCreate", "(II[II)I", (void*)nSimpleMeshCreate }, -{"nSimpleMeshBindVertex", "(III)V", (void*)nSimpleMeshBindVertex }, -{"nSimpleMeshBindIndex", "(II)V", (void*)nSimpleMeshBindIndex }, +{"_nInit", "()V", (void*)_nInit }, + +{"nDeviceCreate", "()I", (void*)nDeviceCreate }, +{"nDeviceDestroy", "(I)V", (void*)nDeviceDestroy }, +{"nDeviceSetConfig", "(III)V", (void*)nDeviceSetConfig }, +{"nContextGetUserMessage", "(I[I)V", (void*)nContextGetUserMessage }, +{"nContextGetErrorMessage", "(I)Ljava/lang/String;", (void*)nContextGetErrorMessage }, +{"nContextPeekMessage", "(I[IZ)I", (void*)nContextPeekMessage }, + +{"nContextInitToClient", "(I)V", (void*)nContextInitToClient }, +{"nContextDeinitToClient", "(I)V", (void*)nContextDeinitToClient }, + + +// All methods below are thread protected in java. +{"rsnContextCreate", "(II)I", (void*)nContextCreate }, +{"rsnContextCreateGL", "(IIIIIIIIIIIIFI)I", (void*)nContextCreateGL }, +{"rsnContextFinish", "(I)V", (void*)nContextFinish }, +{"rsnContextSetPriority", "(II)V", (void*)nContextSetPriority }, +{"rsnContextSetSurface", "(IIILandroid/view/Surface;)V", (void*)nContextSetSurface }, +{"rsnContextDestroy", "(I)V", (void*)nContextDestroy }, +{"rsnContextDump", "(II)V", (void*)nContextDump }, +{"rsnContextPause", "(I)V", (void*)nContextPause }, +{"rsnContextResume", "(I)V", (void*)nContextResume }, +{"rsnAssignName", "(II[B)V", (void*)nAssignName }, +{"rsnGetName", "(II)Ljava/lang/String;", (void*)nGetName }, +{"rsnObjDestroy", "(II)V", (void*)nObjDestroy }, + +{"rsnFileA3DCreateFromFile", "(ILjava/lang/String;)I", (void*)nFileA3DCreateFromFile }, +{"rsnFileA3DCreateFromAssetStream", "(II)I", (void*)nFileA3DCreateFromAssetStream }, +{"rsnFileA3DCreateFromAsset", "(ILandroid/content/res/AssetManager;Ljava/lang/String;)I", (void*)nFileA3DCreateFromAsset }, +{"rsnFileA3DGetNumIndexEntries", "(II)I", (void*)nFileA3DGetNumIndexEntries }, +{"rsnFileA3DGetIndexEntries", "(III[I[Ljava/lang/String;)V", (void*)nFileA3DGetIndexEntries }, +{"rsnFileA3DGetEntryByIndex", "(III)I", (void*)nFileA3DGetEntryByIndex }, + +{"rsnFontCreateFromFile", "(ILjava/lang/String;FI)I", (void*)nFontCreateFromFile }, +{"rsnFontCreateFromAssetStream", "(ILjava/lang/String;FII)I", (void*)nFontCreateFromAssetStream }, +{"rsnFontCreateFromAsset", "(ILandroid/content/res/AssetManager;Ljava/lang/String;FI)I", (void*)nFontCreateFromAsset }, + +{"rsnElementCreate", "(IIIZI)I", (void*)nElementCreate }, +{"rsnElementCreate2", "(I[I[Ljava/lang/String;[I)I", (void*)nElementCreate2 }, +{"rsnElementGetNativeData", "(II[I)V", (void*)nElementGetNativeData }, +{"rsnElementGetSubElements", "(II[I[Ljava/lang/String;)V", (void*)nElementGetSubElements }, + +{"rsnTypeCreate", "(IIIIIZZ)I", (void*)nTypeCreate }, +{"rsnTypeGetNativeData", "(II[I)V", (void*)nTypeGetNativeData }, + +{"rsnAllocationCreateTyped", "(IIII)I", (void*)nAllocationCreateTyped }, +{"rsnAllocationCreateFromBitmap", "(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCreateFromBitmap }, +{"rsnAllocationCubeCreateFromBitmap","(IIILandroid/graphics/Bitmap;I)I", (void*)nAllocationCubeCreateFromBitmap }, + +{"rsnAllocationCopyFromBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationCopyFromBitmap }, +{"rsnAllocationCopyToBitmap", "(IILandroid/graphics/Bitmap;)V", (void*)nAllocationCopyToBitmap }, + +{"rsnAllocationSyncAll", "(III)V", (void*)nAllocationSyncAll }, +{"rsnAllocationData1D", "(IIIII[II)V", (void*)nAllocationData1D_i }, +{"rsnAllocationData1D", "(IIIII[SI)V", (void*)nAllocationData1D_s }, +{"rsnAllocationData1D", "(IIIII[BI)V", (void*)nAllocationData1D_b }, +{"rsnAllocationData1D", "(IIIII[FI)V", (void*)nAllocationData1D_f }, +{"rsnAllocationElementData1D", "(IIIII[BI)V", (void*)nAllocationElementData1D }, +{"rsnAllocationData2D", "(IIIIIIII[II)V", (void*)nAllocationData2D_i }, +{"rsnAllocationData2D", "(IIIIIIII[SI)V", (void*)nAllocationData2D_s }, +{"rsnAllocationData2D", "(IIIIIIII[BI)V", (void*)nAllocationData2D_b }, +{"rsnAllocationData2D", "(IIIIIIII[FI)V", (void*)nAllocationData2D_f }, +{"rsnAllocationRead", "(II[I)V", (void*)nAllocationRead_i }, +{"rsnAllocationRead", "(II[S)V", (void*)nAllocationRead_s }, +{"rsnAllocationRead", "(II[B)V", (void*)nAllocationRead_b }, +{"rsnAllocationRead", "(II[F)V", (void*)nAllocationRead_f }, +{"rsnAllocationGetType", "(II)I", (void*)nAllocationGetType}, +{"rsnAllocationResize1D", "(III)V", (void*)nAllocationResize1D }, +{"rsnAllocationResize2D", "(IIII)V", (void*)nAllocationResize2D }, +{"rsnAllocationGenerateMipmaps", "(II)V", (void*)nAllocationGenerateMipmaps }, + +{"rsnScriptBindAllocation", "(IIII)V", (void*)nScriptBindAllocation }, +{"rsnScriptSetTimeZone", "(II[B)V", (void*)nScriptSetTimeZone }, +{"rsnScriptInvoke", "(III)V", (void*)nScriptInvoke }, +{"rsnScriptInvokeV", "(III[B)V", (void*)nScriptInvokeV }, +{"rsnScriptSetVarI", "(IIII)V", (void*)nScriptSetVarI }, +{"rsnScriptSetVarJ", "(IIIJ)V", (void*)nScriptSetVarJ }, +{"rsnScriptSetVarF", "(IIIF)V", (void*)nScriptSetVarF }, +{"rsnScriptSetVarD", "(IIID)V", (void*)nScriptSetVarD }, +{"rsnScriptSetVarV", "(III[B)V", (void*)nScriptSetVarV }, +{"rsnScriptSetVarObj", "(IIII)V", (void*)nScriptSetVarObj }, + +{"rsnScriptCBegin", "(I)V", (void*)nScriptCBegin }, +{"rsnScriptCSetScript", "(I[BII)V", (void*)nScriptCSetScript }, +{"rsnScriptCCreate", "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)I", (void*)nScriptCCreate }, + +{"rsnProgramStoreBegin", "(III)V", (void*)nProgramStoreBegin }, +{"rsnProgramStoreDepthFunc", "(II)V", (void*)nProgramStoreDepthFunc }, +{"rsnProgramStoreDepthMask", "(IZ)V", (void*)nProgramStoreDepthMask }, +{"rsnProgramStoreColorMask", "(IZZZZ)V", (void*)nProgramStoreColorMask }, +{"rsnProgramStoreBlendFunc", "(III)V", (void*)nProgramStoreBlendFunc }, +{"rsnProgramStoreDither", "(IZ)V", (void*)nProgramStoreDither }, +{"rsnProgramStoreCreate", "(I)I", (void*)nProgramStoreCreate }, + +{"rsnProgramBindConstants", "(IIII)V", (void*)nProgramBindConstants }, +{"rsnProgramBindTexture", "(IIII)V", (void*)nProgramBindTexture }, +{"rsnProgramBindSampler", "(IIII)V", (void*)nProgramBindSampler }, + +{"rsnProgramFragmentCreate", "(ILjava/lang/String;[I)I", (void*)nProgramFragmentCreate }, + +{"rsnProgramRasterCreate", "(IZZZ)I", (void*)nProgramRasterCreate }, +{"rsnProgramRasterSetLineWidth", "(IIF)V", (void*)nProgramRasterSetLineWidth }, +{"rsnProgramRasterSetCullMode", "(III)V", (void*)nProgramRasterSetCullMode }, + +{"rsnProgramVertexCreate", "(ILjava/lang/String;[I)I", (void*)nProgramVertexCreate }, + +{"rsnContextBindRootScript", "(II)V", (void*)nContextBindRootScript }, +{"rsnContextBindProgramStore", "(II)V", (void*)nContextBindProgramStore }, +{"rsnContextBindProgramFragment", "(II)V", (void*)nContextBindProgramFragment }, +{"rsnContextBindProgramVertex", "(II)V", (void*)nContextBindProgramVertex }, +{"rsnContextBindProgramRaster", "(II)V", (void*)nContextBindProgramRaster }, + +{"rsnSamplerBegin", "(I)V", (void*)nSamplerBegin }, +{"rsnSamplerSet", "(III)V", (void*)nSamplerSet }, +{"rsnSamplerSet2", "(IIF)V", (void*)nSamplerSet2 }, +{"rsnSamplerCreate", "(I)I", (void*)nSamplerCreate }, + +{"rsnMeshCreate", "(III)I", (void*)nMeshCreate }, +{"rsnMeshBindVertex", "(IIII)V", (void*)nMeshBindVertex }, +{"rsnMeshBindIndex", "(IIIII)V", (void*)nMeshBindIndex }, +{"rsnMeshInitVertexAttribs", "(II)V", (void*)nMeshInitVertexAttribs }, + +{"rsnMeshGetVertexBufferCount", "(II)I", (void*)nMeshGetVertexBufferCount }, +{"rsnMeshGetIndexCount", "(II)I", (void*)nMeshGetIndexCount }, +{"rsnMeshGetVertices", "(II[II)V", (void*)nMeshGetVertices }, +{"rsnMeshGetIndices", "(II[I[II)V", (void*)nMeshGetIndices }, }; diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java b/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java new file mode 100644 index 0000000..09820ef --- /dev/null +++ b/graphics/tests/graphicstests/src/android/graphics/BitmapFactoryTest.java @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics; + +import android.os.ParcelFileDescriptor; +import android.test.suitebuilder.annotation.SmallTest; + +import java.io.ByteArrayOutputStream; +import java.io.FileDescriptor; + +import junit.framework.TestCase; + + +public class BitmapFactoryTest extends TestCase { + + // tests that we can decode bitmaps from MemoryFiles + @SmallTest + public void testBitmapParcelFileDescriptor() throws Exception { + Bitmap bitmap1 = Bitmap.createBitmap( + new int[] { Color.BLUE }, 1, 1, Bitmap.Config.RGB_565); + ByteArrayOutputStream out = new ByteArrayOutputStream(); + bitmap1.compress(Bitmap.CompressFormat.PNG, 100, out); + ParcelFileDescriptor pfd = ParcelFileDescriptor.fromData(out.toByteArray(), null); + FileDescriptor fd = pfd.getFileDescriptor(); + assertNotNull("Got null FileDescriptor", fd); + assertTrue("Got invalid FileDescriptor", fd.valid()); + Bitmap bitmap = BitmapFactory.decodeFileDescriptor(fd); + assertNotNull("BitmapFactory returned null", bitmap); + assertEquals("Bitmap width", 1, bitmap.getWidth()); + assertEquals("Bitmap height", 1, bitmap.getHeight()); + } + +} diff --git a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java b/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java index 6734bb7..685a998 100644 --- a/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java +++ b/graphics/tests/graphicstests/src/android/graphics/BitmapTest.java @@ -16,8 +16,6 @@ package android.graphics; -import android.graphics.Bitmap; -import android.graphics.Color; import android.test.suitebuilder.annotation.SmallTest; import junit.framework.TestCase; @@ -42,6 +40,10 @@ public class BitmapTest extends TestCase { assertEquals("rowbytes", 200, bm2.getRowBytes()); assertEquals("rowbytes", 200, bm3.getRowBytes()); + assertEquals("byteCount", 80000, bm1.getByteCount()); + assertEquals("byteCount", 40000, bm2.getByteCount()); + assertEquals("byteCount", 40000, bm3.getByteCount()); + assertEquals("height", 200, bm1.getHeight()); assertEquals("height", 200, bm2.getHeight()); assertEquals("height", 200, bm3.getHeight()); diff --git a/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java b/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java new file mode 100644 index 0000000..5fcc3bc --- /dev/null +++ b/graphics/tests/graphicstests/src/android/graphics/drawable/MipmapDrawableTest.java @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2010 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package android.graphics.drawable; + +import android.graphics.Canvas; +import android.graphics.ColorFilter; +import android.graphics.Rect; +import android.graphics.drawable.Drawable; +import android.graphics.drawable.MipmapDrawable; +import android.graphics.drawable.DrawableContainer.DrawableContainerState; +import android.test.InstrumentationTestCase; + +public class MipmapDrawableTest extends InstrumentationTestCase { + private MockMipmapDrawable mMipmapDrawable; + + private DrawableContainerState mDrawableContainerState; + + @Override + protected void setUp() throws Exception { + super.setUp(); + mMipmapDrawable = new MockMipmapDrawable(); + mDrawableContainerState = (DrawableContainerState) mMipmapDrawable.getConstantState(); + } + + public void testMipmapDrawable() { + new MipmapDrawable(); + // Check the values set in the constructor + assertNotNull(new MipmapDrawable().getConstantState()); + assertTrue(new MockMipmapDrawable().hasCalledOnBoundsChanged()); + } + + public void testAddDrawable() { + assertEquals(0, mDrawableContainerState.getChildCount()); + + // nothing happens if drawable is null + mMipmapDrawable.reset(); + mMipmapDrawable.addDrawable(null); + assertEquals(0, mDrawableContainerState.getChildCount()); + assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged()); + + mMipmapDrawable.reset(); + mMipmapDrawable.addDrawable(new MockDrawable()); + assertEquals(1, mDrawableContainerState.getChildCount()); + assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged()); + + mMipmapDrawable.reset(); + mMipmapDrawable.addDrawable(new MockDrawable()); + assertEquals(2, mDrawableContainerState.getChildCount()); + assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged()); + } + + public void testSortedByHeight() { + Drawable small = new MockDrawable(8); + Drawable medium = new MockDrawable(32); + Drawable large = new MockDrawable(128); + + mMipmapDrawable.addDrawable(medium); + assertSame(medium, mDrawableContainerState.getChildren()[0]); + + mMipmapDrawable.addDrawable(small); + assertSame(small, mDrawableContainerState.getChildren()[0]); + assertSame(medium, mDrawableContainerState.getChildren()[1]); + + mMipmapDrawable.addDrawable(large); + assertSame(small, mDrawableContainerState.getChildren()[0]); + assertSame(medium, mDrawableContainerState.getChildren()[1]); + assertSame(large, mDrawableContainerState.getChildren()[2]); + + mMipmapDrawable.addDrawable(small); + assertSame(small, mDrawableContainerState.getChildren()[0]); + assertSame(small, mDrawableContainerState.getChildren()[1]); + assertSame(medium, mDrawableContainerState.getChildren()[2]); + assertSame(large, mDrawableContainerState.getChildren()[3]); + + mMipmapDrawable.addDrawable(medium); + assertSame(small, mDrawableContainerState.getChildren()[0]); + assertSame(small, mDrawableContainerState.getChildren()[1]); + assertSame(medium, mDrawableContainerState.getChildren()[2]); + assertSame(medium, mDrawableContainerState.getChildren()[3]); + assertSame(large, mDrawableContainerState.getChildren()[4]); + + mMipmapDrawable.addDrawable(large); + assertSame(small, mDrawableContainerState.getChildren()[0]); + assertSame(small, mDrawableContainerState.getChildren()[1]); + assertSame(medium, mDrawableContainerState.getChildren()[2]); + assertSame(medium, mDrawableContainerState.getChildren()[3]); + assertSame(large, mDrawableContainerState.getChildren()[4]); + assertSame(large, mDrawableContainerState.getChildren()[5]); + } + + public void testSetBoundsOneItem() { + // the method is not called if same bounds are set + mMipmapDrawable.reset(); + mMipmapDrawable.setBounds(mMipmapDrawable.getBounds()); + assertFalse(mMipmapDrawable.hasCalledOnBoundsChanged()); + + // the method is called if different bounds are set, even without drawables + mMipmapDrawable.reset(); + mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1)); + assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged()); + + // adding an item should check bounds to see if new drawable is more appropriate + mMipmapDrawable.reset(); + Drawable item = new MockDrawable(42); + mMipmapDrawable.addDrawable(item); + assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged()); + + // the method is called if different bounds are set + mMipmapDrawable.setBounds(new Rect(0, 0, 0, mMipmapDrawable.getBounds().height() + 1)); + assertTrue(mMipmapDrawable.hasCalledOnBoundsChanged()); + + // check that correct drawable is selected for any size. + mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() - 1)); + assertSame(item, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight())); + assertSame(item, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, item.getIntrinsicHeight() + 1)); + assertSame(item, mMipmapDrawable.getCurrent()); + } + + public void testSetBounds() { + Drawable small = new MockDrawable(8); + Drawable medium = new MockDrawable(32); + Drawable large = new MockDrawable(128); + + mMipmapDrawable.addDrawable(large); + mMipmapDrawable.addDrawable(small); + mMipmapDrawable.addDrawable(medium); + + // check that correct drawable is selected. + mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() - 1)); + assertSame(small, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight())); + assertSame(small, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, small.getIntrinsicHeight() + 1)); + assertSame(medium, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() - 1)); + assertSame(medium, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight())); + assertSame(medium, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, medium.getIntrinsicHeight() + 1)); + assertSame(large, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() - 1)); + assertSame(large, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight())); + assertSame(large, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.setBounds(new Rect(0, 0, 0, large.getIntrinsicHeight() + 1)); + assertSame(large, mMipmapDrawable.getCurrent()); + } + + public void testSizes() { + // Check default value with no mipmap defined + assertEquals(-1, mMipmapDrawable.getIntrinsicHeight()); + assertEquals(-1, mMipmapDrawable.getIntrinsicWidth()); + assertEquals(0, mMipmapDrawable.getMinimumHeight()); + assertEquals(0, mMipmapDrawable.getMinimumWidth()); + + Drawable small = new MockDrawable(8, 4); + Drawable medium = new MockDrawable(32, 16); + Drawable large = new MockDrawable(128, 64); + + mMipmapDrawable.addDrawable(medium); + assertEquals(medium.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight()); + assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight()); + + mMipmapDrawable.addDrawable(large); + assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight()); + assertEquals(medium.getMinimumHeight(), mMipmapDrawable.getMinimumHeight()); + + mMipmapDrawable.addDrawable(small); + assertEquals(large.getIntrinsicHeight(), mMipmapDrawable.getIntrinsicHeight()); + assertEquals(small.getMinimumHeight(), mMipmapDrawable.getMinimumHeight()); + } + + public void testReplacementWhenAdded() { + Drawable small = new MockDrawable(8); + Drawable medium = new MockDrawable(32); + Drawable large = new MockDrawable(128); + + // Small bounds, so that the smallest mipmap should always be selected + mMipmapDrawable.setBounds(new Rect(0, 0, 0, 0)); + + // Providing smaller versions, that should immediately be used as current + mMipmapDrawable.addDrawable(large); + assertSame(large, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.addDrawable(medium); + assertSame(medium, mMipmapDrawable.getCurrent()); + + mMipmapDrawable.addDrawable(small); + assertSame(small, mMipmapDrawable.getCurrent()); + } + + private class MockMipmapDrawable extends MipmapDrawable { + private boolean mHasCalledOnBoundsChanged; + + public boolean hasCalledOnBoundsChanged() { + return mHasCalledOnBoundsChanged; + } + + public void reset() { + mHasCalledOnBoundsChanged = false; + } + + @Override + protected void onBoundsChange(Rect bounds) { + super.onBoundsChange(bounds); + mHasCalledOnBoundsChanged = true; + } + } + + private class MockDrawable extends Drawable { + int mIntrinsicHeight; + int mMinimumHeight; + + public MockDrawable() { + this(0); + } + + public MockDrawable(int intrinsicHeight) { + this(intrinsicHeight, intrinsicHeight); + } + + public MockDrawable(int intrinsicHeight, int minimumHeight) { + mIntrinsicHeight = intrinsicHeight; + mMinimumHeight = minimumHeight; + } + + @Override + public void draw(Canvas canvas) { + } + + @Override + public int getOpacity() { + return 0; + } + + @Override + public void setAlpha(int alpha) { + } + + @Override + public void setColorFilter(ColorFilter cf) { + } + + @Override + public int getIntrinsicHeight() { + return mIntrinsicHeight; + } + + @Override + public int getMinimumHeight() { + return mMinimumHeight; + } + } +} |