AI 143309: am: CL 143160 am: CL 142856 new-new-new-new rotation animation. it may still change one more time.
Original author: mathias
Merged from: //branches/cupcake/...
Original author: android-build
Merged from: //branches/donutburger/...
Automated import of CL 143309
diff --git a/libs/surfaceflinger/LayerOrientationAnimRotate.cpp b/libs/surfaceflinger/LayerOrientationAnimRotate.cpp
new file mode 100644
index 0000000..12d5d80
--- /dev/null
+++ b/libs/surfaceflinger/LayerOrientationAnimRotate.cpp
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2007 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.
+ */
+
+#define LOG_TAG "SurfaceFlinger"
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <sys/types.h>
+
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+#include <core/SkBitmap.h>
+
+#include <ui/EGLDisplaySurface.h>
+
+#include "LayerBase.h"
+#include "LayerOrientationAnim.h"
+#include "LayerOrientationAnimRotate.h"
+#include "SurfaceFlinger.h"
+#include "DisplayHardware/DisplayHardware.h"
+#include "OrientationAnimation.h"
+
+namespace android {
+// ---------------------------------------------------------------------------
+
+const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
+const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
+
+// ---------------------------------------------------------------------------
+
+const float ROTATION = M_PI * 0.5f;
+const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
+const float DURATION = ms2ns(200);
+const float BOUNCES_PER_SECOND = 0.8;
+const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
+
+LayerOrientationAnimRotate::LayerOrientationAnimRotate(
+ SurfaceFlinger* flinger, DisplayID display,
+ OrientationAnimation* anim,
+ const LayerBitmap& bitmap,
+ const LayerBitmap& bitmapIn)
+ : LayerOrientationAnimBase(flinger, display), mAnim(anim),
+ mBitmap(bitmap), mBitmapIn(bitmapIn),
+ mTextureName(-1), mTextureNameIn(-1)
+{
+ mStartTime = systemTime();
+ mFinishTime = 0;
+ mOrientationCompleted = false;
+ mFirstRedraw = false;
+ mLastNormalizedTime = 0;
+ mLastAngle = 0;
+ mLastScale = 0;
+ mNeedsBlending = false;
+}
+
+LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
+{
+ if (mTextureName != -1U) {
+ LayerBase::deletedTextures.add(mTextureName);
+ }
+ if (mTextureNameIn != -1U) {
+ LayerBase::deletedTextures.add(mTextureNameIn);
+ }
+}
+
+bool LayerOrientationAnimRotate::needsBlending() const
+{
+ return mNeedsBlending;
+}
+
+Point LayerOrientationAnimRotate::getPhysicalSize() const
+{
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ return Point(hw.getWidth(), hw.getHeight());
+}
+
+void LayerOrientationAnimRotate::validateVisibility(const Transform&)
+{
+ const Layer::State& s(drawingState());
+ const Transform tr(s.transform);
+ const Point size(getPhysicalSize());
+ uint32_t w = size.x;
+ uint32_t h = size.y;
+ mTransformedBounds = tr.makeBounds(w, h);
+ mLeft = tr.tx();
+ mTop = tr.ty();
+ transparentRegionScreen.clear();
+ mTransformed = true;
+ mCanUseCopyBit = false;
+}
+
+void LayerOrientationAnimRotate::onOrientationCompleted()
+{
+ mFinishTime = systemTime();
+ mOrientationCompleted = true;
+ mFirstRedraw = true;
+ mNeedsBlending = true;
+ mFlinger->invalidateLayerVisibility(this);
+}
+
+void LayerOrientationAnimRotate::onDraw(const Region& clip) const
+{
+ // Animation...
+
+ // FIXME: works only for portrait framebuffers
+ const Point size(getPhysicalSize());
+ const float TARGET_SCALE = size.x * (1.0f / size.y);
+
+ const nsecs_t now = systemTime();
+ float angle, scale, alpha;
+
+ if (mOrientationCompleted) {
+ if (mFirstRedraw) {
+ // make a copy of what's on screen
+ copybit_image_t image;
+ mBitmapIn.getBitmapSurface(&image);
+ const DisplayHardware& hw(graphicPlane(0).displayHardware());
+ hw.copyBackToImage(image);
+
+ // FIXME: code below is gross
+ mFirstRedraw = false;
+ mNeedsBlending = false;
+ LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
+ mFlinger->invalidateLayerVisibility(self);
+ }
+
+ // make sure pick-up where we left off
+ const float duration = DURATION * mLastNormalizedTime;
+ const float normalizedTime = (float(now - mFinishTime) / duration);
+ if (normalizedTime <= 1.0f) {
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
+ scale = (1.0f - mLastScale)*squaredTime + mLastScale;
+ alpha = normalizedTime;
+ } else {
+ mAnim->onAnimationFinished();
+ angle = ROTATION;
+ alpha = 1.0f;
+ scale = 1.0f;
+ }
+ } else {
+ const float normalizedTime = float(now - mStartTime) / DURATION;
+ if (normalizedTime <= 1.0f) {
+ mLastNormalizedTime = normalizedTime;
+ const float squaredTime = normalizedTime*normalizedTime;
+ angle = ROTATION * squaredTime;
+ scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
+ alpha = 0;
+ } else {
+ mLastNormalizedTime = 1.0f;
+ angle = ROTATION;
+ if (BOUNCES_AMPLITUDE) {
+ const float to_seconds = DURATION / seconds(1);
+ const float phi = BOUNCES_PER_SECOND *
+ (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
+ angle += BOUNCES_AMPLITUDE * sinf(phi);
+ }
+ scale = TARGET_SCALE;
+ alpha = 0;
+ }
+ mLastAngle = angle;
+ mLastScale = scale;
+ }
+ drawScaled(angle, scale, alpha);
+}
+
+void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
+{
+ copybit_image_t dst;
+ const GraphicPlane& plane(graphicPlane(0));
+ const DisplayHardware& hw(plane.displayHardware());
+ hw.getDisplaySurface(&dst);
+
+ // clear screen
+ // TODO: with update on demand, we may be able
+ // to not erase the screen at all during the animation
+ glDisable(GL_BLEND);
+ glDisable(GL_DITHER);
+ glDisable(GL_SCISSOR_TEST);
+ glClearColor(0,0,0,0);
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ const int w = dst.w;
+ const int h = dst.h;
+
+ copybit_image_t src;
+ mBitmap.getBitmapSurface(&src);
+ const copybit_rect_t srect = { 0, 0, src.w, src.h };
+
+
+ GGLSurface t;
+ t.version = sizeof(GGLSurface);
+ t.width = src.w;
+ t.height = src.h;
+ t.stride = src.w;
+ t.vstride= src.h;
+ t.format = src.format;
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+
+ const int targetOrientation = plane.getOrientation();
+ if (!targetOrientation) {
+ f = -f;
+ }
+
+ Transform tr;
+ tr.set(f, w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+
+ // FIXME: we should not access mVertices and mDrawingState like that,
+ // but since we control the animation, we know it's going to work okay.
+ // eventually we'd need a more formal way of doing things like this.
+ LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
+ // Too slow to do this in software
+ self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
+ }
+
+ if (UNLIKELY(mTextureName == -1LU)) {
+ mTextureName = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureName, t, w, h);
+ }
+ self.mDrawingState.alpha = 255; //-int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureName, t);
+
+ if (alpha > 0) {
+ const float sign = (!targetOrientation) ? 1.0f : -1.0f;
+ tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
+ tr.scale(s, w*0.5f, h*0.5f);
+ tr.transform(self.mVertices[0], 0, 0);
+ tr.transform(self.mVertices[1], 0, src.h);
+ tr.transform(self.mVertices[2], src.w, src.h);
+ tr.transform(self.mVertices[3], src.w, 0);
+
+ copybit_image_t src;
+ mBitmapIn.getBitmapSurface(&src);
+ t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
+ if (UNLIKELY(mTextureNameIn == -1LU)) {
+ mTextureNameIn = createTexture();
+ GLuint w=0, h=0;
+ const Region dirty(Rect(t.width, t.height));
+ loadTexture(dirty, mTextureNameIn, t, w, h);
+ }
+ self.mDrawingState.alpha = int(alpha*255);
+ const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
+ drawWithOpenGL(clip, mTextureNameIn, t);
+ }
+}
+
+// ---------------------------------------------------------------------------
+
+}; // namespace android