1 /* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.ex.carousel; 18 19 import android.content.res.Resources; 20 import android.graphics.Bitmap; 21 import android.graphics.Rect; 22 import android.renderscript.*; 23 import static android.renderscript.Element.*; 24 import android.renderscript.Program.TextureType; 25 import android.renderscript.RenderScript.RSMessageHandler; 26 import android.util.Log; 27 28 /** 29 * This is a support class for Carousel renderscript. It handles most of the low-level interactions 30 * with Renderscript as well as dispatching events. 31 * 32 */ 33 public class CarouselRS { 34 private static final int DEFAULT_VISIBLE_SLOTS = 1; 35 private static final int DEFAULT_CARD_COUNT = 0; 36 private static final int DEFAULT_ROW_COUNT = 1; 37 38 // Client messages *** THIS LIST MUST MATCH THOSE IN carousel.rs *** 39 public static final int CMD_CARD_SELECTED = 100; 40 public static final int CMD_DETAIL_SELECTED = 105; 41 public static final int CMD_CARD_LONGPRESS = 110; 42 public static final int CMD_REQUEST_TEXTURE = 200; 43 public static final int CMD_INVALIDATE_TEXTURE = 210; 44 public static final int CMD_REQUEST_GEOMETRY = 300; 45 public static final int CMD_INVALIDATE_GEOMETRY = 310; 46 public static final int CMD_ANIMATION_STARTED = 400; 47 public static final int CMD_ANIMATION_FINISHED = 500; 48 public static final int CMD_REQUEST_DETAIL_TEXTURE = 600; 49 public static final int CMD_INVALIDATE_DETAIL_TEXTURE = 610; 50 public static final int CMD_PING = 1000; // for debugging 51 52 // Drag models *** THIS LIST MUST MATCH THOSE IN carousel.rs *** 53 public static final int DRAG_MODEL_SCREEN_DELTA = 0; 54 public static final int DRAG_MODEL_PLANE = 1; 55 public static final int DRAG_MODEL_CYLINDER_INSIDE = 2; 56 public static final int DRAG_MODEL_CYLINDER_OUTSIDE = 3; 57 58 public static final int FILL_DIRECTION_CCW = +1; 59 public static final int FILL_DIRECTION_CW = -1; 60 61 private static final String TAG = "CarouselRS"; 62 private static final int DEFAULT_SLOT_COUNT = 10; 63 private static final Allocation.MipmapControl MIPMAP = 64 Allocation.MipmapControl.MIPMAP_NONE; 65 private static final boolean DBG = false; 66 67 private RenderScriptGL mRS; 68 private Resources mRes; 69 private ScriptC_carousel mScript; 70 private ScriptField_Card mCards; 71 private ScriptField_FragmentShaderConstants_s mFSConst; 72 private ScriptField_ProgramStore_s mProgramStoresCard; 73 private ProgramFragment mSingleTextureFragmentProgram; 74 private ProgramFragment mSingleTextureBlendingFragmentProgram; 75 private ProgramFragment mMultiTextureFragmentProgram; 76 private ProgramFragment mMultiTextureBlendingFragmentProgram; 77 private ProgramVertex mVertexProgram; 78 private ProgramRaster mRasterProgram; 79 private Allocation[] mAllocationPool; 80 private boolean mForceBlendCardsWithZ; 81 private int mVisibleSlots; 82 private int mRowCount; 83 private int mPrefetchCardCount; 84 private CarouselCallback mCallback; 85 private float[] mEyePoint = new float[] { 2.0f, 0.0f, 0.0f }; 86 private float[] mAtPoint = new float[] { 0.0f, 0.0f, 0.0f }; 87 private float[] mUp = new float[] { 0.0f, 1.0f, 0.0f }; 88 89 private static final String mSingleTextureShader = new String( 90 "varying vec2 varTex0;" + 91 "void main() {" + 92 "vec2 t0 = varTex0.xy;" + 93 "vec4 col = texture2D(UNI_Tex0, t0);" + 94 "gl_FragColor = col; " + 95 "}"); 96 97 private static final String mSingleTextureBlendingShader = new String( 98 "varying vec2 varTex0;" + 99 "void main() {" + 100 "vec2 t0 = varTex0.xy;" + 101 "vec4 col = texture2D(UNI_Tex0, t0);" + 102 "gl_FragColor = col * UNI_overallAlpha; " + 103 "}"); 104 105 private static final String mMultiTextureShader = new String( 106 "varying vec2 varTex0;" + 107 "void main() {" + 108 "vec2 t0 = varTex0.xy;" + 109 "vec4 col = texture2D(UNI_Tex0, t0);" + 110 "vec4 col2 = texture2D(UNI_Tex1, t0);" + 111 "gl_FragColor = mix(col, col2, UNI_fadeAmount);}"); 112 113 private static final String mMultiTextureBlendingShader = new String( 114 "varying vec2 varTex0;" + 115 "void main() {" + 116 "vec2 t0 = varTex0.xy;" + 117 "vec4 col = texture2D(UNI_Tex0, t0);" + 118 "vec4 col2 = texture2D(UNI_Tex1, t0);" + 119 "gl_FragColor = mix(col, col2, UNI_fadeAmount) * UNI_overallAlpha;" + 120 "}" 121 ); 122 123 public static interface CarouselCallback { 124 /** 125 * Called when a card is selected 126 * @param n the id of the card 127 */ 128 void onCardSelected(int n); 129 130 /** 131 * Called when the detail texture for a card is tapped 132 * @param n the id of the card 133 * @param x how far the user tapped from the left edge of the card, in pixels 134 * @param y how far the user tapped from the top edge of the card, in pixels 135 */ 136 void onDetailSelected(int n, int x, int y); 137 138 /** 139 * Called when a card is long-pressed 140 * @param n the id of the card 141 * @param touchPosition position of where the user pressed, in screen coordinates 142 * @param detailCoordinates position of detail texture, in screen coordinates 143 */ 144 void onCardLongPress(int n, int touchPosition[], Rect detailCoordinates); 145 146 /** 147 * Called when texture is needed for card n. This happens when the given card becomes 148 * visible. 149 * @param n the id of the card 150 */ 151 void onRequestTexture(int n); 152 153 /** 154 * Called when a texture is no longer needed for card n. This happens when the card 155 * goes out of view. 156 * @param n the id of the card 157 */ 158 void onInvalidateTexture(int n); 159 160 /** 161 * Called when detail texture is needed for card n. This happens when the given card 162 * becomes visible. 163 * @param n the id of the card 164 */ 165 void onRequestDetailTexture(int n); 166 167 /** 168 * Called when a detail texture is no longer needed for card n. This happens when the card 169 * goes out of view. 170 * @param n the id of the card 171 */ 172 void onInvalidateDetailTexture(int n); 173 174 /** 175 * Called when geometry is needed for card n. 176 * @param n the id of the card. 177 */ 178 void onRequestGeometry(int n); 179 180 /** 181 * Called when geometry is no longer needed for card n. This happens when the card goes 182 * out of view. 183 * @param n the id of the card 184 */ 185 void onInvalidateGeometry(int n); 186 187 /** 188 * Called when card animation (e.g. a fling) has started. 189 */ 190 void onAnimationStarted(); 191 192 /** 193 * Called when card animation has stopped. 194 * @param carouselRotationAngle the angle of rotation, in radians, at which the animation 195 * stopped. 196 */ 197 void onAnimationFinished(float carouselRotationAngle); 198 }; 199 200 private RSMessageHandler mRsMessage = new RSMessageHandler() { 201 public void run() { 202 if (mCallback == null) return; 203 switch (mID) { 204 case CMD_CARD_SELECTED: 205 mCallback.onCardSelected(mData[0]); 206 break; 207 208 case CMD_DETAIL_SELECTED: 209 mCallback.onDetailSelected(mData[0], mData[1], mData[2]); 210 break; 211 212 case CMD_CARD_LONGPRESS: 213 int touchPosition[] = { mData[1], mData[2] }; 214 Rect detailCoordinates = new Rect(mData[3], mData[4], mData[5], mData[6]); 215 mCallback.onCardLongPress(mData[0], touchPosition, detailCoordinates); 216 break; 217 218 case CMD_REQUEST_TEXTURE: 219 mCallback.onRequestTexture(mData[0]); 220 break; 221 222 case CMD_INVALIDATE_TEXTURE: 223 setTexture(mData[0], null); 224 mCallback.onInvalidateTexture(mData[0]); 225 break; 226 227 case CMD_REQUEST_DETAIL_TEXTURE: 228 mCallback.onRequestDetailTexture(mData[0]); 229 break; 230 231 case CMD_INVALIDATE_DETAIL_TEXTURE: 232 setDetailTexture(mData[0], 0.0f, 0.0f, 0.0f, 0.0f, null); 233 mCallback.onInvalidateDetailTexture(mData[0]); 234 break; 235 236 case CMD_REQUEST_GEOMETRY: 237 mCallback.onRequestGeometry(mData[0]); 238 break; 239 240 case CMD_INVALIDATE_GEOMETRY: 241 setGeometry(mData[0], null); 242 mCallback.onInvalidateGeometry(mData[0]); 243 break; 244 245 case CMD_ANIMATION_STARTED: 246 mCallback.onAnimationStarted(); 247 break; 248 249 case CMD_ANIMATION_FINISHED: 250 mCallback.onAnimationFinished(Float.intBitsToFloat(mData[0])); 251 break; 252 253 case CMD_PING: 254 if (DBG) Log.v(TAG, "PING..."); 255 break; 256 257 default: 258 Log.e(TAG, "Unknown RSMessage: " + mID); 259 } 260 } 261 }; 262 263 public CarouselRS(RenderScriptGL rs, Resources res, int resId) { 264 mRS = rs; 265 mRes = res; 266 267 // create the script object 268 mScript = new ScriptC_carousel(mRS, mRes, resId); 269 mRS.setMessageHandler(mRsMessage); 270 initProgramStore(); 271 initFragmentProgram(); 272 initRasterProgram(); 273 initVertexProgram(); 274 setSlotCount(DEFAULT_SLOT_COUNT); 275 setVisibleSlots(DEFAULT_VISIBLE_SLOTS); 276 setRowCount(DEFAULT_ROW_COUNT); 277 createCards(DEFAULT_CARD_COUNT); 278 setStartAngle(0.0f); 279 setCarouselRotationAngle(0.0f); 280 setRadius(1.0f); 281 setLookAt(mEyePoint, mAtPoint, mUp); 282 setRadius(20.0f); 283 // Fov: 25 284 } 285 286 public void setLookAt(float[] eye, float[] at, float[] up) { 287 for (int i = 0; i < 3; i++) { 288 mEyePoint[i] = eye[i]; 289 mAtPoint[i] = at[i]; 290 mUp[i] = up[i]; 291 } 292 mScript.invoke_lookAt(eye[0], eye[1], eye[2], at[0], at[1], at[2], up[0], up[1], up[2]); 293 } 294 295 public void setRadius(float radius) { 296 mScript.invoke_setRadius(radius); 297 } 298 299 public void setCardRotation(float cardRotation) { 300 mScript.set_cardRotation(cardRotation); 301 } 302 303 public void setCardsFaceTangent(boolean faceTangent) { 304 mScript.set_cardsFaceTangent(faceTangent); 305 } 306 307 public void setSwaySensitivity(float swaySensitivity) { 308 mScript.set_swaySensitivity(swaySensitivity); 309 } 310 311 public void setFrictionCoefficient(float frictionCoeff) { 312 mScript.set_frictionCoeff(frictionCoeff); 313 } 314 315 public void setDragFactor(float dragFactor) { 316 mScript.set_dragFactor(dragFactor); 317 } 318 319 public void setDragModel(int model) { 320 mScript.set_dragModel(model); 321 } 322 323 public void setFillDirection(int direction) { 324 mScript.set_fillDirection(direction); 325 } 326 327 private Matrix4f matrixFromFloat(float[] matrix) { 328 int dimensions; 329 if (matrix == null || matrix.length == 0) { 330 dimensions = 0; 331 } else if (matrix.length == 16) { 332 dimensions = 4; 333 } else if (matrix.length == 9) { 334 dimensions = 3; 335 } else { 336 throw new IllegalArgumentException("matrix length not 0,9 or 16"); 337 } 338 339 Matrix4f rsMatrix = new Matrix4f(); // initialized as identity. 340 for (int i = 0; i < dimensions; i++) { 341 for (int j = 0; j < dimensions; j++) { 342 rsMatrix.set(i, j, matrix[i*dimensions + j]); 343 } 344 } 345 346 return rsMatrix; 347 } 348 349 public void setDefaultCardMatrix(float[] matrix) { 350 mScript.set_defaultCardMatrix(matrixFromFloat(matrix)); 351 } 352 353 private void initVertexProgram() { 354 ProgramVertexFixedFunction.Builder pvb = new ProgramVertexFixedFunction.Builder(mRS); 355 mVertexProgram = pvb.create(); 356 ProgramVertexFixedFunction.Constants pva = new ProgramVertexFixedFunction.Constants(mRS); 357 ((ProgramVertexFixedFunction)mVertexProgram).bindConstants(pva); 358 Matrix4f proj = new Matrix4f(); 359 proj.loadProjectionNormalized(1, 1); 360 pva.setProjection(proj); 361 mScript.set_vertexProgram(mVertexProgram); 362 } 363 364 private void initRasterProgram() { 365 ProgramRaster.Builder programRasterBuilder = new ProgramRaster.Builder(mRS); 366 mRasterProgram = programRasterBuilder.create(); 367 //mRasterProgram.setCullMode(CullMode.NONE); 368 mScript.set_rasterProgram(mRasterProgram); 369 } 370 371 private void initFragmentProgram() { 372 // 373 // Single texture program 374 // 375 ProgramFragment.Builder pfbSingle = new ProgramFragment.Builder(mRS); 376 // Specify the resource that contains the shader string 377 pfbSingle.setShader(mSingleTextureShader); 378 // Tell the builder how many textures we have 379 pfbSingle.addTexture(Program.TextureType.TEXTURE_2D); 380 mSingleTextureFragmentProgram = pfbSingle.create(); 381 // Bind the source of constant data 382 mSingleTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 383 384 // 385 // Single texture program, plus blending 386 // 387 mFSConst = new ScriptField_FragmentShaderConstants_s(mRS, 1); 388 mScript.bind_shaderConstants(mFSConst); 389 ProgramFragment.Builder pfbSingleBlend = new ProgramFragment.Builder(mRS); 390 // Specify the resource that contains the shader string 391 pfbSingleBlend.setShader(mSingleTextureBlendingShader); 392 // Tell the builder how many textures we have 393 pfbSingleBlend.addTexture(Program.TextureType.TEXTURE_2D); 394 // Define the constant input layout 395 pfbSingleBlend.addConstant(mFSConst.getAllocation().getType()); 396 mSingleTextureBlendingFragmentProgram = pfbSingleBlend.create(); 397 // Bind the source of constant data 398 mSingleTextureBlendingFragmentProgram.bindConstants(mFSConst.getAllocation(), 0); 399 mSingleTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 400 401 // 402 // Multi texture program 403 // 404 ProgramFragment.Builder pfbMulti = new ProgramFragment.Builder(mRS); 405 // Specify the resource that contains the shader string 406 pfbMulti.setShader(mMultiTextureShader); 407 // Tell the builder how many textures we have 408 pfbMulti.addTexture(Program.TextureType.TEXTURE_2D); 409 pfbMulti.addTexture(Program.TextureType.TEXTURE_2D); 410 // Define the constant input layout 411 pfbMulti.addConstant(mFSConst.getAllocation().getType()); 412 mMultiTextureFragmentProgram = pfbMulti.create(); 413 // Bind the source of constant data 414 mMultiTextureFragmentProgram.bindConstants(mFSConst.getAllocation(), 0); 415 mMultiTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 416 mMultiTextureFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 1); 417 418 // 419 // Multi texture program, plus blending 420 // 421 ProgramFragment.Builder pfbMultiBlend = new ProgramFragment.Builder(mRS); 422 // Specify the resource that contains the shader string 423 pfbMultiBlend.setShader(mMultiTextureBlendingShader); 424 // Tell the builder how many textures we have 425 pfbMultiBlend.addTexture(Program.TextureType.TEXTURE_2D); 426 pfbMultiBlend.addTexture(Program.TextureType.TEXTURE_2D); 427 // Define the constant input layout 428 pfbMultiBlend.addConstant(mFSConst.getAllocation().getType()); 429 mMultiTextureBlendingFragmentProgram = pfbMultiBlend.create(); 430 // Bind the source of constant data 431 mMultiTextureBlendingFragmentProgram.bindConstants(mFSConst.getAllocation(), 0); 432 mMultiTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 0); 433 mMultiTextureBlendingFragmentProgram.bindSampler(Sampler.CLAMP_LINEAR(mRS), 1); 434 435 mScript.set_linearClamp(Sampler.CLAMP_LINEAR(mRS)); 436 mScript.set_singleTextureFragmentProgram(mSingleTextureFragmentProgram); 437 mScript.set_singleTextureBlendingFragmentProgram(mSingleTextureBlendingFragmentProgram); 438 mScript.set_multiTextureFragmentProgram(mMultiTextureFragmentProgram); 439 mScript.set_multiTextureBlendingFragmentProgram(mMultiTextureBlendingFragmentProgram); 440 } 441 442 private void initProgramStore() { 443 resizeProgramStoresCard(1); 444 445 final boolean dither = true; 446 final ProgramStore.DepthFunc depthFunc = mForceBlendCardsWithZ ? 447 ProgramStore.DepthFunc.LESS : ProgramStore.DepthFunc.ALWAYS; 448 449 // Background: Alpha disabled, depth optional 450 mScript.set_programStoreBackground(new ProgramStore.Builder(mRS) 451 .setBlendFunc(ProgramStore.BlendSrcFunc.ONE, ProgramStore.BlendDstFunc.ZERO) 452 .setDitherEnabled(dither) 453 .setDepthFunc(depthFunc) 454 .setDepthMaskEnabled(mForceBlendCardsWithZ) 455 .create()); 456 457 // Card: Alpha enabled, depth optional 458 setProgramStoreCard(0, new ProgramStore.Builder(mRS) 459 .setBlendFunc(ProgramStore.BlendSrcFunc.ONE, 460 ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA) 461 .setDitherEnabled(dither) 462 .setDepthFunc(depthFunc) 463 .setDepthMaskEnabled(mForceBlendCardsWithZ) 464 .create()); 465 466 // Detail: Alpha enabled, depth disabled 467 mScript.set_programStoreDetail(new ProgramStore.Builder(mRS) 468 .setBlendFunc(ProgramStore.BlendSrcFunc.ONE, 469 ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA) 470 .setDitherEnabled(dither) 471 .setDepthFunc(ProgramStore.DepthFunc.ALWAYS) 472 .setDepthMaskEnabled(false) 473 .create()); 474 } 475 476 public void createCards(int count) 477 { 478 // Because RenderScript can't have allocations with 0 dimensions, we always create 479 // an allocation of at least one card. This relies on invoke_createCards() to keep 480 // track of when the allocation is not valid. 481 if (mCards != null && count > 0) { 482 // resize the array 483 int oldSize = mCards.getAllocation().getType().getX(); 484 mCards.resize(count); 485 mScript.invoke_createCards(oldSize, count); 486 } else { 487 // create array from scratch 488 mCards = new ScriptField_Card(mRS, count > 0 ? count : 1); 489 mScript.bind_cards(mCards); 490 mScript.invoke_createCards(0, count); 491 } 492 } 493 494 public void setVisibleSlots(int count) 495 { 496 mVisibleSlots = count; 497 mScript.set_visibleSlotCount(count); 498 } 499 500 public void setVisibleDetails(int count) { 501 mScript.set_visibleDetailCount(count); 502 } 503 504 public void setRowCount(int count) { 505 mRowCount = count; 506 mScript.set_rowCount(count); 507 } 508 509 public void setRowSpacing(float spacing) { 510 mScript.set_rowSpacing(spacing); 511 } 512 513 public void setOverscrollSlots(float slots) { 514 mScript.set_overscrollSlots(slots); 515 } 516 517 public void setFirstCardTop(boolean first) { 518 mScript.set_firstCardTop(first); 519 } 520 521 public void setPrefetchCardCount(int count) { 522 mPrefetchCardCount = count; 523 mScript.set_prefetchCardCount(count); 524 } 525 526 public void setDetailTextureAlignment(int alignment) { 527 mScript.set_detailTextureAlignment(alignment); 528 } 529 530 private void resizeProgramStoresCard(int count) { 531 // enableResize works around a Renderscript bug that keeps resizes from being propagated. 532 // TODO(jshuma): Remove enableResize once the Renderscript bug is fixed 533 final boolean enableResize = false; 534 535 if (mProgramStoresCard != null && enableResize) { 536 int newSize = count > 0 ? count : 1; 537 mProgramStoresCard.resize(newSize); 538 } else { 539 mProgramStoresCard = new ScriptField_ProgramStore_s(mRS, count > 0 ? count : 1); 540 mScript.bind_programStoresCard(mProgramStoresCard); 541 } 542 } 543 544 private void setProgramStoreCard(int n, ProgramStore programStore) { 545 ScriptField_ProgramStore_s.Item item = mProgramStoresCard.get(n); 546 if (item == null) { 547 item = new ScriptField_ProgramStore_s.Item(); 548 } 549 item.programStore = programStore; 550 mProgramStoresCard.set(item, n, false); 551 mScript.invoke_setProgramStoresCard(n, programStore); 552 } 553 554 public void setStoreConfigs(int configs[]) { 555 if (configs == null) { 556 initProgramStore(); 557 return; 558 } 559 560 final int count = configs.length; 561 562 resizeProgramStoresCard(count); 563 for (int i=0; i<count; ++i) { 564 final int config = configs[i]; 565 566 final boolean alpha = (config & CarouselController.STORE_CONFIG_ALPHA) != 0; 567 final boolean depthReads = (config & CarouselController.STORE_CONFIG_DEPTH_READS) != 0; 568 final boolean depthWrites = 569 (config & CarouselController.STORE_CONFIG_DEPTH_WRITES) != 0; 570 571 final boolean dither = true; 572 final ProgramStore.BlendDstFunc dstFunc = alpha ? 573 ProgramStore.BlendDstFunc.ONE_MINUS_SRC_ALPHA : 574 ProgramStore.BlendDstFunc.ZERO; 575 final ProgramStore.DepthFunc depthFunc = depthReads ? 576 ProgramStore.DepthFunc.LESS : 577 ProgramStore.DepthFunc.ALWAYS; 578 579 final ProgramStore ps = new ProgramStore.Builder(mRS) 580 .setBlendFunc(ProgramStore.BlendSrcFunc.ONE, dstFunc) 581 .setDitherEnabled(dither) 582 .setDepthFunc(depthFunc) 583 .setDepthMaskEnabled(depthWrites) 584 .create(); 585 586 setProgramStoreCard(i, ps); 587 } 588 } 589 590 /** 591 * Sets whether the background texture and default card geometry are to be drawn with respect 592 * to the depth buffer (both reading from it and writing to it). 593 * 594 * This method is a specialization of functionality that can be done with greater flexibility 595 * by setStoreConfigs. Calling setForceBlendCardsWithZ() after calling setStoreConfigs() 596 * results in the values set in setStoreConfigs() being discarded. 597 * 598 * @param enabled true to read from and write to the depth buffer, false to ignore it 599 */ 600 public void setForceBlendCardsWithZ(boolean enabled) { 601 mForceBlendCardsWithZ = enabled; 602 initProgramStore(); 603 } 604 605 public void setDrawRuler(boolean drawRuler) { 606 mScript.set_drawRuler(drawRuler); 607 } 608 609 public void setDefaultBitmap(Bitmap bitmap) 610 { 611 mScript.set_defaultTexture(allocationFromBitmap(bitmap, MIPMAP)); 612 } 613 614 public void setLoadingBitmap(Bitmap bitmap) 615 { 616 mScript.set_loadingTexture(allocationFromBitmap(bitmap, MIPMAP)); 617 } 618 619 public void setDefaultGeometry(Mesh mesh) 620 { 621 mScript.set_defaultGeometry(mesh); 622 } 623 624 public void setLoadingGeometry(Mesh mesh) 625 { 626 mScript.set_loadingGeometry(mesh); 627 } 628 629 public void setStartAngle(float theta) 630 { 631 mScript.set_startAngle(theta); 632 } 633 634 public void setCarouselRotationAngle(float theta) { 635 mScript.invoke_setCarouselRotationAngle(theta); 636 } 637 638 public void setCarouselRotationAngle(float endAngle, int milliseconds, int interpolationMode, 639 float maxAnimatedArc) { 640 mScript.invoke_setCarouselRotationAngle2(endAngle, milliseconds, interpolationMode, 641 maxAnimatedArc); 642 } 643 644 public void setCallback(CarouselCallback callback) 645 { 646 mCallback = callback; 647 } 648 649 private Allocation allocationFromBitmap(Bitmap bitmap, Allocation.MipmapControl mipmap) 650 { 651 if (bitmap == null) return null; 652 Allocation allocation = Allocation.createFromBitmap(mRS, bitmap, 653 mipmap, Allocation.USAGE_GRAPHICS_TEXTURE); 654 return allocation; 655 } 656 657 private Allocation allocationFromPool(int n, Bitmap bitmap, Allocation.MipmapControl mipmap) 658 { 659 int count = (mVisibleSlots + 2*mPrefetchCardCount) * mRowCount; 660 if (mAllocationPool == null || mAllocationPool.length != count) { 661 Allocation[] tmp = new Allocation[count]; 662 int oldsize = mAllocationPool == null ? 0 : mAllocationPool.length; 663 for (int i = 0; i < Math.min(count, oldsize); i++) { 664 tmp[i] = mAllocationPool[i]; 665 } 666 mAllocationPool = tmp; 667 } 668 Allocation allocation = mAllocationPool[n % count]; 669 if (allocation == null) { 670 allocation = allocationFromBitmap(bitmap, mipmap); 671 mAllocationPool[n % count] = allocation; 672 } else if (bitmap != null) { 673 if (bitmap.getWidth() == allocation.getType().getX() 674 && bitmap.getHeight() == allocation.getType().getY()) { 675 allocation.copyFrom(bitmap); 676 } else { 677 Log.v(TAG, "Warning, bitmap has different size. Taking slow path"); 678 allocation = allocationFromBitmap(bitmap, mipmap); 679 mAllocationPool[n % count] = allocation; 680 } 681 } 682 return allocation; 683 } 684 685 private ScriptField_Card.Item getCard(int n) { 686 ScriptField_Card.Item item; 687 try { 688 item = mCards.get(n); 689 } 690 catch (ArrayIndexOutOfBoundsException e) { 691 if (DBG) Log.v(TAG, "getCard(): no item at index " + n); 692 item = null; 693 } 694 return item; 695 } 696 697 private ScriptField_Card.Item getOrCreateCard(int n) { 698 ScriptField_Card.Item item = getCard(n); 699 if (item == null) { 700 if (DBG) Log.v(TAG, "getOrCreateCard(): no item at index " + n + "; creating new"); 701 item = new ScriptField_Card.Item(); 702 } 703 return item; 704 } 705 706 private void setCard(int n, ScriptField_Card.Item item) { 707 try { 708 mCards.set(item, n, false); // This is primarily used for reference counting. 709 } 710 catch (ArrayIndexOutOfBoundsException e) { 711 // The specified index didn't exist. This can happen when a stale invalidate 712 // request outlived an array resize request. Something might be getting dropped, 713 // but there's not much we can do about this at this point to recover. 714 Log.w(TAG, "setCard(" + n + "): Texture " + n + " doesn't exist"); 715 } 716 } 717 718 public void setTexture(int n, Bitmap bitmap) 719 { 720 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 721 722 synchronized(this) { 723 ScriptField_Card.Item item = getOrCreateCard(n); 724 if (bitmap != null) { 725 item.texture = allocationFromPool(n, bitmap, MIPMAP); 726 } else { 727 if (item.texture != null) { 728 if (DBG) Log.v(TAG, "unloading texture " + n); 729 item.texture = null; 730 } 731 } 732 setCard(n, item); 733 mScript.invoke_setTexture(n, item.texture); 734 } 735 } 736 737 void setDetailTexture(int n, float offx, float offy, float loffx, float loffy, Bitmap bitmap) 738 { 739 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 740 741 synchronized(this) { 742 ScriptField_Card.Item item = getOrCreateCard(n); 743 float width = 0.0f; 744 float height = 0.0f; 745 if (bitmap != null) { 746 item.detailTexture = allocationFromBitmap(bitmap, MIPMAP); 747 width = bitmap.getWidth(); 748 height = bitmap.getHeight(); 749 } else { 750 if (item.detailTexture != null) { 751 if (DBG) Log.v(TAG, "unloading detail texture " + n); 752 // Don't wait for GC to free native memory. 753 // Only works if textures are not shared. 754 item.detailTexture.destroy(); 755 item.detailTexture = null; 756 } 757 } 758 setCard(n, item); 759 mScript.invoke_setDetailTexture(n, offx, offy, loffx, loffy, item.detailTexture); 760 } 761 } 762 763 void invalidateTexture(int n, boolean eraseCurrent) 764 { 765 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 766 767 synchronized(this) { 768 ScriptField_Card.Item item = getCard(n); 769 if (item == null) { 770 // This card was never created, so there's nothing to invalidate. 771 return; 772 } 773 if (eraseCurrent && item.texture != null) { 774 if (DBG) Log.v(TAG, "unloading texture " + n); 775 // Don't wait for GC to free native memory. 776 // Only works if textures are not shared. 777 item.texture.destroy(); 778 item.texture = null; 779 } 780 setCard(n, item); 781 mScript.invoke_invalidateTexture(n, eraseCurrent); 782 } 783 } 784 785 void invalidateDetailTexture(int n, boolean eraseCurrent) 786 { 787 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 788 789 synchronized(this) { 790 ScriptField_Card.Item item = getCard(n); 791 if (item == null) { 792 // This card was never created, so there's nothing to invalidate. 793 return; 794 } 795 if (eraseCurrent && item.detailTexture != null) { 796 if (DBG) Log.v(TAG, "unloading detail texture " + n); 797 // Don't wait for GC to free native memory. 798 // Only works if textures are not shared. 799 item.detailTexture.destroy(); 800 item.detailTexture = null; 801 } 802 setCard(n, item); 803 mScript.invoke_invalidateDetailTexture(n, eraseCurrent); 804 } 805 } 806 807 public void setGeometry(int n, Mesh geometry) 808 { 809 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 810 811 synchronized(this) { 812 final boolean mipmap = false; 813 ScriptField_Card.Item item = getOrCreateCard(n); 814 if (geometry != null) { 815 item.geometry = geometry; 816 } else { 817 if (DBG) Log.v(TAG, "unloading geometry " + n); 818 if (item.geometry != null) { 819 // item.geometry.destroy(); 820 item.geometry = null; 821 } 822 } 823 setCard(n, item); 824 mScript.invoke_setGeometry(n, item.geometry); 825 } 826 } 827 828 public void setMatrix(int n, float[] matrix) { 829 if (n < 0) throw new IllegalArgumentException("Index cannot be negative"); 830 831 synchronized(this) { 832 final boolean mipmap = false; 833 ScriptField_Card.Item item = getOrCreateCard(n); 834 if (matrix != null) { 835 item.matrix = matrixFromFloat(matrix); 836 } else { 837 if (DBG) Log.v(TAG, "unloading matrix " + n); 838 item.matrix = null; 839 } 840 setCard(n, item); 841 mScript.invoke_setMatrix(n, item.matrix); 842 } 843 } 844 845 public void setBackgroundColor(Float4 color) { 846 mScript.set_backgroundColor(color); 847 } 848 849 public void setBackgroundTexture(Bitmap bitmap) { 850 Allocation texture = null; 851 if (bitmap != null) { 852 texture = Allocation.createFromBitmap(mRS, bitmap, 853 MIPMAP, Allocation.USAGE_GRAPHICS_TEXTURE); 854 } 855 mScript.set_backgroundTexture(texture); 856 } 857 858 public void setDetailLineTexture(Bitmap bitmap) { 859 Allocation texture = null; 860 if (bitmap != null) { 861 texture = Allocation.createFromBitmap(mRS, bitmap, 862 MIPMAP, Allocation.USAGE_GRAPHICS_TEXTURE); 863 } 864 mScript.set_detailLineTexture(texture); 865 } 866 867 public void setDetailLoadingTexture(Bitmap bitmap) { 868 Allocation texture = null; 869 if (bitmap != null) { 870 texture = Allocation.createFromBitmap(mRS, bitmap, 871 MIPMAP, Allocation.USAGE_GRAPHICS_TEXTURE); 872 } 873 mScript.set_detailLoadingTexture(texture); 874 } 875 876 public void pauseRendering() { 877 // Used to update multiple states at once w/o redrawing for each. 878 mRS.bindRootScript(null); 879 } 880 881 public void resumeRendering() { 882 mRS.bindRootScript(mScript); 883 } 884 885 public void doLongPress() { 886 mScript.invoke_doLongPress(); 887 } 888 889 public void doMotion(float x, float y, long t) { 890 mScript.invoke_doMotion(x, y, t); 891 } 892 893 public void doStart(float x, float y, long t) { 894 mScript.invoke_doStart(x, y, t); 895 } 896 897 public void doStop(float x, float y, long t) { 898 mScript.invoke_doStop(x, y, t); 899 } 900 901 public void setSlotCount(int n) { 902 mScript.set_slotCount(n); 903 } 904 905 public void setRezInCardCount(float alpha) { 906 mScript.set_rezInCardCount(alpha); 907 } 908 909 public void setFadeInDuration(long t) { 910 mScript.set_fadeInDuration((int)t); // TODO: Remove cast when RS supports exporting longs 911 } 912 913 public void setCardCreationFadeDuration(long t) { 914 mScript.set_cardCreationFadeDuration((int)t); 915 } 916 917 private Element elementForBitmap(Bitmap bitmap, Bitmap.Config defaultConfig) { 918 Bitmap.Config config = bitmap.getConfig(); 919 if (config == null) { 920 config = defaultConfig; 921 } 922 if (config == Bitmap.Config.ALPHA_8) { 923 return A_8(mRS); 924 } else if (config == Bitmap.Config.RGB_565) { 925 return RGB_565(mRS); 926 } else if (config == Bitmap.Config.ARGB_4444) { 927 return RGBA_4444(mRS); 928 } else if (config == Bitmap.Config.ARGB_8888) { 929 return RGBA_8888(mRS); 930 } else { 931 throw new IllegalArgumentException("Unknown configuration"); 932 } 933 } 934 935 public Mesh loadGeometry(int resId) { 936 if (resId == 0) { 937 return null; 938 } 939 FileA3D model = FileA3D.createFromResource(mRS, mRes, resId); 940 if (model == null) { 941 return null; 942 } 943 FileA3D.IndexEntry entry = model.getIndexEntry(0); 944 if(entry == null || entry.getEntryType() != FileA3D.EntryType.MESH) { 945 return null; 946 } 947 return (Mesh) entry.getObject(); 948 } 949 } 950