Allow fading of the entire card
Give cards an overall timestamp, separate from the texture
timestamp. This allows cards to fade in before their
texture has been set.
Bug: 3281327
Change-Id: I9405636ebcbfc2c27d777d435f3abf24265dfbe9
diff --git a/carousel/java/com/android/ex/carousel/CarouselController.java b/carousel/java/com/android/ex/carousel/CarouselController.java
index 762fa58..4b774aa 100644
--- a/carousel/java/com/android/ex/carousel/CarouselController.java
+++ b/carousel/java/com/android/ex/carousel/CarouselController.java
@@ -85,6 +85,7 @@
private CarouselCallback mCarouselCallback;
private float mRezInCardCount = 0.0f;
private long mFadeInDuration = 250L;
+ private long mCardCreationFadeDuration = 0L;
private Bitmap mDetailLoadingBitmap = Bitmap.createBitmap(
new int[] {0}, 0, 1, 1, 1, Bitmap.Config.ARGB_4444);
private int mDragModel = CarouselRS.DRAG_MODEL_SCREEN_DELTA;
@@ -136,6 +137,7 @@
setLookAt(mEye, mAt, mUp);
setRezInCardCount(mRezInCardCount);
setFadeInDuration(mFadeInDuration);
+ setCardCreationFadeDuration(mCardCreationFadeDuration);
setDetailLoadingBitmap(mDetailLoadingBitmap);
setStoreConfigs(mStoreConfigs);
}
@@ -679,7 +681,7 @@
* until all of the cards have faded in. Note: using large values will extend the
* animation until all cards have faded in.
*
- * @param t
+ * @param t The time, in milliseconds
*/
public void setFadeInDuration(long t) {
mFadeInDuration = t;
@@ -689,6 +691,19 @@
}
/**
+ * This sets the duration (in ms) that a card takes to fade in when it is initially created,
+ * such as when it is added or when the application starts. The timer starts at the moment
+ * when the card is first created. Replacing a card's contents does not affect the timer.
+ * @param t The time, in milliseconds
+ */
+ public void setCardCreationFadeDuration(long t) {
+ mCardCreationFadeDuration = t;
+ if (mRenderScript != null) {
+ mRenderScript.setCardCreationFadeDuration(t);
+ }
+ }
+
+ /**
* Tells the carousel that a touch event has started at the designated location.
* @param x The number of pixels from the left edge that the event occurred
* @param y The number of pixels from the top edge that the event occurred
diff --git a/carousel/java/com/android/ex/carousel/CarouselRS.java b/carousel/java/com/android/ex/carousel/CarouselRS.java
index fca1791..a9dfc89 100644
--- a/carousel/java/com/android/ex/carousel/CarouselRS.java
+++ b/carousel/java/com/android/ex/carousel/CarouselRS.java
@@ -71,7 +71,9 @@
private ScriptField_FragmentShaderConstants_s mFSConst;
private ScriptField_ProgramStore_s mProgramStoresCard;
private ProgramFragment mSingleTextureFragmentProgram;
+ private ProgramFragment mSingleTextureBlendingFragmentProgram;
private ProgramFragment mMultiTextureFragmentProgram;
+ private ProgramFragment mMultiTextureBlendingFragmentProgram;
private ProgramVertex mVertexProgram;
private ProgramRaster mRasterProgram;
private Allocation[] mAllocationPool;
@@ -92,6 +94,14 @@
"gl_FragColor = col; " +
"}");
+ private static final String mSingleTextureBlendingShader = new String(
+ "varying vec2 varTex0;" +
+ "void main() {" +
+ "vec2 t0 = varTex0.xy;" +
+ "vec4 col = texture2D(UNI_Tex0, t0);" +
+ "gl_FragColor = col * UNI_overallAlpha; " +
+ "}");
+
private static final String mMultiTextureShader = new String(
"varying vec2 varTex0;" +
"void main() {" +
@@ -100,6 +110,16 @@
"vec4 col2 = texture2D(UNI_Tex1, t0);" +
"gl_FragColor = mix(col, col2, UNI_fadeAmount);}");
+ private static final String mMultiTextureBlendingShader = new String(
+ "varying vec2 varTex0;" +
+ "void main() {" +
+ "vec2 t0 = varTex0.xy;" +
+ "vec4 col = texture2D(UNI_Tex0, t0);" +
+ "vec4 col2 = texture2D(UNI_Tex1, t0);" +
+ "gl_FragColor = mix(col, col2, UNI_fadeAmount) * UNI_overallAlpha;" +
+ "}"
+ );
+
public static interface CarouselCallback {
/**
* Called when a card is selected
@@ -355,10 +375,25 @@
mSingleTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
//
- // Multi texture program
+ // Single texture program, plus blending
//
mFSConst = new ScriptField_FragmentShaderConstants_s(mRS, 1);
mScript.bind_shaderConstants(mFSConst);
+ ProgramFragment.ShaderBuilder pfbSingleBlend = new ProgramFragment.ShaderBuilder(mRS);
+ // Specify the resource that contains the shader string
+ pfbSingleBlend.setShader(mSingleTextureBlendingShader);
+ // Tell the builder how many textures we have
+ pfbSingleBlend.setTextureCount(1);
+ // Define the constant input layout
+ pfbSingleBlend.addConstant(mFSConst.getAllocation().getType());
+ mSingleTextureBlendingFragmentProgram = pfbSingleBlend.create();
+ // Bind the source of constant data
+ mSingleTextureBlendingFragmentProgram.bindConstants(mFSConst.getAllocation(), 0);
+ mSingleTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+
+ //
+ // Multi texture program
+ //
ProgramFragment.ShaderBuilder pfbMulti = new ProgramFragment.ShaderBuilder(mRS);
// Specify the resource that contains the shader string
pfbMulti.setShader(mMultiTextureShader);
@@ -372,9 +407,27 @@
mMultiTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
mMultiTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 1);
+ //
+ // Multi texture program, plus blending
+ //
+ ProgramFragment.ShaderBuilder pfbMultiBlend = new ProgramFragment.ShaderBuilder(mRS);
+ // Specify the resource that contains the shader string
+ pfbMultiBlend.setShader(mMultiTextureBlendingShader);
+ // Tell the builder how many textures we have
+ pfbMultiBlend.setTextureCount(2);
+ // Define the constant input layout
+ pfbMultiBlend.addConstant(mFSConst.getAllocation().getType());
+ mMultiTextureBlendingFragmentProgram = pfbMultiBlend.create();
+ // Bind the source of constant data
+ mMultiTextureBlendingFragmentProgram.bindConstants(mFSConst.getAllocation(), 0);
+ mMultiTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0);
+ mMultiTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 1);
+
mScript.set_linearClamp(Sampler.CLAMP_LINEAR(mRS));
mScript.set_singleTextureFragmentProgram(mSingleTextureFragmentProgram);
+ mScript.set_singleTextureBlendingFragmentProgram(mSingleTextureBlendingFragmentProgram);
mScript.set_multiTextureFragmentProgram(mMultiTextureFragmentProgram);
+ mScript.set_multiTextureBlendingFragmentProgram(mMultiTextureBlendingFragmentProgram);
}
private void initProgramStore() {
@@ -801,6 +854,10 @@
mScript.set_fadeInDuration((int)t); // TODO: Remove cast when RS supports exporting longs
}
+ public void setCardCreationFadeDuration(long t) {
+ mScript.set_cardCreationFadeDuration((int)t);
+ }
+
private Element elementForBitmap(Bitmap bitmap, Bitmap.Config defaultConfig) {
Bitmap.Config config = bitmap.getConfig();
if (config == null) {
diff --git a/carousel/java/com/android/ex/carousel/carousel.rs b/carousel/java/com/android/ex/carousel/carousel.rs
index 4de05d9..5c9ae5b 100644
--- a/carousel/java/com/android/ex/carousel/carousel.rs
+++ b/carousel/java/com/android/ex/carousel/carousel.rs
@@ -34,8 +34,9 @@
int geometryState; // whether or not geometry is loaded
int cardVisible; // not bool because of packing bug?
int detailVisible; // not bool because of packing bug?
- int64_t textureTimeStamp; // time when this texture was last updated, in seconds
- int64_t detailTextureTimeStamp; // time when this texture was last updated, in seconds
+ int64_t textureTimeStamp; // time when this texture was last updated, in ms
+ int64_t detailTextureTimeStamp; // time when this texture was last updated, in ms
+ int64_t geometryTimeStamp; // time when the card itself was last updated, in ms
} Card_t;
typedef struct Ray_s {
@@ -70,6 +71,7 @@
typedef struct FragmentShaderConstants_s {
float fadeAmount;
+ float overallAlpha;
} FragmentShaderConstants;
// Request states. Used for loading 3D object properties from the Java client.
@@ -170,6 +172,7 @@
float frictionCoeff; // how much to slow down the carousel over time
float dragFactor; // a scale factor for how sensitive the carousel is to user dragging
int fadeInDuration; // amount of time (in ms) for smoothly switching out textures
+int cardCreationFadeDuration; // amount of time (in ms) to fade while initially showing a card
float rezInCardCount; // this controls how rapidly distant card textures will be rez-ed in
float detailFadeRate; // rate at which details fade as they move into the distance
float4 backgroundColor;
@@ -183,7 +186,9 @@
rs_program_store programStoreBackground;
rs_program_store programStoreDetail;
rs_program_fragment singleTextureFragmentProgram;
+rs_program_fragment singleTextureBlendingFragmentProgram;
rs_program_fragment multiTextureFragmentProgram;
+rs_program_fragment multiTextureBlendingFragmentProgram;
rs_program_vertex vertexProgram;
rs_program_raster rasterProgram;
rs_allocation defaultTexture; // shown when no other texture is assigned
@@ -321,6 +326,7 @@
card->detailVisible = false;
card->textureTimeStamp = 0;
card->detailTextureTimeStamp = 0;
+ card->geometryTimeStamp = rsUptimeMillis();
}
void createCards(int start, int total)
@@ -343,10 +349,10 @@
}
// Computes an alpha value for a card using elapsed time and constant fadeInDuration
-static float getAnimatedAlpha(int64_t startTime, int64_t currentTime)
+static float getAnimatedAlpha(int64_t startTime, int64_t currentTime, int64_t duration)
{
double timeElapsed = (double) (currentTime - startTime); // in ms
- double alpha = (double) timeElapsed / fadeInDuration;
+ double alpha = duration > 0 ? (double) timeElapsed / duration : 1.0;
return min(1.0f, (float) alpha);
}
@@ -514,6 +520,7 @@
cards[n].geometryState = STATE_LOADED;
else
cards[n].geometryState = STATE_INVALID;
+ cards[n].geometryTimeStamp = rsUptimeMillis();
}
void setProgramStoresCard(int n, rs_program_store programStore)
@@ -640,8 +647,11 @@
for (int i = cardCount-1; i >= 0; i--) {
if (cards[i].cardVisible) {
// If this card was recently loaded, this will be < 1.0f until the animation completes
- float animatedAlpha = getAnimatedAlpha(cards[i].textureTimeStamp, currentTime);
- if (animatedAlpha < 1.0f) {
+ float animatedAlpha = getAnimatedAlpha(cards[i].textureTimeStamp, currentTime,
+ fadeInDuration);
+ float overallAlpha = getAnimatedAlpha(cards[i].geometryTimeStamp, currentTime,
+ cardCreationFadeDuration);
+ if (animatedAlpha < 1.0f || overallAlpha < 1.0f) {
stillAnimating = true;
}
@@ -656,6 +666,7 @@
// Set alpha for blending between the textures
shaderConstants->fadeAmount = min(1.0f, animatedAlpha * positionAlpha);
+ shaderConstants->overallAlpha = overallAlpha;
rsAllocationMarkDirty(rsGetAllocation(shaderConstants));
// Bind the appropriate shader network. If there's no alpha blend, then
@@ -664,15 +675,29 @@
const bool loaded = (state == STATE_LOADED) || (state == STATE_STALE) ||
(state == STATE_UPDATING);
if (shaderConstants->fadeAmount == 1.0f || shaderConstants->fadeAmount < 0.01f) {
- rsgBindProgramFragment(singleTextureFragmentProgram);
- rsgBindTexture(singleTextureFragmentProgram, 0,
- (loaded && shaderConstants->fadeAmount == 1.0f) ?
- cards[i].texture : loadingTexture);
+ if (overallAlpha < 1.0) {
+ rsgBindProgramFragment(singleTextureBlendingFragmentProgram);
+ rsgBindTexture(singleTextureBlendingFragmentProgram, 0,
+ (loaded && shaderConstants->fadeAmount == 1.0f) ?
+ cards[i].texture : loadingTexture);
+ } else {
+ rsgBindProgramFragment(singleTextureFragmentProgram);
+ rsgBindTexture(singleTextureFragmentProgram, 0,
+ (loaded && shaderConstants->fadeAmount == 1.0f) ?
+ cards[i].texture : loadingTexture);
+ }
} else {
- rsgBindProgramFragment(multiTextureFragmentProgram);
- rsgBindTexture(multiTextureFragmentProgram, 0, loadingTexture);
- rsgBindTexture(multiTextureFragmentProgram, 1, loaded ?
- cards[i].texture : loadingTexture);
+ if (overallAlpha < 1.0) {
+ rsgBindProgramFragment(multiTextureBlendingFragmentProgram);
+ rsgBindTexture(multiTextureBlendingFragmentProgram, 0, loadingTexture);
+ rsgBindTexture(multiTextureBlendingFragmentProgram, 1, loaded ?
+ cards[i].texture : loadingTexture);
+ } else {
+ rsgBindProgramFragment(multiTextureFragmentProgram);
+ rsgBindTexture(multiTextureFragmentProgram, 0, loadingTexture);
+ rsgBindTexture(multiTextureFragmentProgram, 1, loaded ?
+ cards[i].texture : loadingTexture);
+ }
}
// Draw geometry
@@ -815,7 +840,8 @@
// Compute alpha for gradually fading in details. Applied to both line and
// detail texture. TODO: use a separate background texture for line.
- float animatedAlpha = getAnimatedAlpha(cards[i].detailTextureTimeStamp, currentTime);
+ float animatedAlpha = getAnimatedAlpha(cards[i].detailTextureTimeStamp,
+ currentTime, fadeInDuration);
if (animatedAlpha < 1.0f) {
stillAnimating = true;
}