Merge "Add support for circular gradients to the GL renderer."
This commit is contained in:
@@ -226,10 +226,8 @@ static SkShader* LinearGradient_create2(JNIEnv* env, jobject o,
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
|
||||
float x, float y, float radius,
|
||||
jintArray colorArray, jfloatArray posArray, int tileMode)
|
||||
{
|
||||
static SkShader* RadialGradient_create1(JNIEnv* env, jobject, float x, float y, float radius,
|
||||
jintArray colorArray, jfloatArray posArray, int tileMode) {
|
||||
SkPoint center;
|
||||
center.set(SkFloatToScalar(x), SkFloatToScalar(y));
|
||||
|
||||
@@ -259,10 +257,8 @@ static SkShader* RadialGradient_create1(JNIEnv* env, jobject,
|
||||
return shader;
|
||||
}
|
||||
|
||||
static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
|
||||
float x, float y, float radius,
|
||||
int color0, int color1, int tileMode)
|
||||
{
|
||||
static SkShader* RadialGradient_create2(JNIEnv* env, jobject, float x, float y, float radius,
|
||||
int color0, int color1, int tileMode) {
|
||||
SkPoint center;
|
||||
center.set(SkFloatToScalar(x), SkFloatToScalar(y));
|
||||
|
||||
@@ -276,11 +272,65 @@ static SkShader* RadialGradient_create2(JNIEnv* env, jobject,
|
||||
return s;
|
||||
}
|
||||
|
||||
static SkiaShader* RadialGradient_postCreate1(JNIEnv* env, jobject o, SkShader* shader,
|
||||
float x, float y, float radius, jintArray colorArray, jfloatArray posArray, int tileMode) {
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
size_t count = env->GetArrayLength(colorArray);
|
||||
const jint* colorValues = env->GetIntArrayElements(colorArray, NULL);
|
||||
|
||||
jfloat* storedPositions = new jfloat[count];
|
||||
uint32_t* storedColors = new uint32_t[count];
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
storedColors[i] = static_cast<uint32_t>(colorValues[i]);
|
||||
}
|
||||
|
||||
if (posArray) {
|
||||
AutoJavaFloatArray autoPos(env, posArray, count);
|
||||
const float* posValues = autoPos.ptr();
|
||||
for (size_t i = 0; i < count; i++) {
|
||||
storedPositions[i] = posValues[i];
|
||||
}
|
||||
} else {
|
||||
storedPositions[0] = 0.0f;
|
||||
storedPositions[1] = 1.0f;
|
||||
}
|
||||
|
||||
SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
|
||||
storedPositions, count, shader, (SkShader::TileMode) tileMode, NULL,
|
||||
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
|
||||
|
||||
env->ReleaseIntArrayElements(colorArray, const_cast<jint*>(colorValues), JNI_ABORT);
|
||||
return skiaShader;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static SkiaShader* RadialGradient_postCreate2(JNIEnv* env, jobject o, SkShader* shader,
|
||||
float x, float y, float radius, int color0, int color1, int tileMode) {
|
||||
#ifdef USE_OPENGL_RENDERER
|
||||
float* storedPositions = new float[2];
|
||||
storedPositions[0] = 0.0f;
|
||||
storedPositions[1] = 1.0f;
|
||||
|
||||
uint32_t* storedColors = new uint32_t[2];
|
||||
storedColors[0] = static_cast<uint32_t>(color0);
|
||||
storedColors[1] = static_cast<uint32_t>(color1);
|
||||
|
||||
SkiaShader* skiaShader = new SkiaCircularGradientShader(x, y, radius, storedColors,
|
||||
storedPositions, 2, shader, (SkShader::TileMode) tileMode, NULL,
|
||||
(shader->getFlags() & SkShader::kOpaqueAlpha_Flag) == 0);
|
||||
|
||||
return skiaShader;
|
||||
#else
|
||||
return NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
|
||||
jintArray jcolors, jfloatArray jpositions)
|
||||
{
|
||||
jintArray jcolors, jfloatArray jpositions) {
|
||||
size_t count = env->GetArrayLength(jcolors);
|
||||
const jint* colors = env->GetIntArrayElements(jcolors, NULL);
|
||||
|
||||
@@ -307,8 +357,7 @@ static SkShader* SweepGradient_create1(JNIEnv* env, jobject, float x, float y,
|
||||
}
|
||||
|
||||
static SkShader* SweepGradient_create2(JNIEnv* env, jobject, float x, float y,
|
||||
int color0, int color1)
|
||||
{
|
||||
int color0, int color1) {
|
||||
SkColor colors[2];
|
||||
colors[0] = color0;
|
||||
colors[1] = color1;
|
||||
@@ -437,22 +486,24 @@ static JNINativeMethod gLinearGradientMethods[] = {
|
||||
};
|
||||
|
||||
static JNINativeMethod gRadialGradientMethods[] = {
|
||||
{"nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 },
|
||||
{"nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 }
|
||||
{ "nativeCreate1", "(FFF[I[FI)I", (void*)RadialGradient_create1 },
|
||||
{ "nativeCreate2", "(FFFIII)I", (void*)RadialGradient_create2 },
|
||||
{ "nativePostCreate1", "(IFFF[I[FI)I", (void*)RadialGradient_postCreate1 },
|
||||
{ "nativePostCreate2", "(IFFFIII)I", (void*)RadialGradient_postCreate2 }
|
||||
};
|
||||
|
||||
static JNINativeMethod gSweepGradientMethods[] = {
|
||||
{"nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 },
|
||||
{"nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 },
|
||||
{ "nativeCreate1", "(FF[I[F)I", (void*)SweepGradient_create1 },
|
||||
{ "nativeCreate2", "(FFII)I", (void*)SweepGradient_create2 },
|
||||
{ "nativePostCreate1", "(IFF[I[F)I", (void*)SweepGradient_postCreate1 },
|
||||
{ "nativePostCreate2", "(IFFII)I", (void*)SweepGradient_postCreate2 }
|
||||
};
|
||||
|
||||
static JNINativeMethod gComposeShaderMethods[] = {
|
||||
{"nativeCreate1", "(III)I", (void*)ComposeShader_create1 },
|
||||
{"nativeCreate2", "(III)I", (void*)ComposeShader_create2 },
|
||||
{"nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 },
|
||||
{"nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 }
|
||||
{ "nativeCreate1", "(III)I", (void*)ComposeShader_create1 },
|
||||
{ "nativeCreate2", "(III)I", (void*)ComposeShader_create2 },
|
||||
{ "nativePostCreate1", "(IIII)I", (void*)ComposeShader_postCreate1 },
|
||||
{ "nativePostCreate2", "(IIII)I", (void*)ComposeShader_postCreate2 }
|
||||
};
|
||||
|
||||
#include <android_runtime/AndroidRuntime.h>
|
||||
|
||||
@@ -40,6 +40,8 @@ public class RadialGradient extends Shader {
|
||||
throw new IllegalArgumentException("color and position arrays must be of equal length");
|
||||
}
|
||||
native_instance = nativeCreate1(x, y, radius, colors, positions, tile.nativeInt);
|
||||
native_shader = nativePostCreate1(native_instance, x, y, radius, colors, positions,
|
||||
tile.nativeInt);
|
||||
}
|
||||
|
||||
/** Create a shader that draws a radial gradient given the center and radius.
|
||||
@@ -56,11 +58,18 @@ public class RadialGradient extends Shader {
|
||||
throw new IllegalArgumentException("radius must be > 0");
|
||||
}
|
||||
native_instance = nativeCreate2(x, y, radius, color0, color1, tile.nativeInt);
|
||||
native_shader = nativePostCreate2(native_instance, x, y, radius, color0, color1,
|
||||
tile.nativeInt);
|
||||
}
|
||||
|
||||
private static native int nativeCreate1(float x, float y, float radius,
|
||||
int colors[], float positions[], int tileMode);
|
||||
int colors[], float positions[], int tileMode);
|
||||
private static native int nativeCreate2(float x, float y, float radius,
|
||||
int color0, int color1, int tileMode);
|
||||
int color0, int color1, int tileMode);
|
||||
|
||||
private static native int nativePostCreate1(int native_shader, float x, float y, float radius,
|
||||
int colors[], float positions[], int tileMode);
|
||||
private static native int nativePostCreate2(int native_shader, float x, float y, float radius,
|
||||
int color0, int color1, int tileMode);
|
||||
}
|
||||
|
||||
|
||||
@@ -144,6 +144,12 @@ float Matrix4::getTranslateY() {
|
||||
return data[kTranslateY];
|
||||
}
|
||||
|
||||
void Matrix4::multiply(float v) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
data[i] *= v;
|
||||
}
|
||||
}
|
||||
|
||||
void Matrix4::loadTranslate(float x, float y, float z) {
|
||||
loadIdentity();
|
||||
data[kTranslateX] = x;
|
||||
|
||||
@@ -83,6 +83,8 @@ public:
|
||||
load(u);
|
||||
}
|
||||
|
||||
void multiply(float v);
|
||||
|
||||
void translate(float x, float y, float z) {
|
||||
Matrix4 u;
|
||||
u.loadTranslate(x, y, z);
|
||||
|
||||
@@ -40,9 +40,12 @@ const char* gVS_Header_Uniforms_HasGradient[3] = {
|
||||
"uniform vec2 gradientStart;\n"
|
||||
"uniform mat4 screenSpace;\n",
|
||||
// Circular
|
||||
"",
|
||||
"uniform vec2 gradientStart;\n"
|
||||
"uniform mat4 gradientMatrix;\n"
|
||||
"uniform mat4 screenSpace;\n",
|
||||
// Sweep
|
||||
"uniform vec2 gradientStart;\n"
|
||||
"uniform mat4 gradientMatrix;\n"
|
||||
"uniform mat4 screenSpace;\n"
|
||||
};
|
||||
const char* gVS_Header_Uniforms_HasBitmap =
|
||||
@@ -56,7 +59,7 @@ const char* gVS_Header_Varyings_HasGradient[3] = {
|
||||
// Linear
|
||||
"varying float index;\n",
|
||||
// Circular
|
||||
"",
|
||||
"varying vec2 circular;\n",
|
||||
// Sweep
|
||||
"varying vec2 sweep;\n"
|
||||
};
|
||||
@@ -69,10 +72,11 @@ const char* gVS_Main_OutGradient[3] = {
|
||||
" vec4 location = screenSpace * position;\n"
|
||||
" index = dot(location.xy - gradientStart, gradient) * gradientLength;\n",
|
||||
// Circular
|
||||
"",
|
||||
" vec4 location = screenSpace * position;\n"
|
||||
" circular = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n",
|
||||
// Sweep
|
||||
" vec4 location = screenSpace * position;\n"
|
||||
" sweep = location.xy - gradientStart;\n"
|
||||
" sweep = (gradientMatrix * vec4(location.xy - gradientStart, 0.0, 0.0)).xy;\n"
|
||||
};
|
||||
const char* gVS_Main_OutBitmapTexCoords =
|
||||
" vec4 bitmapCoords = textureTransform * position;\n"
|
||||
@@ -98,6 +102,7 @@ const char* gFS_Uniforms_GradientSampler[3] = {
|
||||
// Linear
|
||||
"uniform sampler2D gradientSampler;\n",
|
||||
// Circular
|
||||
"uniform float gradientRadius;\n"
|
||||
"uniform sampler2D gradientSampler;\n",
|
||||
// Sweep
|
||||
"uniform sampler2D gradientSampler;\n"
|
||||
@@ -129,7 +134,8 @@ const char* gFS_Main_FetchGradient[3] = {
|
||||
// Linear
|
||||
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
|
||||
// Circular
|
||||
"",
|
||||
" float index = length(circular) * gradientRadius;\n"
|
||||
" vec4 gradientColor = texture2D(gradientSampler, vec2(index, 0.5));\n",
|
||||
// Sweep
|
||||
" float index = atan(sweep.y, sweep.x) * 0.15915494309; // inv(2 * PI)\n"
|
||||
" vec4 gradientColor = texture2D(gradientSampler, vec2(index - floor(index), 0.5));\n"
|
||||
|
||||
@@ -208,6 +208,30 @@ void SkiaLinearGradientShader::updateTransforms(Program* program, const mat4& mo
|
||||
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Circular gradient shader
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SkiaCircularGradientShader::SkiaCircularGradientShader(float x, float y, float radius,
|
||||
uint32_t* colors, float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
|
||||
SkMatrix* matrix, bool blend):
|
||||
SkiaSweepGradientShader(kCircularGradient, x, y, colors, positions, count, key,
|
||||
tileMode, matrix, blend),
|
||||
mRadius(radius) {
|
||||
}
|
||||
|
||||
void SkiaCircularGradientShader::describe(ProgramDescription& description,
|
||||
const Extensions& extensions) {
|
||||
description.hasGradient = true;
|
||||
description.gradientType = ProgramDescription::kGradientCircular;
|
||||
}
|
||||
|
||||
void SkiaCircularGradientShader::setupProgram(Program* program, const mat4& modelView,
|
||||
const Snapshot& snapshot, GLuint* textureUnit) {
|
||||
SkiaSweepGradientShader::setupProgram(program, modelView, snapshot, textureUnit);
|
||||
glUniform1f(program->getUniform("gradientRadius"), 1.0f / mRadius);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
// Sweep gradient shader
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
@@ -219,6 +243,13 @@ SkiaSweepGradientShader::SkiaSweepGradientShader(float x, float y, uint32_t* col
|
||||
mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
|
||||
}
|
||||
|
||||
SkiaSweepGradientShader::SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors,
|
||||
float* positions, int count, SkShader* key, SkShader::TileMode tileMode,
|
||||
SkMatrix* matrix, bool blend):
|
||||
SkiaShader(type, key, tileMode, tileMode, matrix, blend),
|
||||
mX(x), mY(y), mColors(colors), mPositions(positions), mCount(count) {
|
||||
}
|
||||
|
||||
SkiaSweepGradientShader::~SkiaSweepGradientShader() {
|
||||
delete[] mColors;
|
||||
delete[] mPositions;
|
||||
@@ -243,10 +274,15 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi
|
||||
float left = mX;
|
||||
float top = mY;
|
||||
|
||||
mat4 shaderMatrix;
|
||||
if (mMatrix) {
|
||||
mat4 shaderMatrix(*mMatrix);
|
||||
shaderMatrix.load(*mMatrix);
|
||||
shaderMatrix.mapPoint(left, top);
|
||||
}
|
||||
|
||||
mat4 copy(shaderMatrix);
|
||||
shaderMatrix.loadInverse(copy);
|
||||
|
||||
snapshot.transform->mapPoint(left, top);
|
||||
|
||||
mat4 screenSpace(*snapshot.transform);
|
||||
@@ -255,6 +291,7 @@ void SkiaSweepGradientShader::setupProgram(Program* program, const mat4& modelVi
|
||||
// Uniforms
|
||||
bindTexture(texture->id, gTileModes[mTileX], gTileModes[mTileY], textureSlot);
|
||||
glUniform1i(program->getUniform("gradientSampler"), textureSlot);
|
||||
glUniformMatrix4fv(program->getUniform("gradientMatrix"), 1, GL_FALSE, &shaderMatrix.data[0]);
|
||||
glUniform2f(program->getUniform("gradientStart"), left, top);
|
||||
glUniformMatrix4fv(program->getUniform("screenSpace"), 1, GL_FALSE, &screenSpace.data[0]);
|
||||
}
|
||||
|
||||
@@ -152,18 +152,36 @@ struct SkiaSweepGradientShader: public SkiaShader {
|
||||
SkShader* key, SkMatrix* matrix, bool blend);
|
||||
~SkiaSweepGradientShader();
|
||||
|
||||
void describe(ProgramDescription& description, const Extensions& extensions);
|
||||
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
|
||||
virtual void describe(ProgramDescription& description, const Extensions& extensions);
|
||||
virtual void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
|
||||
GLuint* textureUnit);
|
||||
void updateTransforms(Program* program, const mat4& modelView, const Snapshot& snapshot);
|
||||
|
||||
private:
|
||||
protected:
|
||||
SkiaSweepGradientShader(Type type, float x, float y, uint32_t* colors, float* positions,
|
||||
int count, SkShader* key, SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
|
||||
|
||||
float mX, mY;
|
||||
uint32_t* mColors;
|
||||
float* mPositions;
|
||||
int mCount;
|
||||
}; // struct SkiaSweepGradientShader
|
||||
|
||||
/**
|
||||
* A shader that draws a circular gradient.
|
||||
*/
|
||||
struct SkiaCircularGradientShader: public SkiaSweepGradientShader {
|
||||
SkiaCircularGradientShader(float x, float y, float radius, uint32_t* colors, float* positions,
|
||||
int count, SkShader* key,SkShader::TileMode tileMode, SkMatrix* matrix, bool blend);
|
||||
|
||||
void describe(ProgramDescription& description, const Extensions& extensions);
|
||||
void setupProgram(Program* program, const mat4& modelView, const Snapshot& snapshot,
|
||||
GLuint* textureUnit);
|
||||
|
||||
private:
|
||||
float mRadius;
|
||||
}; // struct SkiaCircularGradientShader
|
||||
|
||||
/**
|
||||
* A shader that draws two shaders, composited with an xfermode.
|
||||
*/
|
||||
|
||||
@@ -42,19 +42,25 @@ public class AdvancedGradientsActivity extends Activity {
|
||||
private final RadialGradient mRadialGradient;
|
||||
private final Matrix mMatrix;
|
||||
private final Matrix mMatrix2;
|
||||
private final Matrix mMatrix3;
|
||||
|
||||
GradientsView(Context c) {
|
||||
super(c);
|
||||
|
||||
mSweepGradient = new SweepGradient(100.0f, 100.0f, 0xff000000, 0xffffffff);
|
||||
mRadialGradient = new RadialGradient(100.0f, 100.0f, 100.0f, 0xff000000, 0xffffffff,
|
||||
mSweepGradient = new SweepGradient(0.0f, 0.0f, 0xff000000, 0xffffffff);
|
||||
mRadialGradient = new RadialGradient(0.0f, 0.0f, 100.0f, 0xff000000, 0xffffffff,
|
||||
Shader.TileMode.MIRROR);
|
||||
|
||||
mMatrix = new Matrix();
|
||||
mMatrix.setTranslate(50.0f, 50.0f);
|
||||
mMatrix.setRotate(-45, 0.0f, 0.0f);
|
||||
mMatrix.postTranslate(100.0f, 100.0f);
|
||||
|
||||
mMatrix2 = new Matrix();
|
||||
mMatrix2.setScale(2.0f, 2.0f);
|
||||
mMatrix2.setScale(1.0f, 2.0f);
|
||||
mMatrix2.postRotate(-45, 0.0f, 0.0f);
|
||||
|
||||
mMatrix3 = new Matrix();
|
||||
mMatrix3.setTranslate(100.0f, 100.0f);
|
||||
|
||||
mPaint = new Paint();
|
||||
}
|
||||
@@ -64,30 +70,42 @@ public class AdvancedGradientsActivity extends Activity {
|
||||
super.onDraw(canvas);
|
||||
canvas.drawRGB(255, 255, 255);
|
||||
|
||||
// Bitmap shaders
|
||||
canvas.save();
|
||||
canvas.translate(130.0f, 100.0f);
|
||||
|
||||
mSweepGradient.setLocalMatrix(null);
|
||||
mSweepGradient.setLocalMatrix(mMatrix3);
|
||||
mPaint.setShader(mSweepGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(400.0f, 000.0f);
|
||||
|
||||
mPaint.setShader(mRadialGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(400.0f, 000.0f);
|
||||
|
||||
mSweepGradient.setLocalMatrix(mMatrix);
|
||||
mPaint.setShader(mSweepGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(-800.0f, 300.0f);
|
||||
canvas.translate(400.0f, 000.0f);
|
||||
|
||||
mSweepGradient.setLocalMatrix(mMatrix2);
|
||||
mPaint.setShader(mSweepGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(-800.0f, 300.0f);
|
||||
|
||||
mRadialGradient.setLocalMatrix(null);
|
||||
mPaint.setShader(mRadialGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(400.0f, 000.0f);
|
||||
|
||||
mRadialGradient.setLocalMatrix(mMatrix);
|
||||
mPaint.setShader(mRadialGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
canvas.translate(400.0f, 000.0f);
|
||||
|
||||
mRadialGradient.setLocalMatrix(mMatrix2);
|
||||
mPaint.setShader(mRadialGradient);
|
||||
canvas.drawRect(0.0f, 0.0f, 200.0f, 200.0f, mPaint);
|
||||
|
||||
|
||||
canvas.restore();
|
||||
|
||||
Reference in New Issue
Block a user