michael@0: /* michael@0: * Copyright (C) 2011 The Android Open Source Project michael@0: * michael@0: * Licensed under the Apache License, Version 2.0 (the "License"); michael@0: * you may not use this file except in compliance with the License. michael@0: * You may obtain a copy of the License at michael@0: * michael@0: * http://www.apache.org/licenses/LICENSE-2.0 michael@0: * michael@0: * Unless required by applicable law or agreed to in writing, software michael@0: * distributed under the License is distributed on an "AS IS" BASIS, michael@0: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. michael@0: * See the License for the specific language governing permissions and michael@0: * limitations under the License. michael@0: */ michael@0: michael@0: #ifndef _UI_SPRITES_H michael@0: #define _UI_SPRITES_H michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: #include michael@0: #endif michael@0: michael@0: #include michael@0: michael@0: namespace android { michael@0: michael@0: /* michael@0: * Transformation matrix for a sprite. michael@0: */ michael@0: struct SpriteTransformationMatrix { michael@0: inline SpriteTransformationMatrix() : dsdx(1.0f), dtdx(0.0f), dsdy(0.0f), dtdy(1.0f) { } michael@0: inline SpriteTransformationMatrix(float dsdx, float dtdx, float dsdy, float dtdy) : michael@0: dsdx(dsdx), dtdx(dtdx), dsdy(dsdy), dtdy(dtdy) { } michael@0: michael@0: float dsdx; michael@0: float dtdx; michael@0: float dsdy; michael@0: float dtdy; michael@0: michael@0: inline bool operator== (const SpriteTransformationMatrix& other) { michael@0: return dsdx == other.dsdx michael@0: && dtdx == other.dtdx michael@0: && dsdy == other.dsdy michael@0: && dtdy == other.dtdy; michael@0: } michael@0: michael@0: inline bool operator!= (const SpriteTransformationMatrix& other) { michael@0: return !(*this == other); michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * Icon that a sprite displays, including its hotspot. michael@0: */ michael@0: struct SpriteIcon { michael@0: inline SpriteIcon() : hotSpotX(0), hotSpotY(0) { } michael@0: #ifdef HAVE_ANDROID_OS michael@0: inline SpriteIcon(const SkBitmap& bitmap, float hotSpotX, float hotSpotY) : michael@0: bitmap(bitmap), hotSpotX(hotSpotX), hotSpotY(hotSpotY) { } michael@0: michael@0: SkBitmap bitmap; michael@0: #endif michael@0: float hotSpotX; michael@0: float hotSpotY; michael@0: michael@0: inline SpriteIcon copy() const { michael@0: #ifdef HAVE_ANDROID_OS michael@0: SkBitmap bitmapCopy; michael@0: bitmap.copyTo(&bitmapCopy, SkBitmap::kARGB_8888_Config); michael@0: return SpriteIcon(bitmapCopy, hotSpotX, hotSpotY); michael@0: #else michael@0: return SpriteIcon(); michael@0: #endif michael@0: } michael@0: michael@0: inline void reset() { michael@0: #ifdef HAVE_ANDROID_OS michael@0: bitmap.reset(); michael@0: hotSpotX = 0; michael@0: hotSpotY = 0; michael@0: #endif michael@0: } michael@0: michael@0: inline bool isValid() const { michael@0: #ifdef HAVE_ANDROID_OS michael@0: return !bitmap.isNull() && !bitmap.empty(); michael@0: #else michael@0: return false; michael@0: #endif michael@0: } michael@0: }; michael@0: michael@0: /* michael@0: * A sprite is a simple graphical object that is displayed on-screen above other layers. michael@0: * The basic sprite class is an interface. michael@0: * The implementation is provided by the sprite controller. michael@0: */ michael@0: class Sprite : public RefBase { michael@0: protected: michael@0: Sprite() { } michael@0: virtual ~Sprite() { } michael@0: michael@0: public: michael@0: enum { michael@0: // The base layer for pointer sprites. michael@0: BASE_LAYER_POINTER = 0, // reserve space for 1 pointer michael@0: michael@0: // The base layer for spot sprites. michael@0: BASE_LAYER_SPOT = 1, // reserve space for MAX_POINTER_ID spots michael@0: }; michael@0: michael@0: /* Sets the bitmap that is drawn by the sprite. michael@0: * The sprite retains a copy of the bitmap for subsequent rendering. */ michael@0: virtual void setIcon(const SpriteIcon& icon) = 0; michael@0: michael@0: inline void clearIcon() { michael@0: setIcon(SpriteIcon()); michael@0: } michael@0: michael@0: /* Sets whether the sprite is visible. */ michael@0: virtual void setVisible(bool visible) = 0; michael@0: michael@0: /* Sets the sprite position on screen, relative to the sprite's hot spot. */ michael@0: virtual void setPosition(float x, float y) = 0; michael@0: michael@0: /* Sets the layer of the sprite, relative to the system sprite overlay layer. michael@0: * Layer 0 is the overlay layer, > 0 appear above this layer. */ michael@0: virtual void setLayer(int32_t layer) = 0; michael@0: michael@0: /* Sets the sprite alpha blend ratio between 0.0 and 1.0. */ michael@0: virtual void setAlpha(float alpha) = 0; michael@0: michael@0: /* Sets the sprite transformation matrix. */ michael@0: virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix) = 0; michael@0: }; michael@0: michael@0: /* michael@0: * Displays sprites on the screen. michael@0: * michael@0: * This interface is used by PointerController and SpotController to draw pointers or michael@0: * spot representations of fingers. It is not intended for general purpose use michael@0: * by other components. michael@0: * michael@0: * All sprite position updates and rendering is performed asynchronously. michael@0: * michael@0: * Clients are responsible for animating sprites by periodically updating their properties. michael@0: */ michael@0: class SpriteController : public MessageHandler { michael@0: protected: michael@0: virtual ~SpriteController(); michael@0: michael@0: public: michael@0: SpriteController(const sp& looper, int32_t overlayLayer); michael@0: michael@0: /* Creates a new sprite, initially invisible. */ michael@0: sp createSprite(); michael@0: michael@0: /* Opens or closes a transaction to perform a batch of sprite updates as part of michael@0: * a single operation such as setPosition and setAlpha. It is not necessary to michael@0: * open a transaction when updating a single property. michael@0: * Calls to openTransaction() nest and must be matched by an equal number michael@0: * of calls to closeTransaction(). */ michael@0: void openTransaction(); michael@0: void closeTransaction(); michael@0: michael@0: private: michael@0: enum { michael@0: MSG_UPDATE_SPRITES, michael@0: MSG_DISPOSE_SURFACES, michael@0: }; michael@0: michael@0: enum { michael@0: DIRTY_BITMAP = 1 << 0, michael@0: DIRTY_ALPHA = 1 << 1, michael@0: DIRTY_POSITION = 1 << 2, michael@0: DIRTY_TRANSFORMATION_MATRIX = 1 << 3, michael@0: DIRTY_LAYER = 1 << 4, michael@0: DIRTY_VISIBILITY = 1 << 5, michael@0: DIRTY_HOTSPOT = 1 << 6, michael@0: }; michael@0: michael@0: /* Describes the state of a sprite. michael@0: * This structure is designed so that it can be copied during updates so that michael@0: * surfaces can be resized and redrawn without blocking the client by holding a lock michael@0: * on the sprites for a long time. michael@0: * Note that the SkBitmap holds a reference to a shared (and immutable) pixel ref. */ michael@0: struct SpriteState { michael@0: inline SpriteState() : michael@0: dirty(0), visible(false), michael@0: positionX(0), positionY(0), layer(0), alpha(1.0f), michael@0: surfaceWidth(0), surfaceHeight(0), surfaceDrawn(false), surfaceVisible(false) { michael@0: } michael@0: michael@0: uint32_t dirty; michael@0: michael@0: SpriteIcon icon; michael@0: bool visible; michael@0: float positionX; michael@0: float positionY; michael@0: int32_t layer; michael@0: float alpha; michael@0: SpriteTransformationMatrix transformationMatrix; michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: sp surfaceControl; michael@0: #endif michael@0: int32_t surfaceWidth; michael@0: int32_t surfaceHeight; michael@0: bool surfaceDrawn; michael@0: bool surfaceVisible; michael@0: michael@0: inline bool wantSurfaceVisible() const { michael@0: return visible && alpha > 0.0f && icon.isValid(); michael@0: } michael@0: }; michael@0: michael@0: /* Client interface for a sprite. michael@0: * Requests acquire a lock on the controller, update local state and request the michael@0: * controller to invalidate the sprite. michael@0: * The real heavy lifting of creating, resizing and redrawing surfaces happens michael@0: * asynchronously with no locks held except in short critical section to copy michael@0: * the sprite state before the work and update the sprite surface control afterwards. michael@0: */ michael@0: class SpriteImpl : public Sprite { michael@0: protected: michael@0: virtual ~SpriteImpl(); michael@0: michael@0: public: michael@0: SpriteImpl(const sp controller); michael@0: michael@0: virtual void setIcon(const SpriteIcon& icon); michael@0: virtual void setVisible(bool visible); michael@0: virtual void setPosition(float x, float y); michael@0: virtual void setLayer(int32_t layer); michael@0: virtual void setAlpha(float alpha); michael@0: virtual void setTransformationMatrix(const SpriteTransformationMatrix& matrix); michael@0: michael@0: inline const SpriteState& getStateLocked() const { michael@0: return mLocked.state; michael@0: } michael@0: michael@0: inline void resetDirtyLocked() { michael@0: mLocked.state.dirty = 0; michael@0: } michael@0: michael@0: #ifdef HAVE_ANDROID_OS michael@0: inline void setSurfaceLocked(const sp& surfaceControl, michael@0: int32_t width, int32_t height, bool drawn, bool visible) { michael@0: mLocked.state.surfaceControl = surfaceControl; michael@0: mLocked.state.surfaceWidth = width; michael@0: mLocked.state.surfaceHeight = height; michael@0: mLocked.state.surfaceDrawn = drawn; michael@0: mLocked.state.surfaceVisible = visible; michael@0: } michael@0: #endif michael@0: michael@0: private: michael@0: sp mController; michael@0: michael@0: struct Locked { michael@0: SpriteState state; michael@0: } mLocked; // guarded by mController->mLock michael@0: michael@0: void invalidateLocked(uint32_t dirty); michael@0: }; michael@0: michael@0: /* Stores temporary information collected during the sprite update cycle. */ michael@0: struct SpriteUpdate { michael@0: inline SpriteUpdate() : surfaceChanged(false) { } michael@0: inline SpriteUpdate(const sp sprite, const SpriteState& state) : michael@0: sprite(sprite), state(state), surfaceChanged(false) { michael@0: } michael@0: michael@0: sp sprite; michael@0: SpriteState state; michael@0: bool surfaceChanged; michael@0: }; michael@0: michael@0: mutable Mutex mLock; michael@0: michael@0: sp mLooper; michael@0: const int32_t mOverlayLayer; michael@0: #ifdef HAVE_ANDROID_OS michael@0: sp mHandler; michael@0: michael@0: sp mSurfaceComposerClient; michael@0: #endif michael@0: michael@0: struct Locked { michael@0: Vector > invalidatedSprites; michael@0: #ifdef HAVE_ANDROID_OS michael@0: Vector > disposedSurfaces; michael@0: #endif michael@0: uint32_t transactionNestingCount; michael@0: bool deferredSpriteUpdate; michael@0: } mLocked; // guarded by mLock michael@0: michael@0: void invalidateSpriteLocked(const sp& sprite); michael@0: #ifdef HAVE_ANDROID_OS michael@0: void disposeSurfaceLocked(const sp& surfaceControl); michael@0: michael@0: void handleMessage(const Message& message); michael@0: #endif michael@0: void doUpdateSprites(); michael@0: void doDisposeSurfaces(); michael@0: michael@0: void ensureSurfaceComposerClient(); michael@0: #ifdef HAVE_ANDROID_OS michael@0: sp obtainSurface(int32_t width, int32_t height); michael@0: #endif michael@0: }; michael@0: michael@0: } // namespace android michael@0: michael@0: #endif // _UI_SPRITES_H