package com.glview.graphics.shader;
import com.glview.libgdx.graphics.glutils.ShaderProgram;
import com.glview.libgdx.graphics.glutils.ShaderProgram.HandleInfo;
public class LinearGradient extends DefaultTextureShader {
private static final int TYPE_COLORS_AND_POSITIONS = 1;
private static final int TYPE_COLOR_START_AND_COLOR_END = 2;
/**
* Type of the LinearGradient: can be either TYPE_COLORS_AND_POSITIONS or
* TYPE_COLOR_START_AND_COLOR_END.
*/
private int mType;
private float mX0;
private float mY0;
private float mX1;
private float mY1;
private int[] mColors;
private float[] mPositions;
private int mColor0;
private int mColor1;
private TileMode mTileMode;
HandleInfo mStartColorHandle;
HandleInfo mEndColorHandle;
HandleInfo mStartPointHandle;
HandleInfo mEndPointHandle;
public LinearGradient(float x0, float y0, float x1, float y1, int colors[], float positions[],
TileMode tile) {
if (colors.length < 2) {
throw new IllegalArgumentException("needs >= 2 number of colors");
}
if (positions != null && colors.length != positions.length) {
throw new IllegalArgumentException("color and position arrays must be of equal length");
}
if (colors.length == 2 && positions == null) {
initColorStartAndColorEnd(x0, y0, x1, y1, colors[0], colors[1], tile);
} else {
mType = TYPE_COLORS_AND_POSITIONS;
mX0 = x0;
mY0 = y0;
mX1 = x1;
mY1 = y1;
mColors = colors;
if (positions == null) {
float dis = 1f / (mColors.length - 1);
positions = new float[mColors.length];
for (int i = 0; i < mColors.length; i ++) {
positions[i] = dis * i;
}
}
mPositions = positions;
mTileMode = tile;
mStartPointHandle = new HandleInfo("u_startPoint");
mEndPointHandle = new HandleInfo("u_endPoint");
}
}
public LinearGradient(float x0, float y0, float x1, float y1,
int color0, int color1) {
this(x0, y0, x1, y1, color0, color1, TileMode.CLAMP);
}
public LinearGradient(float x0, float y0, float x1, float y1,
int color0, int color1, TileMode tile) {
initColorStartAndColorEnd(x0, y0, x1, y1, color0, color1, tile);
}
private void initColorStartAndColorEnd(float x0, float y0, float x1, float y1,
int color0, int color1, TileMode tile) {
mType = TYPE_COLOR_START_AND_COLOR_END;
this.mX0 = x0;
this.mY0 = y0;
this.mX1 = x1;
this.mY1 = y1;
this.mColor0 = color0;
this.mColor1 = color1;
mTileMode = tile;
mStartColorHandle = new HandleInfo("u_startColor");
mEndColorHandle = new HandleInfo("u_endColor");
mStartPointHandle = new HandleInfo("u_startPoint");
mEndPointHandle = new HandleInfo("u_endPoint");
}
boolean isSimplemGradient() {
return mType == TYPE_COLOR_START_AND_COLOR_END;
}
public void setPosition(float x0, float y0, float x1, float y1) {
this.mX0 = x0;
this.mY0 = y0;
this.mX1 = x1;
this.mY1 = y1;
}
public void setColors(int color0, int color1) {
this.mColor0 = color0;
this.mColor1 = color1;
}
@Override
public void setHasTexture(boolean hasTexture) {
if (mHasTexture != hasTexture) {
super.setHasTexture(hasTexture);
// recreate this shader.
invalidate();
}
}
protected String generateVertexShader() {
StringBuffer vertexShader = new StringBuffer();
vertexShader.append("attribute vec4 " + ShaderProgram.POSITION_ATTRIBUTE + ";\n"); //
vertexShader.append("uniform mat4 u_projTrans;\n"); //
vertexShader.append("uniform vec2 u_startPoint;\n");//
vertexShader.append("uniform vec2 u_endPoint;\n"); //
if (mHasTexture) {
vertexShader.append("varying vec2 v_texCoords;\n"); //
}
vertexShader.append("varying float linear;\n"); //
vertexShader.append("\n"); //
vertexShader.append("void main()\n"); //
vertexShader.append("{\n"); //
if (mHasTexture) {
vertexShader.append(" v_texCoords = vec2(("+ ShaderProgram.POSITION_ATTRIBUTE + ".x - u_texSize.x)/u_texSize.z, ("+ ShaderProgram.POSITION_ATTRIBUTE + ".y - u_texSize.y)/u_texSize.w);\n");
}
vertexShader.append(" vec2 a = u_endPoint - u_startPoint;\n");
vertexShader.append(" vec2 b = vec2(" + ShaderProgram.POSITION_ATTRIBUTE + ".x, " + ShaderProgram.POSITION_ATTRIBUTE + ".y) - u_startPoint;\n");
vertexShader.append(" float length1 = length(b * a / length(a));\n");
vertexShader.append(" linear = length1 / length(a);\n");
vertexShader.append(" gl_Position = u_projTrans * " + ShaderProgram.POSITION_ATTRIBUTE + ";\n"); //
vertexShader.append("}\n");;
return vertexShader.toString();
}
@Override
protected String generateFragmentShader() {
StringBuffer fragmentShader = new StringBuffer();
fragmentShader.append("#ifdef GL_ES\n"); //
fragmentShader.append("#define LOWP lowp\n"); //
fragmentShader.append("precision mediump float;\n"); //
fragmentShader.append("#else\n"); //
fragmentShader.append("#define LOWP \n"); //
fragmentShader.append("#endif\n"); //
if (isSimplemGradient()) {
fragmentShader.append("uniform vec4 u_startColor;\n"); //
fragmentShader.append("uniform vec4 u_endColor;\n"); //
}
fragmentShader.append("uniform vec4 u_ColorTotal;\n"); //
if (mHasTexture) {
fragmentShader.append("uniform sampler2D u_texture;\n"); //
}
fragmentShader.append("varying float linear;\n");//
generateLinearWrap(fragmentShader);
fragmentShader.append("void main()\n");//
fragmentShader.append("{\n"); //
generateLinearColor(fragmentShader);
if (mHasTexture) {
fragmentShader.append(" gl_FragColor = gradientColor*u_ColorTotal*texture2D(u_texture, v_texCoords);\n"); //
} else {
fragmentShader.append(" gl_FragColor = gradientColor * u_ColorTotal;\n"); //
}
fragmentShader.append("}");
return fragmentShader.toString();
}
private void generateLinearColor(StringBuffer s) {
s.append(" float al = clamp(wrap(linear), 0.0, 1.0);\n");
s.append(" vec4 gradientColor;\n");
if (isSimplemGradient()) {
s.append(" gradientColor = mix(u_startColor, u_endColor, al);\n");
} else {
for (int i = 0; i < mColors.length - 1; i ++) {
s.append(((i > 0) ? " else" : "") + " if (al >= " + mPositions[i] + " && al <= " + mPositions[i + 1] + ") {\n");
float dis = mPositions[i + 1] - mPositions[i];
float[] startColor = swapColor(mColors[i]);
float[] endColor = swapColor(mColors[i + 1]);
if (dis <= 0) {
s.append(" gradientColor = vec4(" + startColor[0] + ", " + startColor[1] + ", " + startColor[2] + ", " + startColor[3] + ");\n");
} else {
s.append(" gradientColor = mix(vec4(" + startColor[0]
+ ", " + startColor[1] + ", " + startColor[2]
+ ", " + startColor[3] + "), vec4(" + endColor[0]
+ ", " + endColor[1] + ", " + endColor[2] + ", "
+ endColor[3] + "), clamp((al - " + mPositions[i] + ") / " + dis + ", 0.0, 1.0));\n");
}
s.append(" }\n");
}
}
}
private float[] swapColor(int color) {
float prealpha = ((color >>> 24)&0xFF)*1.0f/255;
float colorR = Math.round(((color >> 16) & 0xFF) * prealpha)*1.0f/255;
float colorG = Math.round(((color >> 8) & 0xFF) * prealpha)*1.0f/255;
float colorB = Math.round((color & 0xFF) * prealpha)*1.0f/255;
float colorA = Math.round(255 * prealpha)*1.0f/255;
return new float[] {colorR, colorG, colorB, colorA};
}
private void generateLinearWrap(StringBuffer s) {
s.append("highp float wrap(highp float linear) {\n");
if (mTileMode == TileMode.MIRROR) {
s.append(" highp float mod2 = mod(linear, 2.0);\n");
s.append(" if (mod2 > 1.0) mod2 = 2.0 - mod2;\n");
}
s.append(" return ");
switch (mTileMode) {
case CLAMP:
s.append("linear");
break;
case REPEAT:
s.append("mod(linear, 1.0)");
break;
case MIRROR:
s.append("mod2");
break;
default:
break;
}
s.append(";\n}\n");
}
@Override
public void setupCustomValues() {
if (isSimplemGradient()) {
float prealpha = ((mColor0 >>> 24)&0xFF)*1.0f/255;
float colorR = Math.round(((mColor0 >> 16) & 0xFF) * prealpha)*1.0f/255;
float colorG = Math.round(((mColor0 >> 8) & 0xFF) * prealpha)*1.0f/255;
float colorB = Math.round((mColor0 & 0xFF) * prealpha)*1.0f/255;
float colorA = Math.round(255 * prealpha)*1.0f/255;
getShaderProgram().setUniformf(mStartColorHandle, colorR, colorG, colorB, colorA);
prealpha = ((mColor1 >>> 24)&0xFF)*1.0f/255;
colorR = Math.round(((mColor1 >> 16) & 0xFF) * prealpha)*1.0f/255;
colorG = Math.round(((mColor1 >> 8) & 0xFF) * prealpha)*1.0f/255;
colorB = Math.round((mColor1 & 0xFF) * prealpha)*1.0f/255;
colorA = Math.round(255 * prealpha)*1.0f/255;
getShaderProgram().setUniformf(mEndColorHandle, colorR, colorG, colorB, colorA);
} else {
}
getShaderProgram().setUniformf(mStartPointHandle, mX0, mY0);
getShaderProgram().setUniformf(mEndPointHandle, mX1, mY1);
}
@Override
public void setupTextureCoords(float x, float y, float width, float height) {
if (mHasTexture) {
super.setupTextureCoords(x, y, width, height);
}
}
@Override
public void setupColor(float r, float g, float b, float a) {
super.setupColor(r, g, b, a);
}
}