Merge "Implement support for PorterDuff's blending modes."

This commit is contained in:
Romain Guy
2010-06-28 17:15:24 -07:00
committed by Android (Google) Code Review
4 changed files with 259 additions and 31 deletions

View File

@@ -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

View File

@@ -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

View File

@@ -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>

View File

@@ -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();
}
}
}