/*******************************************************************************
* Copyright 2012-present Pixate, Inc.
*
* 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.
******************************************************************************/
/**
* Copyright (c) 2012-2013 Pixate, Inc. All rights reserved.
*/
package com.pixate.freestyle.cg.paints;
import java.util.ArrayList;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.RadialGradient;
import android.graphics.Rect;
import android.graphics.Shader.TileMode;
import com.pixate.freestyle.util.ObjectPool;
import com.pixate.freestyle.util.ObjectUtil;
import com.pixate.freestyle.util.PXColorUtil;
import com.pixate.freestyle.util.PXLog;
/**
* Radial gradient representation.
*/
public class PXRadialGradient extends PXGradient {
private static String TAG = PXRadialGradient.class.getSimpleName();
protected PointF center;
protected float radius;
/**
* Constructs a new radial gradient. The center point of this gradient is
* (0, 0), and a radius of 0.
*/
public PXRadialGradient() {
center = new PointF();
}
/**
* Returns the gradient's center point.
*
* @return The center point.
*/
public PointF getCenter() {
return center;
}
/**
* Sets the gradient's center point.
*
* @param center
*/
public void setCenter(PointF center) {
this.center = center;
}
/**
* Returns the radial gradient radius.
*
* @return The radius
*/
public float getRadius() {
return radius;
}
/**
* Sets the radial gradient radius.
*
* @param radius
*/
public void setRadius(float radius) {
this.radius = radius;
}
/*
* (non-Javadoc)
* @see
* com.pixate.freestyle.pxengine.cg.PXPaint#applyFillToPath(android.graphics
* .Path, android.graphics.Paint, android.graphics.Canvas)
*/
public void applyFillToPath(Path path, Paint paint, Canvas context) {
context.save();
// clip to path
context.clipPath(path);
// transform gradient space
context.concat(transform);
// do the gradient (note that we cannot really do a a radial gradient
// with 2 center points, like in iOS).
Rect bounds = new Rect();
context.getClipBounds(bounds);
Paint p = ObjectPool.paintPool.checkOut(paint);
p.setAntiAlias(true);
p.setShader(getGradient(bounds));
// apply the blending mode
p.setXfermode(blendingMode);
// draw
context.drawPaint(p);
// restore coordinate system
context.restore();
// Check the paint back into the pool
ObjectPool.paintPool.checkIn(p);
}
public PXPaint lightenByPercent(float percent) {
PXRadialGradient result = createCopyWithoutColors();
// copy and lighten colors
for (int color : colors) {
addColor(PXColorUtil.lightterByPercent(color, percent));
}
return result;
}
public PXPaint darkenByPercent(float percent) {
PXRadialGradient result = createCopyWithoutColors();
// copy and darken colors
for (int color : colors) {
addColor(PXColorUtil.lightterByPercent(color, percent));
}
return result;
}
private PXRadialGradient createCopyWithoutColors() {
PXRadialGradient result = new PXRadialGradient();
// copy properties
result.setCenter(new PointF(center.x, center.y));
result.setRadius(radius);
// copy PXGradient properties, but not colors
result.setTransform(new Matrix(transform));
result.offsets = new ArrayList<Float>(offsets);
return result;
}
/*
* (non-Javadoc)
* @see com.pixate.freestyle.pxengine.cg.PXGradient#equals(java.lang.Object)
*/
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other instanceof PXRadialGradient && super.equals(other)) {
PXRadialGradient gradient = (PXRadialGradient) other;
return radius == gradient.radius && ObjectUtil.areEqual(center, gradient.center);
}
return false;
}
// Create and return the gradient.
private RadialGradient getGradient(Rect bounds) {
adjustGradientColors();
int count = colors.size();
int[] colors = new int[count];
float[] positions = new float[count];
for (int i = 0; i < count; i++) {
colors[i] = this.colors.get(i);
positions[i] = this.offsets.get(i);
}
try {
float r;
PointF c;
if (radius == 0) {
c = new PointF(bounds.exactCenterX(), bounds.exactCenterY());
r = Math.min(bounds.width() * 0.5f, bounds.height() * 0.5f);
} else if (gradientUnits == PXGradientUnits.USER_SPACE) {
c = new PointF(center.x, center.y);
r = radius;
} else {
// linear-gradient points are based on the shape's bbox, so grab
// that
Rect pathBounds = bounds;
// grab the x,y offset which we will apply later
int left = pathBounds.left;
int top = pathBounds.top;
// grab the positions within the bbox for each point
float p1x = pathBounds.width() * center.x;
float p1y = pathBounds.height() * center.y;
// create final points by offsetting the bbox coordinates by the
// bbox origin
c = new PointF(left + p1x, top + p1y);
// TODO: need rx and ry. Using width for both now
r = pathBounds.width() * radius;
}
RadialGradient gradient = new RadialGradient(c.x, c.y, r, colors, positions,
TileMode.CLAMP);
return gradient;
} catch (Exception e) {
if (PXLog.isLogging()) {
PXLog.e(TAG, e, "Error while instantiating a RadialGradient");
}
return null;
}
}
}