Merge "Add support for saveLayer()."
This commit is contained in:
@@ -171,35 +171,7 @@ bool OpenGLRenderer::restoreSnapshot() {
|
||||
sp<Snapshot> previous = mSnapshot->previous;
|
||||
|
||||
if (restoreLayer) {
|
||||
// Unbind current FBO and restore previous one
|
||||
// Most of the time, previous->fbo will be 0 to bind the default buffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
|
||||
|
||||
// Restore the clip from the previous snapshot
|
||||
const Rect& clip = previous->getMappedClip();
|
||||
glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
|
||||
|
||||
// Compute the correct texture coordinates for the FBO texture
|
||||
// The texture is currently as big as the window but drawn with
|
||||
// a quad of the appropriate size
|
||||
const Rect& layer = current->layer;
|
||||
Rect texCoords(current->layer);
|
||||
mSnapshot->transform.mapRect(texCoords);
|
||||
|
||||
const float u1 = texCoords.left / float(mWidth);
|
||||
const float v1 = (mHeight - texCoords.top) / float(mHeight);
|
||||
const float u2 = texCoords.right / float(mWidth);
|
||||
const float v2 = (mHeight - texCoords.bottom) / float(mHeight);
|
||||
|
||||
resetDrawTextureTexCoords(u1, v1, u2, v1);
|
||||
|
||||
drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
|
||||
current->texture, current->alpha);
|
||||
|
||||
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
|
||||
|
||||
glDeleteFramebuffers(1, ¤t->fbo);
|
||||
glDeleteTextures(1, ¤t->texture);
|
||||
composeLayer(current, previous);
|
||||
}
|
||||
|
||||
mSnapshot = previous;
|
||||
@@ -208,31 +180,81 @@ bool OpenGLRenderer::restoreSnapshot() {
|
||||
return restoreClip;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::composeLayer(sp<Snapshot> current, sp<Snapshot> previous) {
|
||||
// Unbind current FBO and restore previous one
|
||||
// Most of the time, previous->fbo will be 0 to bind the default buffer
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, previous->fbo);
|
||||
|
||||
// Restore the clip from the previous snapshot
|
||||
const Rect& clip = previous->getMappedClip();
|
||||
glScissor(clip.left, mHeight - clip.bottom, clip.getWidth(), clip.getHeight());
|
||||
|
||||
// Compute the correct texture coordinates for the FBO texture
|
||||
// The texture is currently as big as the window but drawn with
|
||||
// a quad of the appropriate size
|
||||
const Rect& layer = current->layer;
|
||||
Rect texCoords(current->layer);
|
||||
mSnapshot->transform.mapRect(texCoords);
|
||||
|
||||
const float u1 = texCoords.left / float(mWidth);
|
||||
const float v1 = (mHeight - texCoords.top) / float(mHeight);
|
||||
const float u2 = texCoords.right / float(mWidth);
|
||||
const float v2 = (mHeight - texCoords.bottom) / float(mHeight);
|
||||
|
||||
resetDrawTextureTexCoords(u1, v1, u2, v1);
|
||||
|
||||
drawTextureRect(layer.left, layer.top, layer.right, layer.bottom,
|
||||
current->texture, current->alpha, current->mode, true);
|
||||
|
||||
resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
|
||||
|
||||
glDeleteFramebuffers(1, ¤t->fbo);
|
||||
glDeleteTextures(1, ¤t->texture);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Layers
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
int OpenGLRenderer::saveLayer(float left, float top, float right, float bottom,
|
||||
const SkPaint* p, int flags) {
|
||||
// TODO Implement
|
||||
return saveSnapshot();
|
||||
int count = saveSnapshot();
|
||||
|
||||
int alpha = 255;
|
||||
SkXfermode::Mode mode;
|
||||
|
||||
if (p) {
|
||||
alpha = p->getAlpha();
|
||||
const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
|
||||
if (!isMode) {
|
||||
// Assume SRC_OVER
|
||||
mode = SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
} else {
|
||||
mode = SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
|
||||
createLayer(mSnapshot, left, top, right, bottom, alpha, mode, flags);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bottom,
|
||||
int alpha, int flags) {
|
||||
int count = saveSnapshot();
|
||||
createLayer(mSnapshot, left, top, right, bottom, alpha, SkXfermode::kSrcOver_Mode, flags);
|
||||
return count;
|
||||
}
|
||||
|
||||
mSnapshot->flags |= Snapshot::kFlagIsLayer;
|
||||
mSnapshot->alpha = alpha / 255.0f;
|
||||
mSnapshot->layer.set(left, top, right, bottom);
|
||||
|
||||
bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
|
||||
float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
|
||||
// Generate the FBO and attach the texture
|
||||
glGenFramebuffers(1, &mSnapshot->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, mSnapshot->fbo);
|
||||
glGenFramebuffers(1, &snapshot->fbo);
|
||||
glBindFramebuffer(GL_FRAMEBUFFER, snapshot->fbo);
|
||||
|
||||
// Generate the texture in which the FBO will draw
|
||||
glGenTextures(1, &mSnapshot->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, mSnapshot->texture);
|
||||
glGenTextures(1, &snapshot->texture);
|
||||
glBindTexture(GL_TEXTURE_2D, snapshot->texture);
|
||||
|
||||
// The FBO will not be scaled, so we can use lower quality filtering
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
@@ -255,17 +277,24 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot
|
||||
|
||||
// Bind texture to FBO
|
||||
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D,
|
||||
mSnapshot->texture, 0);
|
||||
snapshot->texture, 0);
|
||||
|
||||
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
|
||||
if (status != GL_FRAMEBUFFER_COMPLETE) {
|
||||
LOGD("Framebuffer incomplete %d", status);
|
||||
|
||||
glDeleteFramebuffers(1, &mSnapshot->fbo);
|
||||
glDeleteTextures(1, &mSnapshot->texture);
|
||||
glDeleteFramebuffers(1, &snapshot->fbo);
|
||||
glDeleteTextures(1, &snapshot->texture);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return count;
|
||||
snapshot->flags |= Snapshot::kFlagIsLayer;
|
||||
snapshot->mode = mode;
|
||||
snapshot->alpha = alpha / 255.0f;
|
||||
snapshot->layer.set(left, top, right, bottom);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -406,16 +435,20 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
|
||||
GLuint texture, float alpha) {
|
||||
GLuint texture, float alpha, SkXfermode::Mode mode, bool isPremultiplied) {
|
||||
mModelView.loadTranslate(left, top, 0.0f);
|
||||
mModelView.scale(right - left, bottom - top, 1.0f);
|
||||
|
||||
mDrawTextureShader->use(&mOrthoMatrix[0], &mModelView.data[0], &mSnapshot->transform.data[0]);
|
||||
|
||||
// TODO Correctly set the blend function, based on texture format and xfermode
|
||||
GLenum sourceMode = gBlends[mode].src;
|
||||
if (!isPremultiplied && sourceMode == GL_ONE) {
|
||||
sourceMode = GL_SRC_ALPHA;
|
||||
}
|
||||
|
||||
// TODO: Try to disable blending when the texture is opaque and alpha == 1.0f
|
||||
glEnable(GL_BLEND);
|
||||
// For not pre-multiplied sources
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glBlendFunc(sourceMode, gBlends[mode].dst);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
|
||||
@@ -125,6 +125,34 @@ private:
|
||||
*/
|
||||
void setScissorFromClip();
|
||||
|
||||
/**
|
||||
* Compose the layer defined in the current snapshot with the layer
|
||||
* defined by the previous snapshot.
|
||||
*
|
||||
* The current snapshot *must* be a layer (flag kFlagIsLayer set.)
|
||||
*
|
||||
* @param curent The current snapshot containing the layer to compose
|
||||
* @param previous The previous snapshot to compose the current layer with
|
||||
*/
|
||||
void composeLayer(sp<Snapshot> current, sp<Snapshot> previous);
|
||||
|
||||
/**
|
||||
* Creates a new layer stored in the specified snapshot.
|
||||
*
|
||||
* @param snapshot The snapshot associated with the new layer
|
||||
* @param left The left coordinate of the layer
|
||||
* @param top The top coordinate of the layer
|
||||
* @param right The right coordinate of the layer
|
||||
* @param bottom The bottom coordinate of the layer
|
||||
* @param alpha The translucency of the layer
|
||||
* @param mode The blending mode of the layer
|
||||
* @param flags The layer save flags
|
||||
*
|
||||
* @return True if the layer was successfully created, false otherwise
|
||||
*/
|
||||
bool createLayer(sp<Snapshot> snapshot, float left, float top, float right, float bottom,
|
||||
int alpha, SkXfermode::Mode mode, int flags);
|
||||
|
||||
/**
|
||||
* Draws a colored rectangle with the specified color. The specified coordinates
|
||||
* are transformed by the current snapshot's transform matrix.
|
||||
@@ -149,9 +177,11 @@ private:
|
||||
* @param bottom The bottom coordinate of the rectangle
|
||||
* @param texture The texture name to map onto the rectangle
|
||||
* @param alpha An additional translucency parameter, between 0.0f and 1.0f
|
||||
* @param mode The blending mode
|
||||
* @param isPremultiplied Indicates whether the texture has premultiplied alpha
|
||||
*/
|
||||
void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
|
||||
float alpha);
|
||||
float alpha, SkXfermode::Mode mode, bool isPremultiplied = false);
|
||||
|
||||
/**
|
||||
* Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <GLES2/gl2.h>
|
||||
#include <GLES2/gl2ext.h>
|
||||
|
||||
#include <SkXfermode.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
|
||||
#include "Matrix.h"
|
||||
@@ -133,6 +135,11 @@ public:
|
||||
* Only set when the flag kFlagIsLayer is set.
|
||||
*/
|
||||
float alpha;
|
||||
/**
|
||||
* Blending mode of the layer.
|
||||
* Only set when the flag kFlagIsLayer is set.
|
||||
*/
|
||||
SkXfermode::Mode mode;
|
||||
|
||||
private:
|
||||
// Clipping rectangle mapped with the transform
|
||||
|
||||
@@ -22,8 +22,18 @@
|
||||
android:hardwareAccelerated="true">
|
||||
|
||||
<activity
|
||||
android:name="HwUiActivity"
|
||||
android:label="_Layers">
|
||||
android:name="AlphaLayersActivity"
|
||||
android:label="_αLayers">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="LayersActivity"
|
||||
android:label="_Layers"
|
||||
android:theme="@android:style/Theme.Translucent">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
|
||||
@@ -29,7 +29,7 @@ import android.view.animation.Animation;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class HwUiActivity extends Activity {
|
||||
public class AlphaLayersActivity extends Activity {
|
||||
private static final String LOG_TAG = "HwUi";
|
||||
|
||||
@Override
|
||||
@@ -0,0 +1,110 @@
|
||||
/*
|
||||
* Copyright (C) 2010 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.
|
||||
*/
|
||||
|
||||
package com.google.android.test.hwui;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class LayersActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
setContentView(new LayersView(this));
|
||||
}
|
||||
|
||||
static class LayersView extends View {
|
||||
private Paint mLayerPaint;
|
||||
private final Paint mRectPaint;
|
||||
|
||||
LayersView(Context c) {
|
||||
super(c);
|
||||
|
||||
mLayerPaint = new Paint();
|
||||
mRectPaint = new Paint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
|
||||
canvas.translate(140.0f, 100.0f);
|
||||
|
||||
//canvas.drawRGB(255, 255, 255);
|
||||
|
||||
int count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
mRectPaint.setColor(0xffff0000);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
canvas.translate(0.0f, 125.0f);
|
||||
|
||||
count = canvas.saveLayer(0.0f, 0.0f, 200.0f, 100.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
mRectPaint.setColor(0xff00ff00);
|
||||
mRectPaint.setAlpha(50);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 100.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
canvas.translate(25.0f, 125.0f);
|
||||
|
||||
mRectPaint.setColor(0xff0000ff);
|
||||
mRectPaint.setAlpha(255);
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
mLayerPaint.setAlpha(127);
|
||||
mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC_OUT));
|
||||
count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
mRectPaint.setColor(0xffff0000);
|
||||
canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
canvas.translate(0.0f, 125.0f);
|
||||
|
||||
mRectPaint.setColor(0xff0000ff);
|
||||
mRectPaint.setAlpha(255);
|
||||
canvas.drawRect(0.0f, 0.0f, 100.0f, 50.0f, mRectPaint);
|
||||
|
||||
mLayerPaint.setColor(0xffff0000);
|
||||
mLayerPaint.setAlpha(127);
|
||||
mLayerPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_ATOP));
|
||||
count = canvas.saveLayer(50.0f, 25.0f, 150.0f, 75.0f, mLayerPaint,
|
||||
Canvas.ALL_SAVE_FLAG);
|
||||
|
||||
mRectPaint.setColor(0xffff0000);
|
||||
canvas.drawRect(50.0f, 25.0f, 150.0f, 75.0f, mRectPaint);
|
||||
|
||||
canvas.restoreToCount(count);
|
||||
|
||||
mLayerPaint = new Paint();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,11 +35,6 @@ public class XfermodeActivity extends Activity {
|
||||
|
||||
setContentView(new XfermodesView(this));
|
||||
}
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
static int dipToPx(Context c, int dip) {
|
||||
return (int) (c.getResources().getDisplayMetrics().density * dip + 0.5f);
|
||||
}
|
||||
|
||||
static class XfermodesView extends View {
|
||||
private final Paint mBluePaint;
|
||||
|
||||
Reference in New Issue
Block a user