Merge "Implement support for PorterDuff's blending modes."
This commit is contained in:
@@ -40,34 +40,42 @@ namespace uirenderer {
|
||||
// Globals
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
const SimpleVertex gDrawColorVertices[] = {
|
||||
static const SimpleVertex gDrawColorVertices[] = {
|
||||
SV(0.0f, 0.0f),
|
||||
SV(1.0f, 0.0f),
|
||||
SV(0.0f, 1.0f),
|
||||
SV(1.0f, 1.0f)
|
||||
};
|
||||
const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
|
||||
const GLsizei gDrawColorVertexCount = 4;
|
||||
static const GLsizei gDrawColorVertexStride = sizeof(SimpleVertex);
|
||||
static const GLsizei gDrawColorVertexCount = 4;
|
||||
|
||||
TextureVertex gDrawTextureVertices[] = {
|
||||
// This array is never used directly but used as a memcpy source in the
|
||||
// OpenGLRenderer constructor
|
||||
static const TextureVertex gDrawTextureVertices[] = {
|
||||
FV(0.0f, 0.0f, 0.0f, 1.0f),
|
||||
FV(1.0f, 0.0f, 1.0f, 1.0f),
|
||||
FV(0.0f, 1.0f, 0.0f, 0.0f),
|
||||
FV(1.0f, 1.0f, 1.0f, 0.0f)
|
||||
};
|
||||
const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
|
||||
const GLsizei gDrawTextureVertexCount = 4;
|
||||
static const GLsizei gDrawTextureVertexStride = sizeof(TextureVertex);
|
||||
static const GLsizei gDrawTextureVertexCount = 4;
|
||||
|
||||
static inline void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
|
||||
gDrawTextureVertices[0].texture[0] = u1;
|
||||
gDrawTextureVertices[0].texture[1] = v2;
|
||||
gDrawTextureVertices[1].texture[0] = u2;
|
||||
gDrawTextureVertices[1].texture[1] = v2;
|
||||
gDrawTextureVertices[2].texture[0] = u1;
|
||||
gDrawTextureVertices[2].texture[1] = v1;
|
||||
gDrawTextureVertices[3].texture[0] = u2;
|
||||
gDrawTextureVertices[3].texture[1] = v1;
|
||||
}
|
||||
// In this array, the index of each Blender equals the value of the first
|
||||
// entry. For instance, gBlends[1] == gBlends[SkXfermode::kSrc_Mode]
|
||||
static const Blender gBlends[] = {
|
||||
{ SkXfermode::kClear_Mode, GL_ZERO, GL_ZERO },
|
||||
{ SkXfermode::kSrc_Mode, GL_ONE, GL_ZERO },
|
||||
{ SkXfermode::kDst_Mode, GL_ZERO, GL_ONE },
|
||||
{ SkXfermode::kSrcOver_Mode, GL_ONE, GL_ONE_MINUS_SRC_ALPHA },
|
||||
{ SkXfermode::kDstOver_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE },
|
||||
{ SkXfermode::kSrcIn_Mode, GL_DST_ALPHA, GL_ZERO },
|
||||
{ SkXfermode::kDstIn_Mode, GL_ZERO, GL_SRC_ALPHA },
|
||||
{ SkXfermode::kSrcOut_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ZERO },
|
||||
{ SkXfermode::kDstOut_Mode, GL_ZERO, GL_ONE_MINUS_SRC_ALPHA },
|
||||
{ SkXfermode::kSrcATop_Mode, GL_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA },
|
||||
{ SkXfermode::kDstATop_Mode, GL_ONE_MINUS_DST_ALPHA, GL_SRC_ALPHA },
|
||||
{ SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors/destructor
|
||||
@@ -78,6 +86,8 @@ OpenGLRenderer::OpenGLRenderer() {
|
||||
|
||||
mDrawColorShader = new DrawColorProgram;
|
||||
mDrawTextureShader = new DrawTextureProgram;
|
||||
|
||||
memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
|
||||
}
|
||||
|
||||
OpenGLRenderer::~OpenGLRenderer() {
|
||||
@@ -336,22 +346,43 @@ bool OpenGLRenderer::clipRect(float left, float top, float right, float bottom)
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OpenGLRenderer::drawColor(int color, SkXfermode::Mode mode) {
|
||||
// TODO: Set the transfer mode
|
||||
const Rect& clip = mSnapshot->clipRect;
|
||||
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color);
|
||||
drawColorRect(clip.left, clip.top, clip.right, clip.bottom, color, mode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawRect(float left, float top, float right, float bottom, const SkPaint* p) {
|
||||
// TODO Support more than just color
|
||||
// TODO: Set the transfer mode
|
||||
drawColorRect(left, top, right, bottom, p->getColor());
|
||||
SkXfermode::Mode mode;
|
||||
|
||||
const bool isMode = SkXfermode::IsMode(p->getXfermode(), &mode);
|
||||
if (!isMode) {
|
||||
// Assume SRC_OVER
|
||||
mode = SkXfermode::kSrcOver_Mode;
|
||||
}
|
||||
|
||||
// Skia draws using the color's alpha channel if < 255
|
||||
// Otherwise, it uses the paint's alpha
|
||||
int color = p->getColor();
|
||||
if (((color >> 24) & 0xFF) == 255) {
|
||||
color |= p->getAlpha() << 24;
|
||||
}
|
||||
|
||||
drawColorRect(left, top, right, bottom, color, mode);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom, int color) {
|
||||
GLfloat a = ((color >> 24) & 0xFF) / 255.0f;
|
||||
GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
|
||||
GLfloat g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
GLfloat b = ((color ) & 0xFF) / 255.0f;
|
||||
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
|
||||
int color, SkXfermode::Mode mode) {
|
||||
const int alpha = (color >> 24) & 0xFF;
|
||||
const bool blend = alpha < 255 || mode != SkXfermode::kSrcOver_Mode;
|
||||
|
||||
const GLfloat a = alpha / 255.0f;
|
||||
const GLfloat r = ((color >> 16) & 0xFF) / 255.0f;
|
||||
const GLfloat g = ((color >> 8) & 0xFF) / 255.0f;
|
||||
const GLfloat b = ((color ) & 0xFF) / 255.0f;
|
||||
|
||||
if (blend) {
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(gBlends[mode].src, gBlends[mode].dst);
|
||||
}
|
||||
|
||||
mModelView.loadTranslate(left, top, 0.0f);
|
||||
mModelView.scale(right - left, bottom - top, 1.0f);
|
||||
@@ -368,6 +399,10 @@ void OpenGLRenderer::drawColorRect(float left, float top, float right, float bot
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
|
||||
|
||||
glDisableVertexAttribArray(mDrawColorShader->position);
|
||||
|
||||
if (blend) {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
|
||||
@@ -379,15 +414,16 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
|
||||
|
||||
// TODO Correctly set the blend function, based on texture format and xfermode
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
|
||||
// For not pre-multiplied sources
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glUniform1i(mDrawTextureShader->sampler, 0);
|
||||
|
||||
const GLvoid* p = &gDrawTextureVertices[0].position[0];
|
||||
const GLvoid* t = &gDrawTextureVertices[0].texture[0];
|
||||
const GLvoid* p = &mDrawTextureVertices[0].position[0];
|
||||
const GLvoid* t = &mDrawTextureVertices[0].texture[0];
|
||||
|
||||
glEnableVertexAttribArray(mDrawTextureShader->position);
|
||||
glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
@@ -408,5 +444,16 @@ void OpenGLRenderer::drawTextureRect(float left, float top, float right, float b
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::resetDrawTextureTexCoords(float u1, float v1, float u2, float v2) {
|
||||
mDrawTextureVertices[0].texture[0] = u1;
|
||||
mDrawTextureVertices[0].texture[1] = v2;
|
||||
mDrawTextureVertices[1].texture[0] = u2;
|
||||
mDrawTextureVertices[1].texture[1] = v2;
|
||||
mDrawTextureVertices[2].texture[0] = u1;
|
||||
mDrawTextureVertices[2].texture[1] = v1;
|
||||
mDrawTextureVertices[3].texture[0] = u2;
|
||||
mDrawTextureVertices[3].texture[1] = v1;
|
||||
}
|
||||
|
||||
}; // namespace uirenderer
|
||||
}; // namespace android
|
||||
|
||||
@@ -53,6 +53,15 @@ struct TextureVertex {
|
||||
float texture[2];
|
||||
}; // struct TextureVertex
|
||||
|
||||
/**
|
||||
* Structure mapping Skia xfermodes to OpenGL blending factors.
|
||||
*/
|
||||
struct Blender {
|
||||
SkXfermode::Mode mode;
|
||||
GLenum src;
|
||||
GLenum dst;
|
||||
}; // struct Blender
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Renderer
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -125,8 +134,10 @@ private:
|
||||
* @param right The right coordinate of the rectangle
|
||||
* @param bottom The bottom coordinate of the rectangle
|
||||
* @param color The rectangle's ARGB color, defined as a packed 32 bits word
|
||||
* @param mode The Skia xfermode to use
|
||||
*/
|
||||
void drawColorRect(float left, float top, float right, float bottom, int color);
|
||||
void drawColorRect(float left, float top, float right, float bottom,
|
||||
int color, SkXfermode::Mode mode);
|
||||
|
||||
/**
|
||||
* Draws a textured rectangle with the specified texture. The specified coordinates
|
||||
@@ -142,6 +153,19 @@ private:
|
||||
void drawTextureRect(float left, float top, float right, float bottom, GLuint texture,
|
||||
float alpha);
|
||||
|
||||
/**
|
||||
* Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
|
||||
* back to default is achieved by calling:
|
||||
*
|
||||
* resetDrawTextureTexCoords(0.0f, 1.0f, 1.0f, 0.0f);
|
||||
*
|
||||
* @param u1 The left coordinate of the texture
|
||||
* @param v1 The bottom coordinate of the texture
|
||||
* @param u2 The right coordinate of the texture
|
||||
* @param v2 The top coordinate of the texture
|
||||
*/
|
||||
void resetDrawTextureTexCoords(float u1, float v1, float u2, float v2);
|
||||
|
||||
// Dimensions of the drawing surface
|
||||
int mWidth, mHeight;
|
||||
|
||||
@@ -161,6 +185,9 @@ private:
|
||||
// Shaders
|
||||
sp<DrawColorProgram> mDrawColorShader;
|
||||
sp<DrawTextureProgram> mDrawTextureShader;
|
||||
|
||||
// Used to draw textured quads
|
||||
TextureVertex mDrawTextureVertices[4];
|
||||
}; // class OpenGLRenderer
|
||||
|
||||
}; // namespace uirenderer
|
||||
|
||||
@@ -21,12 +21,24 @@
|
||||
android:label="HwUi"
|
||||
android:hardwareAccelerated="true">
|
||||
|
||||
<activity android:name="HwUiActivity">
|
||||
<activity
|
||||
android:name="HwUiActivity"
|
||||
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="XfermodeActivity"
|
||||
android:label="_Xfermodes"
|
||||
android:theme="@android:style/Theme.Translucent">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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;
|
||||
|
||||
import static android.graphics.PorterDuff.Mode;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class XfermodeActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
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;
|
||||
private final Paint mRedPaint;
|
||||
|
||||
XfermodesView(Context c) {
|
||||
super(c);
|
||||
|
||||
mBluePaint = new Paint();
|
||||
mBluePaint.setColor(0xff0000ff);
|
||||
|
||||
mRedPaint = new Paint();
|
||||
mRedPaint.setColor(0x7fff0000);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
//canvas.drawRGB(255, 255, 255);
|
||||
|
||||
canvas.translate(100.0f, 100.0f);
|
||||
|
||||
// SRC modes
|
||||
canvas.save();
|
||||
|
||||
drawRects(canvas, Mode.SRC_OVER);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.SRC_IN);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.SRC_OUT);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.SRC_ATOP);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.SRC);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.translate(100.0f, 0.0f);
|
||||
|
||||
// DST modes
|
||||
canvas.save();
|
||||
|
||||
drawRects(canvas, Mode.DST_OVER);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.DST_IN);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.DST_OUT);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.DST_ATOP);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.DST);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
canvas.translate(100.0f, 0.0f);
|
||||
|
||||
// Other modes
|
||||
canvas.save();
|
||||
|
||||
drawRects(canvas, Mode.CLEAR);
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
drawRects(canvas, Mode.XOR);
|
||||
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
mBluePaint.setAlpha(127);
|
||||
canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);
|
||||
|
||||
canvas.translate(0.0f, 100.0f);
|
||||
|
||||
mBluePaint.setAlpha(10);
|
||||
mBluePaint.setColor(0x7f0000ff);
|
||||
canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);
|
||||
|
||||
mBluePaint.setColor(0xff0000ff);
|
||||
mBluePaint.setAlpha(255);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
|
||||
private void drawRects(Canvas canvas, PorterDuff.Mode mode) {
|
||||
canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mBluePaint);
|
||||
|
||||
canvas.save();
|
||||
canvas.translate(25.0f, 25.0f);
|
||||
mRedPaint.setXfermode(new PorterDuffXfermode(mode));
|
||||
canvas.drawRect(0.0f, 0.0f, 50.0f, 50.0f, mRedPaint);
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user