diff options
Diffstat (limited to 'graphics/java/android')
80 files changed, 6189 insertions, 1827 deletions
diff --git a/graphics/java/android/graphics/Bitmap.java b/graphics/java/android/graphics/Bitmap.java index dd83c3b..d283dea 100644 --- a/graphics/java/android/graphics/Bitmap.java +++ b/graphics/java/android/graphics/Bitmap.java @@ -19,12 +19,16 @@ package android.graphics; import android.os.Parcel; import android.os.Parcelable; import android.util.DisplayMetrics; +import android.util.Finalizers; import java.io.OutputStream; import java.nio.Buffer; import java.nio.ByteBuffer; import java.nio.IntBuffer; import java.nio.ShortBuffer; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; public final class Bitmap implements Parcelable { /** @@ -35,9 +39,13 @@ 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; private final boolean mIsMutable; private byte[] mNinePatchChunk; // may be null @@ -51,7 +59,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,8 +85,7 @@ public final class Bitmap implements Parcelable { This can be called from JNI code. */ - private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk, - int density) { + private Bitmap(int nativeBitmap, boolean isMutable, byte[] ninePatchChunk, int density) { if (nativeBitmap == 0) { throw new RuntimeException("internal error: native bitmap is 0"); } @@ -90,6 +97,13 @@ public final class Bitmap implements Parcelable { if (density >= 0) { mDensity = density; } + + // If the finalizers queue is null, we are running in zygote and the + // bitmap will never be reclaimed, so we don't need to run our native + // destructor + if (Finalizers.getQueue() != null) { + new BitmapFinalizer(this); + } } /** @@ -172,6 +186,19 @@ 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. + * + * @hide + */ + public int getGenerationId() { + return nativeGenerationId(mNativeBitmap); + } + + /** * This is called by methods that want to throw an exception if the bitmap * has already been recycled. */ @@ -428,28 +455,30 @@ public final class Bitmap implements Parcelable { Rect srcR = new Rect(x, y, x + width, y + height); RectF dstR = new RectF(0, 0, width, height); + final Config newConfig = source.getConfig() == Config.ARGB_8888 ? + Config.ARGB_8888 : Config.RGB_565; + 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 +503,30 @@ 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) { 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; } @@ -1008,12 +1059,22 @@ public final class Bitmap implements Parcelable { nativePrepareToDraw(mNativeBitmap); } - @Override - protected void finalize() throws Throwable { - try { + private static class BitmapFinalizer extends Finalizers.ReclaimableReference<Bitmap> { + private static final Set<BitmapFinalizer> sFinalizers = Collections.synchronizedSet( + new HashSet<BitmapFinalizer>()); + + private int mNativeBitmap; + + BitmapFinalizer(Bitmap b) { + super(b, Finalizers.getQueue()); + mNativeBitmap = b.mNativeBitmap; + sFinalizers.add(this); + } + + @Override + public void reclaim() { nativeDestructor(mNativeBitmap); - } finally { - super.finalize(); + sFinalizers.remove(this); } } @@ -1050,6 +1111,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 +1127,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 7b49bc5..ea5ed6b 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; @@ -84,7 +83,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. @@ -507,9 +506,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); @@ -530,18 +527,6 @@ 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); - } - } catch (IOException ex) { - // invalid filedescriptor, no need to call nativeDecodeFileDescriptor() - return null; - } Bitmap bm = nativeDecodeFileDescriptor(fd, outPadding, opts); return finishDecode(bm, outPadding, opts); } diff --git a/graphics/java/android/graphics/BitmapRegionDecoder.java b/graphics/java/android/graphics/BitmapRegionDecoder.java new file mode 100644 index 0000000..454eb4a --- /dev/null +++ b/graphics/java/android/graphics/BitmapRegionDecoder.java @@ -0,0 +1,263 @@ +/* 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.content.res.AssetManager; + +import java.io.BufferedInputStream; +import java.io.FileDescriptor; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; + +/** + * BitmapRegionDecoder can be used to decode a rectangle region from an image. + * BitmapRegionDecoder is particularly useful when an original image is large and + * you only need parts of the image. + * + * <p>To create a BitmapRegionDecoder, call newInstance(...). + * Given a BitmapRegionDecoder, users can call decodeRegion() repeatedly + * to get a decoded Bitmap of the specified region. + * + */ +public final class BitmapRegionDecoder { + private int mNativeBitmapRegionDecoder; + private boolean mRecycled; + + /** + * Create a BitmapRegionDecoder from the specified byte array. + * Currently only the Jpeg format is supported. + * + * @param data byte array of compressed image data. + * @param offset offset into data for where the decoder should begin + * parsing. + * @param length the number of bytes, beginning at offset, to parse + * @param isShareable If this is true, then the BitmapRegionDecoder may keep a + * shallow reference to the input. If this is false, + * then the BitmapRegionDecoder will explicitly make a copy of the + * input data, and keep that. Even if sharing is allowed, + * the implementation may still decide to make a deep + * copy of the input data. If an image is progressively encoded, + * allowing sharing may degrade the decoding speed. + * @return BitmapRegionDecoder, or null if the image data could not be decoded. + * @throws IOException if the image format is not supported or can not be decoded. + */ + public static BitmapRegionDecoder newInstance(byte[] data, + int offset, int length, boolean isShareable) throws IOException { + if ((offset | length) < 0 || data.length < offset + length) { + throw new ArrayIndexOutOfBoundsException(); + } + return nativeNewInstance(data, offset, length, isShareable); + } + + /** + * Create a BitmapRegionDecoder from the file descriptor. + * The position within the descriptor will not be changed when + * this returns, so the descriptor can be used again as is. + * Currently only the Jpeg format is supported. + * + * @param fd The file descriptor containing the data to decode + * @param isShareable If this is true, then the BitmapRegionDecoder may keep a + * shallow reference to the input. If this is false, + * then the BitmapRegionDecoder will explicitly make a copy of the + * input data, and keep that. Even if sharing is allowed, + * the implementation may still decide to make a deep + * copy of the input data. If an image is progressively encoded, + * allowing sharing may degrade the decoding speed. + * @return BitmapRegionDecoder, or null if the image data could not be decoded. + * @throws IOException if the image format is not supported or can not be decoded. + */ + public static BitmapRegionDecoder newInstance( + FileDescriptor fd, boolean isShareable) throws IOException { + return nativeNewInstance(fd, isShareable); + } + + /** + * Create a BitmapRegionDecoder from an input stream. + * The stream's position will be where ever it was after the encoded data + * was read. + * Currently only the Jpeg format is supported. + * + * @param is The input stream that holds the raw data to be decoded into a + * BitmapRegionDecoder. + * @param isShareable If this is true, then the BitmapRegionDecoder may keep a + * shallow reference to the input. If this is false, + * then the BitmapRegionDecoder will explicitly make a copy of the + * input data, and keep that. Even if sharing is allowed, + * the implementation may still decide to make a deep + * copy of the input data. If an image is progressively encoded, + * allowing sharing may degrade the decoding speed. + * @return BitmapRegionDecoder, or null if the image data could not be decoded. + * @throws IOException if the image format is not supported or can not be decoded. + */ + public static BitmapRegionDecoder newInstance(InputStream is, + boolean isShareable) throws IOException { + // we need mark/reset to work properly in JNI + + if (!is.markSupported()) { + is = new BufferedInputStream(is, 16 * 1024); + } + + if (is instanceof AssetManager.AssetInputStream) { + return nativeNewInstance( + ((AssetManager.AssetInputStream) is).getAssetInt(), + isShareable); + } else { + // pass some temp storage down to the native code. 1024 is made up, + // but should be large enough to avoid too many small calls back + // into is.read(...). + byte [] tempStorage = new byte[16 * 1024]; + return nativeNewInstance(is, tempStorage, isShareable); + } + } + + /** + * Create a BitmapRegionDecoder from a file path. + * Currently only the Jpeg format is supported. + * + * @param pathName complete path name for the file to be decoded. + * @param isShareable If this is true, then the BitmapRegionDecoder may keep a + * shallow reference to the input. If this is false, + * then the BitmapRegionDecoder will explicitly make a copy of the + * input data, and keep that. Even if sharing is allowed, + * the implementation may still decide to make a deep + * copy of the input data. If an image is progressively encoded, + * allowing sharing may degrade the decoding speed. + * @return BitmapRegionDecoder, or null if the image data could not be decoded. + * @throws IOException if the image format is not supported or can not be decoded. + */ + public static BitmapRegionDecoder newInstance(String pathName, + boolean isShareable) throws IOException { + BitmapRegionDecoder decoder = null; + InputStream stream = null; + + try { + stream = new FileInputStream(pathName); + decoder = newInstance(stream, isShareable); + } finally { + if (stream != null) { + try { + stream.close(); + } catch (IOException e) { + // do nothing here + } + } + } + return decoder; + } + + /* Private constructor that must receive an already allocated native + region decoder int (pointer). + + This can be called from JNI code. + */ + private BitmapRegionDecoder(int decoder) { + mNativeBitmapRegionDecoder = decoder; + mRecycled = false; + } + + /** + * Decodes a rectangle region in the image specified by rect. + * + * @param rect The rectangle that specified the region to be decode. + * @param options null-ok; Options that control downsampling. + * inPurgeable is not supported. + * @return The decoded bitmap, or null if the image data could not be + * decoded. + */ + public Bitmap decodeRegion(Rect rect, BitmapFactory.Options options) { + checkRecycled("decodeRegion called on recycled region decoder"); + if (rect.left < 0 || rect.top < 0 || rect.right > getWidth() + || rect.bottom > getHeight()) + throw new IllegalArgumentException("rectangle is not inside the image"); + return nativeDecodeRegion(mNativeBitmapRegionDecoder, rect.left, rect.top, + rect.right - rect.left, rect.bottom - rect.top, options); + } + + /** Returns the original image's width */ + public int getWidth() { + checkRecycled("getWidth called on recycled region decoder"); + return nativeGetWidth(mNativeBitmapRegionDecoder); + } + + /** Returns the original image's height */ + public int getHeight() { + checkRecycled("getHeight called on recycled region decoder"); + return nativeGetHeight(mNativeBitmapRegionDecoder); + } + + /** + * Frees up the memory associated with this region decoder, and mark the + * region decoder as "dead", meaning it will throw an exception if decodeRegion(), + * getWidth() or getHeight() is called. + * + * <p>This operation cannot be reversed, so it should only be called if you are + * sure there are no further uses for the region decoder. 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 region decoder. + */ + public void recycle() { + if (!mRecycled) { + nativeClean(mNativeBitmapRegionDecoder); + mRecycled = true; + } + } + + /** + * Returns true if this region decoder has been recycled. + * If so, then it is an error to try use its method. + * + * @return true if the region decoder has been recycled + */ + public final boolean isRecycled() { + return mRecycled; + } + + /** + * Called by methods that want to throw an exception if the region decoder + * has already been recycled. + */ + private void checkRecycled(String errorMessage) { + if (mRecycled) { + throw new IllegalStateException(errorMessage); + } + } + + @Override + protected void finalize() throws Throwable { + try { + recycle(); + } finally { + super.finalize(); + } + } + + private static native Bitmap nativeDecodeRegion(int lbm, + int start_x, int start_y, int width, int height, + BitmapFactory.Options options); + private static native int nativeGetWidth(int lbm); + private static native int nativeGetHeight(int lbm); + private static native void nativeClean(int lbm); + + private static native BitmapRegionDecoder nativeNewInstance( + byte[] data, int offset, int length, boolean isShareable); + private static native BitmapRegionDecoder nativeNewInstance( + FileDescriptor fd, boolean isShareable); + private static native BitmapRegionDecoder nativeNewInstance( + InputStream is, byte[] storage, boolean isShareable); + private static native BitmapRegionDecoder nativeNewInstance( + int asset, boolean isShareable); +} diff --git a/graphics/java/android/graphics/BitmapShader.java b/graphics/java/android/graphics/BitmapShader.java index 612b0ab..4ba679b 100644 --- a/graphics/java/android/graphics/BitmapShader.java +++ b/graphics/java/android/graphics/BitmapShader.java @@ -16,10 +16,16 @@ 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. + */ + @SuppressWarnings({"FieldCanBeLocal", "UnusedDeclaration"}) + private final Bitmap mBitmap; /** * Call this to create a new shader that will draw with a bitmap. @@ -30,12 +36,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/Canvas.java b/graphics/java/android/graphics/Canvas.java index a587d0d..07fe66c 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,39 @@ 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; + + /** * 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 @@ -89,47 +105,37 @@ public class Canvas { mDensity = bitmap.mDensity; } - /*package*/ Canvas(int nativeCanvas) { + Canvas(int nativeCanvas) { if (nativeCanvas == 0) { throw new IllegalStateException(); } mNativeCanvas = 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()}. + * @deprecated This method is not supported and should not be invoked. */ - 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. - */ - 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 +149,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 +163,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 +382,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 +447,16 @@ 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 + */ + public int getNativeMatrix() { + return 0; + } /** * Return a new matrix with a copy of the canvas' current transformation @@ -621,7 +636,11 @@ public class Canvas { EdgeType(int nativeInt) { this.nativeInt = nativeInt; } - final int nativeInt; + + /** + * @hide + */ + public final int nativeInt; } /** @@ -958,6 +977,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. * @@ -1246,8 +1280,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 +1293,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 +1314,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 +1336,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 +1497,7 @@ public class Canvas { } native_drawTextOnPath(mNativeCanvas, text, index, count, path.ni(), hOffset, vOffset, - paint.mNativePaint); + paint.mBidiFlags, paint.mNativePaint); } /** @@ -1388,7 +1517,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 +1561,74 @@ public class Canvas { drawPicture(picture); restore(); } - + + /** + * <p>Acquires the Canvas context. After invoking this method, the Canvas + * context can be modified by the caller. For instance, if you acquire + * the context of an OpenGL Canvas you can reset the GL viewport, scissor, + * etc.</p> + * + * <p>A call to {@link #acquireContext()} should aways be followed by + * a call to {@link #releaseContext()}, preferrably using a try block:</p> + * + * <pre> + * try { + * if (canvas.acquireContext()) { + * // Use the canvas and/or its context + * } + * } finally { + * canvas.releaseContext(); + * } + * </pre> + * + * <p>Acquiring the context can be an expensive operation and should not + * be done unless absolutely necessary.</p> + * + * <p>Applications should never invoke this method directly.</p> + * + * @return True if the context could be acquired successfully, false + * otherwise (if the context is already acquired for instance.) + * + * @see #releaseContext() + * + * @hide + */ + public boolean acquireContext() { + return false; + } + + /** + * <p>Release the context acquired with {@link #acquireContext()}.</p> + * + * @see #acquireContext() + * + * @hide + */ + public void releaseContext() { + } + + @Override 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); + try { + super.finalize(); + } finally { + // 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 +1731,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 +1755,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..8d5c913 100644 --- a/graphics/java/android/graphics/ComposeShader.java +++ b/graphics/java/android/graphics/ComposeShader.java @@ -20,6 +20,14 @@ 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". @@ -29,8 +37,18 @@ public class ComposeShader extends Shader { 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. @@ -41,11 +59,20 @@ public class ComposeShader extends Shader { @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/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..62fbfb4 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(); @@ -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); } /** @@ -1232,10 +1407,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 +1457,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, 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 +1752,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 +1774,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()); } /** @@ -1404,9 +1859,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 +1882,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..e540806 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 @@ -325,10 +333,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,7 +353,7 @@ public class Region implements Parcelable { this(ni); } - /*package*/ final int ni() { + final int ni() { return mNativeRegion; } @@ -370,6 +382,4 @@ public class Region implements Parcelable { Parcel p); private static native boolean nativeEquals(int native_r1, int native_r2); - - private final int mNativeRegion; } diff --git a/graphics/java/android/graphics/Shader.java b/graphics/java/android/graphics/Shader.java index ae0304e..0400b5c 100644 --- a/graphics/java/android/graphics/Shader.java +++ b/graphics/java/android/graphics/Shader.java @@ -23,9 +23,16 @@ 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 - /* package */ int native_instance; + /** + * This is set by subclasses, but don't make it public. + * + * @hide + */ + public int native_instance; + /** + * @hide + */ + public int native_shader; public enum TileMode { /** @@ -64,17 +71,21 @@ 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); + 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 void nativeDestructor(int native_shader, int native_skiaShader); private static native boolean nativeGetLocalMatrix(int native_shader, - int matrix_instance); + int matrix_instance); private static native void nativeSetLocalMatrix(int native_shader, - int matrix_instance); + int native_skiaShader, int matrix_instance); } 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/BitmapDrawable.java b/graphics/java/android/graphics/drawable/BitmapDrawable.java index 32111e8..032244f 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/ColorDrawable.java b/graphics/java/android/graphics/drawable/ColorDrawable.java index 604c602..4d560be 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 3125321..2f13bef 100644 --- a/graphics/java/android/graphics/drawable/Drawable.java +++ b/graphics/java/android/graphics/drawable/Drawable.java @@ -16,21 +16,30 @@ 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.util.Arrays; /** * A Drawable is a general abstraction for "something that can be drawn." Most @@ -414,6 +423,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 +488,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 +664,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 +770,8 @@ public abstract class Drawable { drawable = new StateListDrawable(); } else if (name.equals("level-list")) { drawable = new LevelListDrawable(); + } else if (name.equals("mipmap")) { + drawable = new MipmapDrawable(); } else if (name.equals("layer-list")) { drawable = new LayerDrawable(); } else if (name.equals("transition")) { @@ -770,7 +793,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 +828,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 +839,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 +852,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 +891,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 c6f57d4..e55a746 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,22 +235,19 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { return mCurrDrawable != null ? mCurrDrawable.getMinimumHeight() : 0; } - public void invalidateDrawable(Drawable who) - { + public void invalidateDrawable(Drawable who) { if (who == mCurrDrawable && mCallback != null) { mCallback.invalidateDrawable(this); } } - public void scheduleDrawable(Drawable who, Runnable what, long when) - { + public void scheduleDrawable(Drawable who, Runnable what, long when) { if (who == mCurrDrawable && mCallback != null) { mCallback.scheduleDrawable(this, what, when); } } - public void unscheduleDrawable(Drawable who, Runnable what) - { + public void unscheduleDrawable(Drawable who, Runnable what) { if (who == mCurrDrawable && mCallback != null) { mCallback.unscheduleDrawable(this, what); } @@ -184,6 +256,9 @@ public class DrawableContainer extends Drawable implements Drawable.Callback { @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 33ecbea..da8bb1b 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 diff --git a/graphics/java/android/graphics/drawable/LayerDrawable.java b/graphics/java/android/graphics/drawable/LayerDrawable.java index 8047dd4..b6cce7e 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; @@ -266,6 +269,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) { diff --git a/graphics/java/android/graphics/drawable/MipmapDrawable.java b/graphics/java/android/graphics/drawable/MipmapDrawable.java new file mode 100644 index 0000000..75fdeed --- /dev/null +++ b/graphics/java/android/graphics/drawable/MipmapDrawable.java @@ -0,0 +1,309 @@ +/* + * 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; + +/** + * 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 00416d8..35b8319 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/ScaleDrawable.java b/graphics/java/android/graphics/drawable/ScaleDrawable.java index b623d80..dcaf20b 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); } @@ -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 be1892e..92252fc 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 @@ -344,6 +351,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/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..9dc291b 100644 --- a/graphics/java/android/renderscript/Allocation.java +++ b/graphics/java/android/renderscript/Allocation.java @@ -35,28 +35,41 @@ public class Allocation extends BaseObj { Bitmap mBitmap; Allocation(int id, RenderScript rs, Type t) { - super(rs); - mID = id; + super(id, rs); mType = t; } + Allocation(int id, RenderScript rs) { + super(id, rs); + } + + @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) { mRS.validate(); - mRS.nAllocationUploadToTexture(mID, false, baseMipLevel); + mRS.nAllocationUploadToTexture(getID(), false, baseMipLevel); } public void uploadToTexture(boolean genMips, int baseMipLevel) { mRS.validate(); - mRS.nAllocationUploadToTexture(mID, genMips, baseMipLevel); + mRS.nAllocationUploadToTexture(getID(), genMips, baseMipLevel); } public void uploadToBufferObject() { mRS.validate(); - mRS.nAllocationUploadToBufferObject(mID); + mRS.nAllocationUploadToBufferObject(getID()); } public void data(int[] d) { @@ -76,103 +89,161 @@ public class Allocation extends BaseObj { subData1D(0, mType.getElementCount(), d); } + public void updateFromBitmap(Bitmap b) { + + mRS.validate(); + if(mType.getX() != b.getWidth() || + mType.getY() != b.getHeight()) { + throw new RSIllegalArgumentException("Cannot update allocation from bitmap, sizes mismatch"); + } + + mRS.nAllocationUpdateFromBitmap(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.nAllocationSubData1D(getID(), xoff, 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.nAllocationSubElementData1D(getID(), xoff, 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.getElementCount()) { + throw new RSIllegalArgumentException("Overflow, Available count " + mType.getElementCount() + + ", 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) { int dataSize = mType.mElement.getSizeBytes() * count; data1DChecks(off, count, d.length * 4, dataSize); - mRS.nAllocationSubData1D(mID, off, count, d, dataSize); + mRS.nAllocationSubData1D(getID(), off, count, d, dataSize); } public void subData1D(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.nAllocationSubData1D(getID(), off, count, d, dataSize); } public void subData1D(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.nAllocationSubData1D(getID(), off, count, d, dataSize); } public void subData1D(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.nAllocationSubData1D(getID(), off, count, d, dataSize); } - 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); + mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4); } 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); + mRS.nAllocationSubData2D(getID(), xoff, yoff, w, h, d, d.length * 4); } public void readData(int[] d) { mRS.validate(); - mRS.nAllocationRead(mID, d); + mRS.nAllocationRead(getID(), d); } public void readData(float[] d) { mRS.validate(); - mRS.nAllocationRead(mID, d); + mRS.nAllocationRead(getID(), d); } - public void data(Object o) { - mRS.validate(); - mRS.nAllocationSubDataFromObject(mID, mType, 0, o); - } + public synchronized void resize(int dimX) { + if ((mType.getY() > 0)|| (mType.getZ() > 0) || mType.getFaces() || mType.getLOD()) { + 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 read(Object o) { - mRS.validate(); - mRS.nAllocationSubReadFromObject(mID, mType, 0, o); + int typeID = mRS.nAllocationGetType(getID()); + mType = new Type(typeID, mRS); + mType.updateFromNative(); } - public void subData(int offset, Object o) { - mRS.validate(); - mRS.nAllocationSubDataFromObject(mID, mType, offset, o); + /* + 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."); + } + if (mType.getY() == 0) { + throw new RSIllegalStateException("Resize only support for 2D allocations at this time."); + } + mRS.nAllocationResize2D(getID(), dimX, dimY); } + */ public class Adapter1D extends BaseObj { Adapter1D(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } public void setConstraint(Dimension dim, int value) { mRS.validate(); - mRS.nAdapter1DSetConstraint(mID, dim.mID, value); + mRS.nAdapter1DSetConstraint(getID(), dim.mID, value); } public void data(int[] d) { mRS.validate(); - mRS.nAdapter1DData(mID, d); + mRS.nAdapter1DData(getID(), d); } public void data(float[] d) { mRS.validate(); - mRS.nAdapter1DData(mID, d); + mRS.nAdapter1DData(getID(), d); } public void subData(int off, int count, int[] d) { mRS.validate(); - mRS.nAdapter1DSubData(mID, off, count, d); + mRS.nAdapter1DSubData(getID(), off, count, d); } public void subData(int off, int count, float[] d) { mRS.validate(); - mRS.nAdapter1DSubData(mID, off, count, d); + mRS.nAdapter1DSubData(getID(), off, count, d); } } @@ -180,42 +251,41 @@ public class Allocation extends BaseObj { mRS.validate(); int id = mRS.nAdapter1DCreate(); if(id == 0) { - throw new IllegalStateException("allocation failed."); + throw new RSRuntimeException("Adapter creation failed."); } - mRS.nAdapter1DBindAllocation(id, mID); + mRS.nAdapter1DBindAllocation(id, getID()); return new Adapter1D(id, mRS); } public class Adapter2D extends BaseObj { Adapter2D(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } public void setConstraint(Dimension dim, int value) { mRS.validate(); - mRS.nAdapter2DSetConstraint(mID, dim.mID, value); + mRS.nAdapter2DSetConstraint(getID(), dim.mID, value); } public void data(int[] d) { mRS.validate(); - mRS.nAdapter2DData(mID, d); + mRS.nAdapter2DData(getID(), d); } public void data(float[] d) { mRS.validate(); - mRS.nAdapter2DData(mID, d); + mRS.nAdapter2DData(getID(), d); } public void subData(int xoff, int yoff, int w, int h, int[] d) { mRS.validate(); - mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d); + mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d); } public void subData(int xoff, int yoff, int w, int h, float[] d) { mRS.validate(); - mRS.nAdapter2DSubData(mID, xoff, yoff, w, h, d); + mRS.nAdapter2DSubData(getID(), xoff, yoff, w, h, d); } } @@ -223,9 +293,12 @@ public class Allocation extends BaseObj { mRS.validate(); int id = mRS.nAdapter2DCreate(); if(id == 0) { - throw new IllegalStateException("allocation failed."); + throw new RSRuntimeException("allocation failed."); + } + mRS.nAdapter2DBindAllocation(id, getID()); + if(id == 0) { + throw new RSRuntimeException("Adapter creation failed."); } - mRS.nAdapter2DBindAllocation(id, mID); return new Adapter2D(id, mRS); } @@ -237,14 +310,16 @@ public class Allocation extends BaseObj { mBitmapOptions.inScaled = false; } - static public Allocation createTyped(RenderScript rs, Type type) - throws IllegalArgumentException { + static public Allocation createTyped(RenderScript rs, Type type) { 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.getID()); + if(id == 0) { + throw new RSRuntimeException("Allocation creation failed."); } - int id = rs.nAllocationCreateTyped(type.mID); return new Allocation(id, rs, type); } @@ -256,9 +331,9 @@ public class Allocation extends BaseObj { b.add(Dimension.X, count); Type t = b.create(); - int id = rs.nAllocationCreateTyped(t.mID); + int id = rs.nAllocationCreateTyped(t.getID()); if(id == 0) { - throw new IllegalStateException("Bad element."); + throw new RSRuntimeException("Allocation creation failed."); } return new Allocation(id, rs, t); } @@ -277,7 +352,7 @@ 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."); } static private Type typeFromBitmap(RenderScript rs, Bitmap b) { @@ -288,28 +363,26 @@ public class Allocation extends BaseObj { return tb.create(); } - static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) - throws IllegalArgumentException { + static public Allocation createFromBitmap(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) { rs.validate(); Type t = typeFromBitmap(rs, b); - int id = rs.nAllocationCreateFromBitmap(dstFmt.mID, genMips, b); + int id = rs.nAllocationCreateFromBitmap(dstFmt.getID(), genMips, b); if(id == 0) { - throw new IllegalStateException("Load failed."); + throw new RSRuntimeException("Load failed."); } return new Allocation(id, rs, t); } - static public Allocation createBitmapRef(RenderScript rs, Bitmap b) - throws IllegalArgumentException { + static public Allocation createBitmapRef(RenderScript rs, Bitmap b) { rs.validate(); Type t = typeFromBitmap(rs, b); int id = rs.nAllocationCreateBitmapRef(t.getID(), b); if(id == 0) { - throw new IllegalStateException("Load failed."); + throw new RSRuntimeException("Load failed."); } Allocation a = new Allocation(id, rs, t); @@ -317,19 +390,7 @@ public class Allocation extends BaseObj { return a; } - static Allocation createFromBitmapBoxed(RenderScript rs, Bitmap b, Element dstFmt, boolean genMips) - throws IllegalArgumentException { - - rs.validate(); - int id = rs.nAllocationCreateFromBitmapBoxed(dstFmt.mID, genMips, b); - if(id == 0) { - throw new IllegalStateException("Load failed."); - } - return new Allocation(id, rs, null); - } - - static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) - throws IllegalArgumentException { + static public Allocation createFromBitmapResource(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) { rs.validate(); InputStream is = null; @@ -338,15 +399,12 @@ public class Allocation extends BaseObj { is = res.openRawResource(id, value); int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); - int allocationId = rs.nAllocationCreateFromAssetStream(dstFmt.mID, genMips, - asset); + int aId = rs.nAllocationCreateFromAssetStream(dstFmt.getID(), genMips, asset); - if(allocationId == 0) { - throw new IllegalStateException("Load failed."); + if (aId == 0) { + throw new RSRuntimeException("Load failed."); } - return new Allocation(allocationId, rs, null); - } catch (Exception e) { - // Ignore + return new Allocation(aId, rs, null); } finally { if (is != null) { try { @@ -356,26 +414,19 @@ public class Allocation extends BaseObj { } } } - - return null; } - static public Allocation createFromBitmapResourceBoxed(RenderScript rs, Resources res, int id, Element dstFmt, boolean genMips) - throws IllegalArgumentException { - - 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; + static public Allocation createFromString(RenderScript rs, String str) { + byte[] allocArray = null; + try { + allocArray = str.getBytes("UTF-8"); + Allocation alloc = Allocation.createSized(rs, Element.U8(rs), allocArray.length); + alloc.data(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/BaseObj.java b/graphics/java/android/renderscript/BaseObj.java index 002fc78..78b5617 100644 --- a/graphics/java/android/renderscript/BaseObj.java +++ b/graphics/java/android/renderscript/BaseObj.java @@ -21,48 +21,73 @@ 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; } + 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 + */ public int getID() { + if (mDestroyed) { + throw new RSInvalidStateException("using a destroyed object."); + } return mID; } - int mID; - boolean mDestroyed; - String mName; + 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.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 +98,28 @@ class BaseObj { super.finalize(); } - public void destroy() { + /** + * destroy disconnects the object from the native object effectivly + * rendering this java object dead. The primary use is to force immediate + * cleanup of resources when its 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/Vector2f.java b/graphics/java/android/renderscript/Byte2.java index 567d57f..95cf88c 100644 --- a/graphics/java/android/renderscript/Vector2f.java +++ b/graphics/java/android/renderscript/Byte2.java @@ -24,12 +24,12 @@ import android.util.Log; * @hide * **/ -public class Vector2f { - public Vector2f() { +public class Byte2 { + public Byte2() { } - public float x; - public float y; + public byte x; + public byte y; } diff --git a/graphics/java/android/renderscript/Vector3f.java b/graphics/java/android/renderscript/Byte3.java index f2842f3..a6c0ca9 100644 --- a/graphics/java/android/renderscript/Vector3f.java +++ b/graphics/java/android/renderscript/Byte3.java @@ -24,13 +24,13 @@ import android.util.Log; * @hide * **/ -public class Vector3f { - public Vector3f() { +public class Byte3 { + public Byte3() { } - public float x; - public float y; - public float z; + public byte x; + public byte y; + public byte z; } diff --git a/graphics/java/android/renderscript/Vector4f.java b/graphics/java/android/renderscript/Byte4.java index fabd959..a5bfc61 100644 --- a/graphics/java/android/renderscript/Vector4f.java +++ b/graphics/java/android/renderscript/Byte4.java @@ -24,14 +24,14 @@ import android.util.Log; * @hide * **/ -public class Vector4f { - public Vector4f() { +public class Byte4 { + public Byte4() { } - public float x; - public float y; - public float z; - public float w; + 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..4b007f2 100644 --- a/graphics/java/android/renderscript/Element.java +++ b/graphics/java/android/renderscript/Element.java @@ -17,15 +17,36 @@ package android.renderscript; import java.lang.reflect.Field; +import android.util.Log; /** * @hide * + * Element is the basic data type of RenderScript. An element can be of 2 + * forms. Basic elements contain a single component of data. This can be of + * any of the legal RS types. Examples of basic element types. + * Single float value + * 4 element float vector + * single RGB-565 color + * single unsigned int 16 + * + * Complex elements will contain a list of sub-elements and names. This in + * effect 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. + * + * The primary source of elements will be from scripts. A script that exports a + * bind point for a data structure will generate a RS element to represent the + * data exported by the script. **/ public class Element extends BaseObj { int mSize; Element[] mElements; String[] mElementNames; + int[] mArraySizes; DataType mType; DataKind mKind; @@ -34,33 +55,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 +112,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 +133,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 rs.mElement_USER_U8; + 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; } - public static Element USER_I8(RenderScript rs) { - if(rs.mElement_USER_I8 == null) { - rs.mElement_USER_I8 = createUser(rs, DataType.SIGNED_8); + /** + * 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_USER_I8; + return rs.mElement_I32; } - 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 U64(RenderScript rs) { + if(rs.mElement_U64 == null) { + rs.mElement_U64 = createUser(rs, DataType.UNSIGNED_64); } - return rs.mElement_USER_U32; + return rs.mElement_U64; } - 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 I64(RenderScript rs) { + if(rs.mElement_I64 == null) { + rs.mElement_I64 = createUser(rs, DataType.SIGNED_64); } - return rs.mElement_USER_I32; + return rs.mElement_I64; } - 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 F32(RenderScript rs) { + if(rs.mElement_F32 == null) { + rs.mElement_F32 = createUser(rs, DataType.FLOAT_32); } - return rs.mElement_USER_F32; + 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_MESH; + } + + 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_PROGRAM_FRAGMENT; + } + + 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_PROGRAM_VERTEX; + } + + 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_PROGRAM_RASTER; + } + + 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_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 +362,196 @@ 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_4X4; } - 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); + Element(int id, RenderScript rs, DataType dt, DataKind dk, boolean norm, int size) { + super(id, rs); mSize = dt.mSize * size; mType = dt; mKind = dk; mNormalized = norm; mVectorSize = size; - mID = rs.nElementCreate(dt.mID, dk.mID, norm, size); } - public void destroy() throws IllegalStateException { - super.destroy(); + Element(int id, RenderScript rs) { + super(id, rs); } - 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"); + @Override + void updateFromNative() { + super.updateFromNative(); + + // we will pack mType; mKind; mNormalized; mVectorSize; NumSubElements + int[] dataBuffer = new int[5]; + mRS.nElementGetNativeData(getID(), dataBuffer); + + 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; + } + } + for (DataKind dk: DataKind.values()) { + if(dk.mID == dataBuffer[1]){ + mKind = dk; } } - return b.create(); - } - - ///////////////////////////////////////// - public static Element createUser(RenderScript rs, DataType dt) { - return new Element(rs, dt, DataKind.USER, false, 1); - } + int numSubElements = dataBuffer[4]; + if(numSubElements > 0) { + mElements = new Element[numSubElements]; + mElementNames = new String[numSubElements]; - public static Element createVector(RenderScript rs, DataType dt, int size) { - if (size < 2 || size > 4) { - throw new IllegalArgumentException("Bad size"); + 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; + } } - return new Element(rs, dt, DataKind.USER, false, size); - } - public static Element createIndex(RenderScript rs) { - return new Element(rs, DataType.UNSIGNED_16, DataKind.INDEX, false, 1); } - 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"); - } + public void destroy() { + super.destroy(); + } - 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"); - } + /** + * 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 + */ + public static Element createUser(RenderScript rs, DataType dt) { + DataKind dk = DataKind.USER; + boolean norm = false; + int vecSize = 1; + int id = rs.nElementCreate(dt.mID, dk.mID, norm, vecSize); + return new Element(id, rs, dt, dk, norm, vecSize); + } - 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"); + /** + * 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 rance 2-4."); } - + DataKind dk = DataKind.USER; boolean norm = false; - if (dk == DataKind.COLOR && dt == DataType.UNSIGNED_8) { - norm = true; - } - - return new Element(rs, dt, dk, norm, size); + 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,43 +565,96 @@ 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 void 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++; } + /** + * Add a single element to this Element. + * + * @param element + * @param name + */ + public void add(Element element, String name) { + 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); + + 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..ff3e22b 100644 --- a/graphics/java/android/renderscript/FieldPacker.java +++ b/graphics/java/android/renderscript/FieldPacker.java @@ -33,21 +33,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 +62,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 +74,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 +92,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 +104,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 +120,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(Int2 v) { + addU32(v.x); + addU32(v.y); + } + public void addU32(Int3 v) { + addU32(v.x); + addU32(v.y); + addU32(v.z); + } + public void addU32(Int4 v) { + addU32(v.x); + addU32(v.y); + addU32(v.z); + addU32(v.w); + } + + public void addObj(Matrix4f v) { + for (int i=0; i < v.mMat.length; i++) { + addF32(v.mMat[i]); + } + } + + public void addObj(Matrix3f v) { + for (int i=0; i < v.mMat.length; i++) { + addF32(v.mMat[i]); + } + } + + public void addObj(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..af85d8e --- /dev/null +++ b/graphics/java/android/renderscript/FileA3D.java @@ -0,0 +1,208 @@ +/* + * 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.IOException; +import java.io.InputStream; + +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; + +/** + * @hide + * + **/ +public class FileA3D extends BaseObj { + + public enum ClassID { + + UNKNOWN, + MESH, + TYPE, + ELEMENT, + ALLOCATION, + PROGRAM_VERTEX, + PROGRAM_RASTER, + PROGRAM_FRAGMENT, + PROGRAM_STORE, + SAMPLER, + ANIMATION, + ADAPTER_1D, + ADAPTER_2D, + SCRIPT_C; + + public static ClassID toClassID(int intID) { + return ClassID.values()[intID]; + } + } + + // Read only class with index entries + public static class IndexEntry { + RenderScript mRS; + int mIndex; + int mID; + String mName; + ClassID mClassID; + BaseObj mLoadedObj; + + public String getName() { + return mName; + } + + public ClassID getClassID() { + return mClassID; + } + + public BaseObj getObject() { + mRS.validate(); + BaseObj obj = internalCreate(mRS, this); + return obj; + } + + static synchronized BaseObj internalCreate(RenderScript rs, IndexEntry entry) { + if(entry.mLoadedObj != null) { + return entry.mLoadedObj; + } + + if(entry.mClassID == ClassID.UNKNOWN) { + return null; + } + + int objectID = rs.nFileA3DGetEntryByIndex(entry.mID, entry.mIndex); + if(objectID == 0) { + return null; + } + + switch (entry.mClassID) { + case MESH: + entry.mLoadedObj = new Mesh(objectID, rs); + break; + case TYPE: + entry.mLoadedObj = new Type(objectID, rs); + break; + case ELEMENT: + entry.mLoadedObj = null; + break; + case ALLOCATION: + entry.mLoadedObj = null; + break; + case PROGRAM_VERTEX: + entry.mLoadedObj = new ProgramVertex(objectID, rs); + break; + case PROGRAM_RASTER: + break; + case PROGRAM_FRAGMENT: + break; + case PROGRAM_STORE: + break; + case SAMPLER: + break; + case ANIMATION: + break; + case ADAPTER_1D: + break; + case ADAPTER_2D: + break; + case SCRIPT_C: + break; + } + + entry.mLoadedObj.updateFromNative(); + + return entry.mLoadedObj; + } + + IndexEntry(RenderScript rs, int index, int id, String name, ClassID classID) { + mRS = rs; + mIndex = index; + mID = id; + mName = name; + mClassID = classID; + 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], ClassID.toClassID(ids[i])); + } + } + + public int getNumIndexEntries() { + if(mFileEntries == null) { + return 0; + } + return mFileEntries.length; + } + + public IndexEntry getIndexEntry(int index) { + if(getNumIndexEntries() == 0 || index < 0 || index >= mFileEntries.length) { + return null; + } + return mFileEntries[index]; + } + + static public FileA3D createFromResource(RenderScript rs, Resources res, int id) + throws IllegalArgumentException { + + rs.validate(); + InputStream is = null; + try { + final TypedValue value = new TypedValue(); + is = res.openRawResource(id, value); + + int asset = ((AssetManager.AssetInputStream) is).getAssetInt(); + + int fileId = rs.nFileA3DCreateFromAssetStream(asset); + + if(fileId == 0) { + throw new IllegalStateException("Load failed."); + } + FileA3D fa3d = new FileA3D(fileId, rs, is); + fa3d.initEntries(); + return fa3d; + + } catch (Exception e) { + // Ignore + } + + return null; + } +} diff --git a/graphics/java/android/renderscript/Float2.java b/graphics/java/android/renderscript/Float2.java new file mode 100644 index 0000000..889bf7b --- /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; + + +/** + * @hide + * + **/ +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..ebe140d --- /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; + + +/** + * @hide + * + **/ +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..847732f --- /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; + + +/** + * @hide + * + **/ +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..de25014 --- /dev/null +++ b/graphics/java/android/renderscript/Font.java @@ -0,0 +1,165 @@ +/* + * 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.IOException; +import java.io.InputStream; +import java.util.Map; +import java.util.HashMap; + +import android.content.res.Resources; +import android.content.res.AssetManager; +import android.util.Log; +import android.util.TypedValue; + +/** + * @hide + * + **/ +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 create(RenderScript rs, Resources res, String fileName, int size) + throws IllegalArgumentException { + + rs.validate(); + try { + int dpi = res.getDisplayMetrics().densityDpi; + int fontId = rs.nFontCreateFromFile(fileName, size, dpi); + + if(fontId == 0) { + throw new IllegalStateException("Failed loading a font"); + } + Font rsFont = new Font(fontId, rs); + + return rsFont; + + } catch (Exception e) { + // Ignore + } + + return null; + } + + /** + * 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 createFromFamily(RenderScript rs, Resources res, String familyName, Style fontStyle, int size) + throws IllegalArgumentException { + String fileName = getFontFileName(familyName, fontStyle); + return create(rs, res, fileName, size); + } +} diff --git a/graphics/java/android/renderscript/Int2.java b/graphics/java/android/renderscript/Int2.java new file mode 100644 index 0000000..56e2fe9 --- /dev/null +++ b/graphics/java/android/renderscript/Int2.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; + + +/** + * @hide + * + **/ +public class Int2 { + public Int2() { + } + + 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..1b27509 --- /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; + + +/** + * @hide + * + **/ +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..3d6f3f5 --- /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; + + +/** + * @hide + * + **/ +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/Long2.java b/graphics/java/android/renderscript/Long2.java new file mode 100644 index 0000000..11ead2f --- /dev/null +++ b/graphics/java/android/renderscript/Long2.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; + + +/** + * @hide + * + **/ +public class Long2 { + public Long2() { + } + + 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..1604532 --- /dev/null +++ b/graphics/java/android/renderscript/Long3.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; + + +/** + * @hide + * + **/ +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..2fd2747 --- /dev/null +++ b/graphics/java/android/renderscript/Long4.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; + + +/** + * @hide + * + **/ +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..99d23db 100644 --- a/graphics/java/android/renderscript/Matrix2f.java +++ b/graphics/java/android/renderscript/Matrix2f.java @@ -51,6 +51,57 @@ public class Matrix2f { System.arraycopy(mMat, 0, src, 0, 4); } + 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; + } + + public void loadScale(float x, float y) { + loadIdentity(); + mMat[0] = x; + mMat[3] = y; + } + 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); + } + } + + public void multiply(Matrix2f rhs) { + Matrix2f tmp = new Matrix2f(); + tmp.loadMultiply(this, rhs); + load(tmp); + } + public void rotate(float rot) { + Matrix2f tmp = new Matrix2f(); + tmp.loadRotate(rot); + multiply(tmp); + } + public void scale(float x, float y) { + Matrix2f tmp = new Matrix2f(); + tmp.loadScale(x, y); + multiply(tmp); + } + 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..961bc5d 100644 --- a/graphics/java/android/renderscript/Matrix3f.java +++ b/graphics/java/android/renderscript/Matrix3f.java @@ -57,6 +57,124 @@ public class Matrix3f { System.arraycopy(mMat, 0, src, 0, 9); } + 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; + } + + 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[3] = s; + mMat[4] = c; + } + + public void loadScale(float x, float y) { + loadIdentity(); + mMat[0] = x; + mMat[4] = y; + } + + public void loadScale(float x, float y, float z) { + loadIdentity(); + mMat[0] = x; + mMat[4] = y; + mMat[8] = z; + } + + public void loadTranslate(float x, float y) { + loadIdentity(); + mMat[6] = x; + mMat[7] = y; + } + + 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); + } + } + + public void multiply(Matrix3f rhs) { + Matrix3f tmp = new Matrix3f(); + tmp.loadMultiply(this, rhs); + load(tmp); + } + public void rotate(float rot, float x, float y, float z) { + Matrix3f tmp = new Matrix3f(); + tmp.loadRotate(rot, x, y, z); + multiply(tmp); + } + public void rotate(float rot) { + Matrix3f tmp = new Matrix3f(); + tmp.loadRotate(rot); + multiply(tmp); + } + public void scale(float x, float y) { + Matrix3f tmp = new Matrix3f(); + tmp.loadScale(x, y); + multiply(tmp); + } + public void scale(float x, float y, float z) { + Matrix3f tmp = new Matrix3f(); + tmp.loadScale(x, y, z); + multiply(tmp); + } + public void translate(float x, float y) { + Matrix3f tmp = new Matrix3f(); + tmp.loadTranslate(x, y); + multiply(tmp); + } + 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..5ffc21a 100644 --- a/graphics/java/android/renderscript/Matrix4f.java +++ b/graphics/java/android/renderscript/Matrix4f.java @@ -179,6 +179,85 @@ public class 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; + + 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; + } + + 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; + } + + 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; + } + + 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..4187992 --- /dev/null +++ b/graphics/java/android/renderscript/Mesh.java @@ -0,0 +1,481 @@ +/* + * 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; + +/** + * @hide + * + **/ +public class Mesh extends BaseObj { + + Allocation[] mVertexBuffers; + Allocation[] mIndexBuffers; + Primitive[] mPrimitives; + + Mesh(int id, RenderScript rs) { + super(id, rs); + } + + public int getVertexAllocationCount() { + if(mVertexBuffers == null) { + return 0; + } + return mVertexBuffers.length; + } + public Allocation getVertexAllocation(int slot) { + return mVertexBuffers[slot]; + } + + public int getPrimitiveCount() { + if(mIndexBuffers == null) { + return 0; + } + return mIndexBuffers.length; + } + public Allocation getIndexAllocation(int slot) { + return mIndexBuffers[slot]; + } + 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); + mVertexBuffers[i].updateFromNative(); + } + } + + for(int i = 0; i < idxCount; i ++) { + if(idxIDs[i] != 0) { + mIndexBuffers[i] = new Allocation(idxIDs[i], mRS); + mIndexBuffers[i].updateFromNative(); + } + mPrimitives[i] = Primitive.values()[primitives[i]]; + } + } + + public static class Builder { + RenderScript mRS; + + class Entry { + Type t; + Element e; + int size; + Primitive prim; + } + + int mVertexTypeCount; + Entry[] mVertexTypes; + Vector mIndexTypes; + + public Builder(RenderScript rs) { + mRS = rs; + mVertexTypeCount = 0; + mVertexTypes = new Entry[16]; + mIndexTypes = new Vector(); + } + + 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; + mVertexTypes[mVertexTypeCount].e = null; + 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].t = null; + mVertexTypes[mVertexTypeCount].e = e; + mVertexTypes[mVertexTypeCount].size = size; + mVertexTypeCount++; + return addedIndex; + } + + public int addIndexType(Type t, Primitive p) { + int addedIndex = mIndexTypes.size(); + Entry indexType = new Entry(); + indexType.t = t; + indexType.e = null; + indexType.size = 0; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return addedIndex; + } + + public int addIndexType(Primitive p) { + int addedIndex = mIndexTypes.size(); + Entry indexType = new Entry(); + indexType.t = null; + indexType.e = null; + indexType.size = 0; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return addedIndex; + } + + public int addIndexType(Element e, int size, Primitive p) { + int addedIndex = mIndexTypes.size(); + Entry indexType = new Entry(); + indexType.t = null; + indexType.e = e; + indexType.size = size; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return addedIndex; + } + + Type newType(Element e, int size) { + Type.Builder tb = new Type.Builder(mRS, e); + tb.add(Dimension.X, 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); + } + else if(entry.e != null) { + alloc = Allocation.createSized(rs, entry.e, entry.size); + } + 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); + } else if(entry.e != null) { + alloc = Allocation.createSized(rs, entry.e, entry.size); + } + rs.nMeshBindVertex(id, alloc.getID(), ct); + newMesh.mVertexBuffers[ct] = alloc; + } + rs.nMeshInitVertexAttribs(id); + + return newMesh; + } + + public Mesh create() { + mRS.validate(); + Mesh sm = internalCreate(mRS, this); + return sm; + } + } + + 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(); + } + + public int addVertexAllocation(Allocation a) throws IllegalStateException { + if (mVertexTypeCount >= mVertexTypes.length) { + throw new IllegalStateException("Max vertex types exceeded."); + } + + int addedIndex = mVertexTypeCount; + mVertexTypes[mVertexTypeCount] = new Entry(); + mVertexTypes[mVertexTypeCount].a = a; + mVertexTypeCount++; + return addedIndex; + } + + public int addIndexAllocation(Allocation a, Primitive p) { + int addedIndex = mIndexTypes.size(); + Entry indexType = new Entry(); + indexType.a = a; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return addedIndex; + } + + public int addIndexType(Primitive p) { + int addedIndex = mIndexTypes.size(); + Entry indexType = new Entry(); + indexType.a = null; + indexType.prim = p; + mIndexTypes.addElement(indexType); + return addedIndex; + } + + 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; + } + + public Mesh create() { + mRS.validate(); + Mesh sm = internalCreate(mRS, this); + 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 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(); + + Builder smb = new Builder(mRS); + smb.addVertexType(mElement, mVtxCount / floatCount); + smb.addIndexType(Element.U16(mRS), mIndexCount, Primitive.TRIANGLE); + + Mesh sm = smb.create(); + + sm.getVertexAllocation(0).data(mVtxData); + if(uploadToBufferObject) { + sm.getVertexAllocation(0).uploadToBufferObject(); + } + + sm.getIndexAllocation(0).data(mIndexData); + sm.getIndexAllocation(0).uploadToBufferObject(); + + return sm; + } + } +} + diff --git a/graphics/java/android/renderscript/Program.java b/graphics/java/android/renderscript/Program.java index 1614ec5..83c3601 100644 --- a/graphics/java/android/renderscript/Program.java +++ b/graphics/java/android/renderscript/Program.java @@ -17,6 +17,11 @@ 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; @@ -38,12 +43,18 @@ public class Program extends BaseObj { String mShader; Program(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } 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."); + } + mRS.nProgramBindConstants(getID(), slot, a.getID()); } public void bindTexture(Allocation va, int slot) @@ -53,7 +64,7 @@ public class Program extends BaseObj { throw new IllegalArgumentException("Slot ID out of range."); } - mRS.nProgramBindTexture(mID, slot, va.mID); + mRS.nProgramBindTexture(getID(), slot, va.getID()); } public void bindSampler(Sampler vs, int slot) @@ -63,7 +74,7 @@ public class Program extends BaseObj { throw new IllegalArgumentException("Slot ID out of range."); } - mRS.nProgramBindSampler(mID, slot, vs.mID); + mRS.nProgramBindSampler(getID(), slot, vs.getID()); } @@ -91,14 +102,56 @@ public class Program extends BaseObj { mTextureCount = 0; } - public void setShader(String s) { + public BaseProgramBuilder setShader(String s) { mShader = s; + return this; + } + + 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(); + } + + try { + mShader = new String(str, 0, strLength, "UTF-8"); + } catch (UnsupportedEncodingException e) { + Log.e("Renderscript shader creation", "Could not decode shader string"); + } + + 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."); + throw new RSIllegalArgumentException("Max input count exceeded."); + } + if (e.isComplex()) { + throw new RSIllegalArgumentException("Complex elements not allowed."); } mInputs[mInputCount++] = e; } @@ -106,26 +159,40 @@ public class Program extends BaseObj { 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."); + throw new RSIllegalArgumentException("Max output count exceeded."); + } + if (e.isComplex()) { + throw new RSIllegalArgumentException("Complex elements not allowed."); } mOutputs[mOutputCount++] = e; } + void resetConstant() { + mConstantCount = 0; + for(int i = 0; i < MAX_CONSTANT; i ++) { + mConstants[i] = null; + } + } + public int 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++; } - public void setTextureCount(int count) throws IllegalArgumentException { + public BaseProgramBuilder setTextureCount(int count) throws IllegalArgumentException { // Should check for consistant and non-conflicting names... - if(count >= MAX_CONSTANT) { + if(count >= MAX_TEXTURE) { throw new IllegalArgumentException("Max texture count exceeded."); } mTextureCount = count; + return this; } protected void initProgram(Program p) { diff --git a/graphics/java/android/renderscript/ProgramFragment.java b/graphics/java/android/renderscript/ProgramFragment.java index 5e04f0c..d30e483 100644 --- a/graphics/java/android/renderscript/ProgramFragment.java +++ b/graphics/java/android/renderscript/ProgramFragment.java @@ -42,30 +42,31 @@ public class ProgramFragment extends Program { for (int i=0; i < mInputCount; i++) { tmp[idx++] = 0; - tmp[idx++] = mInputs[i].mID; + tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { tmp[idx++] = 1; - tmp[idx++] = mOutputs[i].mID; + tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { tmp[idx++] = 2; - tmp[idx++] = mConstants[i].mID; + tmp[idx++] = mConstants[i].getID(); } tmp[idx++] = 3; tmp[idx++] = mTextureCount; - int id = mRS.nProgramFragmentCreate2(mShader, tmp); + int id = mRS.nProgramFragmentCreate(mShader, tmp); ProgramFragment pf = new ProgramFragment(id, mRS); initProgram(pf); return pf; } } - public static class Builder { + public static class Builder extends ShaderBuilder { public static final int MAX_TEXTURE = 2; - RenderScript mRS; + int mNumTextures; boolean mPointSpriteEnable; + boolean mVaryingColorEnable; public enum EnvMode { REPLACE (1), @@ -100,39 +101,126 @@ public class ProgramFragment extends Program { } 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"; + } + public Builder(RenderScript rs) { + super(rs); mRS = rs; mSlots = new Slot[MAX_TEXTURE]; mPointSpriteEnable = false; } - public void setTexture(EnvMode env, Format fmt, int slot) + 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; } - public void setPointSpriteTexCoordinateReplacement(boolean enable) { + public Builder setPointSpriteTexCoordinateReplacement(boolean enable) { mPointSpriteEnable = enable; + return this; + } + + public Builder setVaryingColor(boolean enable) { + mVaryingColorEnable = enable; + return this; } + @Override 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; + mNumTextures = 0; + for(int i = 0; i < MAX_TEXTURE; i ++) { + if(mSlots[i] != null) { + mNumTextures ++; + } } - if (mSlots[1] != null) { - tmp[2] = mSlots[1].env.mID; - tmp[3] = mSlots[1].format.mID; + resetConstant(); + buildShaderString(); + 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.add(Dimension.X, 1); + constType = typeBuilder.create(); + addConstant(constType); } - tmp[4] = mPointSpriteEnable ? 1 : 0; - int id = mRS.nProgramFragmentCreate(tmp); - ProgramFragment pf = new ProgramFragment(id, mRS); + setTextureCount(mNumTextures); + + ProgramFragment pf = super.create(); pf.mTextureCount = MAX_TEXTURE; + if (!mVaryingColorEnable) { + Allocation constantData = Allocation.createTyped(mRS,constType); + float[] data = new float[4]; + data[0] = data[1] = data[2] = data[3] = 1.0f; + constantData.data(data); + pf.bindConstants(constantData, 0); + } return pf; } } diff --git a/graphics/java/android/renderscript/ProgramRaster.java b/graphics/java/android/renderscript/ProgramRaster.java index 56f9bf4..5b55015 100644 --- a/graphics/java/android/renderscript/ProgramRaster.java +++ b/graphics/java/android/renderscript/ProgramRaster.java @@ -26,76 +26,113 @@ import android.util.Log; * **/ 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 setPointSpriteEnable(boolean enable) { + mPointSprite = enable; + return this; } - public void setPointSmoothEnable(boolean enable) { - mPR.mPointSmooth = enable; + public Builder setPointSmoothEnable(boolean enable) { + mPointSmooth = enable; + return this; } - public void setLineSmoothEnable(boolean enable) { - mPR.mLineSmooth = enable; + public Builder setLineSmoothEnable(boolean enable) { + mLineSmooth = enable; + return this; } + public Builder setCullMode(CullMode m) { + mCullMode = m; + return this; + } 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 +148,4 @@ public class ProgramRaster extends BaseObj { + diff --git a/graphics/java/android/renderscript/ProgramStore.java b/graphics/java/android/renderscript/ProgramStore.java index 69be245..d191b06 100644 --- a/graphics/java/android/renderscript/ProgramStore.java +++ b/graphics/java/android/renderscript/ProgramStore.java @@ -76,11 +76,143 @@ public class ProgramStore extends BaseObj { ProgramStore(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } + 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.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_NONE_DEPTH_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_TEST; + } + public static ProgramStore BLEND_NONE_DEPTH_NO_DEPTH(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.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_NO_DEPTH; + } + public static ProgramStore BLEND_NONE_DEPTH_NO_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_NONE_DEPTH_NO_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); + builder.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_NONE_DEPTH_NO_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_NO_TEST; + } + public static ProgramStore BLEND_NONE_DEPTH_NO_WRITE(RenderScript rs) { + if(rs.mProgramStore_BLEND_NONE_DEPTH_NO_WRITE == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.LESS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ZERO); + builder.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_NONE_DEPTH_NO_WRITE = builder.create(); + } + return rs.mProgramStore_BLEND_NONE_DEPTH_NO_WRITE; + } + + 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.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_ALPHA_DEPTH_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_TEST; + } + public static ProgramStore BLEND_ALPHA_DEPTH_NO_DEPTH(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.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH; + } + public static ProgramStore BLEND_ALPHA_DEPTH_NO_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_TEST; + } + public static ProgramStore BLEND_ALPHA_DEPTH_NO_WRITE(RenderScript rs) { + if(rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_WRITE == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.LESS); + builder.setBlendFunc(BlendSrcFunc.SRC_ALPHA, BlendDstFunc.ONE_MINUS_SRC_ALPHA); + builder.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_WRITE = builder.create(); + } + return rs.mProgramStore_BLEND_ALPHA_DEPTH_NO_WRITE; + } + public static ProgramStore BLEND_ADD_DEPTH_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_ADD_DEPTH_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.LESS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_ADD_DEPTH_TEST = builder.create(); + } + return rs.mProgramStore_BLEND_ADD_DEPTH_TEST; + } + public static ProgramStore BLEND_ADD_DEPTH_NO_DEPTH(RenderScript rs) { + if(rs.mProgramStore_BLEND_ADD_DEPTH_NO_DEPTH == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_ADD_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_ADD_DEPTH_NO_DEPTH; + } + public static ProgramStore BLEND_ADD_DEPTH_NO_TEST(RenderScript rs) { + if(rs.mProgramStore_BLEND_ADD_DEPTH_NO_TEST == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnable(false); + builder.setDepthMask(true); + rs.mProgramStore_BLEND_ADD_DEPTH_NO_DEPTH = builder.create(); + } + return rs.mProgramStore_BLEND_ADD_DEPTH_NO_TEST; + } + public static ProgramStore BLEND_ADD_DEPTH_NO_WRITE(RenderScript rs) { + if(rs.mProgramStore_BLEND_ADD_DEPTH_NO_WRITE == null) { + ProgramStore.Builder builder = new ProgramStore.Builder(rs); + builder.setDepthFunc(ProgramStore.DepthFunc.ALWAYS); + builder.setBlendFunc(BlendSrcFunc.ONE, BlendDstFunc.ONE); + builder.setDitherEnable(false); + builder.setDepthMask(false); + rs.mProgramStore_BLEND_ADD_DEPTH_NO_WRITE = builder.create(); + } + return rs.mProgramStore_BLEND_ADD_DEPTH_NO_WRITE; + } public static class Builder { RenderScript mRS; @@ -110,54 +242,63 @@ public class ProgramStore extends BaseObj { mColorMaskA = true; mBlendSrc = BlendSrcFunc.ONE; mBlendDst = BlendDstFunc.ZERO; + } - + public Builder(RenderScript rs) { + mRS = rs; + mIn = null; + mOut = null; + mDepthFunc = DepthFunc.ALWAYS; + mDepthMask = false; + mColorMaskR = true; + mColorMaskG = true; + mColorMaskB = true; + mColorMaskA = true; + mBlendSrc = BlendSrcFunc.ONE; + mBlendDst = BlendDstFunc.ZERO; } - public void setDepthFunc(DepthFunc func) { + public Builder setDepthFunc(DepthFunc func) { mDepthFunc = func; + return this; } - public void setDepthMask(boolean enable) { + public Builder setDepthMask(boolean enable) { mDepthMask = enable; + return this; } - public void setColorMask(boolean r, boolean g, boolean b, boolean a) { + public Builder setColorMask(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) { + public Builder setBlendFunc(BlendSrcFunc src, BlendDstFunc dst) { mBlendSrc = src; mBlendDst = dst; + return this; } - public void setDitherEnable(boolean enable) { + public Builder setDitherEnable(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); } diff --git a/graphics/java/android/renderscript/ProgramVertex.java b/graphics/java/android/renderscript/ProgramVertex.java index 1b155d7..13f017a 100644 --- a/graphics/java/android/renderscript/ProgramVertex.java +++ b/graphics/java/android/renderscript/ProgramVertex.java @@ -17,6 +17,7 @@ package android.renderscript; +import android.graphics.Matrix; import android.util.Config; import android.util.Log; @@ -38,25 +39,6 @@ public class ProgramVertex extends Program { 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); - } - } - public static class ShaderBuilder extends BaseProgramBuilder { public ShaderBuilder(RenderScript rs) { super(rs); @@ -69,26 +51,88 @@ public class ProgramVertex extends Program { for (int i=0; i < mInputCount; i++) { tmp[idx++] = 0; - tmp[idx++] = mInputs[i].mID; + tmp[idx++] = mInputs[i].getID(); } for (int i=0; i < mOutputCount; i++) { tmp[idx++] = 1; - tmp[idx++] = mOutputs[i].mID; + tmp[idx++] = mOutputs[i].getID(); } for (int i=0; i < mConstantCount; i++) { tmp[idx++] = 2; - tmp[idx++] = mConstants[i].mID; + tmp[idx++] = mConstants[i].getID(); } 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 Builder extends ShaderBuilder { + boolean mTextureMatrixEnable; + + public Builder(RenderScript rs, Element in, Element out) { + super(rs); + } + public Builder(RenderScript rs) { + super(rs); + } + + 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.add(Dimension.X, 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"; + } + + @Override + public ProgramVertex create() { + buildShaderString(); + + 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"); + addInput(b.create()); + + return super.create(); + } + } + public static class MatrixAllocation { @@ -101,16 +145,17 @@ public class ProgramVertex extends Program { Matrix4f mTexture; public Allocation mAlloc; + private FieldPacker mIOBuffer; 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); + Type constInputType = ProgramVertex.Builder.getConstantInputType(rs); + mAlloc = Allocation.createTyped(rs, constInputType); + int bufferSize = constInputType.getElement().getSizeBytes()* + constInputType.getElementCount(); + mIOBuffer = new FieldPacker(bufferSize); + loadModelview(new Matrix4f()); + loadProjection(new Matrix4f()); + loadTexture(new Matrix4f()); } public void destroy() { @@ -118,24 +163,32 @@ public class ProgramVertex extends Program { 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.data(mIOBuffer.getData()); + } + public void loadModelview(Matrix4f m) { mModel = m; - mAlloc.subData1D(MODELVIEW_OFFSET, 16, m.mMat); + addToBuffer(MODELVIEW_OFFSET*4, m); } public void loadProjection(Matrix4f m) { mProjection = m; - mAlloc.subData1D(PROJECTION_OFFSET, 16, m.mMat); + addToBuffer(PROJECTION_OFFSET*4, m); } public void loadTexture(Matrix4f m) { mTexture = m; - mAlloc.subData1D(TEXTURE_OFFSET, 16, m.mMat); + addToBuffer(TEXTURE_OFFSET*4, m); } public void setupOrthoWindow(int w, int h) { mProjection.loadOrtho(0,w, h,0, -1,1); - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); + addToBuffer(PROJECTION_OFFSET*4, mProjection); } public void setupOrthoNormalized(int w, int h) { @@ -147,7 +200,7 @@ public class ProgramVertex extends Program { float aspect = ((float)h) / w; mProjection.loadOrtho(-1,1, -aspect,aspect, -1,1); } - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); + addToBuffer(PROJECTION_OFFSET*4, mProjection); } public void setupProjectionNormalized(int w, int h) { @@ -173,7 +226,7 @@ public class ProgramVertex extends Program { m1.loadMultiply(m1, m2); mProjection = m1; - mAlloc.subData1D(PROJECTION_OFFSET, 16, mProjection.mMat); + addToBuffer(PROJECTION_OFFSET*4, mProjection); } } diff --git a/graphics/java/android/renderscript/RSDriverException.java b/graphics/java/android/renderscript/RSDriverException.java new file mode 100644 index 0000000..61787e6 --- /dev/null +++ b/graphics/java/android/renderscript/RSDriverException.java @@ -0,0 +1,32 @@ +/* + * 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 + * @hide + */ +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..8d67a8d --- /dev/null +++ b/graphics/java/android/renderscript/RSIllegalArgumentException.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 + * @hide + */ +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..53b9479 --- /dev/null +++ b/graphics/java/android/renderscript/RSInvalidStateException.java @@ -0,0 +1,32 @@ +/* + * 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 + * @hide + */ +public class RSInvalidStateException extends RSRuntimeException { + public RSInvalidStateException(String string) { + super(string); + } +} + + + diff --git a/graphics/java/android/renderscript/RSRuntimeException.java b/graphics/java/android/renderscript/RSRuntimeException.java new file mode 100644 index 0000000..4c97937 --- /dev/null +++ b/graphics/java/android/renderscript/RSRuntimeException.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 + * @hide + */ +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..2540d01 100644 --- a/graphics/java/android/renderscript/RSSurfaceView.java +++ b/graphics/java/android/renderscript/RSSurfaceView.java @@ -25,7 +25,6 @@ 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; @@ -146,22 +145,18 @@ public class RSSurfaceView extends SurfaceView implements SurfaceHolder.Callback // ---------------------------------------------------------------------- - public RenderScriptGL createRenderScript(boolean useDepth, boolean forceSW) { + public RenderScriptGL createRenderScript(RenderScriptGL.SurfaceConfig sc) { Log.v(RenderScript.LOG_TAG, "createRenderScript"); - mRS = new RenderScriptGL(useDepth, forceSW); + mRS = new RenderScriptGL(sc); return mRS; } - public RenderScriptGL createRenderScript(boolean useDepth) { - return createRenderScript(useDepth, false); - } - public void destroyRenderScript() { Log.v(RenderScript.LOG_TAG, "destroyRenderScript"); mRS.destroy(); mRS = null; } - + public void createRenderScript(RenderScriptGL rs) { mRS = rs; } diff --git a/graphics/java/android/renderscript/RenderScript.java b/graphics/java/android/renderscript/RenderScript.java index a935243..df03e13 100644 --- a/graphics/java/android/renderscript/RenderScript.java +++ b/graphics/java/android/renderscript/RenderScript.java @@ -28,6 +28,13 @@ 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"; @@ -57,151 +64,486 @@ public class RenderScript { } } + // Non-threadsafe functions. native void nInitElements(int a8, int rgba4444, int rgba8888, int rgb565); - 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(); + 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); + 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) { + return rsnContextCreateGL(dev, ver, colorMin, colorPref, + alphaMin, alphaPref, depthMin, depthPref, + stencilMin, stencilPref, + samplesMin, samplesPref, samplesQ); + } + 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() { + rsnContextDestroy(mContext); + } + native void rsnContextSetSurface(int con, int w, int h, Surface sur); + synchronized void nContextSetSurface(int w, int h, Surface sur) { + rsnContextSetSurface(mContext, w, h, sur); + } + native void rsnContextSetPriority(int con, int p); + synchronized void nContextSetPriority(int p) { + rsnContextSetPriority(mContext, p); + } + native void rsnContextDump(int con, int bits); + synchronized void nContextDump(int bits) { + rsnContextDump(mContext, bits); + } + native void rsnContextFinish(int con); + synchronized void nContextFinish() { + rsnContextFinish(mContext); + } + + native void rsnContextBindRootScript(int con, int script); + synchronized void nContextBindRootScript(int script) { + rsnContextBindRootScript(mContext, script); + } + native void rsnContextBindSampler(int con, int sampler, int slot); + synchronized void nContextBindSampler(int sampler, int slot) { + rsnContextBindSampler(mContext, sampler, slot); + } + native void rsnContextBindProgramStore(int con, int pfs); + synchronized void nContextBindProgramStore(int pfs) { + rsnContextBindProgramStore(mContext, pfs); + } + native void rsnContextBindProgramFragment(int con, int pf); + synchronized void nContextBindProgramFragment(int pf) { + rsnContextBindProgramFragment(mContext, pf); + } + native void rsnContextBindProgramVertex(int con, int pv); + synchronized void nContextBindProgramVertex(int pv) { + rsnContextBindProgramVertex(mContext, pv); + } + native void rsnContextBindProgramRaster(int con, int pr); + synchronized void nContextBindProgramRaster(int pr) { + rsnContextBindProgramRaster(mContext, pr); + } + native void rsnContextPause(int con); + synchronized void nContextPause() { + rsnContextPause(mContext); + } + native void rsnContextResume(int con); + synchronized void nContextResume() { + rsnContextResume(mContext); + } + + native void rsnAssignName(int con, int obj, byte[] name); + synchronized void nAssignName(int obj, byte[] name) { + rsnAssignName(mContext, obj, name); + } + native String rsnGetName(int con, int obj); + synchronized String nGetName(int obj) { + return rsnGetName(mContext, obj); + } + native void rsnObjDestroy(int con, int id); + synchronized void nObjDestroy(int id) { + 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) { + 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) { + return rsnElementCreate2(mContext, elements, names, arraySizes); + } + native void rsnElementGetNativeData(int con, int id, int[] elementData); + synchronized void nElementGetNativeData(int id, int[] elementData) { + rsnElementGetNativeData(mContext, id, elementData); + } + native void rsnElementGetSubElements(int con, int id, int[] IDs, String[] names); + synchronized void nElementGetSubElements(int id, int[] IDs, String[] names) { + rsnElementGetSubElements(mContext, id, IDs, names); + } + + native int rsnTypeCreate(int con, int eid, int[] dims, int[] vals); + synchronized int nTypeCreate(int eid, int[] dims, int[] vals) { + return rsnTypeCreate(mContext, eid, dims, vals); + } + native void rsnTypeGetNativeData(int con, int id, int[] typeData); + synchronized void nTypeGetNativeData(int id, int[] typeData) { + rsnTypeGetNativeData(mContext, id, typeData); + } + + native int rsnAllocationCreateTyped(int con, int type); + synchronized int nAllocationCreateTyped(int type) { + return rsnAllocationCreateTyped(mContext, type); + } + native void rsnAllocationUpdateFromBitmap(int con, int alloc, Bitmap bmp); + synchronized void nAllocationUpdateFromBitmap(int alloc, Bitmap bmp) { + rsnAllocationUpdateFromBitmap(mContext, alloc, bmp); + } + native int rsnAllocationCreateFromBitmap(int con, int dstFmt, boolean genMips, Bitmap bmp); + synchronized int nAllocationCreateFromBitmap(int dstFmt, boolean genMips, Bitmap bmp) { + return rsnAllocationCreateFromBitmap(mContext, dstFmt, genMips, bmp); + } + native int rsnAllocationCreateBitmapRef(int con, int type, Bitmap bmp); + synchronized int nAllocationCreateBitmapRef(int type, Bitmap bmp) { + return rsnAllocationCreateBitmapRef(mContext, type, bmp); + } + native int rsnAllocationCreateFromAssetStream(int con, int dstFmt, boolean genMips, int assetStream); + synchronized int nAllocationCreateFromAssetStream(int dstFmt, boolean genMips, int assetStream) { + return rsnAllocationCreateFromAssetStream(mContext, dstFmt, genMips, assetStream); + } + + native void rsnAllocationUploadToTexture(int con, int alloc, boolean genMips, int baseMioLevel); + synchronized void nAllocationUploadToTexture(int alloc, boolean genMips, int baseMioLevel) { + rsnAllocationUploadToTexture(mContext, alloc, genMips, baseMioLevel); + } + native void rsnAllocationUploadToBufferObject(int con, int alloc); + synchronized void nAllocationUploadToBufferObject(int alloc) { + rsnAllocationUploadToBufferObject(mContext, alloc); + } + + native void rsnAllocationSubData1D(int con, int id, int off, int count, int[] d, int sizeBytes); + synchronized void nAllocationSubData1D(int id, int off, int count, int[] d, int sizeBytes) { + rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes); + } + native void rsnAllocationSubData1D(int con, int id, int off, int count, short[] d, int sizeBytes); + synchronized void nAllocationSubData1D(int id, int off, int count, short[] d, int sizeBytes) { + rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes); + } + native void rsnAllocationSubData1D(int con, int id, int off, int count, byte[] d, int sizeBytes); + synchronized void nAllocationSubData1D(int id, int off, int count, byte[] d, int sizeBytes) { + rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes); + } + native void rsnAllocationSubElementData1D(int con, int id, int xoff, int compIdx, byte[] d, int sizeBytes); + synchronized void nAllocationSubElementData1D(int id, int xoff, int compIdx, byte[] d, int sizeBytes) { + rsnAllocationSubElementData1D(mContext, id, xoff, compIdx, d, sizeBytes); + } + native void rsnAllocationSubData1D(int con, int id, int off, int count, float[] d, int sizeBytes); + synchronized void nAllocationSubData1D(int id, int off, int count, float[] d, int sizeBytes) { + rsnAllocationSubData1D(mContext, id, off, count, d, sizeBytes); + } + + native void rsnAllocationSubData2D(int con, int id, int xoff, int yoff, int w, int h, int[] d, int sizeBytes); + synchronized void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, int[] d, int sizeBytes) { + rsnAllocationSubData2D(mContext, id, xoff, yoff, w, h, d, sizeBytes); + } + native void rsnAllocationSubData2D(int con, int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes); + synchronized void nAllocationSubData2D(int id, int xoff, int yoff, int w, int h, float[] d, int sizeBytes) { + rsnAllocationSubData2D(mContext, id, xoff, yoff, w, h, d, sizeBytes); + } + native void rsnAllocationRead(int con, int id, int[] d); + synchronized void nAllocationRead(int id, int[] d) { + rsnAllocationRead(mContext, id, d); + } + native void rsnAllocationRead(int con, int id, float[] d); + synchronized void nAllocationRead(int id, float[] d) { + rsnAllocationRead(mContext, id, d); + } + native int rsnAllocationGetType(int con, int id); + synchronized int nAllocationGetType(int id) { + return rsnAllocationGetType(mContext, id); + } + + native void rsnAllocationResize1D(int con, int id, int dimX); + synchronized void nAllocationResize1D(int id, int dimX) { + rsnAllocationResize1D(mContext, id, dimX); + } + native void rsnAllocationResize2D(int con, int id, int dimX, int dimY); + synchronized void nAllocationResize2D(int id, int dimX, int dimY) { + rsnAllocationResize2D(mContext, id, dimX, dimY); + } + + native int rsnFileA3DCreateFromAssetStream(int con, int assetStream); + synchronized int nFileA3DCreateFromAssetStream(int assetStream) { + return rsnFileA3DCreateFromAssetStream(mContext, assetStream); + } + native int rsnFileA3DGetNumIndexEntries(int con, int fileA3D); + synchronized int nFileA3DGetNumIndexEntries(int fileA3D) { + 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) { + rsnFileA3DGetIndexEntries(mContext, fileA3D, numEntries, IDs, names); + } + native int rsnFileA3DGetEntryByIndex(int con, int fileA3D, int index); + synchronized int nFileA3DGetEntryByIndex(int fileA3D, int index) { + return rsnFileA3DGetEntryByIndex(mContext, fileA3D, index); + } + + native int rsnFontCreateFromFile(int con, String fileName, int size, int dpi); + synchronized int nFontCreateFromFile(String fileName, int size, int dpi) { + return rsnFontCreateFromFile(mContext, fileName, size, dpi); + } + + native void rsnAdapter1DBindAllocation(int con, int ad, int alloc); + synchronized void nAdapter1DBindAllocation(int ad, int alloc) { + rsnAdapter1DBindAllocation(mContext, ad, alloc); + } + native void rsnAdapter1DSetConstraint(int con, int ad, int dim, int value); + synchronized void nAdapter1DSetConstraint(int ad, int dim, int value) { + rsnAdapter1DSetConstraint(mContext, ad, dim, value); + } + native void rsnAdapter1DData(int con, int ad, int[] d); + synchronized void nAdapter1DData(int ad, int[] d) { + rsnAdapter1DData(mContext, ad, d); + } + native void rsnAdapter1DData(int con, int ad, float[] d); + synchronized void nAdapter1DData(int ad, float[] d) { + rsnAdapter1DData(mContext, ad, d); + } + native void rsnAdapter1DSubData(int con, int ad, int off, int count, int[] d); + synchronized void nAdapter1DSubData(int ad, int off, int count, int[] d) { + rsnAdapter1DSubData(mContext, ad, off, count, d); + } + native void rsnAdapter1DSubData(int con, int ad, int off, int count, float[] d); + synchronized void nAdapter1DSubData(int ad, int off, int count, float[] d) { + rsnAdapter1DSubData(mContext, ad, off, count, d); + } + native int rsnAdapter1DCreate(int con); + synchronized int nAdapter1DCreate() { + return rsnAdapter1DCreate(mContext); + } + + native void rsnAdapter2DBindAllocation(int con, int ad, int alloc); + synchronized void nAdapter2DBindAllocation(int ad, int alloc) { + rsnAdapter2DBindAllocation(mContext, ad, alloc); + } + native void rsnAdapter2DSetConstraint(int con, int ad, int dim, int value); + synchronized void nAdapter2DSetConstraint(int ad, int dim, int value) { + rsnAdapter2DSetConstraint(mContext, ad, dim, value); + } + native void rsnAdapter2DData(int con, int ad, int[] d); + synchronized void nAdapter2DData(int ad, int[] d) { + rsnAdapter2DData(mContext, ad, d); + } + native void rsnAdapter2DData(int con, int ad, float[] d); + synchronized void nAdapter2DData(int ad, float[] d) { + rsnAdapter2DData(mContext, ad, d); + } + native void rsnAdapter2DSubData(int con, int ad, int xoff, int yoff, int w, int h, int[] d); + synchronized void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, int[] d) { + rsnAdapter2DSubData(mContext, ad, xoff, yoff, w, h, d); + } + native void rsnAdapter2DSubData(int con, int ad, int xoff, int yoff, int w, int h, float[] d); + synchronized void nAdapter2DSubData(int ad, int xoff, int yoff, int w, int h, float[] d) { + rsnAdapter2DSubData(mContext, ad, xoff, yoff, w, h, d); + } + native int rsnAdapter2DCreate(int con); + synchronized int nAdapter2DCreate() { + return rsnAdapter2DCreate(mContext); + } + + native void rsnScriptBindAllocation(int con, int script, int alloc, int slot); + synchronized void nScriptBindAllocation(int script, int alloc, int slot) { + rsnScriptBindAllocation(mContext, script, alloc, slot); + } + native void rsnScriptSetTimeZone(int con, int script, byte[] timeZone); + synchronized void nScriptSetTimeZone(int script, byte[] timeZone) { + rsnScriptSetTimeZone(mContext, script, timeZone); + } + native void rsnScriptInvoke(int con, int id, int slot); + synchronized void nScriptInvoke(int id, int slot) { + rsnScriptInvoke(mContext, id, slot); + } + native void rsnScriptInvokeV(int con, int id, int slot, byte[] params); + synchronized void nScriptInvokeV(int id, int slot, byte[] params) { + 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) { + 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) { + 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) { + 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) { + 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) { + rsnScriptSetVarV(mContext, id, slot, val); + } + + native void rsnScriptCBegin(int con); + synchronized void nScriptCBegin() { + rsnScriptCBegin(mContext); + } + native void rsnScriptCSetScript(int con, byte[] script, int offset, int length); + synchronized void nScriptCSetScript(byte[] script, int offset, int length) { + rsnScriptCSetScript(mContext, script, offset, length); + } + native int rsnScriptCCreate(int con); + synchronized int nScriptCCreate() { + return rsnScriptCCreate(mContext); + } + + native void rsnSamplerBegin(int con); + synchronized void nSamplerBegin() { + rsnSamplerBegin(mContext); + } + native void rsnSamplerSet(int con, int param, int value); + synchronized void nSamplerSet(int param, int value) { + rsnSamplerSet(mContext, param, value); + } + native void rsnSamplerSet2(int con, int param, float value); + synchronized void nSamplerSet2(int param, float value) { + rsnSamplerSet2(mContext, param, value); + } + native int rsnSamplerCreate(int con); + synchronized int nSamplerCreate() { + return rsnSamplerCreate(mContext); + } + + native void rsnProgramStoreBegin(int con, int in, int out); + synchronized void nProgramStoreBegin(int in, int out) { + rsnProgramStoreBegin(mContext, in, out); + } + native void rsnProgramStoreDepthFunc(int con, int func); + synchronized void nProgramStoreDepthFunc(int func) { + rsnProgramStoreDepthFunc(mContext, func); + } + native void rsnProgramStoreDepthMask(int con, boolean enable); + synchronized void nProgramStoreDepthMask(boolean enable) { + 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) { + rsnProgramStoreColorMask(mContext, r, g, b, a); + } + native void rsnProgramStoreBlendFunc(int con, int src, int dst); + synchronized void nProgramStoreBlendFunc(int src, int dst) { + rsnProgramStoreBlendFunc(mContext, src, dst); + } + native void rsnProgramStoreDither(int con, boolean enable); + synchronized void nProgramStoreDither(boolean enable) { + rsnProgramStoreDither(mContext, enable); + } + native int rsnProgramStoreCreate(int con); + synchronized int nProgramStoreCreate() { + return rsnProgramStoreCreate(mContext); + } + + native int rsnProgramRasterCreate(int con, boolean pointSmooth, boolean lineSmooth, boolean pointSprite); + synchronized int nProgramRasterCreate(boolean pointSmooth, boolean lineSmooth, boolean pointSprite) { + return rsnProgramRasterCreate(mContext, pointSmooth, lineSmooth, pointSprite); + } + native void rsnProgramRasterSetLineWidth(int con, int pr, float v); + synchronized void nProgramRasterSetLineWidth(int pr, float v) { + rsnProgramRasterSetLineWidth(mContext, pr, v); + } + native void rsnProgramRasterSetCullMode(int con, int pr, int mode); + synchronized void nProgramRasterSetCullMode(int pr, int mode) { + rsnProgramRasterSetCullMode(mContext, pr, mode); + } + + native void rsnProgramBindConstants(int con, int pv, int slot, int mID); + synchronized void nProgramBindConstants(int pv, int slot, int mID) { + 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) { + 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) { + rsnProgramBindSampler(mContext, vpf, slot, s); + } + native int rsnProgramFragmentCreate(int con, String shader, int[] params); + synchronized int nProgramFragmentCreate(String shader, int[] params) { + return rsnProgramFragmentCreate(mContext, shader, params); + } + native int rsnProgramVertexCreate(int con, String shader, int[] params); + synchronized int nProgramVertexCreate(String shader, int[] params) { + return rsnProgramVertexCreate(mContext, shader, params); + } + + native int rsnMeshCreate(int con, int vtxCount, int indexCount); + synchronized int nMeshCreate(int vtxCount, int indexCount) { + 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) { + 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) { + rsnMeshBindIndex(mContext, id, alloc, prim, slot); + } + native void rsnMeshInitVertexAttribs(int con, int id); + synchronized void nMeshInitVertexAttribs(int id) { + rsnMeshInitVertexAttribs(mContext, id); + } + native int rsnMeshGetVertexBufferCount(int con, int id); + synchronized int nMeshGetVertexBufferCount(int id) { + return rsnMeshGetVertexBufferCount(mContext, id); + } + native int rsnMeshGetIndexCount(int con, int id); + synchronized int nMeshGetIndexCount(int id) { + return rsnMeshGetIndexCount(mContext, id); + } + native void rsnMeshGetVertices(int con, int id, int[] vtxIds, int vtxIdCount); + synchronized void nMeshGetVertices(int id, int[] vtxIds, int vtxIdCount) { + 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) { + rsnMeshGetIndices(mContext, id, idxIds, primitives, vtxIdCount); + } + protected int mDev; protected int mContext; @SuppressWarnings({"FieldCanBeLocal"}) protected MessageThread mMessageThread; - 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; + 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,25 +552,93 @@ 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_NONE_DEPTH_NO_TEST; + ProgramStore mProgramStore_BLEND_NONE_DEPTH_NO_WRITE; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_TEST; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_NO_DEPTH; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_NO_TEST; + ProgramStore mProgramStore_BLEND_ALPHA_DEPTH_NO_WRITE; + ProgramStore mProgramStore_BLEND_ADD_DEPTH_TEST; + ProgramStore mProgramStore_BLEND_ADD_DEPTH_NO_DEPTH; + ProgramStore mProgramStore_BLEND_ADD_DEPTH_NO_TEST; + ProgramStore mProgramStore_BLEND_ADD_DEPTH_NO_WRITE; + + ProgramRaster mProgramRaster_CULL_BACK; + ProgramRaster mProgramRaster_CULL_FRONT; + ProgramRaster mProgramRaster_CULL_NONE; /////////////////////////////////////////////////////////////////////////////////// // + /** + * Base class application should derive from for handling RS messages + * comming 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 RSMessage 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. + * + */ public RSMessage mMessageCallback = null; + /** + * 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 RSAsyncError implements Runnable { + protected String mErrorMessage; + protected int mErrorNum; + public void run() { + } + } + + /** + * 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. + * + */ + public RSAsyncError mErrorCallback = null; + + /** + * 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 { LOW (5), //ANDROID_PRIORITY_BACKGROUND + 5 NORMAL (-4); //ANDROID_PRIORITY_DISPLAY @@ -241,10 +651,16 @@ 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."); } } + + /** + * Change the priority of the worker threads for this context. + * + * @param p New priority to be set. + */ public void contextSetPriority(Priority p) { validate(); nContextSetPriority(p.mID); @@ -253,6 +669,13 @@ public class RenderScript { protected static class MessageThread extends Thread { RenderScript mRS; boolean mRun = true; + int[] auxData = new int[2]; + + public static final int RS_MESSAGE_TO_CLIENT_NONE = 0; + public static final int RS_MESSAGE_TO_CLIENT_EXCEPTION = 1; + public static final int RS_MESSAGE_TO_CLIENT_RESIZE = 2; + public static final int RS_MESSAGE_TO_CLIENT_ERROR = 3; + public static final int RS_MESSAGE_TO_CLIENT_USER = 4; MessageThread(RenderScript rs) { super("RSMessageThread"); @@ -264,33 +687,65 @@ 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, auxData, true); + int size = auxData[1]; + int subID = auxData[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(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() { } + /** + * Create a basic RenderScript context. + * + * + * @return RenderScript + */ public static RenderScript create() { RenderScript rs = new RenderScript(); @@ -302,17 +757,42 @@ public class RenderScript { return rs; } + /** + * Print the currently available debugging information about the state of + * the RS context to the log. + * + * + * @param bits Currently ignored. + */ public void contextDump(int bits) { validate(); nContextDump(bits); } + /** + * 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 +803,13 @@ public class RenderScript { return mContext != 0; } - /////////////////////////////////////////////////////////////////////////////////// - // Root state - protected 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..181d4bd 100644 --- a/graphics/java/android/renderscript/RenderScriptGL.java +++ b/graphics/java/android/renderscript/RenderScriptGL.java @@ -18,32 +18,129 @@ package android.renderscript; import java.lang.reflect.Field; +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. + * + */ + 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("Prefered must be >= Minimum."); + } + } + + public void setColor(int minimum, int prefered) { + validateRange(minimum, prefered, 5, 8); + mColorMin = minimum; + mColorPref = prefered; + } + public void setAlpha(int minimum, int prefered) { + validateRange(minimum, prefered, 0, 8); + mAlphaMin = minimum; + mAlphaPref = prefered; + } + public void setDepth(int minimum, int prefered) { + validateRange(minimum, prefered, 0, 24); + mDepthMin = minimum; + mDepthPref = prefered; + } + public void setSamples(int minimum, int prefered, float Q) { + validateRange(minimum, prefered, 0, 24); + if (Q < 0.0f || Q > 1.0f) { + throw new RSIllegalArgumentException("Quality out of 0-1 range."); + } + mSamplesMin = minimum; + mSamplesPref = prefered; + mSamplesQ = Q; + } + }; + + SurfaceConfig mSurfaceConfig; + + public void configureSurface(SurfaceHolder sh) { + if (mSurfaceConfig.mAlphaMin > 1) { + sh.setFormat(PixelFormat.RGBA_8888); + } else { + sh.setFormat(PixelFormat.RGBX_8888); + } + } + + public void checkSurface(SurfaceHolder sh) { + } + + public RenderScriptGL(SurfaceConfig sc) { + mSurfaceConfig = new SurfaceConfig(sc); - public RenderScriptGL(boolean useDepth, boolean forceSW) { mSurface = null; mWidth = 0; mHeight = 0; mDev = nDeviceCreate(); - if(forceSW) { - nDeviceSetConfig(mDev, 0, 1); + 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); + 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); @@ -57,6 +154,13 @@ public class RenderScriptGL extends RenderScript { nContextSetSurface(w, h, mSurface); } + public int getHeight() { + return mHeight; + } + + public int getWidth() { + return mWidth; + } void pause() { validate(); @@ -74,9 +178,9 @@ public class RenderScriptGL extends RenderScript { nContextBindRootScript(safeID(s)); } - public void contextBindProgramFragmentStore(ProgramStore p) { + public void contextBindProgramStore(ProgramStore p) { validate(); - nContextBindProgramFragmentStore(safeID(p)); + nContextBindProgramStore(safeID(p)); } public void contextBindProgramFragment(ProgramFragment p) { @@ -94,34 +198,6 @@ public class RenderScriptGL extends RenderScript { 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..b627207 100644 --- a/graphics/java/android/renderscript/Sampler.java +++ b/graphics/java/android/renderscript/Sampler.java @@ -47,10 +47,82 @@ public class Sampler extends BaseObj { } Sampler(int id, RenderScript rs) { - super(rs); - mID = id; + super(id, rs); } + public static Sampler CLAMP_NEAREST(RenderScript rs) { + if(rs.mSampler_CLAMP_NEAREST == null) { + Builder b = new Builder(rs); + b.setMin(Value.NEAREST); + b.setMag(Value.NEAREST); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + rs.mSampler_CLAMP_NEAREST = b.create(); + } + return rs.mSampler_CLAMP_NEAREST; + } + + public static Sampler CLAMP_LINEAR(RenderScript rs) { + if(rs.mSampler_CLAMP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMin(Value.LINEAR); + b.setMag(Value.LINEAR); + b.setWrapS(Value.CLAMP); + b.setWrapT(Value.CLAMP); + rs.mSampler_CLAMP_LINEAR = b.create(); + } + return rs.mSampler_CLAMP_LINEAR; + } + + public static Sampler CLAMP_LINEAR_MIP_LINEAR(RenderScript rs) { + if(rs.mSampler_CLAMP_LINEAR_MIP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMin(Value.LINEAR_MIP_LINEAR); + b.setMag(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; + } + + public static Sampler WRAP_NEAREST(RenderScript rs) { + if(rs.mSampler_WRAP_NEAREST == null) { + Builder b = new Builder(rs); + b.setMin(Value.NEAREST); + b.setMag(Value.NEAREST); + b.setWrapS(Value.WRAP); + b.setWrapT(Value.WRAP); + rs.mSampler_WRAP_NEAREST = b.create(); + } + return rs.mSampler_WRAP_NEAREST; + } + + public static Sampler WRAP_LINEAR(RenderScript rs) { + if(rs.mSampler_WRAP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMin(Value.LINEAR); + b.setMag(Value.LINEAR); + b.setWrapS(Value.WRAP); + b.setWrapT(Value.WRAP); + rs.mSampler_WRAP_LINEAR = b.create(); + } + return rs.mSampler_WRAP_LINEAR; + } + + public static Sampler WRAP_LINEAR_MIP_LINEAR(RenderScript rs) { + if(rs.mSampler_WRAP_LINEAR_MIP_LINEAR == null) { + Builder b = new Builder(rs); + b.setMin(Value.LINEAR_MIP_LINEAR); + b.setMag(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; + } + + public static class Builder { RenderScript mRS; Value mMin; @@ -58,6 +130,7 @@ public class Sampler extends BaseObj { Value mWrapS; Value mWrapT; Value mWrapR; + float mAniso; public Builder(RenderScript rs) { mRS = rs; @@ -66,6 +139,7 @@ public class Sampler extends BaseObj { mWrapS = Value.WRAP; mWrapT = Value.WRAP; mWrapR = Value.WRAP; + mAniso = 1.0f; } public void setMin(Value v) { @@ -110,6 +184,14 @@ public class Sampler extends BaseObj { } } + public void setAnisotropy(float v) { + if(v >= 0.0f) { + mAniso = v; + } else { + throw new IllegalArgumentException("Invalid value"); + } + } + static synchronized Sampler internalCreate(RenderScript rs, Builder b) { rs.nSamplerBegin(); rs.nSamplerSet(0, b.mMin.mID); @@ -117,6 +199,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..7d7dd6d 100644 --- a/graphics/java/android/renderscript/Script.java +++ b/graphics/java/android/renderscript/Script.java @@ -38,39 +38,64 @@ public class Script extends BaseObj { } public void execute() { - mRS.nScriptInvoke(mScript.mID, mSlot); + mRS.nScriptInvoke(mScript.getID(), mSlot); } } + protected void invoke(int slot) { + mRS.nScriptInvoke(getID(), slot); + } + + 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); } 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); + public void setVar(int index, float v) { + mRS.nScriptSetVarF(getID(), index, v); } - public void setClearDepth(float d) { - mRS.validate(); - mRS.nScriptSetClearDepth(mID, d); + public void setVar(int index, double v) { + mRS.nScriptSetVarD(getID(), index, v); } - public void setClearStencil(int stencil) { - mRS.validate(); - mRS.nScriptSetClearStencil(mID, stencil); + public void setVar(int index, int v) { + mRS.nScriptSetVarI(getID(), index, v); + } + + public void setVar(int index, long v) { + mRS.nScriptSetVarJ(getID(), index, v); + } + + public void setVar(int index, boolean v) { + mRS.nScriptSetVarI(getID(), index, v ? 1 : 0); + } + + 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 +103,39 @@ 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; - 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) { + mAllocation = Allocation.createSized(rs, mElement, dimx); } - 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..44fc5fd 100644 --- a/graphics/java/android/renderscript/ScriptC.java +++ b/graphics/java/android/renderscript/ScriptC.java @@ -33,129 +33,49 @@ import java.lang.reflect.Modifier; public class ScriptC extends Script { private static final String TAG = "ScriptC"; - ScriptC(int id, RenderScript 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(); + protected ScriptC(RenderScript rs, Resources resources, int resourceID) { + super(0, rs); + int id = internalCreate(rs, resources, resourceID); + setID(id); + } - public Builder(RenderScript rs) { - super(rs); - } - public void setScript(String s) { + private static synchronized int internalCreate(RenderScript rs, Resources resources, int resourceID) { + byte[] pgm; + int pgmLength; + InputStream is = resources.openRawResource(resourceID); + try { 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); - 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; - } - 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()); - } - 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; - } - - public void addDefine(String name, int value) { - mIntDefines.put(name, value); - } - - 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); - } - - /** - * 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)); - } + 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; } - } catch (IllegalAccessException ex) { - // TODO: Do we want this log? - Log.d(TAG, "addDefines skipping field " + f.getName()); + int bytesRead = is.read(pgm, pgmLength, bytesLeft); + if (bytesRead <= 0) { + break; + } + pgmLength += bytesRead; } + } finally { + is.close(); } + } catch(IOException e) { + throw new Resources.NotFoundException(); } - public ScriptC create() { - return internalCreate(this); - } + rs.nScriptCBegin(); + rs.nScriptCSetScript(pgm, 0, pgmLength); + return rs.nScriptCCreate(); } } diff --git a/graphics/java/android/renderscript/Short2.java b/graphics/java/android/renderscript/Short2.java new file mode 100644 index 0000000..426801f --- /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; + + +/** + * @hide + * + **/ +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..7b9c305 --- /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; + + +/** + * @hide + * + **/ +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..9a474e2 --- /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; + + +/** + * @hide + * + **/ +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..44aee63 100644 --- a/graphics/java/android/renderscript/Type.java +++ b/graphics/java/android/renderscript/Type.java @@ -16,11 +16,27 @@ package android.renderscript; + import java.lang.reflect.Field; +import android.util.Log; /** * @hide * + * 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 and + * storage for the data thus described. + * + * 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. + * + * The LOD and Faces dimensions are booleans to indicate present or not present. + * **/ public class Type extends BaseObj { int mDimX; @@ -31,28 +47,65 @@ public class Type extends BaseObj { int mElementCount; Element mElement; - private int mNativeCache; - Class mJavaClass; - + /** + * 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; } + + /** + * Return if the Type has a mipmap chain. + * + * @return boolean + */ public boolean getLOD() { return mDimLOD; } + + /** + * Return if the Type is a cube map. + * + * @return boolean + */ public boolean getFaces() { return mDimFaces; } + + /** + * Return the total number of accessable cells in the Type. + * + * @return int + */ public int getElementCount() { return mElementCount; } @@ -95,67 +148,42 @@ 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(); } - 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; - } + @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, String scriptName) { - Type t = createFromClass(rs, c, size); - t.setName(scriptName); - return t; - } + mDimX = dataBuffer[0]; + mDimY = dataBuffer[1]; + mDimZ = dataBuffer[2]; + mDimLOD = dataBuffer[3] == 1 ? true : false; + mDimFaces = dataBuffer[4] == 1 ? true : false; + 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; + Dimension[] mDimensions; + int[] mDimensionValues; int mEntryCount; Element mElement; @@ -164,62 +192,100 @@ public class Type extends BaseObj { int mValue; } + /** + * 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."); + if(e.getID() == 0) { + throw new RSIllegalArgumentException("Invalid element."); } mRS = rs; - mEntries = new Entry[4]; + mDimensions = new Dimension[4]; + mDimensionValues = new int[4]; mElement = e; } + /** + * Add a dimension to the Type. + * + * + * @param d + * @param value + */ public void add(Dimension d, 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 Dimensions are not valid."); } - if(mEntries.length >= mEntryCount) { - Entry[] en = new Entry[mEntryCount + 8]; - System.arraycopy(mEntries, 0, en, 0, mEntries.length); - mEntries = en; + if(mDimensions.length >= mEntryCount) { + Dimension[] dn = new Dimension[mEntryCount + 8]; + System.arraycopy(mDimensions, 0, dn, 0, mEntryCount); + mDimensions = dn; + + int[] in = new int[mEntryCount + 8]; + System.arraycopy(mDimensionValues, 0, in, 0, mEntryCount); + mDimensionValues = in; } - mEntries[mEntryCount] = new Entry(); - mEntries[mEntryCount].mDim = d; - mEntries[mEntryCount].mValue = value; + mDimensions[mEntryCount] = d; + mDimensionValues[mEntryCount] = value; mEntryCount++; } - 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); + /** + * Validate structure and create a new type. + * + * @return Type + */ + public Type create() { + int dims[] = new int[mEntryCount]; + for (int ct=0; ct < mEntryCount; ct++) { + dims[ct] = mDimensions[ct].mID; } - int id = rs.nTypeCreate(); - return new Type(id, rs); - } - public Type create() { - Type t = internalCreate(mRS, this); + int id = mRS.nTypeCreate(mElement.getID(), dims, mDimensionValues); + Type t = new Type(id, mRS); t.mElement = mElement; for(int ct=0; ct < mEntryCount; ct++) { - if(mEntries[ct].mDim == Dimension.X) { - t.mDimX = mEntries[ct].mValue; + if(mDimensions[ct] == Dimension.X) { + t.mDimX = mDimensionValues[ct]; } - if(mEntries[ct].mDim == Dimension.Y) { - t.mDimY = mEntries[ct].mValue; + if(mDimensions[ct] == Dimension.Y) { + t.mDimY = mDimensionValues[ct]; } - if(mEntries[ct].mDim == Dimension.Z) { - t.mDimZ = mEntries[ct].mValue; + if(mDimensions[ct] == Dimension.Z) { + t.mDimZ = mDimensionValues[ct]; } - if(mEntries[ct].mDim == Dimension.LOD) { - t.mDimLOD = mEntries[ct].mValue != 0; + if(mDimensions[ct] == Dimension.LOD) { + t.mDimLOD = mDimensionValues[ct] != 0; } - if(mEntries[ct].mDim == Dimension.FACE) { - t.mDimFaces = mEntries[ct].mValue != 0; + if(mDimensions[ct] == Dimension.FACE) { + t.mDimFaces = mDimensionValues[ct] != 0; } } + + if (t.mDimZ > 0) { + if ((t.mDimX < 1) || (t.mDimY < 1)) { + throw new RSInvalidStateException("Both X and Y dimension required when Z is present."); + } + if (t.mDimFaces) { + throw new RSInvalidStateException("Cube maps not supported with 3D types."); + } + } + if (t.mDimY > 0) { + if (t.mDimX < 1) { + throw new RSInvalidStateException("X dimension required when Y is present."); + } + } + if (t.mDimFaces) { + if (t.mDimY < 1) { + throw new RSInvalidStateException("Cube maps require 2D Types."); + } + } + t.calcElementCount(); return t; } |
