Guest User

Untitled

a guest
Dec 11th, 2018
83
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.48 KB | None | 0 0
  1. package the.dreams.wind.blendingfilter;
  2.  
  3. import android.content.Context;
  4. import android.graphics.Bitmap;
  5. import android.opengl.GLES20;
  6. import android.opengl.GLException;
  7. import android.opengl.GLSurfaceView;
  8. import android.opengl.GLUtils;
  9. import android.support.annotation.NonNull;
  10. import android.view.WindowManager;
  11.  
  12. import java.lang.ref.WeakReference;
  13. import java.nio.ByteBuffer;
  14. import java.nio.ByteOrder;
  15. import java.nio.FloatBuffer;
  16. import java.util.Objects;
  17.  
  18. import javax.microedition.khronos.egl.EGLConfig;
  19. import javax.microedition.khronos.opengles.GL10;
  20.  
  21. class BlendingFilterRenderer implements GLSurfaceView.Renderer {
  22. @NonNull
  23. private final Bitmap mBitmap;
  24. @NonNull
  25. private final WeakReference<GLSurfaceView> mHostViewReference;
  26. @NonNull
  27. private final float[] mColorFilter;
  28. @NonNull
  29. private final BlendingFilterUtil.Callback mCallback;
  30. private boolean mFinished = false;
  31.  
  32. // ========================================== //
  33. // Lifecycle
  34. // ========================================== //
  35.  
  36. BlendingFilterRenderer(@NonNull GLSurfaceView hostView, @NonNull Bitmap bitmap,
  37. @NonNull float[] colorFilter,
  38. @NonNull BlendingFilterUtil.Callback callback)
  39. throws IllegalArgumentException {
  40. if (colorFilter.length != 4 * 5) {
  41. throw new IllegalArgumentException("Color filter should be a 4 x 5 matrix");
  42. }
  43. mBitmap = bitmap;
  44. mHostViewReference = new WeakReference<>(hostView);
  45. mColorFilter = colorFilter;
  46. mCallback = callback;
  47. }
  48.  
  49. // ========================================== //
  50. // GLSurfaceView.Renderer
  51. // ========================================== //
  52.  
  53. @Override
  54. public void onSurfaceCreated(GL10 gl, EGLConfig config) {
  55. GLES20.glEnable(GLES20.GL_BLEND);
  56. GLES20.glBlendFunc(GLES20.GL_ONE, GLES20.GL_ZERO);
  57. }
  58.  
  59. @Override
  60. public void onSurfaceChanged(GL10 gl, int width, int height) {
  61. GLES20.glViewport(0, 0, width, height);
  62. final int program = loadProgram();
  63. GLES20.glUseProgram(program);
  64. initVertices(program);
  65. attachTexture(program);
  66. attachColorFilter(program);
  67. }
  68.  
  69. @Override
  70. public void onDrawFrame(GL10 gl) {
  71. GLES20.glClear(GLES20.GL_COLOR_BUFFER_BIT);
  72. GLES20.glDrawArrays(GLES20.GL_TRIANGLE_STRIP, 0, 4);
  73. postResult();
  74. }
  75.  
  76. // ========================================== //
  77. // Private
  78. // ========================================== //
  79.  
  80. private int loadShader(int type, String shaderCode) throws GLException {
  81. int reference = GLES20.glCreateShader(type);
  82. GLES20.glShaderSource(reference, shaderCode);
  83. GLES20.glCompileShader(reference);
  84. int[] compileStatus = new int[1];
  85. GLES20.glGetShaderiv(reference, GLES20.GL_COMPILE_STATUS, compileStatus, 0);
  86. if (compileStatus[0] != GLES20.GL_TRUE) {
  87. GLES20.glDeleteShader(reference);
  88. final String message = GLES20.glGetShaderInfoLog(reference);
  89. throw new GLException(compileStatus[0], message);
  90. }
  91.  
  92. return reference;
  93. }
  94.  
  95. private int loadProgram() {
  96. int fragmentShader = loadShader(GLES20.GL_FRAGMENT_SHADER, "precision mediump float;" +
  97. "struct ColorFilter {" +
  98. " mat4 factor;" +
  99. " vec4 shift;" +
  100. "};" +
  101. "uniform sampler2D uSampler;" +
  102. "uniform ColorFilter uColorFilter;" +
  103. "varying vec2 vTextureCoord;" +
  104. "void main() {" +
  105. " vec4 originalColor = texture2D(uSampler, vTextureCoord);" +
  106. " originalColor.rgb *= originalColor.a;" +
  107. " vec4 filteredColor = (originalColor * uColorFilter.factor) + uColorFilter.shift;" +
  108. " filteredColor.rgb *= filteredColor.a;" +
  109. " gl_FragColor = vec4(originalColor.rgb - filteredColor.rgb, originalColor.a);" +
  110. "}");
  111. int vertexShader = loadShader(GLES20.GL_VERTEX_SHADER, "attribute vec2 aPosition;" +
  112. "attribute vec2 aTextureCoord;" +
  113. "varying vec2 vTextureCoord;" +
  114. "void main() {" +
  115. " gl_Position = vec4(aPosition.x, aPosition.y, 0.0, 1.0);" +
  116. " vTextureCoord = aTextureCoord;"+
  117. "}");
  118. int programReference = GLES20.glCreateProgram();
  119. GLES20.glAttachShader(programReference, vertexShader);
  120. GLES20.glAttachShader(programReference, fragmentShader);
  121. GLES20.glLinkProgram(programReference);
  122. return programReference;
  123. }
  124.  
  125. private FloatBuffer convertToBuffer(float[] array) {
  126. final ByteBuffer buffer = ByteBuffer.allocateDirect(array.length * PrimitiveSizes.FLOAT);
  127. FloatBuffer output = buffer.order(ByteOrder.nativeOrder()).asFloatBuffer();
  128. output.put(array);
  129. output.position(0);
  130. return output;
  131. }
  132.  
  133. private void initVertices(int programReference) {
  134. // for GL the texture coordinates are flipped vertically, but it doesn't matter for the
  135. // purpose of this utility, as we should return the image back to the android coordinate
  136. // system in the end
  137. createVerticesBuffer(new float[] {
  138. //NDCS coords //UV map
  139. -1, 1, 0, 1,
  140. -1, -1, 0, 0,
  141. 1, 1, 1, 1,
  142. 1, -1, 1, 0
  143. });
  144. final int stride = 4 * PrimitiveSizes.FLOAT;
  145. enableVertexAttribute(programReference, "aPosition", 2, stride, 0);
  146. enableVertexAttribute(programReference, "aTextureCoord", 2, stride,
  147. 2 * PrimitiveSizes.FLOAT);
  148. }
  149.  
  150. private void attachTexture(int programReference) {
  151. final int[] textures = new int[1];
  152. GLES20.glGenTextures(1, textures, 0);
  153. final int textureId = textures[0];
  154. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
  155. GLES20.glPixelStorei(GLES20.GL_UNPACK_ALIGNMENT, 1);
  156. GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MIN_FILTER,
  157. GLES20.GL_NEAREST);
  158. GLES20.glTexParameterf(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_MAG_FILTER,
  159. GLES20.GL_NEAREST);
  160. GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_S, GLES20.GL_REPEAT);
  161. GLES20.glTexParameteri(GLES20.GL_TEXTURE_2D, GLES20.GL_TEXTURE_WRAP_T, GLES20.GL_REPEAT);
  162. GLUtils.texImage2D(GLES20.GL_TEXTURE_2D, 0, mBitmap, 0);
  163. GLES20.glActiveTexture(GLES20.GL_TEXTURE0);
  164. GLES20.glBindTexture(GLES20.GL_TEXTURE_2D, textureId);
  165. final int samplerLocation = GLES20.glGetUniformLocation(programReference, "uSampler");
  166. GLES20.glUniform1i(samplerLocation, 0);
  167. }
  168.  
  169. private void attachColorFilter(int program) {
  170. final float[] colorFilterFactor = new float[4 * 4];
  171. final float[] colorFilterShift = new float[4];
  172. for (int i = 0; i < mColorFilter.length; i++) {
  173. final float value = mColorFilter[i];
  174. final int calculateIndex = i + 1;
  175. if (calculateIndex % 5 == 0) {
  176. colorFilterShift[calculateIndex / 5 - 1] = value / 255;
  177. } else {
  178. colorFilterFactor[i - calculateIndex / 5] = value;
  179. }
  180. }
  181. final int colorFactorLocation = GLES20.glGetUniformLocation(program,
  182. "uColorFilter.factor");
  183. GLES20.glUniformMatrix4fv(
  184. colorFactorLocation, 1, false, colorFilterFactor, 0
  185. );
  186. final int colorShiftLocation = GLES20.glGetUniformLocation(program,
  187. "uColorFilter.shift");
  188. GLES20.glUniform4fv(
  189. colorShiftLocation, 1, colorFilterShift, 0
  190. );
  191. }
  192.  
  193. private void createVerticesBuffer(float[] verticesData) {
  194. final int verticesBuffer = createGlBuffer();
  195. GLES20.glBindBuffer(GLES20.GL_ARRAY_BUFFER, verticesBuffer);
  196. GLES20.glBufferData(GLES20.GL_ARRAY_BUFFER, verticesData.length * PrimitiveSizes.FLOAT,
  197. convertToBuffer(verticesData), GLES20.GL_STREAM_DRAW);
  198. }
  199.  
  200. private int createGlBuffer() {
  201. int buffers[] = new int[1];
  202. GLES20.glGenBuffers(1, buffers, 0);
  203. return buffers[0];
  204. }
  205.  
  206. @SuppressWarnings("SameParameterValue")
  207. private void enableVertexAttribute(int program, String attributeName, int size, int stride,
  208. int offset) {
  209. final int attributeLocation = GLES20.glGetAttribLocation(program, attributeName);
  210. GLES20.glVertexAttribPointer(attributeLocation, size, GLES20.GL_FLOAT, false,
  211. stride, offset);
  212. GLES20.glEnableVertexAttribArray(attributeLocation);
  213. }
  214.  
  215. private Bitmap retrieveBitmapFromGl(int width, int height) {
  216. final ByteBuffer pixelBuffer = ByteBuffer.allocateDirect(width * height *
  217. PrimitiveSizes.FLOAT);
  218. pixelBuffer.order(ByteOrder.LITTLE_ENDIAN);
  219. GLES20.glReadPixels(0,0, width, height, GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE,
  220. pixelBuffer);
  221. final Bitmap image = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
  222. image.copyPixelsFromBuffer(pixelBuffer);
  223. return image;
  224. }
  225.  
  226. private GLException getGlError() {
  227. int errorValue = GLES20.glGetError();
  228. switch (errorValue) {
  229. case GLES20.GL_NO_ERROR:
  230. return null;
  231. default:
  232. return new GLException(errorValue);
  233. }
  234. }
  235.  
  236. private void postResult() {
  237. if (mFinished) {
  238. return;
  239. }
  240. final GLSurfaceView hostView = mHostViewReference.get();
  241. if (hostView == null) {
  242. return;
  243. }
  244. GLException glError = getGlError();
  245. if (glError != null) {
  246. hostView.post(() -> {
  247. mCallback.onFailure(glError);
  248. removeHostView(hostView);
  249. });
  250. } else {
  251. final Bitmap result = retrieveBitmapFromGl(mBitmap.getWidth(), mBitmap.getHeight());
  252. hostView.post(() -> {
  253. mCallback.onSuccess(result);
  254. removeHostView(hostView);
  255. });
  256. }
  257. mFinished = true;
  258. }
  259.  
  260. private void removeHostView(@NonNull GLSurfaceView hostView) {
  261. if (hostView.getParent() == null) {
  262. return;
  263. }
  264. final WindowManager windowManager = (WindowManager) hostView.getContext()
  265. .getSystemService(Context.WINDOW_SERVICE);
  266. Objects.requireNonNull(windowManager).removeView(hostView);
  267. }
  268. }
Add Comment
Please, Sign In to add comment