blob: 89ffb19ffb00c3e10f013463f7d6e8b9f394ec17 [file] [log] [blame]
Mathias Agopian0d1318b2009-03-27 17:58:20 -07001/*
2 * Copyright (C) 2007 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#define LOG_TAG "SurfaceFlinger"
18
19#include <stdlib.h>
20#include <stdint.h>
21#include <sys/types.h>
22
23#include <utils/Errors.h>
24#include <utils/Log.h>
25
26#include <core/SkBitmap.h>
27
28#include <ui/EGLDisplaySurface.h>
29
30#include "LayerBase.h"
31#include "LayerOrientationAnim.h"
32#include "LayerOrientationAnimRotate.h"
33#include "SurfaceFlinger.h"
34#include "DisplayHardware/DisplayHardware.h"
35#include "OrientationAnimation.h"
36
37namespace android {
38// ---------------------------------------------------------------------------
39
40const uint32_t LayerOrientationAnimRotate::typeInfo = LayerBase::typeInfo | 0x100;
41const char* const LayerOrientationAnimRotate::typeID = "LayerOrientationAnimRotate";
42
43// ---------------------------------------------------------------------------
44
45const float ROTATION = M_PI * 0.5f;
46const float ROTATION_FACTOR = 1.0f; // 1.0 or 2.0
47const float DURATION = ms2ns(200);
48const float BOUNCES_PER_SECOND = 0.8;
49const float BOUNCES_AMPLITUDE = (5.0f/180.f) * M_PI;
50
51LayerOrientationAnimRotate::LayerOrientationAnimRotate(
52 SurfaceFlinger* flinger, DisplayID display,
53 OrientationAnimation* anim,
54 const LayerBitmap& bitmap,
55 const LayerBitmap& bitmapIn)
56 : LayerOrientationAnimBase(flinger, display), mAnim(anim),
57 mBitmap(bitmap), mBitmapIn(bitmapIn),
58 mTextureName(-1), mTextureNameIn(-1)
59{
60 mStartTime = systemTime();
61 mFinishTime = 0;
62 mOrientationCompleted = false;
63 mFirstRedraw = false;
64 mLastNormalizedTime = 0;
65 mLastAngle = 0;
66 mLastScale = 0;
67 mNeedsBlending = false;
Mathias Agopian253ed062009-03-27 18:12:49 -070068 const GraphicPlane& plane(graphicPlane(0));
69 mOriginalTargetOrientation = plane.getOrientation();
Mathias Agopian0d1318b2009-03-27 17:58:20 -070070}
71
72LayerOrientationAnimRotate::~LayerOrientationAnimRotate()
73{
74 if (mTextureName != -1U) {
75 LayerBase::deletedTextures.add(mTextureName);
76 }
77 if (mTextureNameIn != -1U) {
78 LayerBase::deletedTextures.add(mTextureNameIn);
79 }
80}
81
82bool LayerOrientationAnimRotate::needsBlending() const
83{
84 return mNeedsBlending;
85}
86
87Point LayerOrientationAnimRotate::getPhysicalSize() const
88{
89 const GraphicPlane& plane(graphicPlane(0));
90 const DisplayHardware& hw(plane.displayHardware());
91 return Point(hw.getWidth(), hw.getHeight());
92}
93
94void LayerOrientationAnimRotate::validateVisibility(const Transform&)
95{
96 const Layer::State& s(drawingState());
97 const Transform tr(s.transform);
98 const Point size(getPhysicalSize());
99 uint32_t w = size.x;
100 uint32_t h = size.y;
101 mTransformedBounds = tr.makeBounds(w, h);
102 mLeft = tr.tx();
103 mTop = tr.ty();
104 transparentRegionScreen.clear();
105 mTransformed = true;
106 mCanUseCopyBit = false;
107}
108
109void LayerOrientationAnimRotate::onOrientationCompleted()
110{
111 mFinishTime = systemTime();
112 mOrientationCompleted = true;
113 mFirstRedraw = true;
114 mNeedsBlending = true;
115 mFlinger->invalidateLayerVisibility(this);
116}
117
118void LayerOrientationAnimRotate::onDraw(const Region& clip) const
119{
120 // Animation...
121
Mathias Agopian0d1318b2009-03-27 17:58:20 -0700122 const nsecs_t now = systemTime();
123 float angle, scale, alpha;
124
125 if (mOrientationCompleted) {
126 if (mFirstRedraw) {
127 // make a copy of what's on screen
128 copybit_image_t image;
129 mBitmapIn.getBitmapSurface(&image);
130 const DisplayHardware& hw(graphicPlane(0).displayHardware());
131 hw.copyBackToImage(image);
132
133 // FIXME: code below is gross
134 mFirstRedraw = false;
135 mNeedsBlending = false;
136 LayerOrientationAnimRotate* self(const_cast<LayerOrientationAnimRotate*>(this));
137 mFlinger->invalidateLayerVisibility(self);
138 }
139
140 // make sure pick-up where we left off
141 const float duration = DURATION * mLastNormalizedTime;
142 const float normalizedTime = (float(now - mFinishTime) / duration);
143 if (normalizedTime <= 1.0f) {
144 const float squaredTime = normalizedTime*normalizedTime;
145 angle = (ROTATION*ROTATION_FACTOR - mLastAngle)*squaredTime + mLastAngle;
146 scale = (1.0f - mLastScale)*squaredTime + mLastScale;
147 alpha = normalizedTime;
148 } else {
149 mAnim->onAnimationFinished();
150 angle = ROTATION;
151 alpha = 1.0f;
152 scale = 1.0f;
153 }
154 } else {
Mathias Agopian253ed062009-03-27 18:12:49 -0700155 // FIXME: works only for portrait framebuffers
156 const Point size(getPhysicalSize());
157 const float TARGET_SCALE = size.x * (1.0f / size.y);
Mathias Agopian0d1318b2009-03-27 17:58:20 -0700158 const float normalizedTime = float(now - mStartTime) / DURATION;
159 if (normalizedTime <= 1.0f) {
160 mLastNormalizedTime = normalizedTime;
161 const float squaredTime = normalizedTime*normalizedTime;
162 angle = ROTATION * squaredTime;
163 scale = (TARGET_SCALE - 1.0f)*squaredTime + 1.0f;
164 alpha = 0;
165 } else {
166 mLastNormalizedTime = 1.0f;
167 angle = ROTATION;
168 if (BOUNCES_AMPLITUDE) {
169 const float to_seconds = DURATION / seconds(1);
170 const float phi = BOUNCES_PER_SECOND *
171 (((normalizedTime - 1.0f) * to_seconds)*M_PI*2);
172 angle += BOUNCES_AMPLITUDE * sinf(phi);
173 }
174 scale = TARGET_SCALE;
175 alpha = 0;
176 }
177 mLastAngle = angle;
178 mLastScale = scale;
179 }
180 drawScaled(angle, scale, alpha);
181}
182
183void LayerOrientationAnimRotate::drawScaled(float f, float s, float alpha) const
184{
185 copybit_image_t dst;
186 const GraphicPlane& plane(graphicPlane(0));
187 const DisplayHardware& hw(plane.displayHardware());
188 hw.getDisplaySurface(&dst);
189
190 // clear screen
191 // TODO: with update on demand, we may be able
192 // to not erase the screen at all during the animation
193 glDisable(GL_BLEND);
194 glDisable(GL_DITHER);
195 glDisable(GL_SCISSOR_TEST);
196 glClearColor(0,0,0,0);
197 glClear(GL_COLOR_BUFFER_BIT);
198
199 const int w = dst.w;
200 const int h = dst.h;
201
202 copybit_image_t src;
203 mBitmap.getBitmapSurface(&src);
204 const copybit_rect_t srect = { 0, 0, src.w, src.h };
205
206
207 GGLSurface t;
208 t.version = sizeof(GGLSurface);
209 t.width = src.w;
210 t.height = src.h;
211 t.stride = src.w;
212 t.vstride= src.h;
213 t.format = src.format;
214 t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
215
Mathias Agopian253ed062009-03-27 18:12:49 -0700216 if (!mOriginalTargetOrientation) {
Mathias Agopian0d1318b2009-03-27 17:58:20 -0700217 f = -f;
218 }
219
220 Transform tr;
221 tr.set(f, w*0.5f, h*0.5f);
222 tr.scale(s, w*0.5f, h*0.5f);
223
224 // FIXME: we should not access mVertices and mDrawingState like that,
225 // but since we control the animation, we know it's going to work okay.
226 // eventually we'd need a more formal way of doing things like this.
227 LayerOrientationAnimRotate& self(const_cast<LayerOrientationAnimRotate&>(*this));
228 tr.transform(self.mVertices[0], 0, 0);
229 tr.transform(self.mVertices[1], 0, src.h);
230 tr.transform(self.mVertices[2], src.w, src.h);
231 tr.transform(self.mVertices[3], src.w, 0);
232
233 if (!(mFlags & DisplayHardware::SLOW_CONFIG)) {
234 // Too slow to do this in software
235 self.mDrawingState.flags |= ISurfaceComposer::eLayerFilter;
236 }
237
238 if (UNLIKELY(mTextureName == -1LU)) {
239 mTextureName = createTexture();
240 GLuint w=0, h=0;
241 const Region dirty(Rect(t.width, t.height));
242 loadTexture(dirty, mTextureName, t, w, h);
243 }
244 self.mDrawingState.alpha = 255; //-int(alpha*255);
245 const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
246 drawWithOpenGL(clip, mTextureName, t);
247
248 if (alpha > 0) {
Mathias Agopian253ed062009-03-27 18:12:49 -0700249 const float sign = (!mOriginalTargetOrientation) ? 1.0f : -1.0f;
Mathias Agopian0d1318b2009-03-27 17:58:20 -0700250 tr.set(f + sign*(M_PI * 0.5f * ROTATION_FACTOR), w*0.5f, h*0.5f);
251 tr.scale(s, w*0.5f, h*0.5f);
252 tr.transform(self.mVertices[0], 0, 0);
253 tr.transform(self.mVertices[1], 0, src.h);
254 tr.transform(self.mVertices[2], src.w, src.h);
255 tr.transform(self.mVertices[3], src.w, 0);
256
257 copybit_image_t src;
258 mBitmapIn.getBitmapSurface(&src);
259 t.data = (GGLubyte*)(intptr_t(src.base) + src.offset);
260 if (UNLIKELY(mTextureNameIn == -1LU)) {
261 mTextureNameIn = createTexture();
262 GLuint w=0, h=0;
263 const Region dirty(Rect(t.width, t.height));
264 loadTexture(dirty, mTextureNameIn, t, w, h);
265 }
266 self.mDrawingState.alpha = int(alpha*255);
267 const Region clip(Rect( srect.l, srect.t, srect.r, srect.b ));
268 drawWithOpenGL(clip, mTextureNameIn, t);
269 }
270}
271
272// ---------------------------------------------------------------------------
273
274}; // namespace android