public class ImageFilter {
static final float COORD1[] = {
-1.0f, -1.0f,
1.0f, 1.0f,
-1.0f, 1.0f,
1.0f, -1.0f,
};
static final float BOOK_COORD1[] = {
0.0f, 0.0f,
1.0f, 1.0f,
0.0f, 1.0f,
1.0f, 0.0f,
};
static final float TEXTURE_COORD1[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
//世界坐标系
static final float COORD_REVERSE[] = {
-1.0f, 1.0f,
1.0f, 1.0f,
-1.0f, -1.0f,
1.0f, -1.0f,
};
// 纹理坐标系
static final float TEXTURE_COORD_REVERSE[] = {
1.0f,0f,
0.0f,0.0f,
1.0f,1.0f,
0.0f,1.0f
};
private StringmVertexShader;
private StringmFragmentShader;
private FloatBuffermPositionBuffer;
private FloatBuffermTextureCubeBuffer;
protected int mProgId;
protected int mPosition;
protected int inputTextureBuffer;
protected int mInputTexture;
public ImageFilter(Context context) {
this(OpenGLUtils.readRawTextFile(context,R.raw.base_vert), OpenGLUtils.readRawTextFile(context,R.raw.base_frag));
}
public ImageFilter(String vertexShader, String fragmentShader) {
mVertexShader = vertexShader;
mFragmentShader = fragmentShader;
}
public void loadVertex() {
float[] coord =COORD1;
float[] texture_coord =BOOK_COORD1;
mPositionBuffer = ByteBuffer.allocateDirect(coord.length *4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mPositionBuffer.put(coord).position(0);
mTextureCubeBuffer = ByteBuffer.allocateDirect(texture_coord.length *4)
.order(ByteOrder.nativeOrder())
.asFloatBuffer();
mTextureCubeBuffer.put(texture_coord).position(0);
}
public void initShader() {
mProgId = OpenGLUtils.loadProgram(mVertexShader, mFragmentShader);
mPosition = GLES20.glGetAttribLocation(mProgId, "position");
mInputTexture = GLES20.glGetUniformLocation(mProgId, "inputImageTexture");
inputTextureBuffer = GLES20.glGetAttribLocation(mProgId,
"inputTextureCoordinate");
}
public int init(Bitmap bitmap) {
loadVertex();
initShader();
GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ONE_MINUS_SRC_ALPHA);
return initTexture(bitmap);
}
private int initTexture( Bitmap bitmap) {
int[] textures =new int[1];
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
return textures[0];
}
public void drawFrame(int glTextureId) {
GLES20.glUseProgram(mProgId);
mPositionBuffer.position(0);
GLES20.glVertexAttribPointer(mPosition, 2, GLES20.GL_FLOAT, false, 0, mPositionBuffer);
GLES20.glEnableVertexAttribArray(mPosition);
mTextureCubeBuffer.position(0);
GLES20.glVertexAttribPointer(inputTextureBuffer, 2, GLES20.GL_FLOAT, false, 0,
mTextureCubeBuffer);
GLES20.glEnableVertexAttribArray(inputTextureBuffer);
GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, glTextureId);
GLES20.glUniform1i(mInputTexture, 0);
// 这句话 来进行渲染
GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
GLES20.glDisableVertexAttribArray(mPosition);
GLES20.glDisableVertexAttribArray(inputTextureBuffer);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, 0);
GLES20.glDisable(GLES20.GL_BLEND);
}
}
public class MainActivityextends AppCompatActivity {
private GLSurfaceViewmSurfaceView;
private int mTextureId =-1;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ViewGroup container = (ViewGroup) findViewById(R.id.main);
mSurfaceView =new GLSurfaceView(this);
mSurfaceView.setEGLContextClientVersion(2);
container.addView(mSurfaceView);
final Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.demo);
final ImageFilter filter =new ImageFilter(this);
mSurfaceView.setRenderer(new GLSurfaceView.Renderer() {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
mTextureId =filter.init(bitmap);
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
GLES20.glViewport(0, 0, width, height);
}
@Override
public void onDrawFrame(GL10 gl) {
filter.drawFrame(mTextureId);
}
});
}
}
public class OpenGLUtils {
private static final StringTAG ="OpenGLUtils";
public static final float[]VERTEX = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f
};
public static final float[]TEXURE = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
public static final float[]TEXTURE_NO_ROTATION = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
public static void glGenTextures(int[] textures) {
GLES20.glGenTextures(textures.length, textures, 0);
for (int i =0; i < textures.length; i++) {
//与摄像头不同,摄像头是外部纹理external oes
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[i]);
/**
* 必须:设置纹理过滤参数设置
*/
/*设置纹理缩放过滤*/
// GL_NEAREST: 使用纹理中坐标最接近的一个像素的颜色作为需要绘制的像素颜色
// GL_LINEAR: 使用纹理中坐标最接近的若干个颜色,通过加权平均算法得到需要绘制的像素颜色
// 后者速度较慢,但视觉效果好
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
GLES20.GL_LINEAR);//放大过滤
GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
GLES20.GL_LINEAR);//缩小过滤
/**
* 可选:设置纹理环绕方向
*/
//纹理坐标的范围是0-1。超出这一范围的坐标将被OpenGL根据GL_TEXTURE_WRAP参数的值进行处理
//GL_TEXTURE_WRAP_S, GL_TEXTURE_WRAP_T 分别为x,y方向。
//GL_REPEAT:平铺
//GL_MIRRORED_REPEAT: 纹理坐标是奇数时使用镜像平铺
//GL_CLAMP_TO_EDGE: 坐标超出部分被截取成0、1,边缘拉伸
// GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S,
// GLES20.GL_CLAMP_TO_EDGE);
// GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T,
// GLES20.GL_CLAMP_TO_EDGE);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D,0);
}
}
public static StringreadRawTextFile(Context context, int rawId) {
InputStream is = context.getResources().openRawResource(rawId);
BufferedReader br =new BufferedReader(new InputStreamReader(is));
String line;
StringBuilder sb =new StringBuilder();
try {
while ((line = br.readLine()) !=null) {
sb.append(line);
sb.append("\n");
}
}catch (Exception e) {
e.printStackTrace();
}
try {
br.close();
}catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
}
public static int loadProgram(String vSource, String fSource) {
/**
* 顶点着色器
*/
int vShader = GLES20.glCreateShader(GLES20.GL_VERTEX_SHADER);
//加载着色器代码
GLES20.glShaderSource(vShader, vSource);
//编译(配置)
GLES20.glCompileShader(vShader);
//查看配置 是否成功
int[] status =new int[1];
GLES20.glGetShaderiv(vShader, GLES20.GL_COMPILE_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
//失败
throw new IllegalStateException("load vertex shader:" + GLES20.glGetShaderInfoLog
(vShader));
}
/**
* 片元着色器
* 流程和上面一样
*/
int fShader = GLES20.glCreateShader(GLES20.GL_FRAGMENT_SHADER);
//加载着色器代码
GLES20.glShaderSource(fShader, fSource);
//编译(配置)
GLES20.glCompileShader(fShader);
//查看配置 是否成功
GLES20.glGetShaderiv(fShader, GLES20.GL_COMPILE_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
//失败
throw new IllegalStateException("load fragment shader:" + GLES20.glGetShaderInfoLog
(vShader));
}
/**
* 创建着色器程序
*/
int program = GLES20.glCreateProgram();
//绑定顶点和片元
GLES20.glAttachShader(program, vShader);
GLES20.glAttachShader(program, fShader);
//链接着色器程序
GLES20.glLinkProgram(program);
//获得状态
GLES20.glGetProgramiv(program, GLES20.GL_LINK_STATUS, status, 0);
if (status[0] != GLES20.GL_TRUE) {
throw new IllegalStateException("link program:" + GLES20.glGetProgramInfoLog(program));
}
GLES20.glDeleteShader(vShader);
GLES20.glDeleteShader(fShader);
return program;
}
public static void copyAssets2SdCard(Context context, String src, String dst) {
try {
File file =new File(dst);
if (!file.exists()) {
InputStream is = context.getAssets().open(src);
FileOutputStream fos =new FileOutputStream(file);
int len;
byte[] buffer =new byte[2048];
while ((len = is.read(buffer)) != -1) {
fos.write(buffer, 0, len);
}
is.close();
fos.close();
}
}catch (IOException e) {
e.printStackTrace();
}
}
public static final int NO_TEXTURE = -1;
public static int loadShader(String shaderStr, int type) {
int[] compiled =new int[1];
int iShader = GLES20.glCreateShader(type);
checkGlError("");
GLES20.glShaderSource(iShader, shaderStr);
checkGlError("");
GLES20.glCompileShader(iShader);
checkGlError("");
GLES20.glGetShaderiv(iShader, GLES20.GL_COMPILE_STATUS, compiled, 0);
checkGlError("");
if (compiled[0] ==0) {
Log.d("Load Shader Failed", "Compilation\n" + GLES20.glGetShaderInfoLog(iShader));
return 0;
}
return iShader;
}
public static int loadTexture(final Bitmap bitmap, final int usedTextureId) {
int[] textures =new int[1];
if (usedTextureId ==NO_TEXTURE) {
GLES20.glGenTextures(1, textures, 0);
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textures[0]);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER, GLES20.GL_LINEAR);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_CLAMP_TO_EDGE);
GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_CLAMP_TO_EDGE);
GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, bitmap, 0);
}else {
GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, usedTextureId);
GLUtils.texSubImage2D(GLES20.GL_TEXTURE_2D, 0, 0, 0, bitmap);
textures[0] = usedTextureId;
}
return textures[0];
}
public static void checkGlError(String op) {
int error;
while ((error = GLES20.glGetError()) != GLES20.GL_NO_ERROR) {
Log.e("GLES20_ERROR", op +": glError " + error);
throw new RuntimeException(op +": glError " + error);
}
}
}
varying highp vec2 textureCoordinate;
uniform sampler2D inputImageTexture;
//片元 纹理坐标系2
void main(){
gl_FragColor = texture2D(inputImageTexture, textureCoordinate);
}
attribute vec4 position;
attribute vec4 inputTextureCoordinate;
varying vec2 textureCoordinate;
void main(){
//内置变量: 把坐标点赋值给gl_position 就Ok了。 4 个元素 gl_Position 世界坐标系 为基础
gl_Position = position;
textureCoordinate = inputTextureCoordinate.xy;
}