/** Updates bitmaps for page meshes. */ private void updatePages() { Log.d("artbook", ">>>>>update page(s): " + Thread.currentThread()); if (mPageProvider == null || mPageBitmapWidth <= 0 || mPageBitmapHeight <= 0) { return; } // Remove meshes from renderer. mRenderer.removeCurlMesh(mPageLeft); mRenderer.removeCurlMesh(mPageRight); mRenderer.removeCurlMesh(mPageCurl); int leftIdx = mCurrentIndex - 1; int rightIdx = mCurrentIndex; int curlIdx = -1; if (mCurlState == CURL_LEFT) { curlIdx = leftIdx; --leftIdx; } else if (mCurlState == CURL_RIGHT) { curlIdx = rightIdx; ++rightIdx; } if (rightIdx >= 0 && rightIdx < mPageProvider.getPageCount()) { updatePage(mPageRight.getTexturePage(), rightIdx); mPageRight.setFlipTexture(false); mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); mPageRight.reset(); mRenderer.addCurlMesh(mPageRight); } if (leftIdx >= 0 && leftIdx < mPageProvider.getPageCount()) { updatePage(mPageLeft.getTexturePage(), leftIdx); mPageLeft.setFlipTexture(true); mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); mPageLeft.reset(); if (mRenderLeftPage) { mRenderer.addCurlMesh(mPageLeft); } } if (curlIdx >= 0 && curlIdx < mPageProvider.getPageCount()) { updatePage(mPageCurl.getTexturePage(), curlIdx); if (mCurlState == CURL_RIGHT) { mPageCurl.setFlipTexture(true); mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); } else { mPageCurl.setFlipTexture(false); mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); } mPageCurl.reset(); mRenderer.addCurlMesh(mPageCurl); } }
/** * Set current page index. Page indices are zero based values presenting page being shown on right * side of the book. E.g if you set value to 4; right side front facing bitmap will be with index * 4, back facing 5 and for left side page index 3 is front facing, and index 2 back facing (once * page is on left side it's flipped over). * * <p>Current index is rounded to closest value divisible with 2. */ public void setCurrentIndex(int index) { Log.d("artbook", ">>>>>set current index " + Thread.currentThread()); if (mPageProvider == null || index < 0) { mCurrentIndex = 0; } else { if (mAllowLastPageCurl) { mCurrentIndex = Math.min(index, mPageProvider.getPageCount()); } else { mCurrentIndex = Math.min(index, mPageProvider.getPageCount() - 1); } } updatePages(); requestRender(); }
/** Switches meshes and loads new bitmaps if available. Updated to support 2 pages in landscape */ private void startCurl(int page) { switch (page) { // Once right side page is curled, first right page is assigned into // curled page. And if there are more bitmaps available new bitmap is // loaded into right side mesh. case CURL_RIGHT: { // Remove meshes from renderer. mRenderer.removeCurlMesh(mPageLeft); mRenderer.removeCurlMesh(mPageRight); mRenderer.removeCurlMesh(mPageCurl); // We are curling right page. CurlMesh curl = mPageRight; mPageRight = mPageCurl; mPageCurl = curl; if (mCurrentIndex > 0) { mPageLeft.setFlipTexture(true); mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); mPageLeft.reset(); if (mRenderLeftPage) { mRenderer.addCurlMesh(mPageLeft); } } if (mCurrentIndex < mPageProvider.getPageCount() - 1) { updatePage(mPageRight.getTexturePage(), mCurrentIndex + 1); mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); mPageRight.setFlipTexture(false); mPageRight.reset(); mRenderer.addCurlMesh(mPageRight); } // Add curled page to renderer. mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); mPageCurl.setFlipTexture(false); mPageCurl.reset(); mRenderer.addCurlMesh(mPageCurl); mCurlState = CURL_RIGHT; break; } // On left side curl, left page is assigned to curled page. And if // there are more bitmaps available before currentIndex, new bitmap // is loaded into left page. case CURL_LEFT: { // Remove meshes from renderer. mRenderer.removeCurlMesh(mPageLeft); mRenderer.removeCurlMesh(mPageRight); mRenderer.removeCurlMesh(mPageCurl); // We are curling left page. CurlMesh curl = mPageLeft; mPageLeft = mPageCurl; mPageCurl = curl; if (mCurrentIndex > 1) { updatePage(mPageLeft.getTexturePage(), mCurrentIndex - 2); mPageLeft.setFlipTexture(true); mPageLeft.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); mPageLeft.reset(); if (mRenderLeftPage) { mRenderer.addCurlMesh(mPageLeft); } } // If there is something to show on right page add it to renderer. if (mCurrentIndex < mPageProvider.getPageCount()) { mPageRight.setFlipTexture(false); mPageRight.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); mPageRight.reset(); mRenderer.addCurlMesh(mPageRight); } // How dragging previous page happens depends on view mode. if (mViewMode == SHOW_ONE_PAGE || (mCurlState == CURL_LEFT && mViewMode == SHOW_TWO_PAGES)) { mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT)); mPageCurl.setFlipTexture(false); } else { mPageCurl.setRect(mRenderer.getPageRect(CurlRenderer.PAGE_LEFT)); mPageCurl.setFlipTexture(true); } mPageCurl.reset(); mRenderer.addCurlMesh(mPageCurl); mCurlState = CURL_LEFT; break; } } }
@Override public boolean onTouch(View view, MotionEvent me) { // No dragging during animation at the moment. // TODO: Stop animation on touch event and return to drag mode. if (mAnimate || mPageProvider == null) { return false; } // We need page rects quite extensively so get them for later use. RectF rightRect = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT); RectF leftRect = mRenderer.getPageRect(CurlRenderer.PAGE_LEFT); // Store pointer position. mPointerPos.mPos.set(me.getX(), me.getY()); mRenderer.translate(mPointerPos.mPos); if (mEnableTouchPressure) { mPointerPos.mPressure = me.getPressure(); } else { mPointerPos.mPressure = 0.8f; } switch (me.getAction()) { case MotionEvent.ACTION_DOWN: { // Once we receive pointer down event its position is mapped to // right or left edge of page and that'll be the position from where // user is holding the paper to make curl happen. mDragStartPos.set(mPointerPos.mPos); // First we make sure it's not over or below page. Pages are // supposed to be same height so it really doesn't matter do we use // left or right one. if (mDragStartPos.y > rightRect.top) { mDragStartPos.y = rightRect.top; } else if (mDragStartPos.y < rightRect.bottom) { mDragStartPos.y = rightRect.bottom; } // Then we have to make decisions for the user whether curl is going // to happen from left or right, and on which page. if (mViewMode == SHOW_TWO_PAGES) { // If we have an open book and pointer is on the left from right // page we'll mark drag position to left edge of left page. // Additionally checking mCurrentIndex is higher than zero tells // us there is a visible page at all. if (mDragStartPos.x < rightRect.left && mCurrentIndex > 0) { mDragStartPos.x = leftRect.left; startCurl(CURL_LEFT); } // Otherwise check pointer is on right page's side. else if (mDragStartPos.x >= rightRect.left && mCurrentIndex < mPageProvider.getPageCount()) { mDragStartPos.x = rightRect.right; if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider.getPageCount() - 1) { return false; } startCurl(CURL_RIGHT); } } else if (mViewMode == SHOW_ONE_PAGE) { float halfX = (rightRect.right + rightRect.left) / 2; if (mDragStartPos.x < halfX && mCurrentIndex > 0) { mDragStartPos.x = rightRect.left; startCurl(CURL_LEFT); } else if (mDragStartPos.x >= halfX && mCurrentIndex < mPageProvider.getPageCount()) { mDragStartPos.x = rightRect.right; if (!mAllowLastPageCurl && mCurrentIndex >= mPageProvider.getPageCount() - 1) { return false; } startCurl(CURL_RIGHT); } } // If we have are in curl state, let this case clause flow through // to next one. We have pointer position and drag position defined // and this will create first render request given these points. if (mCurlState == CURL_NONE) { return false; } } case MotionEvent.ACTION_MOVE: { updateCurlPos(mPointerPos); break; } case MotionEvent.ACTION_CANCEL: case MotionEvent.ACTION_UP: { if (mCurlState == CURL_LEFT || mCurlState == CURL_RIGHT) { // Animation source is the point from where animation starts. // Also it's handled in a way we actually simulate touch events // meaning the output is exactly the same as if user drags the // page to other side. While not producing the best looking // result (which is easier done by altering curl position and/or // direction directly), this is done in a hope it made code a // bit more readable and easier to maintain. mAnimationSource.set(mPointerPos.mPos); mAnimationStartTime = System.currentTimeMillis(); // Given the explanation, here we decide whether to simulate // drag to left or right end. if ((mViewMode == SHOW_ONE_PAGE && mPointerPos.mPos.x > (rightRect.left + rightRect.right) / 2) || mViewMode == SHOW_TWO_PAGES && mPointerPos.mPos.x > rightRect.left) { // On right side target is always right page's right border. mAnimationTarget.set(mDragStartPos); mAnimationTarget.x = mRenderer.getPageRect(CurlRenderer.PAGE_RIGHT).right; mAnimationTargetEvent = SET_CURL_TO_RIGHT; } else { // On left side target depends on visible pages. mAnimationTarget.set(mDragStartPos); if (mCurlState == CURL_RIGHT || mViewMode == SHOW_TWO_PAGES) { mAnimationTarget.x = leftRect.left; } else { mAnimationTarget.x = rightRect.left; } mAnimationTargetEvent = SET_CURL_TO_LEFT; } mAnimate = true; requestRender(); } break; } } return true; }