Merge "Add support for BitmapShader."
This commit is contained in:
@@ -17,16 +17,21 @@
|
||||
package android.view;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.DrawFilter;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Path;
|
||||
import android.graphics.Picture;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.RadialGradient;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.RectF;
|
||||
import android.graphics.Region;
|
||||
import android.graphics.Shader;
|
||||
import android.graphics.SweepGradient;
|
||||
|
||||
import javax.microedition.khronos.opengles.GL;
|
||||
|
||||
@@ -369,6 +374,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawPatch(Bitmap bitmap, byte[] chunks, RectF dst, Paint paint) {
|
||||
// Shaders are ignored when drawing patches
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawPatch(mRenderer, bitmap.mNativeBitmap, chunks, dst.left, dst.top,
|
||||
dst.right, dst.bottom, nativePaint);
|
||||
@@ -379,6 +385,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawBitmap(Bitmap bitmap, float left, float top, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, left, top, nativePaint);
|
||||
}
|
||||
@@ -387,6 +394,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawBitmap(Bitmap bitmap, Matrix matrix, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, matrix.native_instance, nativePaint);
|
||||
}
|
||||
@@ -395,6 +403,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawBitmap(Bitmap bitmap, Rect src, Rect dst, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
|
||||
dst.left, dst.top, dst.right, dst.bottom, nativePaint
|
||||
@@ -403,6 +412,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawBitmap(Bitmap bitmap, Rect src, RectF dst, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
nDrawBitmap(mRenderer, bitmap.mNativeBitmap, src.left, src.top, src.right, src.bottom,
|
||||
dst.left, dst.top, dst.right, dst.bottom, nativePaint
|
||||
@@ -416,6 +426,7 @@ class GLES20Canvas extends Canvas {
|
||||
@Override
|
||||
public void drawBitmap(int[] colors, int offset, int stride, float x, float y,
|
||||
int width, int height, boolean hasAlpha, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
final Bitmap.Config config = hasAlpha ? Bitmap.Config.ARGB_8888 : Bitmap.Config.RGB_565;
|
||||
final Bitmap b = Bitmap.createBitmap(colors, offset, stride, width, height, config);
|
||||
final int nativePaint = paint == null ? 0 : paint.mNativePaint;
|
||||
@@ -426,6 +437,7 @@ class GLES20Canvas extends Canvas {
|
||||
@Override
|
||||
public void drawBitmap(int[] colors, int offset, int stride, int x, int y,
|
||||
int width, int height, boolean hasAlpha, Paint paint) {
|
||||
// Shaders are ignored when drawing bitmaps
|
||||
drawBitmap(colors, offset, stride, (float) x, (float) y, width, height, hasAlpha, paint);
|
||||
}
|
||||
|
||||
@@ -532,7 +544,9 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawRect(float left, float top, float right, float bottom, Paint paint) {
|
||||
boolean hasShader = setupShader(paint);
|
||||
nDrawRect(mRenderer, left, top, right, bottom, paint.mNativePaint);
|
||||
if (hasShader) nResetShader(mRenderer);
|
||||
}
|
||||
|
||||
private native void nDrawRect(int renderer, float left, float top, float right, float bottom,
|
||||
@@ -555,7 +569,7 @@ class GLES20Canvas extends Canvas {
|
||||
|
||||
@Override
|
||||
public void drawRoundRect(RectF rect, float rx, float ry, Paint paint) {
|
||||
throw new UnsupportedOperationException();
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -607,4 +621,27 @@ class GLES20Canvas extends Canvas {
|
||||
int indexOffset, int indexCount, Paint paint) {
|
||||
// TODO: Implement
|
||||
}
|
||||
|
||||
private boolean setupShader(Paint paint) {
|
||||
final Shader shader = paint.getShader();
|
||||
if (shader != null) {
|
||||
if (shader instanceof BitmapShader) {
|
||||
final BitmapShader bs = (BitmapShader) shader;
|
||||
nSetupBitmapShader(mRenderer, bs.native_instance, bs.mBitmap.mNativeBitmap,
|
||||
bs.mTileX, bs.mTileY, bs.mLocalMatrix);
|
||||
return true;
|
||||
} else if (shader instanceof LinearGradient) {
|
||||
// TODO: Implement
|
||||
} else if (shader instanceof RadialGradient) {
|
||||
// TODO: Implement
|
||||
} else if (shader instanceof SweepGradient) {
|
||||
// TODO: Implement
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private native void nSetupBitmapShader(int renderer, int shader, int bitmap,
|
||||
int tileX, int tileY, int matrix);
|
||||
private native void nResetShader(int renderer);
|
||||
}
|
||||
|
||||
@@ -220,6 +220,22 @@ static void android_view_GLES20Canvas_drawRect(JNIEnv* env, jobject canvas,
|
||||
renderer->drawRect(left, top, right, bottom, paint);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// Shaders
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
static void android_view_GLES20Canvas_resetShader(JNIEnv* env, jobject canvas,
|
||||
OpenGLRenderer* renderer) {
|
||||
renderer->resetShader();
|
||||
}
|
||||
|
||||
static void android_view_GLES20Canvas_setupBitmapShader(JNIEnv* env, jobject canvas,
|
||||
OpenGLRenderer* renderer, SkShader* shader, SkBitmap* bitmap,
|
||||
SkShader::TileMode tileX, SkShader::TileMode tileY, SkMatrix* matrix) {
|
||||
renderer->setupBitmapShader(bitmap, tileX, tileY, matrix,
|
||||
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
// JNI Glue
|
||||
// ----------------------------------------------------------------------------
|
||||
@@ -259,6 +275,9 @@ static JNINativeMethod gMethods[] = {
|
||||
{ "nDrawColor", "(III)V", (void*) android_view_GLES20Canvas_drawColor },
|
||||
{ "nDrawRect", "(IFFFFI)V", (void*) android_view_GLES20Canvas_drawRect },
|
||||
|
||||
{ "nResetShader", "(I)V", (void*) android_view_GLES20Canvas_resetShader },
|
||||
{ "nSetupBitmapShader", "(IIIIII)V", (void*) android_view_GLES20Canvas_setupBitmapShader },
|
||||
|
||||
{ "nGetClipBounds", "(ILandroid/graphics/Rect;)Z",
|
||||
(void*) android_view_GLES20Canvas_getClipBounds },
|
||||
};
|
||||
|
||||
@@ -23,9 +23,19 @@ package android.graphics;
|
||||
* drawn with that paint will get its color(s) from the shader.
|
||||
*/
|
||||
public class Shader {
|
||||
/**
|
||||
* Local matrix native instance.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public int mLocalMatrix;
|
||||
|
||||
// this is set by subclasses, but don't make it public
|
||||
/* package */ int native_instance;
|
||||
/**
|
||||
* This is set by subclasses, but don't make it public.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public int native_instance;
|
||||
|
||||
public enum TileMode {
|
||||
/**
|
||||
@@ -64,11 +74,12 @@ public class Shader {
|
||||
* @param localM The shader's new local matrix, or null to specify identity
|
||||
*/
|
||||
public void setLocalMatrix(Matrix localM) {
|
||||
nativeSetLocalMatrix(native_instance,
|
||||
localM != null ? localM.native_instance : 0);
|
||||
mLocalMatrix = localM != null ? localM.native_instance : 0;
|
||||
nativeSetLocalMatrix(native_instance, mLocalMatrix);
|
||||
}
|
||||
|
||||
protected void finalize() throws Throwable {
|
||||
super.finalize();
|
||||
nativeDestructor(native_instance);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,12 @@ static const Blender gBlends[] = {
|
||||
{ SkXfermode::kXor_Mode, GL_ONE_MINUS_DST_ALPHA, GL_ONE_MINUS_SRC_ALPHA }
|
||||
};
|
||||
|
||||
static const GLint gTileModes[] = {
|
||||
GL_CLAMP_TO_EDGE, // == SkShader::kClamp_TileMode
|
||||
GL_REPEAT, // == SkShader::kRepeat_Mode
|
||||
GL_MIRRORED_REPEAT // == SkShader::kMirror_TileMode
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Constructors/destructor
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -116,9 +122,15 @@ OpenGLRenderer::OpenGLRenderer():
|
||||
LOGD(" Using default layer cache size of %dMB", DEFAULT_LAYER_CACHE_SIZE);
|
||||
}
|
||||
|
||||
mDrawColorShader = new DrawColorProgram;
|
||||
mDrawTextureShader = new DrawTextureProgram;
|
||||
mCurrentShader = mDrawTextureShader;
|
||||
mDrawColorProgram = new DrawColorProgram;
|
||||
mDrawTextureProgram = new DrawTextureProgram;
|
||||
mCurrentProgram = mDrawTextureProgram;
|
||||
|
||||
mShader = kShaderNone;
|
||||
mShaderTileX = SkShader::kClamp_TileMode;
|
||||
mShaderTileY = SkShader::kClamp_TileMode;
|
||||
mShaderMatrix = NULL;
|
||||
mShaderBitmap = NULL;
|
||||
|
||||
memcpy(mDrawTextureVertices, gDrawTextureVertices, sizeof(gDrawTextureVertices));
|
||||
}
|
||||
@@ -295,7 +307,7 @@ int OpenGLRenderer::saveLayerAlpha(float left, float top, float right, float bot
|
||||
bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
|
||||
float right, float bottom, int alpha, SkXfermode::Mode mode,int flags) {
|
||||
|
||||
LAYER_LOGD("Requesting layer %dx%d", size.width, size.height);
|
||||
LAYER_LOGD("Requesting layer %fx%f", right - left, bottom - top);
|
||||
LAYER_LOGD("Layer cache size = %d", mLayerCache.getSize());
|
||||
|
||||
GLuint previousFbo = snapshot->previous.get() ? snapshot->previous->fbo : 0;
|
||||
@@ -327,7 +339,7 @@ bool OpenGLRenderer::createLayer(sp<Snapshot> snapshot, float left, float top,
|
||||
saveSnapshot();
|
||||
// TODO: This doesn't preserve other transformations (check Skia first)
|
||||
mSnapshot->transform.loadTranslate(-left, -top, 0.0f);
|
||||
mSnapshot->clipRect.set(left, top, right, bottom);
|
||||
mSnapshot->setClip(left, top, right, bottom);
|
||||
mSnapshot->height = bottom - top;
|
||||
setScissorFromClip();
|
||||
|
||||
@@ -512,50 +524,125 @@ void OpenGLRenderer::drawRect(float left, float top, float right, float bottom,
|
||||
// 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) {
|
||||
if (((color >> 24) & 0xff) == 255) {
|
||||
color |= p->getAlpha() << 24;
|
||||
}
|
||||
|
||||
drawColorRect(left, top, right, bottom, color, mode);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Shaders
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OpenGLRenderer::resetShader() {
|
||||
mShader = OpenGLRenderer::kShaderNone;
|
||||
mShaderBlend = false;
|
||||
mShaderTileX = SkShader::kClamp_TileMode;
|
||||
mShaderTileY = SkShader::kClamp_TileMode;
|
||||
}
|
||||
|
||||
void OpenGLRenderer::setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX,
|
||||
SkShader::TileMode tileY, SkMatrix* matrix, bool hasAlpha) {
|
||||
mShader = kShaderBitmap;
|
||||
mShaderBlend = hasAlpha;
|
||||
mShaderBitmap = bitmap;
|
||||
mShaderTileX = tileX;
|
||||
mShaderTileY = tileY;
|
||||
mShaderMatrix = matrix;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Drawing implementation
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
void OpenGLRenderer::drawColorRect(float left, float top, float right, float bottom,
|
||||
int color, SkXfermode::Mode mode, bool ignoreTransform) {
|
||||
// If a shader is set, preserve only the alpha
|
||||
if (mShader != kShaderNone) {
|
||||
color |= 0x00ffffff;
|
||||
}
|
||||
|
||||
// Render using pre-multiplied alpha
|
||||
const int alpha = (color >> 24) & 0xFF;
|
||||
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;
|
||||
const GLfloat a = alpha / 255.0f;
|
||||
const GLfloat r = a * ((color >> 16) & 0xFF) / 255.0f;
|
||||
const GLfloat g = a * ((color >> 8) & 0xFF) / 255.0f;
|
||||
const GLfloat b = a * ((color ) & 0xFF) / 255.0f;
|
||||
|
||||
switch (mShader) {
|
||||
case kShaderBitmap:
|
||||
drawBitmapShader(left, top, right, bottom, a, mode);
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Pre-multiplication happens when setting the shader color
|
||||
chooseBlending(alpha < 255, mode);
|
||||
chooseBlending(alpha < 255 || mShaderBlend, mode);
|
||||
|
||||
mModelView.loadTranslate(left, top, 0.0f);
|
||||
mModelView.scale(right - left, bottom - top, 1.0f);
|
||||
|
||||
const bool inUse = useShader(mDrawColorShader);
|
||||
if (!ignoreTransform) {
|
||||
mDrawColorShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);
|
||||
} else {
|
||||
mat4 identity;
|
||||
mDrawColorShader->set(mOrthoMatrix, mModelView, identity);
|
||||
}
|
||||
|
||||
if (!inUse) {
|
||||
// TODO: Pick the program matching the current shader
|
||||
sp<DrawColorProgram> program = mDrawColorProgram;
|
||||
if (!useProgram(program)) {
|
||||
const GLvoid* p = &gDrawColorVertices[0].position[0];
|
||||
glVertexAttribPointer(mDrawColorShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
glVertexAttribPointer(program->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawColorVertexStride, p);
|
||||
}
|
||||
// Render using pre-multiplied alpha
|
||||
glUniform4f(mDrawColorShader->color, r * a, g * a, b * a, a);
|
||||
|
||||
if (!ignoreTransform) {
|
||||
program->set(mOrthoMatrix, mModelView, mSnapshot->transform);
|
||||
} else {
|
||||
mat4 identity;
|
||||
program->set(mOrthoMatrix, mModelView, identity);
|
||||
}
|
||||
|
||||
glUniform4f(program->color, r, g, b, a);
|
||||
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, gDrawColorVertexCount);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawBitmapShader(float left, float top, float right, float bottom,
|
||||
float alpha, SkXfermode::Mode mode) {
|
||||
const Texture* texture = mTextureCache.get(mShaderBitmap);
|
||||
|
||||
const float width = texture->width;
|
||||
const float height = texture->height;
|
||||
|
||||
// This could be done in the vertex shader but we have only 4 vertices
|
||||
float u1 = 0.0f;
|
||||
float v1 = 0.0f;
|
||||
float u2 = right - left;
|
||||
float v2 = bottom - top;
|
||||
|
||||
if (mShaderMatrix) {
|
||||
SkMatrix inverse;
|
||||
mShaderMatrix->invert(&inverse);
|
||||
mat4 m(inverse);
|
||||
Rect r(u1, v1, u2, v2);
|
||||
m.mapRect(r);
|
||||
|
||||
u1 = r.left;
|
||||
u2 = r.right;
|
||||
v1 = r.top;
|
||||
v2 = r.bottom;
|
||||
}
|
||||
|
||||
u1 /= width;
|
||||
u2 /= width;
|
||||
v1 /= height;
|
||||
v2 /= height;
|
||||
|
||||
resetDrawTextureTexCoords(u1, v1, u2, v2);
|
||||
|
||||
drawTextureMesh(left, top, right, bottom, texture->id, alpha, mode, texture->blend,
|
||||
&mDrawTextureVertices[0].position[0], &mDrawTextureVertices[0].texture[0], NULL);
|
||||
|
||||
resetDrawTextureTexCoords(0.0f, 0.0f, 1.0f, 1.0f);
|
||||
}
|
||||
|
||||
void OpenGLRenderer::drawTextureRect(float left, float top, float right, float bottom,
|
||||
const Texture* texture, const SkPaint* paint) {
|
||||
int alpha;
|
||||
@@ -578,21 +665,22 @@ void OpenGLRenderer::drawTextureMesh(float left, float top, float right, float b
|
||||
mModelView.loadTranslate(left, top, 0.0f);
|
||||
mModelView.scale(right - left, bottom - top, 1.0f);
|
||||
|
||||
useShader(mDrawTextureShader);
|
||||
mDrawTextureShader->set(mOrthoMatrix, mModelView, mSnapshot->transform);
|
||||
useProgram(mDrawTextureProgram);
|
||||
mDrawTextureProgram->set(mOrthoMatrix, mModelView, mSnapshot->transform);
|
||||
|
||||
chooseBlending(blend || alpha < 1.0f, mode);
|
||||
|
||||
// TODO: Only bind/set parameters when needed
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
// TODO handle tiling and filtering here
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gTileModes[mShaderTileX]);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gTileModes[mShaderTileY]);
|
||||
|
||||
// Always premultiplied
|
||||
glUniform4f(mDrawTextureShader->color, alpha, alpha, alpha, alpha);
|
||||
glUniform4f(mDrawTextureProgram->color, alpha, alpha, alpha, alpha);
|
||||
|
||||
glVertexAttribPointer(mDrawTextureShader->position, 2, GL_FLOAT, GL_FALSE,
|
||||
glVertexAttribPointer(mDrawTextureProgram->position, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawTextureVertexStride, vertices);
|
||||
glVertexAttribPointer(mDrawTextureShader->texCoords, 2, GL_FLOAT, GL_FALSE,
|
||||
glVertexAttribPointer(mDrawTextureProgram->texCoords, 2, GL_FLOAT, GL_FALSE,
|
||||
gDrawTextureVertexStride, texCoords);
|
||||
|
||||
if (!indices) {
|
||||
@@ -630,11 +718,11 @@ void OpenGLRenderer::chooseBlending(bool blend, SkXfermode::Mode mode, bool isPr
|
||||
mBlend = blend;
|
||||
}
|
||||
|
||||
bool OpenGLRenderer::useShader(const sp<Program>& shader) {
|
||||
if (!shader->isInUse()) {
|
||||
mCurrentShader->remove();
|
||||
shader->use();
|
||||
mCurrentShader = shader;
|
||||
bool OpenGLRenderer::useProgram(const sp<Program>& program) {
|
||||
if (!program->isInUse()) {
|
||||
mCurrentProgram->remove();
|
||||
program->use();
|
||||
mCurrentProgram = program;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <SkBitmap.h>
|
||||
#include <SkMatrix.h>
|
||||
#include <SkPaint.h>
|
||||
#include <SkShader.h>
|
||||
#include <SkXfermode.h>
|
||||
|
||||
#include <utils/RefBase.h>
|
||||
@@ -98,7 +99,22 @@ public:
|
||||
void drawColor(int color, SkXfermode::Mode mode);
|
||||
void drawRect(float left, float top, float right, float bottom, const SkPaint* paint);
|
||||
|
||||
void resetShader();
|
||||
void setupBitmapShader(SkBitmap* bitmap, SkShader::TileMode tileX, SkShader::TileMode tileY,
|
||||
SkMatrix* matrix, bool hasAlpha);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Type of Skia shader in use.
|
||||
*/
|
||||
enum ShaderType {
|
||||
kShaderNone,
|
||||
kShaderBitmap,
|
||||
kShaderLinearGradient,
|
||||
kShaderCircularGradient,
|
||||
kShaderSweepGradient
|
||||
};
|
||||
|
||||
/**
|
||||
* Saves the current state of the renderer as a new snapshot.
|
||||
* The new snapshot is saved in mSnapshot and the previous snapshot
|
||||
@@ -216,6 +232,19 @@ private:
|
||||
float alpha, SkXfermode::Mode mode, bool blend,
|
||||
GLvoid* vertices, GLvoid* texCoords, GLvoid* indices, GLsizei elementsCount = 0);
|
||||
|
||||
/**
|
||||
* Fills the specified rectangle with the currently set bitmap shader.
|
||||
*
|
||||
* @param left The left coordinate of the rectangle
|
||||
* @param top The top coordinate of the rectangle
|
||||
* @param right The right coordinate of the rectangle
|
||||
* @param bottom The bottom coordinate of the rectangle
|
||||
* @param alpha An additional translucency parameter, between 0.0f and 1.0f
|
||||
* @param mode The blending mode
|
||||
*/
|
||||
void drawBitmapShader(float left, float top, float right, float bottom, float alpha,
|
||||
SkXfermode::Mode mode);
|
||||
|
||||
/**
|
||||
* Resets the texture coordinates stored in mDrawTextureVertices. Setting the values
|
||||
* back to default is achieved by calling:
|
||||
@@ -246,14 +275,16 @@ private:
|
||||
inline void chooseBlending(bool blend, SkXfermode::Mode mode, bool isPremultiplied = true);
|
||||
|
||||
/**
|
||||
* Use the specified shader with the current GL context. If the shader is already
|
||||
* in use, it will not be bound again. If it is not in use, the current shader is
|
||||
* marked unused and the specified shader becomes used and becomes the new
|
||||
* current shader.
|
||||
* Use the specified program with the current GL context. If the program is already
|
||||
* in use, it will not be bound again. If it is not in use, the current program is
|
||||
* marked unused and the specified program becomes used and becomes the new
|
||||
* current program.
|
||||
*
|
||||
* @return true If the specified shader was already in use, false otherwise.
|
||||
* @param program The program to use
|
||||
*
|
||||
* @return true If the specified program was already in use, false otherwise.
|
||||
*/
|
||||
inline bool useShader(const sp<Program>& shader);
|
||||
inline bool useProgram(const sp<Program>& program);
|
||||
|
||||
// Dimensions of the drawing surface
|
||||
int mWidth, mHeight;
|
||||
@@ -272,9 +303,9 @@ private:
|
||||
sp<Snapshot> mSnapshot;
|
||||
|
||||
// Shaders
|
||||
sp<Program> mCurrentShader;
|
||||
sp<DrawColorProgram> mDrawColorShader;
|
||||
sp<DrawTextureProgram> mDrawTextureShader;
|
||||
sp<Program> mCurrentProgram;
|
||||
sp<DrawColorProgram> mDrawColorProgram;
|
||||
sp<DrawTextureProgram> mDrawTextureProgram;
|
||||
|
||||
// Used to draw textured quads
|
||||
TextureVertex mDrawTextureVertices[4];
|
||||
@@ -284,6 +315,14 @@ private:
|
||||
GLenum mLastSrcMode;
|
||||
GLenum mLastDstMode;
|
||||
|
||||
// Skia shader
|
||||
ShaderType mShader;
|
||||
bool mShaderBlend;
|
||||
SkBitmap* mShaderBitmap;
|
||||
SkShader::TileMode mShaderTileX;
|
||||
SkShader::TileMode mShaderTileY;
|
||||
SkMatrix* mShaderMatrix;
|
||||
|
||||
// Various caches
|
||||
TextureCache mTextureCache;
|
||||
LayerCache mLayerCache;
|
||||
|
||||
@@ -105,6 +105,18 @@ public:
|
||||
return clipped;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the current clip.
|
||||
*/
|
||||
void setClip(float left, float top, float right, float bottom) {
|
||||
clipRect.set(left, top, right, bottom);
|
||||
if (flags & kFlagDirtyTransform) {
|
||||
flags &= ~kFlagDirtyTransform;
|
||||
mappedClip.set(clipRect);
|
||||
transform.mapRect(mappedClip);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Height of the framebuffer the snapshot is rendering into.
|
||||
*/
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
SHADER_SOURCE(gDrawColorFragmentShader,
|
||||
|
||||
precision mediump float;
|
||||
|
||||
uniform vec4 color;
|
||||
|
||||
void main(void) {
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
SHADER_SOURCE(gDrawTextureFragmentShader,
|
||||
|
||||
varying mediump vec2 outTexCoords;
|
||||
precision mediump float;
|
||||
|
||||
varying vec2 outTexCoords;
|
||||
|
||||
uniform vec4 color;
|
||||
uniform sampler2D sampler;
|
||||
|
||||
@@ -96,6 +96,15 @@
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="ShadersActivity"
|
||||
android:label="_Shaders">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
</application>
|
||||
</manifest>
|
||||
|
||||
@@ -25,9 +25,11 @@ import android.graphics.Paint;
|
||||
import android.graphics.PorterDuff;
|
||||
import android.graphics.PorterDuffXfermode;
|
||||
import android.os.Bundle;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.ScaleAnimation;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class BitmapsActivity extends Activity {
|
||||
@@ -35,7 +37,9 @@ public class BitmapsActivity extends Activity {
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
final BitmapsView view = new BitmapsView(this);
|
||||
setContentView(view);
|
||||
final FrameLayout layout = new FrameLayout(this);
|
||||
layout.addView(view, new FrameLayout.LayoutParams(480, 800, Gravity.CENTER));
|
||||
setContentView(layout);
|
||||
|
||||
ScaleAnimation a = new ScaleAnimation(1.0f, 2.0f, 1.0f, 2.0f,
|
||||
ScaleAnimation.RELATIVE_TO_SELF, 0.5f,
|
||||
@@ -50,6 +54,7 @@ public class BitmapsActivity extends Activity {
|
||||
private Paint mBitmapPaint;
|
||||
private final Bitmap mBitmap1;
|
||||
private final Bitmap mBitmap2;
|
||||
private final PorterDuffXfermode mDstIn;
|
||||
|
||||
BitmapsView(Context c) {
|
||||
super(c);
|
||||
@@ -58,6 +63,7 @@ public class BitmapsActivity extends Activity {
|
||||
mBitmap2 = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset2);
|
||||
|
||||
mBitmapPaint = new Paint();
|
||||
mDstIn = new PorterDuffXfermode(PorterDuff.Mode.DST_IN);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -81,10 +87,10 @@ public class BitmapsActivity extends Activity {
|
||||
canvas.translate(0.0f, 25.0f);
|
||||
mBitmapPaint.setColor(0xffff0000);
|
||||
canvas.drawRect(0.0f, 0.0f, mBitmap2.getWidth(), mBitmap2.getHeight(), mBitmapPaint);
|
||||
mBitmapPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));
|
||||
mBitmapPaint.setXfermode(mDstIn);
|
||||
canvas.drawBitmap(mBitmap2, 0.0f, 0.0f, mBitmapPaint);
|
||||
|
||||
mBitmapPaint = new Paint();
|
||||
mBitmapPaint.reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,131 @@
|
||||
/*
|
||||
* 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.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.graphics.BitmapShader;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Color;
|
||||
import android.graphics.LinearGradient;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.Shader;
|
||||
import android.os.Bundle;
|
||||
import android.view.View;
|
||||
|
||||
@SuppressWarnings({"UnusedDeclaration"})
|
||||
public class ShadersActivity extends Activity {
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(new ShadersView(this));
|
||||
}
|
||||
|
||||
static class ShadersView extends View {
|
||||
private BitmapShader mRepeatShader;
|
||||
private BitmapShader mTranslatedShader;
|
||||
private BitmapShader mScaledShader;
|
||||
private int mTexWidth;
|
||||
private int mTexHeight;
|
||||
private Paint mPaint;
|
||||
private float mDrawWidth;
|
||||
private float mDrawHeight;
|
||||
private LinearGradient mHorGradient;
|
||||
private LinearGradient mDiagGradient;
|
||||
private LinearGradient mVertGradient;
|
||||
|
||||
ShadersView(Context c) {
|
||||
super(c);
|
||||
|
||||
Bitmap texture = BitmapFactory.decodeResource(c.getResources(), R.drawable.sunset1);
|
||||
mTexWidth = texture.getWidth();
|
||||
mTexHeight = texture.getHeight();
|
||||
mDrawWidth = mTexWidth * 2.2f;
|
||||
mDrawHeight = mTexHeight * 1.2f;
|
||||
|
||||
mRepeatShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
|
||||
Shader.TileMode.REPEAT);
|
||||
|
||||
mTranslatedShader = new BitmapShader(texture, Shader.TileMode.REPEAT,
|
||||
Shader.TileMode.REPEAT);
|
||||
Matrix m1 = new Matrix();
|
||||
m1.setTranslate(mTexWidth / 2.0f, mTexHeight / 2.0f);
|
||||
mTranslatedShader.setLocalMatrix(m1);
|
||||
|
||||
mScaledShader = new BitmapShader(texture, Shader.TileMode.MIRROR,
|
||||
Shader.TileMode.MIRROR);
|
||||
Matrix m2 = new Matrix();
|
||||
m2.setScale(0.5f, 0.5f);
|
||||
mScaledShader.setLocalMatrix(m2);
|
||||
|
||||
mHorGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth, 0.0f,
|
||||
Color.RED, Color.GREEN, Shader.TileMode.REPEAT);
|
||||
|
||||
mDiagGradient = new LinearGradient(0.0f, 0.0f, mDrawWidth / 1.5f, mDrawHeight,
|
||||
Color.BLUE, Color.MAGENTA, Shader.TileMode.CLAMP);
|
||||
|
||||
mVertGradient = new LinearGradient(0.0f, 0.0f, 0.0f, mDrawHeight / 2.0f,
|
||||
Color.YELLOW, Color.MAGENTA, Shader.TileMode.MIRROR);
|
||||
|
||||
mPaint = new Paint();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawRGB(255, 255, 255);
|
||||
|
||||
// Bitmap shaders
|
||||
canvas.save();
|
||||
canvas.translate(40.0f, 40.0f);
|
||||
|
||||
mPaint.setShader(mRepeatShader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mTranslatedShader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mScaledShader);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.restore();
|
||||
|
||||
// Gradients
|
||||
canvas.save();
|
||||
canvas.translate(40.0f + mDrawWidth + 40.0f, 40.0f);
|
||||
|
||||
mPaint.setShader(mHorGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mDiagGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.translate(0.0f, 40.0f + mDrawHeight);
|
||||
mPaint.setShader(mVertGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, mDrawWidth, mDrawHeight, mPaint);
|
||||
|
||||
canvas.restore();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user