Update RecentApplications to use shared Carousel widget.
Change-Id: I5ca7389aeca9ee6f03f48317f9d1034f9fb8c1ca
This commit is contained in:
@@ -39,9 +39,6 @@ LOCAL_SRC_FILES += \
|
||||
core/java/android/webkit/EventLogTags.logtags \
|
||||
telephony/java/com/android/internal/telephony/EventLogTags.logtags \
|
||||
|
||||
# RenderScript files for internal widgets
|
||||
LOCAL_SRC_FILES += $(call all-renderscript-files-under, core/java/com/android/internal/widget)
|
||||
|
||||
# The following filters out code we are temporarily not including at all.
|
||||
# TODO: Move AWT and beans (and associated harmony code) back into libcore.
|
||||
# TODO: Maybe remove javax.microedition entirely?
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.internal.widget;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.graphics.Bitmap;
|
||||
import android.renderscript.*;
|
||||
import android.renderscript.RenderScript.RSMessage;
|
||||
import android.renderscript.Sampler.Value;
|
||||
import android.renderscript.ProgramRaster.CullMode;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
import static android.renderscript.Element.*;
|
||||
import static android.renderscript.Sampler.Value.LINEAR;
|
||||
import static android.renderscript.Sampler.Value.WRAP;
|
||||
import static android.renderscript.Sampler.Value.CLAMP;
|
||||
|
||||
public class CarouselRS {
|
||||
private static final int DEFAULT_VISIBLE_SLOTS = 1;
|
||||
private static final int DEFAULT_CARD_COUNT = 1;
|
||||
|
||||
// Client messages *** THIS LIST MUST MATCH THOSE IN carousel.rs ***
|
||||
public static final int CMD_CARD_SELECTED = 100;
|
||||
public static final int CMD_REQUEST_TEXTURE = 200;
|
||||
public static final int CMD_INVALIDATE_TEXTURE = 210;
|
||||
public static final int CMD_REQUEST_GEOMETRY = 300;
|
||||
public static final int CMD_INVALIDATE_GEOMETRY = 310;
|
||||
public static final int CMD_ANIMATION_STARTED = 400;
|
||||
public static final int CMD_ANIMATION_FINISHED = 500;
|
||||
public static final int CMD_PING = 600; // for debugging
|
||||
|
||||
private static final String TAG = "CarouselRS";
|
||||
private static final int DEFAULT_SLOT_COUNT = 10;
|
||||
private static final boolean MIPMAP = false;
|
||||
|
||||
private RenderScriptGL mRS;
|
||||
private Resources mRes;
|
||||
private ScriptC_Carousel mScript;
|
||||
private ScriptField_Card mCards;
|
||||
private Sampler mSampler;
|
||||
private ProgramRaster mProgramRaster;
|
||||
private ProgramStore mProgramStore;
|
||||
private ProgramFragment mFragmentProgram;
|
||||
private ProgramVertex mVertexProgram;
|
||||
private ProgramRaster mRasterProgram;
|
||||
private CarouselCallback mCallback;
|
||||
private float[] mEyePoint = new float[3];
|
||||
private float[] mAtPoint = new float[3];
|
||||
private float[] mUp = new float[3];
|
||||
|
||||
public static interface CarouselCallback {
|
||||
/**
|
||||
* Called when a card is selected
|
||||
* @param n the id of the card
|
||||
*/
|
||||
void onCardSelected(int n);
|
||||
|
||||
/**
|
||||
* Called when texture is needed for card n. This happens when the given card becomes
|
||||
* visible.
|
||||
* @param n the id of the card
|
||||
*/
|
||||
void onRequestTexture(int n);
|
||||
|
||||
/**
|
||||
* Called when a texture is no longer needed for card n. This happens when the card
|
||||
* goes out of view.
|
||||
* @param n the id of the card
|
||||
*/
|
||||
void onInvalidateTexture(int n);
|
||||
|
||||
/**
|
||||
* Called when geometry is needed for card n.
|
||||
* @param n the id of the card.
|
||||
*/
|
||||
void onRequestGeometry(int n);
|
||||
|
||||
/**
|
||||
* Called when geometry is no longer needed for card n. This happens when the card goes
|
||||
* out of view.
|
||||
* @param n the id of the card
|
||||
*/
|
||||
void onInvalidateGeometry(int n);
|
||||
|
||||
/**
|
||||
* Called when card animation (e.g. a fling) has started.
|
||||
*/
|
||||
void onAnimationStarted();
|
||||
|
||||
/**
|
||||
* Called when card animation has stopped.
|
||||
*/
|
||||
void onAnimationFinished();
|
||||
};
|
||||
|
||||
private RSMessage mRsMessage = new RSMessage() {
|
||||
public void run() {
|
||||
if (mCallback == null) return;
|
||||
switch (mID) {
|
||||
case CMD_CARD_SELECTED:
|
||||
mCallback.onCardSelected(mData[0]);
|
||||
break;
|
||||
|
||||
case CMD_REQUEST_TEXTURE:
|
||||
mCallback.onRequestTexture(mData[0]);
|
||||
break;
|
||||
|
||||
case CMD_INVALIDATE_TEXTURE:
|
||||
mCallback.onInvalidateTexture(mData[0]);
|
||||
break;
|
||||
|
||||
case CMD_REQUEST_GEOMETRY:
|
||||
mCallback.onRequestGeometry(mData[0]);
|
||||
break;
|
||||
|
||||
case CMD_INVALIDATE_GEOMETRY:
|
||||
mCallback.onInvalidateGeometry(mData[0]);
|
||||
break;
|
||||
|
||||
case CMD_ANIMATION_STARTED:
|
||||
mCallback.onAnimationStarted();
|
||||
break;
|
||||
|
||||
case CMD_ANIMATION_FINISHED:
|
||||
mCallback.onAnimationFinished();
|
||||
break;
|
||||
|
||||
case CMD_PING:
|
||||
Log.v(TAG, "PING...");
|
||||
break;
|
||||
|
||||
default:
|
||||
Log.e(TAG, "Unknown RSMessage: " + mID);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void init(RenderScriptGL rs, Resources res) {
|
||||
mRS = rs;
|
||||
mRes = res;
|
||||
|
||||
// create the script object
|
||||
mScript = new ScriptC_Carousel(mRS, mRes, R.raw.carousel, true);
|
||||
mRS.mMessageCallback = mRsMessage;
|
||||
|
||||
initProgramStore();
|
||||
initFragmentProgram();
|
||||
initRasterProgram();
|
||||
initVertexProgram();
|
||||
|
||||
setSlotCount(DEFAULT_SLOT_COUNT);
|
||||
setVisibleSlots(DEFAULT_VISIBLE_SLOTS);
|
||||
createCards(DEFAULT_CARD_COUNT);
|
||||
|
||||
setStartAngle(0.0f);
|
||||
setRadius(1.0f);
|
||||
|
||||
// update the camera
|
||||
boolean pcam = true;
|
||||
if (pcam) {
|
||||
float eye[] = { 20.6829f, 2.77081f, 16.7314f };
|
||||
float at[] = { 14.7255f, -3.40001f, -1.30184f };
|
||||
float up[] = { 0.0f, 1.0f, 0.0f };
|
||||
setLookAt(eye, at, up);
|
||||
setRadius(20.0f);
|
||||
// Fov: 25
|
||||
} else {
|
||||
mScript.invoke_lookAt(2.5f, 2.0f, 2.5f, 0.0f, -0.75f, 0.0f, 0.0f, 1.0f, 0.0f);
|
||||
mScript.set_cardRotation(0.0f);
|
||||
setRadius(1.5f);
|
||||
}
|
||||
|
||||
resumeRendering();
|
||||
}
|
||||
|
||||
public void setLookAt(float[] eye, float[] at, float[] up) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
mEyePoint[i] = eye[i];
|
||||
mAtPoint[i] = at[i];
|
||||
mUp[i] = up[i];
|
||||
}
|
||||
mScript.invoke_lookAt(eye[0], eye[1], eye[2], at[0], at[1], at[2], up[0], up[1], up[2]);
|
||||
}
|
||||
|
||||
public void setRadius(float radius) {
|
||||
mScript.set_radius(radius);
|
||||
}
|
||||
|
||||
private void initVertexProgram() {
|
||||
ProgramVertex.Builder pvb = new ProgramVertex.Builder(mRS, null, null);
|
||||
mVertexProgram = pvb.create();
|
||||
ProgramVertex.MatrixAllocation pva = new ProgramVertex.MatrixAllocation(mRS);
|
||||
mVertexProgram.bindAllocation(pva);
|
||||
pva.setupProjectionNormalized(1, 1);
|
||||
mScript.set_vertexProgram(mVertexProgram);
|
||||
}
|
||||
|
||||
private void initRasterProgram() {
|
||||
ProgramRaster.Builder programRasterBuilder = new ProgramRaster.Builder(mRS);
|
||||
mRasterProgram = programRasterBuilder.create();
|
||||
//mRasterProgram.setCullMode(CullMode.NONE);
|
||||
mScript.set_rasterProgram(mRasterProgram);
|
||||
}
|
||||
|
||||
private void initFragmentProgram() {
|
||||
Sampler.Builder sampleBuilder = new Sampler.Builder(mRS);
|
||||
sampleBuilder.setMin(Value.LINEAR_MIP_LINEAR);
|
||||
sampleBuilder.setMag(LINEAR);
|
||||
sampleBuilder.setWrapS(CLAMP);
|
||||
sampleBuilder.setWrapT(CLAMP);
|
||||
mSampler = sampleBuilder.create();
|
||||
ProgramFragment.Builder fragmentBuilder = new ProgramFragment.Builder(mRS);
|
||||
fragmentBuilder.setTexture(ProgramFragment.Builder.EnvMode.DECAL,
|
||||
ProgramFragment.Builder.Format.RGBA, 0);
|
||||
mFragmentProgram = fragmentBuilder.create();
|
||||
mFragmentProgram.bindSampler(mSampler, 0);
|
||||
mScript.set_fragmentProgram(mFragmentProgram);
|
||||
}
|
||||
|
||||
private void initProgramStore() {
|
||||
ProgramStore.Builder programStoreBuilder = new ProgramStore.Builder(mRS, null, null);
|
||||
programStoreBuilder.setDepthFunc(ProgramStore.DepthFunc.LESS);
|
||||
programStoreBuilder.setBlendFunc(ProgramStore.BlendSrcFunc.SRC_ALPHA,
|
||||
ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA);
|
||||
programStoreBuilder.setDitherEnable(false);
|
||||
programStoreBuilder.setDepthMask(true);
|
||||
mProgramStore = programStoreBuilder.create();
|
||||
mScript.set_programStore(mProgramStore);
|
||||
}
|
||||
|
||||
public void createCards(int count)
|
||||
{
|
||||
mCards = count > 0 ? new ScriptField_Card(mRS, count) : null;
|
||||
mScript.bind_cards(mCards);
|
||||
mScript.invoke_createCards(count);
|
||||
}
|
||||
|
||||
public void setVisibleSlots(int count)
|
||||
{
|
||||
mScript.set_visibleSlotCount(count);
|
||||
}
|
||||
|
||||
public void setDefaultBitmap(Bitmap bitmap)
|
||||
{
|
||||
mScript.set_defaultTexture(allocationFromBitmap(bitmap, MIPMAP));
|
||||
}
|
||||
|
||||
public void setLoadingBitmap(Bitmap bitmap)
|
||||
{
|
||||
mScript.set_loadingTexture(allocationFromBitmap(bitmap, MIPMAP));
|
||||
}
|
||||
|
||||
public void setDefaultGeometry(Mesh mesh)
|
||||
{
|
||||
mScript.set_defaultGeometry(mesh);
|
||||
}
|
||||
|
||||
public void setLoadingGeometry(Mesh mesh)
|
||||
{
|
||||
mScript.set_loadingGeometry(mesh);
|
||||
}
|
||||
|
||||
public void setStartAngle(float theta)
|
||||
{
|
||||
mScript.set_startAngle(theta);
|
||||
}
|
||||
|
||||
public void setCallback(CarouselCallback callback)
|
||||
{
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
private Allocation allocationFromBitmap(Bitmap bitmap, boolean mipmap)
|
||||
{
|
||||
if (bitmap == null) return null;
|
||||
Allocation allocation = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), mipmap);
|
||||
allocation.uploadToTexture(0);
|
||||
return allocation;
|
||||
}
|
||||
|
||||
public void setTexture(int n, Bitmap bitmap)
|
||||
{
|
||||
ScriptField_Card.Item item = mCards.get(n);
|
||||
if (item == null) {
|
||||
Log.v(TAG, "setTexture(): no item at index " + n);
|
||||
item = new ScriptField_Card.Item();
|
||||
}
|
||||
if (bitmap != null) {
|
||||
Log.v(TAG, "creating new bitmap");
|
||||
item.texture = Allocation.createFromBitmap(mRS, bitmap, RGB_565(mRS), MIPMAP);
|
||||
Log.v(TAG, "uploadToTexture(" + n + ")");
|
||||
item.texture.uploadToTexture(0);
|
||||
Log.v(TAG, "done...");
|
||||
} else {
|
||||
if (item.texture != null) {
|
||||
Log.v(TAG, "unloading texture " + n);
|
||||
// Don't wait for GC to free native memory.
|
||||
// Only works if textures are not shared.
|
||||
item.texture.destroy();
|
||||
item.texture = null;
|
||||
}
|
||||
}
|
||||
mCards.set(item, n, false); // This is primarily used for reference counting.
|
||||
mScript.invoke_setTexture(n, item.texture);
|
||||
}
|
||||
|
||||
public void setGeometry(int n, Mesh geometry)
|
||||
{
|
||||
final boolean mipmap = false;
|
||||
ScriptField_Card.Item item = mCards.get(n);
|
||||
if (item == null) {
|
||||
Log.v(TAG, "setGeometry(): no item at index " + n);
|
||||
item = new ScriptField_Card.Item();
|
||||
}
|
||||
if (geometry != null) {
|
||||
item.geometry = geometry;
|
||||
} else {
|
||||
Log.v(TAG, "unloading geometry " + n);
|
||||
if (item.geometry != null) {
|
||||
// item.geometry.destroy();
|
||||
item.geometry = null;
|
||||
}
|
||||
}
|
||||
mCards.set(item, n, false);
|
||||
mScript.invoke_setGeometry(n, item.geometry);
|
||||
}
|
||||
|
||||
public void pauseRendering() {
|
||||
// Used to update multiple states at once w/o redrawing for each.
|
||||
mRS.contextBindRootScript(null);
|
||||
}
|
||||
|
||||
public void resumeRendering() {
|
||||
mRS.contextBindRootScript(mScript);
|
||||
}
|
||||
|
||||
public void doMotion(float x, float y) {
|
||||
mScript.invoke_doMotion(x,y);
|
||||
}
|
||||
|
||||
public void doSelection(float x, float y) {
|
||||
mScript.invoke_doSelection(x, y);
|
||||
}
|
||||
|
||||
public void doStart(float x, float y) {
|
||||
mScript.invoke_doStart(x, y);
|
||||
}
|
||||
|
||||
public void doStop(float x, float y) {
|
||||
mScript.invoke_doStop(x, y);
|
||||
}
|
||||
|
||||
public void setSlotCount(int n) {
|
||||
mScript.set_slotCount(n);
|
||||
}
|
||||
}
|
||||
@@ -1,266 +0,0 @@
|
||||
/*
|
||||
* 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 com.android.internal.widget;
|
||||
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.widget.CarouselRS.CarouselCallback;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.Bitmap.Config;
|
||||
import android.renderscript.FileA3D;
|
||||
import android.renderscript.Mesh;
|
||||
import android.renderscript.RSSurfaceView;
|
||||
import android.renderscript.RenderScriptGL;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.SurfaceHolder;
|
||||
|
||||
public class CarouselView extends RSSurfaceView {
|
||||
private static final boolean USE_DEPTH_BUFFER = true;
|
||||
private final int DEFAULT_SLOT_COUNT = 10;
|
||||
private final Bitmap DEFAULT_BITMAP = Bitmap.createBitmap(1, 1, Config.RGB_565);
|
||||
private static final String TAG = "CarouselView";
|
||||
private CarouselRS mRenderScript;
|
||||
private RenderScriptGL mRS;
|
||||
private Context mContext;
|
||||
private boolean mTracking;
|
||||
private Bitmap mDefaultBitmap;
|
||||
private Bitmap mLoadingBitmap;
|
||||
private Mesh mDefaultGeometry;
|
||||
private Mesh mLoadingGeometry;
|
||||
private int mCardCount = 0;
|
||||
private int mVisibleSlots = 0;
|
||||
private float mStartAngle;
|
||||
private int mSlotCount = DEFAULT_SLOT_COUNT;
|
||||
|
||||
public CarouselView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor used when this widget is created from a layout file.
|
||||
*/
|
||||
public CarouselView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
boolean useDepthBuffer = true;
|
||||
mRS = createRenderScript(USE_DEPTH_BUFFER);
|
||||
mRenderScript = new CarouselRS();
|
||||
mRenderScript.init(mRS, getResources());
|
||||
// TODO: add parameters to layout
|
||||
}
|
||||
|
||||
@Override
|
||||
public void surfaceChanged(SurfaceHolder holder, int format, int w, int h) {
|
||||
super.surfaceChanged(holder, format, w, h);
|
||||
//mRS.contextSetSurface(w, h, holder.getSurface());
|
||||
mRenderScript.init(mRS, getResources());
|
||||
setSlotCount(mSlotCount);
|
||||
createCards(mCardCount);
|
||||
setVisibleSlots(mVisibleSlots);
|
||||
setCallback(mCarouselCallback);
|
||||
setDefaultBitmap(mDefaultBitmap);
|
||||
setLoadingBitmap(mLoadingBitmap);
|
||||
setDefaultGeometry(mDefaultGeometry);
|
||||
setLoadingGeometry(mLoadingGeometry);
|
||||
setStartAngle(mStartAngle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads geometry from a resource id.
|
||||
*
|
||||
* @param resId
|
||||
* @return the loaded mesh or null if it cannot be loaded
|
||||
*/
|
||||
public Mesh loadGeometry(int resId) {
|
||||
Resources res = mContext.getResources();
|
||||
FileA3D model = FileA3D.createFromResource(mRS, res, resId);
|
||||
FileA3D.IndexEntry entry = model.getIndexEntry(0);
|
||||
if(entry == null || entry.getClassID() != FileA3D.ClassID.MESH) {
|
||||
return null;
|
||||
}
|
||||
return (Mesh) entry.getObject();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load A3D file from resource. If resId == 0, will clear geometry for this item.
|
||||
* @param n
|
||||
* @param resId
|
||||
*/
|
||||
public void setGeometryForItem(int n, Mesh mesh) {
|
||||
mRenderScript.setGeometry(n, mesh);
|
||||
}
|
||||
|
||||
public void setSlotCount(int n) {
|
||||
mSlotCount = n;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setSlotCount(n);
|
||||
}
|
||||
}
|
||||
|
||||
public void setVisibleSlots(int n) {
|
||||
mVisibleSlots = n;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setVisibleSlots(n);
|
||||
}
|
||||
}
|
||||
|
||||
public void createCards(int n) {
|
||||
mCardCount = n;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.createCards(n);
|
||||
}
|
||||
}
|
||||
|
||||
public void setTextureForItem(int n, Bitmap bitmap) {
|
||||
if (mRenderScript != null) {
|
||||
Log.v(TAG, "setTextureForItem(" + n + ")");
|
||||
mRenderScript.setTexture(n, bitmap);
|
||||
Log.v(TAG, "done");
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultBitmap(Bitmap bitmap) {
|
||||
mDefaultBitmap = bitmap;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setDefaultBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadingBitmap(Bitmap bitmap) {
|
||||
mLoadingBitmap = bitmap;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setLoadingBitmap(bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
public void setDefaultGeometry(Mesh mesh) {
|
||||
mDefaultGeometry = mesh;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setDefaultGeometry(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
public void setLoadingGeometry(Mesh mesh) {
|
||||
mLoadingGeometry = mesh;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setLoadingGeometry(mesh);
|
||||
}
|
||||
}
|
||||
|
||||
public void setCallback(CarouselCallback callback)
|
||||
{
|
||||
mCarouselCallback = callback;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setCallback(callback);
|
||||
}
|
||||
}
|
||||
|
||||
public void setStartAngle(float angle)
|
||||
{
|
||||
mStartAngle = angle;
|
||||
if (mRenderScript != null) {
|
||||
mRenderScript.setStartAngle(angle);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if(mRS != null) {
|
||||
mRS = null;
|
||||
destroyRenderScript();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mRS == null) {
|
||||
mRS = createRenderScript(USE_DEPTH_BUFFER);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
final float x = event.getX();
|
||||
final float y = event.getY();
|
||||
|
||||
if (mRenderScript == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
switch (action) {
|
||||
case MotionEvent.ACTION_DOWN:
|
||||
mTracking = true;
|
||||
mRenderScript.doStart(x, y);
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
if (mTracking) {
|
||||
mRenderScript.doMotion(x, y);
|
||||
}
|
||||
break;
|
||||
|
||||
case MotionEvent.ACTION_UP:
|
||||
mRenderScript.doStop(x, y);
|
||||
mTracking = false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private final CarouselCallback DEBUG_CALLBACK = new CarouselCallback() {
|
||||
public void onAnimationStarted() {
|
||||
Log.v(TAG, "onAnimationStarted()");
|
||||
}
|
||||
|
||||
public void onAnimationFinished() {
|
||||
Log.v(TAG, "onAnimationFinished()");
|
||||
}
|
||||
|
||||
public void onCardSelected(int n) {
|
||||
Log.v(TAG, "onCardSelected(" + n + ")");
|
||||
}
|
||||
|
||||
public void onRequestGeometry(int n) {
|
||||
Log.v(TAG, "onRequestGeometry(" + n + ")");
|
||||
}
|
||||
|
||||
public void onInvalidateGeometry(int n) {
|
||||
Log.v(TAG, "onInvalidateGeometry(" + n + ")");
|
||||
}
|
||||
|
||||
public void onRequestTexture(final int n) {
|
||||
Log.v(TAG, "onRequestTexture(" + n + ")");
|
||||
}
|
||||
|
||||
public void onInvalidateTexture(int n) {
|
||||
Log.v(TAG, "onInvalidateTexture(" + n + ")");
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
private CarouselCallback mCarouselCallback = DEBUG_CALLBACK;
|
||||
}
|
||||
@@ -1,788 +0,0 @@
|
||||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#pragma version(1)
|
||||
#pragma rs java_package_name(com.android.internal.widget)
|
||||
#pragma rs set_reflect_license()
|
||||
|
||||
#include "rs_graphics.rsh"
|
||||
|
||||
typedef struct __attribute__((aligned(4))) Card {
|
||||
rs_allocation texture;
|
||||
rs_mesh geometry;
|
||||
//rs_matrix4x4 matrix; // custom transform for this card/geometry
|
||||
int textureState; // whether or not the texture is loaded.
|
||||
int geometryState; // whether or not geometry is loaded
|
||||
int visible; // not bool because of packing bug?
|
||||
} Card_t;
|
||||
|
||||
typedef struct Ray_s {
|
||||
float3 position;
|
||||
float3 direction;
|
||||
} Ray;
|
||||
|
||||
typedef struct PerspectiveCamera_s {
|
||||
float3 from;
|
||||
float3 at;
|
||||
float3 up;
|
||||
float fov;
|
||||
float aspect;
|
||||
float near;
|
||||
float far;
|
||||
} PerspectiveCamera;
|
||||
|
||||
// Request states. Used for loading 3D object properties from the Java client.
|
||||
// Typical properties: texture, geometry and matrices.
|
||||
enum {
|
||||
STATE_INVALID = 0, // item hasn't been loaded
|
||||
STATE_LOADING, // we've requested an item but are waiting for it to load
|
||||
STATE_LOADED // item was delivered
|
||||
};
|
||||
|
||||
// Client messages *** THIS LIST MUST MATCH THOSE IN CarouselRS.java. ***
|
||||
static const int CMD_CARD_SELECTED = 100;
|
||||
static const int CMD_REQUEST_TEXTURE = 200;
|
||||
static const int CMD_INVALIDATE_TEXTURE = 210;
|
||||
static const int CMD_REQUEST_GEOMETRY = 300;
|
||||
static const int CMD_INVALIDATE_GEOMETRY = 310;
|
||||
static const int CMD_ANIMATION_STARTED = 400;
|
||||
static const int CMD_ANIMATION_FINISHED = 500;
|
||||
static const int CMD_PING = 600;
|
||||
|
||||
// Constants
|
||||
static const int ANIMATION_SCALE_TIME = 200; // Time it takes to animate selected card, in ms
|
||||
static const float3 SELECTED_SCALE_FACTOR = { 0.2f, 0.2f, 0.2f }; // increase by this %
|
||||
|
||||
// Debug flags
|
||||
bool debugCamera = false; // dumps ray/camera coordinate stuff
|
||||
bool debugPicking = false; // renders picking area on top of geometry
|
||||
|
||||
// Exported variables. These will be reflected to Java set_* variables.
|
||||
Card_t *cards; // array of cards to draw
|
||||
float startAngle; // position of initial card, in radians
|
||||
int slotCount; // number of positions where a card can be
|
||||
int cardCount; // number of cards in stack
|
||||
int visibleSlotCount; // number of visible slots (for culling)
|
||||
float radius; // carousel radius. Cards will be centered on a circle with this radius
|
||||
float cardRotation; // rotation of card in XY plane relative to Z=1
|
||||
rs_program_store programStore;
|
||||
rs_program_fragment fragmentProgram;
|
||||
rs_program_vertex vertexProgram;
|
||||
rs_program_raster rasterProgram;
|
||||
rs_allocation defaultTexture; // shown when no other texture is assigned
|
||||
rs_allocation loadingTexture; // progress texture (shown when app is fetching the texture)
|
||||
rs_mesh defaultGeometry; // shown when no geometry is loaded
|
||||
rs_mesh loadingGeometry; // shown when geometry is loading
|
||||
rs_matrix4x4 projectionMatrix;
|
||||
rs_matrix4x4 modelviewMatrix;
|
||||
|
||||
#pragma rs export_var(radius, cards, slotCount, visibleSlotCount, cardRotation)
|
||||
#pragma rs export_var(programStore, fragmentProgram, vertexProgram, rasterProgram)
|
||||
#pragma rs export_var(startAngle, defaultTexture, loadingTexture, defaultGeometry, loadingGeometry)
|
||||
#pragma rs export_func(createCards, lookAt, doStart, doStop, doMotion, doSelection, setTexture)
|
||||
#pragma rs export_func(setGeometry, debugCamera, debugPicking)
|
||||
|
||||
// Local variables
|
||||
static float bias; // rotation bias, in radians. Used for animation and dragging.
|
||||
static bool updateCamera; // force a recompute of projection and lookat matrices
|
||||
static bool initialized;
|
||||
static float3 backgroundColor = { 0.0f, 0.0f, 0.0f };
|
||||
static const float FLT_MAX = 1.0e37;
|
||||
static int currentSelection = -1;
|
||||
static int64_t touchTime = -1; // time of first touch (see doStart())
|
||||
static float touchBias = 0.0f; // bias on first touch
|
||||
|
||||
// Default geometry when card.geometry is not set.
|
||||
static const float3 cardVertices[4] = {
|
||||
{ -1.0, -1.0, 0.0 },
|
||||
{ 1.0, -1.0, 0.0 },
|
||||
{ 1.0, 1.0, 0.0 },
|
||||
{-1.0, 1.0, 0.0 }
|
||||
};
|
||||
|
||||
// Default camera
|
||||
static PerspectiveCamera camera = {
|
||||
{2,2,2}, // from
|
||||
{0,0,0}, // at
|
||||
{0,1,0}, // up
|
||||
25.0f, // field of view
|
||||
1.0f, // aspect
|
||||
0.1f, // near
|
||||
100.0f // far
|
||||
};
|
||||
|
||||
// Forward references
|
||||
static int intersectGeometry(Ray* ray, float *bestTime);
|
||||
static bool makeRayForPixelAt(Ray* ray, float x, float y);
|
||||
static float deltaTimeInSeconds(int64_t current);
|
||||
|
||||
void init() {
|
||||
// initializers currently have a problem when the variables are exported, so initialize
|
||||
// globals here.
|
||||
rsDebug("Renderscript: init()", 0);
|
||||
startAngle = 0.0f;
|
||||
slotCount = 10;
|
||||
visibleSlotCount = 1;
|
||||
bias = 0.0f;
|
||||
radius = 1.0f;
|
||||
cardRotation = 0.0f;
|
||||
updateCamera = true;
|
||||
initialized = false;
|
||||
}
|
||||
|
||||
static void updateAllocationVars()
|
||||
{
|
||||
// Cards
|
||||
rs_allocation cardAlloc = rsGetAllocation(cards);
|
||||
// TODO: use new rsIsObject()
|
||||
cardCount = cardAlloc.p != 0 ? rsAllocationGetDimX(cardAlloc) : 0;
|
||||
}
|
||||
|
||||
void createCards(int n)
|
||||
{
|
||||
rsDebug("CreateCards: ", n);
|
||||
initialized = false;
|
||||
updateAllocationVars();
|
||||
}
|
||||
|
||||
// Return angle for position p. Typically p will be an integer position, but can be fractional.
|
||||
static float cardPosition(float p)
|
||||
{
|
||||
return startAngle + bias + 2.0f * M_PI * p / slotCount;
|
||||
}
|
||||
|
||||
// Return slot for a card in position p. Typically p will be an integer slot, but can be fractional.
|
||||
static float slotPosition(float p)
|
||||
{
|
||||
return startAngle + 2.0f * M_PI * p / slotCount;
|
||||
}
|
||||
|
||||
// Return the lowest slot number for a given angular position.
|
||||
static int cardIndex(float angle)
|
||||
{
|
||||
return floor(angle - startAngle - bias) * slotCount / (2.0f * M_PI);
|
||||
}
|
||||
|
||||
// Set basic camera properties:
|
||||
// from - position of the camera in x,y,z
|
||||
// at - target we're looking at - used to compute view direction
|
||||
// up - a normalized vector indicating up (typically { 0, 1, 0})
|
||||
//
|
||||
// NOTE: the view direction and up vector cannot be parallel/antiparallel with each other
|
||||
void lookAt(float fromX, float fromY, float fromZ,
|
||||
float atX, float atY, float atZ,
|
||||
float upX, float upY, float upZ)
|
||||
{
|
||||
camera.from.x = fromX;
|
||||
camera.from.y = fromY;
|
||||
camera.from.z = fromZ;
|
||||
camera.at.x = atX;
|
||||
camera.at.y = atY;
|
||||
camera.at.z = atZ;
|
||||
camera.up.x = upX;
|
||||
camera.up.y = upY;
|
||||
camera.up.z = upZ;
|
||||
updateCamera = true;
|
||||
}
|
||||
|
||||
// Load a projection matrix for the given parameters. This is equivalent to gluPerspective()
|
||||
static void loadPerspectiveMatrix(rs_matrix4x4* matrix, float fovy, float aspect, float near, float far)
|
||||
{
|
||||
rsMatrixLoadIdentity(matrix);
|
||||
float top = near * tan((float) (fovy * M_PI / 360.0f));
|
||||
float bottom = -top;
|
||||
float left = bottom * aspect;
|
||||
float right = top * aspect;
|
||||
rsMatrixLoadFrustum(matrix, left, right, bottom, top, near, far);
|
||||
}
|
||||
|
||||
// Construct a matrix based on eye point, center and up direction. Based on the
|
||||
// man page for gluLookat(). Up must be normalized.
|
||||
static void loadLookatMatrix(rs_matrix4x4* matrix, float3 eye, float3 center, float3 up)
|
||||
{
|
||||
float3 f = normalize(center - eye);
|
||||
float3 s = normalize(cross(f, up));
|
||||
float3 u = cross(s, f);
|
||||
float m[16];
|
||||
m[0] = s.x;
|
||||
m[4] = s.y;
|
||||
m[8] = s.z;
|
||||
m[12] = 0.0f;
|
||||
m[1] = u.x;
|
||||
m[5] = u.y;
|
||||
m[9] = u.z;
|
||||
m[13] = 0.0f;
|
||||
m[2] = -f.x;
|
||||
m[6] = -f.y;
|
||||
m[10] = -f.z;
|
||||
m[14] = 0.0f;
|
||||
m[3] = m[7] = m[11] = 0.0f;
|
||||
m[15] = 1.0f;
|
||||
rsMatrixLoad(matrix, m);
|
||||
rsMatrixTranslate(matrix, -eye.x, -eye.y, -eye.z);
|
||||
}
|
||||
|
||||
void setTexture(int n, rs_allocation texture)
|
||||
{
|
||||
cards[n].texture = texture;
|
||||
if (cards[n].texture.p != 0)
|
||||
cards[n].textureState = STATE_LOADED;
|
||||
else
|
||||
cards[n].textureState = STATE_INVALID;
|
||||
}
|
||||
|
||||
void setGeometry(int n, rs_mesh geometry)
|
||||
{
|
||||
cards[n].geometry = geometry;
|
||||
if (cards[n].geometry.p != 0)
|
||||
cards[n].geometryState = STATE_LOADED;
|
||||
else
|
||||
cards[n].geometryState = STATE_INVALID;
|
||||
}
|
||||
|
||||
static float3 getAnimatedScaleForSelected()
|
||||
{
|
||||
int64_t dt = (rsUptimeMillis() - touchTime);
|
||||
float fraction = (dt < ANIMATION_SCALE_TIME) ? (float) dt / ANIMATION_SCALE_TIME : 1.0f;
|
||||
const float3 one = { 1.0f, 1.0f, 1.0f };
|
||||
return one + fraction * SELECTED_SCALE_FACTOR;
|
||||
}
|
||||
|
||||
static void getMatrixForCard(rs_matrix4x4* matrix, int i)
|
||||
{
|
||||
float theta = cardPosition(i);
|
||||
rsMatrixRotate(matrix, degrees(theta), 0, 1, 0);
|
||||
rsMatrixTranslate(matrix, radius, 0, 0);
|
||||
rsMatrixRotate(matrix, degrees(-theta + cardRotation), 0, 1, 0);
|
||||
if (i == currentSelection) {
|
||||
float3 scale = getAnimatedScaleForSelected();
|
||||
rsMatrixScale(matrix, scale.x, scale.y, scale.z);
|
||||
}
|
||||
// TODO: apply custom matrix for cards[i].geometry
|
||||
}
|
||||
|
||||
static void drawCards()
|
||||
{
|
||||
float depth = 1.0f;
|
||||
for (int i = 0; i < cardCount; i++) {
|
||||
if (cards[i].visible) {
|
||||
// Bind texture
|
||||
if (cards[i].textureState == STATE_LOADED) {
|
||||
rsgBindTexture(fragmentProgram, 0, cards[i].texture);
|
||||
} else if (cards[i].textureState == STATE_LOADING) {
|
||||
rsgBindTexture(fragmentProgram, 0, loadingTexture);
|
||||
} else {
|
||||
rsgBindTexture(fragmentProgram, 0, defaultTexture);
|
||||
}
|
||||
|
||||
// Draw geometry
|
||||
rs_matrix4x4 matrix = modelviewMatrix;
|
||||
getMatrixForCard(&matrix, i);
|
||||
rsgProgramVertexLoadModelMatrix(&matrix);
|
||||
if (cards[i].geometryState == STATE_LOADED && cards[i].geometry.p != 0) {
|
||||
rsgDrawMesh(cards[i].geometry);
|
||||
} else if (cards[i].geometryState == STATE_LOADING && loadingGeometry.p != 0) {
|
||||
rsgDrawMesh(loadingGeometry);
|
||||
} else if (defaultGeometry.p != 0) {
|
||||
rsgDrawMesh(defaultGeometry);
|
||||
} else {
|
||||
// Draw place-holder geometry
|
||||
rsgDrawQuad(
|
||||
cardVertices[0].x, cardVertices[0].y, cardVertices[0].z,
|
||||
cardVertices[1].x, cardVertices[1].y, cardVertices[1].z,
|
||||
cardVertices[2].x, cardVertices[2].y, cardVertices[2].z,
|
||||
cardVertices[3].x, cardVertices[3].y, cardVertices[3].z);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void updateCameraMatrix(float width, float height)
|
||||
{
|
||||
float aspect = width / height;
|
||||
if (aspect != camera.aspect || updateCamera) {
|
||||
camera.aspect = aspect;
|
||||
loadPerspectiveMatrix(&projectionMatrix, camera.fov, camera.aspect, camera.near, camera.far);
|
||||
rsgProgramVertexLoadProjectionMatrix(&projectionMatrix);
|
||||
|
||||
loadLookatMatrix(&modelviewMatrix, camera.from, camera.at, camera.up);
|
||||
rsgProgramVertexLoadModelMatrix(&modelviewMatrix);
|
||||
updateCamera = false;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Behavior/Physics
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
static float velocity = 0.0f; // angular velocity in radians/s
|
||||
static bool isDragging;
|
||||
static int64_t lastTime = 0L; // keep track of how much time has passed between frames
|
||||
static float2 lastPosition;
|
||||
static bool animating = false;
|
||||
static float velocityThreshold = 0.1f * M_PI / 180.0f;
|
||||
static float velocityTracker;
|
||||
static int velocityTrackerCount;
|
||||
static float mass = 5.0f; // kg
|
||||
|
||||
static const float G = 9.80f; // gravity constant, in m/s
|
||||
static const float springConstant = 0.0f;
|
||||
static const float frictionCoeff = 10.0f;
|
||||
static const float dragFactor = 0.25f;
|
||||
|
||||
static float dragFunction(float x, float y)
|
||||
{
|
||||
return dragFactor * ((x - lastPosition.x) / rsgGetWidth()) * M_PI;
|
||||
}
|
||||
|
||||
static float deltaTimeInSeconds(int64_t current)
|
||||
{
|
||||
return (lastTime > 0L) ? (float) (current - lastTime) / 1000.0f : 0.0f;
|
||||
}
|
||||
|
||||
int doSelection(float x, float y)
|
||||
{
|
||||
Ray ray;
|
||||
if (makeRayForPixelAt(&ray, x, y)) {
|
||||
float bestTime = FLT_MAX;
|
||||
return intersectGeometry(&ray, &bestTime);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void doStart(float x, float y)
|
||||
{
|
||||
lastPosition.x = x;
|
||||
lastPosition.y = y;
|
||||
velocity = 0.0f;
|
||||
if (animating) {
|
||||
rsSendToClient(CMD_ANIMATION_FINISHED);
|
||||
animating = false;
|
||||
}
|
||||
velocityTracker = 0.0f;
|
||||
velocityTrackerCount = 0;
|
||||
touchTime = rsUptimeMillis();
|
||||
touchBias = bias;
|
||||
currentSelection = doSelection(x, y);
|
||||
}
|
||||
|
||||
|
||||
void doStop(float x, float y)
|
||||
{
|
||||
int64_t currentTime = rsUptimeMillis();
|
||||
updateAllocationVars();
|
||||
if (currentSelection != -1 && (currentTime - touchTime) < ANIMATION_SCALE_TIME) {
|
||||
rsDebug("HIT!", currentSelection);
|
||||
int data[1];
|
||||
data[0] = currentSelection;
|
||||
rsSendToClientBlocking(CMD_CARD_SELECTED, data, sizeof(data));
|
||||
} else {
|
||||
velocity = velocityTrackerCount > 0 ?
|
||||
(velocityTracker / velocityTrackerCount) : 0.0f; // avg velocity
|
||||
if (fabs(velocity) > velocityThreshold) {
|
||||
animating = true;
|
||||
rsSendToClient(CMD_ANIMATION_STARTED);
|
||||
}
|
||||
}
|
||||
currentSelection = -1;
|
||||
lastTime = rsUptimeMillis();
|
||||
}
|
||||
|
||||
void doMotion(float x, float y)
|
||||
{
|
||||
int64_t currentTime = rsUptimeMillis();
|
||||
float deltaOmega = dragFunction(x, y);
|
||||
bias += deltaOmega;
|
||||
lastPosition.x = x;
|
||||
lastPosition.y = y;
|
||||
float dt = deltaTimeInSeconds(currentTime);
|
||||
if (dt > 0.0f) {
|
||||
float v = deltaOmega / dt;
|
||||
//if ((velocityTracker > 0.0f) == (v > 0.0f)) {
|
||||
velocityTracker += v;
|
||||
velocityTrackerCount++;
|
||||
//} else {
|
||||
// velocityTracker = v;
|
||||
// velocityTrackerCount = 1;
|
||||
//}
|
||||
}
|
||||
|
||||
// Drop current selection if user drags position +- a partial slot
|
||||
if (currentSelection != -1) {
|
||||
const float slotMargin = 0.5f * (2.0f * M_PI / slotCount);
|
||||
if (fabs(touchBias - bias) > slotMargin) {
|
||||
currentSelection = -1;
|
||||
}
|
||||
}
|
||||
lastTime = currentTime;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Hit detection using ray casting.
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static bool
|
||||
rayTriangleIntersect(Ray* ray, float3 p0, float3 p1, float3 p2, float *tout)
|
||||
{
|
||||
static const float tmin = 0.0f;
|
||||
|
||||
float3 e1 = p1 - p0;
|
||||
float3 e2 = p2 - p0;
|
||||
float3 s1 = cross(ray->direction, e2);
|
||||
|
||||
float div = dot(s1, e1);
|
||||
if (div == 0.0f) return false; // ray is parallel to plane.
|
||||
|
||||
float3 d = ray->position - p0;
|
||||
float invDiv = 1.0f / div;
|
||||
|
||||
float u = dot(d, s1) * invDiv;
|
||||
if (u < 0.0f || u > 1.0f) return false;
|
||||
|
||||
float3 s2 = cross(d, e1);
|
||||
float v = dot(ray->direction, s2) * invDiv;
|
||||
if ( v < 0.0f || (u+v) > 1.0f) return false;
|
||||
|
||||
float t = dot(e2, s2) * invDiv;
|
||||
if (t < tmin || t > *tout)
|
||||
return false;
|
||||
*tout = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Creates a ray for an Android pixel coordinate.
|
||||
// Note that the Y coordinate is opposite of GL rendering coordinates.
|
||||
static bool makeRayForPixelAt(Ray* ray, float x, float y)
|
||||
{
|
||||
if (debugCamera) {
|
||||
rsDebug("------ makeRay() -------", 0);
|
||||
rsDebug("Camera.from:", camera.from);
|
||||
rsDebug("Camera.at:", camera.at);
|
||||
rsDebug("Camera.dir:", normalize(camera.at - camera.from));
|
||||
}
|
||||
|
||||
// Vector math. This has the potential to be much faster.
|
||||
// TODO: pre-compute lowerLeftRay, du, dv to eliminate most of this math.
|
||||
if (true) {
|
||||
const float u = x / rsgGetWidth();
|
||||
const float v = 1.0f - (y / rsgGetHeight());
|
||||
const float aspect = (float) rsgGetWidth() / rsgGetHeight();
|
||||
const float tanfov2 = 2.0f * tan(radians(camera.fov / 2.0f));
|
||||
float3 dir = normalize(camera.at - camera.from);
|
||||
float3 du = tanfov2 * normalize(cross(dir, camera.up));
|
||||
float3 dv = tanfov2 * normalize(cross(du, dir));
|
||||
du *= aspect;
|
||||
float3 lowerLeftRay = dir - (0.5f * du) - (0.5f * dv);
|
||||
const float3 rayPoint = camera.from;
|
||||
const float3 rayDir = normalize(lowerLeftRay + u*du + v*dv);
|
||||
if (debugCamera) {
|
||||
rsDebug("Ray direction (vector math) = ", rayDir);
|
||||
}
|
||||
|
||||
ray->position = rayPoint;
|
||||
ray->direction = rayDir;
|
||||
}
|
||||
|
||||
// Matrix math. This is more generic if we allow setting model view and projection matrices
|
||||
// directly
|
||||
else {
|
||||
rs_matrix4x4 pm = modelviewMatrix;
|
||||
rsMatrixLoadMultiply(&pm, &projectionMatrix, &modelviewMatrix);
|
||||
if (!rsMatrixInverse(&pm)) {
|
||||
rsDebug("ERROR: SINGULAR PM MATRIX", 0);
|
||||
return false;
|
||||
}
|
||||
const float width = rsgGetWidth();
|
||||
const float height = rsgGetHeight();
|
||||
const float winx = 2.0f * x / width - 1.0f;
|
||||
const float winy = 2.0f * y / height - 1.0f;
|
||||
|
||||
float4 eye = { 0.0f, 0.0f, 0.0f, 1.0f };
|
||||
float4 at = { winx, winy, 1.0f, 1.0f };
|
||||
|
||||
eye = rsMatrixMultiply(&pm, eye);
|
||||
eye *= 1.0f / eye.w;
|
||||
|
||||
at = rsMatrixMultiply(&pm, at);
|
||||
at *= 1.0f / at.w;
|
||||
|
||||
const float3 rayPoint = { eye.x, eye.y, eye.z };
|
||||
const float3 atPoint = { at.x, at.y, at.z };
|
||||
const float3 rayDir = normalize(atPoint - rayPoint);
|
||||
if (debugCamera) {
|
||||
rsDebug("winx: ", winx);
|
||||
rsDebug("winy: ", winy);
|
||||
rsDebug("Ray position (transformed) = ", eye);
|
||||
rsDebug("Ray direction (transformed) = ", rayDir);
|
||||
}
|
||||
ray->position = rayPoint;
|
||||
ray->direction = rayDir;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static int intersectGeometry(Ray* ray, float *bestTime)
|
||||
{
|
||||
int hit = -1;
|
||||
for (int id = 0; id < cardCount; id++) {
|
||||
if (cards[id].visible) {
|
||||
rs_matrix4x4 matrix;
|
||||
float3 p[4];
|
||||
|
||||
// Transform card vertices to world space
|
||||
rsMatrixLoadIdentity(&matrix);
|
||||
getMatrixForCard(&matrix, id);
|
||||
for (int vertex = 0; vertex < 4; vertex++) {
|
||||
float4 tmp = rsMatrixMultiply(&matrix, cardVertices[vertex]);
|
||||
if (tmp.w != 0.0f) {
|
||||
p[vertex].x = tmp.x;
|
||||
p[vertex].y = tmp.y;
|
||||
p[vertex].z = tmp.z;
|
||||
p[vertex] *= 1.0f / tmp.w;
|
||||
} else {
|
||||
rsDebug("Bad w coord: ", tmp);
|
||||
}
|
||||
}
|
||||
|
||||
// Intersect card geometry
|
||||
if (rayTriangleIntersect(ray, p[0], p[1], p[2], bestTime)
|
||||
|| rayTriangleIntersect(ray, p[2], p[3], p[0], bestTime)) {
|
||||
hit = id;
|
||||
}
|
||||
}
|
||||
}
|
||||
return hit;
|
||||
}
|
||||
|
||||
// This method computes the position of all the cards by updating bias based on a
|
||||
// simple physics model.
|
||||
// If the cards are still in motion, returns true.
|
||||
static bool updateNextPosition(int64_t currentTime)
|
||||
{
|
||||
if (animating) {
|
||||
float dt = deltaTimeInSeconds(currentTime);
|
||||
if (dt <= 0.0f)
|
||||
return animating;
|
||||
const float minStepTime = 1.0f / 300.0f; // ~5 steps per frame
|
||||
const int N = (dt > minStepTime) ? (1 + round(dt / minStepTime)) : 1;
|
||||
dt /= N;
|
||||
for (int i = 0; i < N; i++) {
|
||||
// Force friction - always opposes motion
|
||||
const float Ff = -frictionCoeff * velocity;
|
||||
|
||||
// Restoring force to match cards with slots
|
||||
const float theta = startAngle + bias;
|
||||
const float dtheta = 2.0f * M_PI / slotCount;
|
||||
const float position = theta / dtheta;
|
||||
const float fraction = position - floor(position); // fractional position between slots
|
||||
float x;
|
||||
if (fraction > 0.5f) {
|
||||
x = - (1.0f - fraction);
|
||||
} else {
|
||||
x = fraction;
|
||||
}
|
||||
const float Fr = - springConstant * x;
|
||||
|
||||
// compute velocity
|
||||
const float momentum = mass * velocity + (Ff + Fr)*dt;
|
||||
velocity = momentum / mass;
|
||||
bias += velocity * dt;
|
||||
}
|
||||
|
||||
// TODO: Add animation to smoothly move back to slots. Currently snaps to location.
|
||||
if (cardCount <= visibleSlotCount) {
|
||||
// TODO: this aligns the cards to the first slot (theta = startAngle) when there aren't
|
||||
// enough visible cards. It should be generalized to allow alignment to front,
|
||||
// middle or back of the stack.
|
||||
if (cardPosition(0) != slotPosition(0)) {
|
||||
bias = 0.0f;
|
||||
}
|
||||
} else {
|
||||
if (cardPosition(cardCount) < 0.0f) {
|
||||
bias = -slotPosition(cardCount);
|
||||
} else if (cardPosition(0) > slotPosition(0)) {
|
||||
bias = 0.0f;
|
||||
}
|
||||
}
|
||||
|
||||
animating = fabs(velocity) > velocityThreshold;
|
||||
if (!animating) {
|
||||
const float dtheta = 2.0f * M_PI / slotCount;
|
||||
bias = round((startAngle + bias) / dtheta) * dtheta - startAngle;
|
||||
rsSendToClient(CMD_ANIMATION_FINISHED);
|
||||
}
|
||||
}
|
||||
lastTime = currentTime;
|
||||
|
||||
return animating;
|
||||
}
|
||||
|
||||
// Cull cards based on visibility and visibleSlotCount.
|
||||
// If visibleSlotCount is > 0, then only show those slots and cull the rest.
|
||||
// Otherwise, it should cull based on bounds of geometry.
|
||||
static int cullCards()
|
||||
{
|
||||
const float thetaFirst = slotPosition(-1); // -1 keeps the card in front around a bit longer
|
||||
const float thetaLast = slotPosition(visibleSlotCount);
|
||||
|
||||
int count = 0;
|
||||
for (int i = 0; i < cardCount; i++) {
|
||||
if (visibleSlotCount > 0) {
|
||||
// If visibleSlotCount is specified, then only show up to visibleSlotCount cards.
|
||||
float p = cardPosition(i);
|
||||
if (p >= thetaFirst && p < thetaLast) {
|
||||
cards[i].visible = true;
|
||||
count++;
|
||||
} else {
|
||||
cards[i].visible = false;
|
||||
}
|
||||
} else {
|
||||
// Cull the rest of the cards using bounding box of geometry.
|
||||
// TODO
|
||||
cards[i].visible = true;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// Request texture/geometry for items that have come into view
|
||||
// or doesn't have a texture yet.
|
||||
static void updateCardResources()
|
||||
{
|
||||
for (int i = 0; i < cardCount; i++) {
|
||||
int data[1];
|
||||
if (cards[i].visible) {
|
||||
// request texture from client if not loaded
|
||||
if (cards[i].textureState == STATE_INVALID) {
|
||||
data[0] = i;
|
||||
bool enqueued = rsSendToClient(CMD_REQUEST_TEXTURE, data, sizeof(data));
|
||||
if (enqueued) {
|
||||
cards[i].textureState = STATE_LOADING;
|
||||
} else {
|
||||
rsDebug("Couldn't send CMD_REQUEST_TEXTURE", 0);
|
||||
}
|
||||
}
|
||||
// request geometry from client if not loaded
|
||||
if (cards[i].geometryState == STATE_INVALID) {
|
||||
data[0] = i;
|
||||
bool enqueued = rsSendToClient(CMD_REQUEST_GEOMETRY, data, sizeof(data));
|
||||
if (enqueued) {
|
||||
cards[i].geometryState = STATE_LOADING;
|
||||
} else {
|
||||
rsDebug("Couldn't send CMD_REQUEST_GEOMETRY", 0);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// ask the host to remove the texture
|
||||
if (cards[i].textureState == STATE_LOADED) {
|
||||
data[0] = i;
|
||||
bool enqueued = rsSendToClient(CMD_INVALIDATE_TEXTURE, data, sizeof(data));
|
||||
if (enqueued) {
|
||||
cards[i].textureState = STATE_INVALID;
|
||||
} else {
|
||||
rsDebug("Couldn't send CMD_INVALIDATE_TEXTURE", 0);
|
||||
}
|
||||
}
|
||||
// ask the host to remove the geometry
|
||||
if (cards[i].geometryState == STATE_LOADED) {
|
||||
data[0] = i;
|
||||
bool enqueued = rsSendToClient(CMD_INVALIDATE_GEOMETRY, data, sizeof(data));
|
||||
if (enqueued) {
|
||||
cards[i].geometryState = STATE_INVALID;
|
||||
} else {
|
||||
rsDebug("Couldn't send CMD_INVALIDATE_GEOMETRY", 0);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Places dots on geometry to visually inspect that objects can be seen by rays.
|
||||
// NOTE: the color of the dot is somewhat random, as it depends on texture of previously-rendered
|
||||
// card.
|
||||
static void renderWithRays()
|
||||
{
|
||||
const float w = rsgGetWidth();
|
||||
const float h = rsgGetHeight();
|
||||
const int skip = 8;
|
||||
color(1.0f, 0.0f, 0.0f, 1.0f);
|
||||
for (int j = 0; j < (int) h; j+=skip) {
|
||||
float posY = (float) j;
|
||||
for (int i = 0; i < (int) w; i+=skip) {
|
||||
float posX = (float) i;
|
||||
Ray ray;
|
||||
if (makeRayForPixelAt(&ray, posX, posY)) {
|
||||
float bestTime = FLT_MAX;
|
||||
if (intersectGeometry(&ray, &bestTime) != -1) {
|
||||
rsgDrawSpriteScreenspace(posX, h - posY - 1, 0.0f, 2.0f, 2.0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
int root() {
|
||||
int64_t currentTime = rsUptimeMillis();
|
||||
|
||||
rsgClearDepth(1.0f);
|
||||
rsgBindProgramVertex(vertexProgram);
|
||||
rsgBindProgramFragment(fragmentProgram);
|
||||
rsgBindProgramStore(programStore);
|
||||
rsgBindProgramRaster(rasterProgram);
|
||||
|
||||
updateAllocationVars();
|
||||
|
||||
if (!initialized) {
|
||||
for (int i = 0; i < cardCount; i++)
|
||||
cards[i].textureState = STATE_INVALID;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
if (false) { // for debugging - flash the screen so we know we're still rendering
|
||||
static bool toggle;
|
||||
if (toggle)
|
||||
rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
|
||||
else
|
||||
rsgClearColor(1.0f, 0.0f, 0.0f, 1.f);
|
||||
toggle = !toggle;
|
||||
} else {
|
||||
rsgClearColor(backgroundColor.x, backgroundColor.y, backgroundColor.z, 1.0);
|
||||
}
|
||||
|
||||
updateCameraMatrix(rsgGetWidth(), rsgGetHeight());
|
||||
|
||||
const bool timeExpired = (currentTime - touchTime) > ANIMATION_SCALE_TIME;
|
||||
if (timeExpired) {
|
||||
//currentSelection = -1;
|
||||
}
|
||||
bool stillAnimating = updateNextPosition(currentTime) || !timeExpired;
|
||||
|
||||
cullCards();
|
||||
|
||||
updateCardResources();
|
||||
|
||||
drawCards();
|
||||
|
||||
if (debugPicking) {
|
||||
renderWithRays();
|
||||
}
|
||||
|
||||
//rsSendToClient(CMD_PING);
|
||||
|
||||
return stillAnimating ? 1 : 0;
|
||||
}
|
||||
@@ -36,12 +36,12 @@ LOCAL_EXPORT_PACKAGE_RESOURCES := true
|
||||
# Include resources generated by system RenderScript files.
|
||||
framework_GENERATED_SOURCE_DIR := $(call intermediates-dir-for,JAVA_LIBRARIES,framework,,COMMON)/src
|
||||
framework_RenderScript_STAMP_FILE := $(framework_GENERATED_SOURCE_DIR)/RenderScript.stamp
|
||||
LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
|
||||
#LOCAL_RESOURCE_DIR := $(framework_GENERATED_SOURCE_DIR)/renderscript/res $(LOCAL_PATH)/res
|
||||
|
||||
include $(BUILD_PACKAGE)
|
||||
|
||||
# Make sure the system .rs files get compiled before building the package-export.apk.
|
||||
$(resource_export_package): $(framework_RenderScript_STAMP_FILE)
|
||||
# $(resource_export_package): $(framework_RenderScript_STAMP_FILE)
|
||||
|
||||
# define a global intermediate target that other module may depend on.
|
||||
.PHONY: framework-res-package-target
|
||||
|
||||
@@ -45,11 +45,11 @@
|
||||
android:text="@android:string/no_recent_tasks"
|
||||
android:visibility="gone"/>
|
||||
|
||||
<com.android.internal.widget.CarouselView
|
||||
<com.android.systemui.statusbar.RecentApplicationsCarouselView
|
||||
android:id="@+id/carousel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1">
|
||||
</com.android.internal.widget.CarouselView>
|
||||
</com.android.systemui.statusbar.RecentApplicationsCarouselView>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -3,10 +3,13 @@ include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE_TAGS := optional
|
||||
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files)
|
||||
LOCAL_SRC_FILES := $(call all-subdir-java-files) \
|
||||
../../../ex/carousel/java/com/android/ex/carousel/carousel.rs
|
||||
|
||||
LOCAL_JAVA_LIBRARIES := services
|
||||
|
||||
LOCAL_STATIC_JAVA_LIBRARIES := android-common-carousel
|
||||
|
||||
LOCAL_PACKAGE_NAME := SystemUI
|
||||
LOCAL_CERTIFICATE := platform
|
||||
|
||||
|
||||
@@ -17,14 +17,13 @@
|
||||
|
||||
package com.android.systemui.statusbar;
|
||||
|
||||
import com.android.ex.carousel.CarouselView;
|
||||
import com.android.ex.carousel.CarouselRS.CarouselCallback;
|
||||
import com.android.internal.R;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import com.android.internal.widget.CarouselView;
|
||||
import com.android.internal.widget.CarouselRS.CarouselCallback;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.ActivityManager;
|
||||
import android.app.IThumbnailReceiver;
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
/*
|
||||
* 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 com.android.systemui.statusbar;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
|
||||
import com.android.ex.carousel.CarouselView;
|
||||
import com.android.systemui.R;
|
||||
|
||||
public class RecentApplicationsCarouselView extends CarouselView {
|
||||
|
||||
public RecentApplicationsCarouselView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public RecentApplicationsCarouselView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public Info getRenderScriptInfo() {
|
||||
return new Info(R.raw.carousel);
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user